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为空不显示
尝试修改U盘的UUID和LABEL为路径穿越实现触发漏洞
由于UUID无法设置为带“.”的字符,考虑将UUID置空,这样mountdir将使用LABLE
由于USB挂载后将会先执行logger,考虑将将get shell需要的都丢U盘中作为/usr/bin,加执行权限
由于原设备/usr/bin将被劫持为U盘,避免反弹shell后无命令可用的情况,故考虑将原设备的/usr/bin拷贝一份放U盘里就行
准备完毕后卸载U盘
开启监听,成功获取另外一台主机上模拟出来的车机环境,触发漏洞劫持/usr/bin反弹shell