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

CVE-2019-0211 Apache提权漏洞分析

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


简介
从2.4.17(2015年10月9日)到2.4.38(2019年4月1日)的Apache HTTP版本中,存在着一个可以通过数组越界调用任意构造函数的提权漏洞。这个漏洞可以通过重新启动Apache服务(apache2ctl graceful)来触发。在Linux默认配置中,每天会在早上6点25分自动运行一次该命令,从而重启日志文件的处理任务。
该漏洞涉及到三个函数mod_prefork,mod_worker和mod_event。后面的漏洞描述,分析和触发都主要从mod_prefork展开。
漏洞描述
在MPM prefork模式下,服务器主进程会运行在root权限下,管理一个单线程的进程池。低权限(www-data)的Worker进程处理HTTP请求头。Apache通过共享包含有scoreboard(包含诸如PID、请求等Worker进程信息)的共享内存空间(SHM)来处理worker进程返回的信息。每一个Worker进程都对应一个关联自身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
 
PID19447的Worker进程的共享内存空间
(gdb) p ap_scoreboard_image->parent[0]
$6 = {
  pid = 19447,
  generation = 0,
  quiescing = 0 '00',
  not_accepting = 0 '00',
  connections = 0,
  write_completion = 0,
  lingering_close = 0,
  keep_alive = 0,
  suspended = 0,
  bucket = 0 index for all_buckets
}
(gdb) ptype *ap_scoreboard_image->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; index for all_buckets
}
当Apache重启的时候,它的主进程会关闭旧的Worker进程并生成新的来替换掉。在这里主进程会用all_bucket这一函数来使用所有旧的Worker进程占用的bucket(内存空间)值。
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; apr_proc_mutex_t
apr_proc_mutex_t {
    apr_pool_t *pool;
    const apr_proc_mutex_unix_lock_methods_t *meth; int curr_locked;
    char *fname;
    ...
}
(gdb) ptype apr_proc_mutex_unix_lock_methods_t
apr_proc_mutex_unix_lock_methods_t {
    ...
    apr_status_t (*child_init)(apr_proc_mutex_t **, apr_pool_t *, const char *);
这里没有进行边界检查,也就是说任意一个Worker进程都可以改变自身bucket的值来指向共享内存区域,从而在重启的时候控制prefork_child_bucket函数的结构。最终在权限恢复之前,通过mutex->meth->child_init()这一调用过程,实现暂时以root权限调用函数。
存在风险的代码区域
理一遍server/mpm/prefork/prefork.c来看下是什么地方导致了这一漏洞。
(译者注:L数字代表该文件中对应的代码行数)
一个恶意的Worker进程改变自身共享内存中自身的bucket的值,从而指向共享内存空间。
在第二天的早上6.25分,logrotate请求Apache重启一次服务。
之后Apache主进程会关闭第一个Worker进程,生成新的Worker级才能哼。
这个过程是通过发送SIGUSR1信号给Worker进程来实现的,Worker进程收到信号后会立刻退出。
然后调用prefork_run()(L853)函数来生成新的Worker进程。由于存在retained->mpm->was_graceful这一过程,Worker进程不会立刻重启。
在进入主循环(L933)并监控旧的Worker进程的PID,可以看到旧的Worker进程关闭后,ap_wait_or_timeout()函数会返回它PID的值(L940)
process_score的index值以及PID值会存储在child_slot(L948)中
如果删除旧的Worker进程没有报错(L969)的话,make_child()函数会调用ap_get_scoreboard_process(child_slot)->buctet的值作为参数(L985),正如之前提到的一样,bucket的值已经被恶意Worker给修改了。
make_child()函数会fork(L671)主进程来生成新的子进程。
OOB会读取(L691)发生的过程,导致my_bucket函数遭到攻击者的控制。
child_main()函数会调用(L722),相比(L433)处更快调用函数。
SAFE_ACCEPT()只有在Apache监听两个或更多的端口时执行,一般来说服务器通常监听着HTTP(80)和HTTPS(443)
假设成功执行,会调用apr_proc_mutex_child_init()函数,从而通过(*mutex)->meth->child_init(mutex, pool, fname)的调用过程来控制互斥锁。
在执行完(L446)后权限恢复到正常的低权限。
 
利用过程:
利用过程包括四个步骤:1、获取Worker进程的读写权限.2、向共享内存空间(SHM)写入一个假的prefork_child_bucket结构。3、将all_bucket[bucket]指向结构。4、等待构造的函数被调用。

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

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