Linux
正常语句:
http://127.0.0.1/a.jpg
攻击语句:
http://127.0.0.1/a.jpg(非编码空格)\0.php
在对url的解析过程中,路径中存在’.’或url存在’\0’会有如下处理:
#!cpp
case sw_check_uri:
……
case '.':
r->complex_uri = 1; //此作为flag会判断使用ngx_http_parse_complex_uri方法,对路径修复
state = sw_uri;
break;
casesw_check_uri:
……
case '\0': //当遇到\0是,将会判断为非法字符
return NGX_HTTP_PARSE_INVALID_REQUEST;
但是在检查uri中有空格则会进入到sw_check_uri_http_09的逻辑中,那么当我们发送攻击代码的时候,执行流程将如下:
/* space+ after URI */
case sw_check_uri_http_09:
switch (ch) {
case ' ':
break;
case CR:
r->http_minor = 9;
state = sw_almost_done;
break;
case LF:
r->http_minor = 9;
goto done;
case 'H':
r->http_protocol.data = p;
state = sw_http_H;
break;
default:
r->space_in_uri = 1;
state = sw_check_uri;
break;
}
break;
再回到sw_check_uri状态,此时后面的字符串为.php,而.
将被为是uri的扩展名的分隔符
case sw_check_uri:
if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
break;
}
switch (ch) {
case '/':
r->uri_ext = NULL;
state = sw_after_slash_in_uri;
break;
case '.':
r->uri_ext = p + 1;
break;
case ' ':
r->uri_end = p;
state = sw_check_uri_http_09;
break;
case CR:
r->uri_end = p;
r->http_minor = 9;
state = sw_almost_done;
break;
case LF:
r->uri_end = p;
r->http_minor = 9;
goto done;
最终导致nginx认为此次请求的后缀名为php,通过配置,会传给fastcgi进行处理,而fastcgi在查找文件的时候被\0截断,最终取到a.jpg(非编码空格)
文件(注:Linux下php-fpm默认限制的后缀名为php,如未取消限制,访问将出现access denied。测试想要查看执行结果,需修改php-fpm.conf中的security.limit_extensions为空,即允许任意后缀名文件作为php解析。)
Windows
首先,我们了解一下windows读取文件时的特点,即文件系统api创建文件名或查找文件名时,默认会去掉文件名后的空格,再执行操作,参见示例代码,目录下放置a.txt不带空格:
#!cpp
#include "stdafx.h"
#include<windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hFile =CreateFile(L"a.txt ",GENERIC_WRITE|GENERIC_READ, 0, //注意a.txt后有一个空格
NULL,
OPEN_EXISTING, // 打开存在的文件
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile ==INVALID_HANDLE_VALUE)
{
printf("openfailed!");
}
else
{
printf("fileopened");
}
CloseHandle(hFile);
return 0;
}
通过此代码可知道,即使我们传入参数是”a.txt ”带空格,最后访问到却确是”a.txt”不带空格
此时的攻击过程为: