分享
 
 
 

apache的..%5c漏洞原因源代码分析

王朝厨房·作者佚名  2007-01-05
窄屏简体版  字體: |||超大  

我们来看看apache出错原因。

下面是源代码 src\main\http_request.c: 的处理请求的代码:

static void process_request_internal(request_rec *r)

{

int access_status;

/* Ignore embedded %2F's in path for proxy requests */

if (r->proxyreq == NOT_PROXY && r->parsed_uri.path) {

/* 如果不是代理 */

access_status = ap_unescape_url(r->parsed_uri.path);

/* 解码%,rfc要求 */

if (access_status) {

ap_die(access_status, r);

return;

}

}

ap_getparents(r->uri); /* OK --- shrinking transformations... */

/* 处理/../,出错,没考虑windows下面的\..\ */

if ((access_status = location_walk(r))) {

ap_die(access_status, r);

return;

}

if ((access_status = ap_translate_name(r))) {

decl_die(access_status, "translate", r);

return;

}

if (r->proxyreq == NOT_PROXY) {

/*

* We don't want TRACE to run through the normal handler set, we

* handle it specially.

*/

if (r->method_number == M_TRACE) {

if ((access_status = ap_send_http_trace(r)))

ap_die(access_status, r);

else

ap_finalize_request_protocol(r);

return;

}

}

if (r->proto_num > HTTP_VERSION(1,0) && ap_table_get(r->subprocess_env, "downgrade-1.0")) {

r->proto_num = HTTP_VERSION(1,0);

}

/*

* NB: directory_walk() clears the per_dir_config, so we don't inherit

* from location_walk() above

*/

if ((access_status = directory_walk(r))) {

ap_die(access_status, r);

return;

}

if ((access_status = file_walk(r))) {

ap_die(access_status, r);

return;

}

if ((access_status = location_walk(r))) {

ap_die(access_status, r);

return;

}

if ((access_status = ap_header_parse(r))) {

ap_die(access_status, r);

return;

}

switch (ap_satisfies(r)) {

case SATISFY_ALL:

case SATISFY_NOSPEC:

if ((access_status = ap_check_access(r)) != 0) {

decl_die(access_status, "check access", r);

return;

}

if (ap_some_auth_required(r)) {

if (((access_status = ap_check_user_id(r)) != 0) || !ap_auth_type(r)) {

decl_die(access_status, ap_auth_type(r)

? "check user. No user file?"

: "perform authentication. AuthType not set!", r);

return;

}

if (((access_status = ap_check_auth(r)) != 0) || !ap_auth_type(r)) {

decl_die(access_status, ap_auth_type(r)

? "check access. No groups file?"

: "perform authentication. AuthType not set!", r);

return;

}

}

break;

case SATISFY_ANY:

if (((access_status = ap_check_access(r)) != 0) || !ap_auth_type(r)) {

if (!ap_some_auth_required(r)) {

decl_die(access_status ? access_status :

HTTP_INTERNAL_SERVER_ERROR,

ap_auth_type(r) ? "check access"

: "perform authentication. AuthType not set!", r);

return;

}

if (((access_status = ap_check_user_id(r)) != 0) || !ap_auth_type(r)) {

decl_die(access_status, ap_auth_type(r)

? "check user. No user file?"

: "perform authentication. AuthType not set!", r);

return;

}

if (((access_status = ap_check_auth(r)) != 0) || !ap_auth_type(r)) {

decl_die(access_status, ap_auth_type(r)

? "check access. No groups file?"

: "perform authentication. AuthType not set!", r);

return;

}

}

break;

}

if (! (r->proxyreq != NOT_PROXY

&& r->parsed_uri.scheme != NULL

&& strcmp(r->parsed_uri.scheme, "http") == 0) ) {

if ((access_status = ap_find_types(r)) != 0) {

decl_die(access_status, "find types", r);

return;

}

}

if ((access_status = ap_run_fixups(r)) != 0) {

ap_die(access_status, r);

return;

}

if ((access_status = ap_invoke_handler(r)) != 0) {

ap_die(access_status, r);

return;

}

/* Take care of little things that need to happen when we're done */

ap_finalize_request_protocol(r);

}

下面是源代码 src\main\util.c 处理/../的代码:

API_EXPORT(void) ap_getparents(char *name)

{

int l, w;

/* Four paseses, as per RFC 1808 */

/* a) remove ./ path segments */

for (l = 0, w = 0; name[l] != '\0';) {

if (name[l] == '.' && name[l + 1] == '/' && (l == 0 || name[l - 1] == '/'))

l += 2;

else

name[w++] = name[l++];

}

/* b) remove trailing . path, segment */

if (w == 1 && name[0] == '.')

w--;

else if (w > 1 && name[w - 1] == '.' && name[w - 2] == '/')

w--;

name[w] = '\0';

/* c) remove all xx/../ segments. (including leading ../ and /../) */

l = 0;

while (name[l] != '\0') {

if (name[l] == '.' && name[l + 1] == '.' && name[l + 2] == '/' &&

(l == 0 || name[l - 1] == '/')) {

register int m = l + 3, n;

l = l - 2;

if (l >= 0) {

while (l >= 0 && name[l] != '/')

l--;

l++;

}

else

l = 0;

n = l;

while ((name[n] = name[m]))

(++n, ++m);

}

else

++l;

}

/* d) remove trailing xx/.. segment. */

if (l == 2 && name[0] == '.' && name[1] == '.')

name[0] = '\0';

else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.' && name[l - 3] == '/') {

l = l - 4;

if (l >= 0) {

while (l >= 0 && name[l] != '/')

l--;

l++;

}

else

l = 0;

name[l] = '\0';

}

}

大家看到了,显然没有考虑windows下面的“\..\”,看来编写这个函数的人不熟悉WINDOWS的特性,是个长期在*UNIX下面编程的人员。其实没考虑WINDOWS下面的“\..\”已经出过很多问题的了。那为什么直接telnet 用“\..\”不行呢?看来在解码之前把所有“\”替换成了“/”。显然这个转换是该在解码之后,估计上面没有检测“\..\”的原因就是认为先已经转换了,这个就与IIS的%c1%1c漏洞一样。照这样就一定得注意如果有什么编码、解码的,一定得重新考虑前面的一些检测,因为弄不好就能重新编码出不符合前面检测的东西来。

看这是源代码 src\main\http_protocol.c 中将URI中的“\”转化成“/”的处理模块:

/* parse_uri: break apart the uri

* Side Effects:

* - sets r->args to rest after '?' (or NULL if no '?')

* - sets r->uri to request uri (without r->args part)

* - sets r->hostname (if not set already) from request (scheme://host:port)

*/

CORE_EXPORT(void) ap_parse_uri(request_rec *r, const char *uri)

{

int status = HTTP_OK;

r->unparsed_uri = ap_pstrdup(r->pool, uri);

if (r->method_number == M_CONNECT) {

status = ap_parse_hostinfo_components(r->pool, uri, &r->parsed_uri);

} else {

/* Simple syntax Errors in URLs are trapped by parse_uri_components(). */

status = ap_parse_uri_components(r->pool, uri, &r->parsed_uri);

}

if (ap_is_HTTP_SUCCESS(status)) {

/* if it has a scheme we may need to do absoluteURI vhost stuff */

if (r->parsed_uri.scheme

&& !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))) {

r->hostname = r->parsed_uri.hostname;

} else if (r->method_number == M_CONNECT) {

r->hostname = r->parsed_uri.hostname;

}

r->args = r->parsed_uri.query;

r->uri = r->parsed_uri.path ? r->parsed_uri.path

: ap_pstrdup(r->pool, "/");

#if defined(OS2) || defined(WIN32)

/* Handle path translations for OS/2 and plug security hole.

* This will prevent "http://www.wherever.com/..\..\/" from

* returning a directory for the root drive.

*/

{

char *x;

for (x = r->uri; (x = strchr(x, '\\')) != NULL; )

*x = '/';

/* \转换成/ */

}

#endif /* OS2 || WIN32 */

}

else {

r->args = NULL;

r->hostname = NULL;

r->status = status; /* set error status */

r->uri = ap_pstrdup(r->pool, uri);

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有