Linux
正常语句:
http://127.0.0.1/a.jpg
攻击语句:
http://127.0.0.1/a.jpg(非编码空格)\0.php
在对url的解析过程中,路径中存在’.’或url存在’\0’会有如下处理:
#!cppcase 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”不带空格
此时的攻击过程为:
