函数

md5()

用于计算字符串的 MD5 散列。

1
2
3
4
5
<?php
$str = "Hello";
echo md5($str);
?>
运行结果:8b1a9953c4611296a827abf8c47804d7

绕过:

  • 0e绕过:PHP会将每一个以0e开头的哈希值解释为0,那么只要传入的不同字符串经过哈希以后是以0e开头的,那么PHP会认为它们相同。

    s878926199a => 0e545993274517709034328855841020
    s155964671a => 0e342768416822451524974117254469

  • 数组绕过:MD5不能直接对数组进行加密,它会返回NULL。

    要满足$a != $b && md5($a) == md5($b) => 传入 a[]=1&b[]=2 即可绕过

==与===

== 运算符只比较变量的值,不考虑它们的类型。
=== 运算符不仅比较变量的值,还比较它们的类型。

‘10’ == 10 为 true,因为字符串 “10” 会自动转换为整型。
‘10’ === 10 为 false,因为字符串 “10” 和整型 10 的类型不同。

intval()

用于获取变量的整数值。
通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。

1
2
3
4
5
6
7
8
9
10
11
12
13
int intval ( mixed $var [, int $base = 10 ] )
- $var:要转换成 integer 的数量值。
- $base:转化所使用的进制。

如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则,
如果字符串以 "0" 开始,使用 8 进制(octal);否则,
将使用 10 进制 (decimal)。

<?php
echo intval(42); // 42
echo intval(4.2); // 4
echo intval('42'); // 42
?>

绕过:

  • 使用进制绕过。
  • 使用小数点绕过。
  • 使用科学计数法绕过。

strpos()

用于查找字符串在另一字符串中第一次出现的位置(区分大小写)。

1
2
3
4
5
6
7
8
9
strpos (string, find, start) 
- string:必需。规定被搜索的字符串。
- find:必需。规定要查找的字符。
- start:可选。规定开始搜索的位置。

<?php
echo strpos("I love php, I love php too!","php");
?>
运行结果:7

in_array()

用于搜索数组中是否存在指定的值。

1
2
3
4
5
6
7
8
9
10
bool in_array (mixed $needle , array $haystack [, bool $strict = FALSE ] )
- needle:必需。规定要在数组搜索的值。
- haystack:必需。规定要搜索的数组。
- strict:可选。如果该参数设置为 TRUE,则 in_array() 函数检查搜索的数据与数组的值的类型是否相同。

<?php
$sites = array("Google", "Runoob", "Taobao", "Facebook");
in_array("Runoob", $sites) // true
in_array("Alibaba", $sites) // false
?>

绕过:

  • 第三个参数如果不指定为true则不判断类型,相当于==。

用于在数组中搜索某个值,并返回对应的键名。如果找不到该值,则返回 false。

1
2
3
4
5
6
7
8
9
10
array_search(mixed $needle, array $haystack, bool $strict = false): int|string|false
- $needle:必需。规定在数组中搜索的键值。
- $haystack:必需。规定被搜索的数组。
- $strict:可选,默认是 false,只比较值,不比较类型。如果该参数被设置为 TRUE,则函数在数组中搜索数据类型和值都一致的元素。

<?php
$a = array("a"=>"red", "b"=>"green", "c"=>"blue");
echo array_search("red", $a);
?>
运行结果:a

绕过:

  • “ABC” == 0 成立
  • “ABC” == true 成立。

preg_match()

用于执行一个正则表达式匹配。

1
2
3
4
5
6
int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
<?php
$pattern = '/hello/i'; // /i表示不区分大小写匹配
$subject = 'Hello World';
preg_match($pattern, $subject); // true
?>

绕过:

  • a[]='flag.php' 数组写法绕过。
  • 不带/m的正则表达式可以用换行绕过。

str_replace()

用于替换字符串中的一些字符(区分大小写)。

1
2
3
4
5
6
7
8
9
10
str_replace (find, replace, string, count)
- find:必需。规定要查找的值。
- replace:必需。规定替换 find 中的值的值。
- string:必需。规定被搜索的字符串。
- count:可选。一个变量,对替换数进行计数。

<?php
echo str_replace("world","Peter","Hello world!");
?>
运行结果:Hello Peter!

绕过:

  • 双写绕过。如seselectlect将select替换为空后剩余字符串还是select。

魔术方法

__call()

用于处理对未定义或不可访问的方法的调用。也就是说,当你在对象上调用一个不存在或不可见的方法时,__call() 会被自动调用。

1
2
3
4
5
6
7
8
9
<?php
class MyClass {
public function __call($name, $arguments) {
echo "__call 被调用";
}
}

$obj = new MyClass();
$obj->foo('bar', 'baz'); // 调用不存在的 foo 方法

__destruct()

在对象生命周期结束时自动调用,通常用于清理资源。它可以在对象超出作用域、脚本执行结束或显式调用 unset() 时触发。

__invoke()

当尝试以类似函数调用的方式调用对象时,PHP会自动调用对象的__invoke()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 有参数
<?php
class CallableClass {
public function __invoke($name) {
echo "Hello, $name!\n";
}
}

$obj = new CallableClass();
$obj('World'); // 输出:Hello, World

// 无参数
<?php
class NoArgs {
public function __invoke() {
return "This object is invoked without arguments!";
}
}

$obj = new NoArgs();
echo $obj(); // 输出: This object is invoked without arguments!

__get()

用于获取类中不可访问或不存在的属性。当你尝试访问一个未定义或不可见的属性时,PHP 会自动调用 __get() 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class MyClass {
private $data = [];

public function __get($name) {
echo "试图获取属性: $name\n";
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
return null; // 属性不存在时返回 null
}

public function __set($name, $value) {
$this->data[$name] = $value;
}
}

$obj = new MyClass();
$obj->foo = 'bar'; // 使用 __set() 动态设置 'foo' 属性
echo $obj->foo; // 使用 __get() 动态获取 'foo' 属性

试图获取属性: foo
bar

__toString()

尝试将一个对象转换为字符串时,PHP 会自动调用这个方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
class Person {
private $name;
private $age;

public function __construct($name, $age) {
$this->name = $name;
$this->age = $age;
}

public function __toString() {
return $this->name . " is " . $this->age . " years old.";
}
}

$person = new Person("Alice", 30);
echo $person; // 自动调用 __toString() 方法

Alice is 30 years old.

伪协议

file://

  • 作用:用于访问文件(绝对路径、相对路径、网络路径)。
  • 示例:http://www.xx.com?file=file:///etc/passswd

php://

  • 作用:访问输入输出流。

php://filter

  • 作用:读取源代码并进行base64编码输出。
  • 示例:http://www.xx.com?file=php://filter/read=convert.base64-encode/resource=[文件名]

php://input

  • 作用:执行POST数据中的php代码。

  • 示例:http://www.xx.com?cmd=php://input

    POST数据:<?php phpinfo()?>

  • 注意:enctype="multipart/form-data" 的时候 php://input 是无效的。

data://

  • 作用:自PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。一般需要用到base64编码传输。
  • 示例:http://www.xx.com?file=data://text/plain;base64,aGVsbG9jdGY=

    aGVsbG9jdGY=的base64解码为”helloctf”

CTF题相关技巧

绕过空格

  • ${IFS} ,例题:https://www.nssctf.cn/problem/425

    1
    2
    3
    4
    5
    6
    $ip=$_GET['url'];
    if(preg_match("/ /", $ip)){ // 判断有没有空格
    die('nonono');
    }
    $a = shell_exec($ip);
    echo $a;

    构造:?url=ls${IFS}/

  • $IFS$1,例题:https://www.nssctf.cn/problem/1096

  • ${IFS}, $IFS, $IFS$1的区别:首先$IFS在linux下表示分隔符,只有cat$IFSa.txt的时候,bash解释器会把整个IFSa当做变量名,所以导致没有办法运行,然而如果加一个{}就固定了变量名,同理在后面加个$可以起到截断的作用,而$1指的是当前系统shell进程的第1个参数的持有者,就是一个空字符串,因此$1相当于没有加东西,等于做了一个前后隔离,同理$1~$9都可实现相同的效果。

绕过请求中的 .

例题:第十五届极客大挑战 rce_me
其中一段代码如下:

1
2
3
4
5
6
7
8
if (
sha1((string) $_POST["__2024.geekchallenge.ctf"]) == md5("Geekchallenge2024_bmKtL") &&
(string) $_POST["__2024.geekchallenge.ctf"] != "Geekchallenge2024_bmKtL" &&
is_numeric(intval($_POST["__2024.geekchallenge.ctf"]))
) {
echo "You took the first step!<br>";
···
}

这里如果直接传入 __2024.geekchallenge.ctf 的话,PHP在处理的时候会转换成 __2024_geekchallenge_ctf ,这样的话 $_POST["__2024.geekchallenge.ctf"] 读出来就是null,PHP的官方手册也对其进行了解释:

绕过:

当PHP版本小于8时,如果参数中出现中括号[,中括号会被转换成下划线_,但是会出现转换错误,导致后面的非法字符不会转换成下划线_

因此构造参数 _[2024.geekchallenge.ctf 即可满足要求。