UNICORN CTF 2020 Writeup

この大会は2020/8/8 19:00(JST)~2020/8/10 19:00(JST)に開催されました。
今回もチームで参戦。結果は1397点で285チーム中43位でした。
自分で解けた問題をWriteupとして書いておきます。

Sanity Check (Joy)

Telegramに入って、メッセージを遡るとフラグが書いてあった。

unictf{Un1c0rnCTF_th1s_1s_v3ry_n000t_d3f4ult_CTF}

Without many words (Misc)

jpgの後ろにrarが付いているので、rarファイルを抽出したが、パスワードがかかっている。John the Ripperでクラックする。

$ rar2john love.rar > hash.txt
$ john --wordlist=dict/rockyou.txt hash.txt --rules
Using default input encoding: UTF-8
Loaded 2 password hashes with no different salts (RAR5 [PBKDF2-SHA256 128/128 AVX 4x])
Cost 1 (iteration count) is 32768 for all loaded hashes
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
ilovetoeat       (love.rar)
ilovetoeat       (love.rar)
2g 0:00:46:51 DONE (2020-08-08 23:29) 0.000711g/s 147.4p/s 147.4c/s 294.9C/s iloveulove..ilovesuzie
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

このパスワードで解凍すると、lvl1.rarとlvl1.txtが展開される。
lvl1.txtにはDNAコードと思われるコードが書かれている。

CCT CTT TTA CTC TGA TAG ACG AGA

https://www.dcode.fr/codons-genetic-codeで出力フォーマット「AMINO ACIDS (1 LETTER)」を指定してデコードする。

G E N E T I C S

パスワード"GENETICS"でlvl1.rarを解凍すると、lvl2.rarとlvl2.txtが展開される。
lvl1.txtには以下のように書かれている。

\/// /\/ \\/\ \/\ /\/ /\ /\/\

TOM TOM Codeというのがあるらしい。https://www.dcode.fr/tom-tom-codeでデコードする。

N O T S O E Z

パスワード"NOTSOEZ"でlvl2.rarを解凍すると、lvl3.rarとlvl3.bmpが展開される。
f:id:satou-y:20200820222657j:plain
lvl3.bmpにはBill Symbol Cipherの暗号が書かれているので、以下のサイトを参考に復号する。

https://www.nicepng.com/ourpic/u2w7w7u2e6a9r5i1_bill-symbol-cipher-gravity-falls-bill-cipher-language/
GRAVITY
FALLS

パスワード"GRAVITYFALLS"でlvl3.rarを解凍すると、Flag.jpgが展開される。

$ exiftool Flag.jpg 
ExifTool Version Number         : 10.80
File Name                       : Flag.jpg
Directory                       : .
File Size                       : 207 kB
File Modification Date/Time     : 2020:08:02 20:55:43+09:00
File Access Date/Time           : 2020:08:09 13:15:40+09:00
File Inode Change Date/Time     : 2020:08:02 20:55:43+09:00
File Permissions                : rwxrwxrwx
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Resolution Unit                 : inches
X Resolution                    : 96
Y Resolution                    : 96
Exif Byte Order                 : Big-endian (Motorola, MM)
Orientation                     : Horizontal (normal)
Exif Version                    : 0232
Components Configuration        : Y, Cb, Cr, -
User Comment                    : 'https://pastebin.com/9TXHurPR'
Flashpix Version                : 0100
Color Space                     : Uncalibrated
Comment                         : CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90.
Image Width                     : 1080
Image Height                    : 1083
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 1080x1083
Megapixels                      : 1.2

EXIFのコメントにあるhttps://pastebin.com/9TXHurPRにアクセスしてみると、フラグが書いてあった。

unictf{th1ngs_4lw4ys_s33m_m0r3_d1ff1cult_th4n_th3y_4ctu4lly_4r3}

Keekle Accounts (Mobile Reverse)

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

package ru.omp.keekle.data;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class LoginDataController {
   private static final String HEX = "0123456789ABCDEF";
   private static final byte[] keyValue = "ponyponyponypony".getBytes();

   private static void appendHex(StringBuffer var0, byte var1) {
      var0.append("0123456789ABCDEF".charAt(var1 >> 4 & 15));
      var0.append("0123456789ABCDEF".charAt(var1 & 15));
   }

   private static byte[] getRawKey() throws Exception {
      return (new SecretKeySpec(keyValue, "AES")).getEncoded();
   }

   public static String read(String var0) throws Exception {
      return new String(read(toByte(var0)));
   }

   private static byte[] read(byte[] var0) throws Exception {
      SecretKeySpec var1 = new SecretKeySpec(keyValue, "AES");
      Cipher var2 = Cipher.getInstance("AES");
      var2.init(2, var1);
      return var2.doFinal(var0);
   }

   public static byte[] toByte(String var0) {
      int var1 = var0.length() / 2;
      byte[] var2 = new byte[var1];

      for(int var3 = 0; var3 < var1; ++var3) {
         var2[var3] = Integer.valueOf(var0.substring(var3 * 2, var3 * 2 + 2), 16).byteValue();
      }

      return var2;
   }

   public static String toHex(byte[] var0) {
      if (var0 == null) {
         return "";
      } else {
         StringBuffer var1 = new StringBuffer(var0.length * 2);

         for(int var2 = 0; var2 < var0.length; ++var2) {
            appendHex(var1, var0[var2]);
         }

         return var1.toString();
      }
   }
}

res/raw/devkey.encに暗号化データがある。

441A65DEFFEFC5A3B3F4A83ED6A9EA463D7782E23D516226A5CFC8477757D46F023A8E39FF4BCE61C6F883B202728978

これをAES-CBCで、以下のパラメータを使って復号する。

key: 'ponyponyponypony'
iv: '\x00' * 16
from Crypto.Cipher import AES

def unpad(s):
    return s[:-ord(s[-1])]

enc = '441A65DEFFEFC5A3B3F4A83ED6A9EA463D7782E23D516226A5CFC8477757D46F023A8E39FF4BCE61C6F883B202728978'
enc = enc.decode('hex')

key = 'ponyponyponypony'
iv = '\x00' * 16
cipher = AES.new(key, AES.MODE_CBC, iv)

flag = unpad(cipher.decrypt(enc))
print flag
unictf{h0p3_70u-d1D't_u53-fR33d4}

Domestic Metallurgy 1 (Misc)

mkvをmp4に変換してみる。

>ffmpeg -i OP2.mkv -vcodec copy OP2.mp4

変換したmp4を再生すると、すぐにフラグが現れた。
f:id:satou-y:20200820223015p:plain

unictf{extend_your_vision}

Feedback (Joy)

アンケートフォームのHTMLソースを見ると、フラグが見つかった。

unictf{4chieve_succ3ss}