欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

Apache Httpd本地提权漏洞分析(CVE-2019-0211)

来源:本站整理 作者:佚名 时间:2019-04-09 TAG: 我要投稿

一、概述
近日,Apache爆出存在本地权限提升漏洞,该漏洞影响2.4.17(2015年10月9日发布)至2.4.38版本(2019年4月1日),其原因在于越界数组访问导致的任意函数调用,使得Apache HTTP将受到本地root权限提升。在Apache正常重新启动时,将会触发这一漏洞(apache2ctl graceful)。在标准Linux配置中,logrotate实用程序每天上午6:25会运行一次此命令,以便重置日志文件句柄。
该漏洞影响mod_prefork、mod_worker和mod_event。在本文的漏洞分析中,我们所分析的代码和漏洞利用目标均为mod_prefork。
二、漏洞描述
在MPM prefork中,以root身份运行的主服务器进程管理一个单线程、低权限(www-data)的工作进程池,用于处理HTTP请求。为了从工作进程那里获得反馈,Apache维护了一个共享内存区域(SHM)计分板,其中包含各种信息,例如工作进程的PID,以及它们处理的最后一个请求。每个工作进程都以维护与其PID相关联的process_score结构为目标,并且具有对SHM的完全读/写访问权限。
ap_scoreboard_image:指向共享内存块的指针
(gdb) p *ap_scoreboard_image
$3 = {
  global = 0x7f4a9323e008,
  parent = 0x7f4a9323e020,
  servers = 0x55835eddea78
}
(gdb) p ap_scoreboard_image->servers[0]
$5 = (worker_score *) 0x7f4a93240820
与工作进程PID 19447相关联的共享内存示例:
(gdb) p ap_scoreboard_image->parent[0]
$6 = {
  pid = 19447,
  generation = 0,
  quiescing = 0 '\000',
  not_accepting = 0 '\000',
  connections = 0,
  write_completion = 0,
  lingering_close = 0,
  keep_alive = 0,
  suspended = 0,
  bucket = 0 parent
type = struct process_score {
    pid_t pid;
    ap_generation_t generation;
    char quiescing;
    char not_accepting;
    apr_uint32_t connections;
    apr_uint32_t write_completion;
    apr_uint32_t lingering_close;
    apr_uint32_t keep_alive;
    apr_uint32_t suspended;
    int bucket;
当Apache正常重启时,其主进程会杀死旧的Worker,并用新的Worker替换它们。此时,主进程将使用每个旧Worker的Bucket值,来访问他的all_buckets数组。
all_buckets
(gdb) p $index = ap_scoreboard_image->parent[0]->bucket
(gdb) p all_buckets[$index]
$7 = {
  pod = 0x7f19db2c7408,
  listeners = 0x7f19db35e9d0,
  mutex = 0x7f19db2c7550
}
(gdb) ptype all_buckets[$index]
type = struct prefork_child_bucket {
    ap_pod_t *pod;
    ap_listen_rec *listeners;
    apr_proc_mutex_t *mutex;
在这里,并没有发生绑定检查。因此,攻击者的恶意Worker可以更改其Bucket索引,并使其指向共享内存,以便在重新启动时控制prefork_child_bucket结构。最终,在删除权限之前,调用mutex->meth->child_init()。这导致以root身份执行任意函数调用。
三、易受攻击的代码
我们将在server/mpm/prefork/prefork.c中找到漏洞发生的位置和方式。
恶意Worker在共享内存中更改其Bucket索引,使其指向它的结构,也同样在SHM中。
在转天上午的6:25,logrotate请求从Apache正常重启。
在此之后,主要的Apache进程将首先杀死Worker,然后产生新的Worker。
通过向Worker发送SIGUSR1来完成进程的终止,预计可以迅速退出。
然后,调用prefork_run()(L853)来生成新的Worker。由于retained->mpm->was_graceful为True(L861),Worker不会立即重启。
相反,我们进入主循环(L933)并监视被终止Worker的PID。当旧Worker被终止时,ap_wait_or_timeout()返回其PID(L940)。
与此PID相关联的process_score结构的索引存储在child_slot(L948)中。
如果这个Worker被终止,但没有产生致命错误(L969),那么使用ap_get_scoreboard_process(child_slot)->bucket作为第三个参数调用make_child()(L985)。如前所述,一个恶意的Worker改变了Bucket的值。
make_child()创建一个新的子进程,并对主进程进行fork()(L671)。
进行OOB读取(L691),因此my_bucket受到攻击者的控制。
调用child_main()(L722),函数调用在后续还会发生。
如果Apache侦听两个或更多端口,那么SAFE_ACCEPT()将只会执行,这通常是由于服务器侦听HTTP(80端口)和HTTPS(443端口)。
假设被执行,则会调用apr_proc_mutex_child_init(),这将导致调用(*mutex)->meth->child_init(mutex, pool, fname),并且控制互斥锁。
在执行后,特权将会被提升(L446)。
四、漏洞利用
漏洞利用过程分为四个步骤:
1. 获取工作进程中的R/W访问权限。
2. 在SHM中编写伪造的prefork_child_bucket结构。
3. 使all_buckets[bucket]指向结构。
4. 等待早上6:25获取任意函数调用。
其优点在于,主进程永远不会退出,因此我们通过读取/proc/self/maps就可以知道所有内容的映射位置(ASLR和PIE没有作用)。当一个Worker被终止(或发生段错误时),会被主进程自动重启,因此没有对Apache进行DOS的风险。
其问题在于,PHP不允许对/proc/self/mem进行读取/写入,我们无法通过简单地编辑SHM来实现在正常重启后重新分配all_buckets。
1. 获得Worker进程的读取/写入访问权限
(1) PHP UAF 0-day
由于mod_prefork经常与mod_php结合使用,因此通过PHP进行漏洞利用似乎非常自然。CVE-2019-6977是一个完美的备选漏洞,但我在最初开始编写漏洞利用代码时,这个漏洞并没有出现。我在PHP 7.x中使用了一个UAF 0-day漏洞(似乎也适用于PHP 5.x)。

[1] [2] [3]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载