U盘路径穿越漏洞复现
2025-02-12 15:03:57

U盘路径穿越漏洞复现

参考链接:

https://delikely.eu.org/2021/06/04/U%E7%9B%98%E7%9B%AE%E5%BD%95%E7%A9%BF%E8%B6%8A%E8%8E%B7%E5%8F%96%E8%BD%A6%E6%9C%BASHELL/
https://www.cnblogs.com/Cl0ud/p/17643514.html
https://github.com/ea/bosch_headunit_root

模拟环境

https://github.com/delikely/DVVA.git

sudo docker build -t delikely/bosch_headunit_root:automount .
sudo docker run -itd --privileged=true --name bosch_headunit_root  delikely/bosch_headunit_root:automount
#通过--privileged参数将使用特权模式运行容器,容器内的进程将具有与主机相同的权限,包括挂载文件系统等

漏洞成因

在Linux中,提供一个名为 udev 的驱动管理库,专门用于管理外设的加载、卸载以及状态更新。它通过初始化设备、读取驱动器信息并通知内核来实现热插拔功能。相关配置文件存放于/etc/udev,udev

在车机模拟环境中,自定义了U盘挂载脚本,于udev配置文件/etc/udev/local.rules指定了block设备由脚本/etc/udev/scripts/mount.sh处理:

/etc/udev/local.rules:

SUBSYSTEM=="block", ACTION=="add",    KERNEL=="sd*", ENV{ID_FS_TYPE}=="?*", \
		    ENV{DKD_PARTITION_TABLE}!="1", \
		    ENV{DKD_PRESENTATION_HIDE}!="1", \
		    RUN+="/etc/udev/scripts/mount.sh", RUN+="/etc/udev/scripts/trace_proxy.sh"
SUBSYSTEM=="block", ACTION=="remove", KERNEL=="sd*", ENV{ID_FS_TYPE}=="?*", RUN+="/etc/udev/scripts/mount.sh", RUN+="/etc/udev/scripts/trace_proxy.sh"
SUBSYSTEM=="block", ACTION=="change", KERNEL=="sd*", ENV{DEVTYPE}=="disk",  RUN+="/etc/udev/scripts/mount.sh"

SUBSYSTEM=="block", ACTION=="add",    KERNEL=="mmcblk[1-7]p*", ENV{DKD_PRESENTATION_HIDE}!="1", RUN+="/etc/udev/scripts/mount.sh"
SUBSYSTEM=="block", ACTION=="remove", KERNEL=="mmcblk[1-7]p*", RUN+="/etc/udev/scripts/mount.sh"

/etc/udev/scripts/mount.sh:漏洞所在点

#自动挂载函数
automount() {
    if [ -z "${ID_FS_TYPE}" ]; then #判断设备类型
	logger -p user.err "mount.sh/automount" "$DEVNAME has no filesystem, not mounting"
	return
    fi

    # Determine the name for the mount point.  First check for the
    # uuid, then for the label and then for a unique name.
    #使用设备的UUID或者LABLE(没有UUID情况)作为mountdir
    if [ -n "${ID_FS_UUID}" ]; then  
	mountdir=${ID_FS_UUID}
    elif [ -n "${ID_FS_LABEL}" ]; then
	mountdir=${ID_FS_LABEL}
    else
	mountdir="disk"
	while [ -d $MOUNTPT/$mountdir ]; do
	    mountdir="${mountdir}_"
	done
    fi

    # Create the mount point.
    #拼接作为最终挂载点
    ! test -d "$MOUNTPT/$mountdir" && mkdir -p "$MOUNTPT/$mountdir"

    # And mount the disk or partition.
    if [ -n ${ID_FS_TYPE} ]
    then
      if [ "vfat" = ${ID_FS_TYPE} ]
      then
        IOCHARSET=",utf8=1"
      elif [ "ntfs" = ${ID_FS_TYPE} ]
      then
        IOCHARSET=",nls=utf8"
      fi
    fi
    
    #最终挂载,并将所有的输出(包括成功信息和错误信息)保存到 result 变量中。如果挂载成功,result 将包含挂载过程的输出信息;如果挂载失败,result 将包含错误信息。
    result=$($MOUNT -t ${ID_FS_TYPE} -o sync,ro$IOCHARSET $DEVNAME "$MOUNTPT/$mountdir" 2>&1)
    status=$?
    #不管挂载是否成功,都将调用logger命令去记录日志
    if [ ${status} -ne 0 ]; then
	logger -p user.err "mount.sh/automount" "$MOUNT -t ${ID_FS_TYPE} -o sync,ro $DEVNAME \"$MOUNTPT/$mountdir\" failed: ${result}"
	rm_dir "$MOUNTPT/$mountdir"
    else
	logger "mount.sh/automount" "mount [$MOUNTPT/$mountdir] with type ${ID_FS_TYPE} successful"
	mkdir -p ${MOUNTDB}
	echo -n "$MOUNTPT/$mountdir" > "${MOUNTDB}/$devname"
    fi
}

可以看的在脚本中挂载路径为

MOUNTPT="/dev/media"
"$MOUNTPT/$mountdir"

由于没有任何相关合法性检查,可以考虑构造为路径穿越/dev/media/../../../path

而mountdir又使用设备的UUID或者LABLE(没有UUID情况)==》将设备的UUID或LABLE修改为../../path即可实现

挂载不管成功失败都将使用logger记录日志==》劫持挂载路径为/usr/bin,这样就可以劫持logger命令

最终效果==》伪造设备的UUID或LABLE为../../usr/bin,更改logger为[get shell];插入设备,触发路径穿越,设备路径被挂载为/usr/bin,劫持原设备的/usr/bin,设备路径下的logger也将为/usr/bin/logger,脚本文件继续执行,调用劫持后的logger[get shell]命令,成功拿到shell

漏洞利用

插入U盘,需要先将U盘格式化为ext4格式

sudo umount /dev/sdb1 # 必须先卸载该分区

sudo mkfs.ext4 /dev/sdb1  # 格式化为ext4分区

此时U盘格式化为ext4格式,例:可通过blkid查看UUID、LABLE、TYPE等,在属性值为空的情况下默认不显示,此处的LABLE为空不显示

img

尝试修改U盘的UUID和LABEL为路径穿越实现触发漏洞

由于UUID无法设置为带“.”的字符,考虑将UUID置空,这样mountdir将使用LABLE

img

由于USB挂载后将会先执行logger,考虑将将get shell需要的都丢U盘中作为/usr/bin,加执行权限

img

由于原设备/usr/bin将被劫持为U盘,避免反弹shell后无命令可用的情况,故考虑将原设备的/usr/bin拷贝一份放U盘里就行

img

准备完毕后卸载U盘

img

开启监听,成功获取另外一台主机上模拟出来的车机环境,触发漏洞劫持/usr/bin反弹shell

img