基础项
比较
== 只比较值,不比较类型
=== 除了比较值,也比较类型
0 == false: bool(true)
0 === false: bool(false)
ps:在php中 "字符串"==0
是成立的
输出
-
echo
- 可以输出一个或多个字符串 -
print
- 只允许输出一个字符串,返回值总为 1
数组
array()
函数用于创建数组
|
|
魔术常量
行如 __FILE__
这样的 __XXX__
预定义常量,被称为魔术常量。
|
|
表单数据
$_GET —— 接受 GET 请求传递的参数。
示例: example.com/index.php?book=HELLOCTF
,你可以使用 $_GET['book']
来获取相应的值。
$_POST —— 接受 POST 请求传递的参数。
示例:对 example.com/index.php
进行 POST 传参,参数名为 book 内容为 HelloCTF,你可以使用 $_POST['book']
来获取相应的值。
$_REQUEST —— 接受 GET 和 POST 以及 Cookie 请求传递的参数。 示例:
-
如果你通过 URL 传递了一个参数
example.com/index.php?key=value_from_get
,你可以通过$_REQUEST['key']
获取这个值。 -
如果你通过 POST 方法提交了一个表单,其中有一个名为 key 的字段且其值为
value_from_post
,你也可以通过$_REQUEST['key']
获取这个值。 -
同时,如果你设置了一个名为 key 的 cookie,其值为 value_from_cookie,你还是可以使用 $_REQUEST[‘key’] 来获取这个值。
懒人必备^o^/
函数
一般来说名字≈功能,所以理解大于记忆,列几个常见的
-
assert()
: 用于调试,检查一个条件是否为 true。 -
unserialize()
: 将一个已序列化的字符串转换回 PHP 的值。例如:$array = unserialize($serializedStr)
可以将一个序列化的数组字符串转换为数组。 -
mysql_query()
: 发送一个 MySQL 查询。
函数安全
常见绕过
|
|
想要绕过可以在数字前面或者后面加上 %0a %0b %0c %0d %09
例如: ?a="404%0a"
弱类型比较
strcmp()
当 strcmp 比较出错后,会返回 null,null 则为 0 。
|
|
为了使 strcmp 比较出错,可以传入一个数组
Payload: ?str[]
is_switch()
|
|
case 会自动将字符转换成数值,即遇到非数字就停止
md5()
md5 在处理哈希字符串的时候,如果 md5 编码后的哈希值时 0e (科学计数法)开头的,都一律解释为 0
例如:
|
|
此时找到两个不相同但md5编码后以0e开头的字符串即可
如果是这样:
|
|
用上述 0e 方法自然是不可行的(注意:===
),这时候就得使用数组来绕过了,如果传入一个数组的值,会报出错误(md5 只能使用字符串),报错后就相当于绕过 ===
这个条件了
注: 在 PHP 8.0.0 时,该方法行不通了
如果遇到不能传入数组,只能传入字符串的时候,如下例
|
|
这时候就得需要 md5 碰撞,上面判断条件的意思是,str1 和 str2 内容必须不同,但是 md5 必须相同(详细方法待整理)
sha1()
sha1 的参数不能为数组,传入数组会返回 NULL
|
|
Payload: ?get[]=&teg[]=1
变量覆盖漏洞
环境得先开启
register_globals=ON //此时传递的参数会自动注册为全局变量
最简单的一种就是我们传入参数例如 ?id=1
把原来id的值给替换
$$
类似于c++的指针,例如:
|
|
传入
?a=I'm A&b=I'm B
后,得到
A
B
I'm A
I'm B
b
I'm B
这里使用了 foreach 来遍历数组的值,遍历 I'm B
到这一项,后面的代码表示把数组的键名b赋值给key,数组的键值赋值给value,并且key可以指向value
就当成指针理解吧[]`( ̄▽ ̄)’*
extract()
描述:extract(array,flags,prefix)
功能:将数组元素动态转换为变量,常用于处理表单数据(如 $_POST、$_GET)或配置数组。
flags: 可选,控制冲突处理方式(默认 EXTR_OVERWRITE) 常用值:
- EXTR_OVERWRITE:如果有冲突,覆盖已有变量
- EXTR_SKIP:跳过冲突
- EXTR_PREFIX_ALL:如果有冲突,为所有变量添加前缀
prefix: 可选,仅在指定flags为前缀模式时有效,用于生成变量名前缀。
parse_str()
描述:parse_str(str) 用于将字符串解析成多个变量,没有返回值。简而言之,就是你输入(“a=1&b=2”)它会自动地生成a,b两个变量
伪协议
php://filter
php://filter/read or write=/resource=数据流
-
resource=< 要过滤的数据流> (必须) 它指定了你要筛选过滤的数据流
-
read和write可选对应对筛选列表的操作
常用过滤器convert.base64
- 编码 convert.base64-encode
- 解码 convert.base64-decode
例如
php://filter/read=convert.base64-encode/resource=files.txt
更多的可以看P神的谈一谈php://filter的妙用
php://input
如果 html 表单编码设置为"multipart/form-data",请求是无效的。 一般在 CTF 中用于执行 php 代码(一般在bp里使用)
需要在php 中设置 allow_url_include = On
zip:// & bzip2 & zlib://
需要:
-
allow_url_fopen: on
-
allow_url_include: on
zip的一般格式:
zip://[压缩文件绝对路径]%23[压缩文件内的子文件名](#编码为%23)
file://
和zip一样需要打开两个_url_,用于访问本地文件系统,在 CTF 中通常用来读取本地文件
data://
常用于绕过php://过滤,直接执行PHP代码
语法:
data:[<mediatype>][;charset=<encoding>][;base64],<data>
- mediatype:数据类型(如text/plain、image/png、text/html)。
- charset:字符编码(如utf-8)。
- base64:若数据需编码则添加此标识。
- data:实际内容(如PHP代码或文件路径)。
需存在文件包含漏洞(如 include($_GET['file'])
)和打开两个_url_
序列化及反序列化
-
序列化 是将 PHP 对象转换为字符串的过程,可以使用
serialize()
函数来实现。该函数将对象的状态以及它的类名和属性值编码为一个字符串。序列化后的字符串可以存储在文件中,存储在数据库中,或者通过网络传输到其他地方。 -
反序列化 是将序列化后的字符串转换回 PHP 对象的过程,可以使用
unserialize()
函数来实现。该函数会将序列化的字符串解码,并将其转换回原始的 PHP 对象。
普通对象注意 protected
和 private
类型的变量中都加入了不可见字符:
如果是 protected
变量,则会在变量名前加上 \x00*\x00
如果是 private
变量,则会在变量名前加上 \x00类名
一般我们在输出的时候都会先编码后输出
自定义类时,例如:
|
|
此时输出的格式如图:
by hello ctf
其它一些标识,一般都是英文首字母
-
b:boolean bool 值
-
C:custom object 自定义对象序列化
-
d:double 小数
-
i:integer 整数
-
O:Object 对象
-
r:reference 对象引用 && R:pointer reference 指针引用
-
S:encoded string
-
N:null NULL 值
魔术方法
在 PHP 的序列化中,魔术方法(Magic Methods)是一组特殊的方法,这些方法以双下划线(__)作为前缀,可以在特定的序列化阶段触发从而使开发者能够进一步的控制 序列化 / 反序列化 的过程。
一般在题目中常见的几个方法如下:
|
|
详细可参考:PHP:魔术方法 - Manual
属性重载
- 在给不可访问(protected 或 private)或不存在的属性赋值时,__set() 会被调用。
- 读取不可访问(protected 或 private)或不存在的属性的值时,__get() 会被调用。
- 当对不可访问(protected 或 private)或不存在的属性调用 isset() 或 empty() 时,__isset() 会被调用。
- 当对不可访问(protected 或 private)或不存在的属性调用 unset() 时,__unset() 会被调用。
详细可参考:PHP:重载 - Manual
本文参考资料:Hello CTF (其实就是摘抄啦)