点击蓝字
关注我们
声明
本文作者:wendell
本文字数:4099
阅读时长:11min
附件/链接:点击查看原文下载
本文属于【狼组安全社区】原创奖励计划,未经许可禁止转载
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,狼组安全团队以及文章作者不为此承担任何责任。
狼组安全团队有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经狼组安全团队允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。
前言
最近Apache出了不少洞, 但更多的是漏洞局部的分析, 我更想知道这些漏洞在Apache的整体构架的位置,模块之间是如何作用的,导致产生了这样的漏洞,所以 有了这篇分析.
这篇文章,我准备从以下几个问题入手
-
整个Apache的程序结构是什么.
-
个个模块之间是如何影响http处理的
-
如何以宏观的视角分析最近Apache SSRF CVE-2021-40438
Apache整体结构
我们先看一下apache的层次结构,
整个Apache可被划分为四个大层次,
-
可移值运行库(APR)
-
Apache的跨平台特性主要是通过APR来实现的, 例如进程的创建,APR提供了apr_proc_create函数,对上层调用者屏蔽了unix系列的fork,或者win系列的createProcess的不同系统调用的差别,这样apache开发者就不必顾虑操作系统细节
-
Apache核心功能层
-
核心功能层, 包括Apache的一些核心组件和核心模块,核心组件用于实现Apache服务器的基本功能,包括启动Apache, conf处理,接受处理Http连接, mod_core核心模块,进行大部分配置解析,mod_so核心模块负责动态加载其他模块.
-
Apache 可选功能层,
-
一般是一些Apache的可选模块
-
Apache第三方支持库.
核心组件和模块的关系
那么模块是如何发挥作用的呢
一般这中多个模块影响主流程的情况,可以使用hook思想来做, Apache也是这样处理的
那么apache的hook是怎样实现的呢
对Apache核心来说,并没有对核心模块和可选模块的区分,都是通过Hook点进行调用.
我们先看一下Apache如何声明和触发Hook
在http_connection中,通过AP_DECLARE_HOOK宏声明一个handler这样一个hook,这个hook最终是通过下面这样一个宏来实现的
//include/http_connfig.h
AP_DECLARE_HOOK(int,handler,(request_rec *r))
typedef ret ns
link
const char * const *aszPre,
const char * const *aszSucc, int nOrder);
link
APR_IMPLEMENT_HOOK_GET_PROTO(ns,link,name);
typedef struct ns
{
ns
const char *szName;
const char * const *aszPredecessors;
const char * const *aszSuccessors;
int nOrder;
} ns
在Apache中,可以通过 ap_run_hookname(), 例如ap_run_handler(),触发一个hook,
可以看到在apache核心组件中调用了ap_run_handler触发了这个hook,而ap_invoke_handler,又被ap_process_async_request调用,这些都在apache核心组件的请求处理流程中.
#server/config.c
ap_invoke_handler(request_rec *r)
{
...
ap_run_insert_filter(r);
...
result = invoke_filter_init(r, r->input_filters);
if (result != OK) {
return result;
}
result = invoke_filter_init(r, r->output_filters);
....
result = ap_run_handler(r);
对于一个模块来说
static void register_hooks(apr_pool_t *p)
static const char * const aszSucc[] = { "mod_rewrite.c", NULL};
static const char *const aszPred[] = { "mpm_winnt.c", "mod_proxy_balancer.c",
"mod_proxy_hcheck.c", NULL};
...
ap_hook_handler(proxy_handler, NULL, NULL, APR_HOOK_FIRST);
/* filename-to-URI translation */
ap_hook_translate_name(proxy_trans, aszSucc, NULL, APR_HOOK_FIRST);
/* walk <Proxy > entries and suppress default TRACE behavior */
ap_hook_post_read_request(proxy_detect, NULL, NULL, APR_HOOK_FIRST);
...
proxy_util_register_hooks(p);
}
AP_DECLARE_MODULE(proxy) =
{
STANDARD20_MODULE_STUFF,
create_proxy_dir_config, /* create per-directory config structure */
merge_proxy_dir_config, /* merge per-directory config structures */
create_proxy_config, /* create per-server config structure */
merge_proxy_config, /* merge per-server config structures */
proxy_cmds, /* command table */
register_hooks
};
通过AP_DECLARE_MODULE声明一个模块,在register_hooks中通过ap_hook_handler(proxy_handler, NULL, NULL, APR_HOOK_FIRST);将模块自己实现的proxy_handler函数注册进入hook点handler中
这种图列出了一些请求流程中一些常见的hook,
所有hook可以参考这个文档
https://ci.apache.org/projects/httpd/trunk/doxygen/group__hooks.html
apache中也可以自己定义hook,代理模块就,就自定义定义了大量hook
至此,模块如何影响组件已经分析完成了, 其他还是一个关键点指令和配置的解析没有设计,不过他并不影响漏洞的主线,就暂且不分析.
Apache ssrf漏洞分析
我们知道问题产生于
在对r.filename的判断中, 使用了搜索unix:的子串方式,导致可以利用url查询参数伪造,fix_uds_filename被ap_proxy_pre_request调用,进一步回溯,调用者为proxy_handler,正是我们之前分析注册在handler hook点的函数.
static int proxy_handler(request_rec *r)
{
...
/* Try to obtain the most suitable worker */
access_status = ap_proxy_pre_request(&worker, &balancer, r, conf, &url);
...
}
而r.filename来自与哪里呢,
在http.conf配置了反代目的服务器为http服务器后,
proxy_http_canon中进行了r→filename的设置
这里根据反代配置,修正请求地址,并且把查询参数,附加在请求地址后,正是这里为我们引入了可控的查询字符.
proxy_http_canon注册在canon_handler,canon_handler其实是一个mod_proxy声明的一个hook,
在mod_proxy的proxy_fixup中调用了proxy_run_canon_handler,触发了这个hook,
而proxy_fixup正是注册在请求流程的fixups hook中的。
后记
参考资料
http://httpd.apache.org/docs/2.4/en/developer/
https://articles.zsxq.com/id_8fvzqudhj1fm.html
《Apache源代码全景分析》
https://www.leavesongs.com/PENETRATION/apache-mod-proxy-ssrf-cve-2021-40438.html
扫描关注公众号回复加群
和师傅们一起讨论研究~
长
按
关
注
WgpSec狼组安全团队
微信号:wgpsec
Twitter:@wgpsec
原文始发于微信公众号(WgpSec狼组安全团队):从Apache整体结构入手分析Apache CVE-2021-40438