satto1237’s diary

s4tt01237’s diary

ラーメンとかCTFとかセキュリティとか

UTCTF 2020 Write-up

はじめに

2020/03/07 ~ 2020/03/09に開催されたUTCTFにチーム(NekochanNano!)で参加しました.

成績

チームとしては23問解いて44位でした (1001チーム中).
今回は自分が解いた12問のWrite-upを書きます.

Rev

[basics] Reverse Engineering

know there's a string in this binary somewhere.... Now where did I leave it?

> file calc
calc: ELF 64-bit LSB shared object x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f5ca6bb761ab5d70a7ecd74041af001fe88ea383, for GNU/Linux 3.2.0, not stripped

アプローチ:strings

> strings calc | grep utflag
utflag{str1ngs_1s_y0ur_fr13nd}

utflag{str1ngs_1s_y0ur_fr13nd}

.PNG2

In an effort to get rid of all of the bloat in the .png format, I'm proud to announce .PNG2! The first pixel is #7F7F7F, can you get the rest of the image?

> file pic.png2
pic.png2: data
> xxd pic.png2 | head
00000000: 504e 4732 7769 6474 683d 05cf 6865 6967  PNG2width=..heig
00000010: 6874 3d02 887f 7f7f 7f7f 7f7f 7f7f 7f7f  ht=.............
00000020: 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f  ................
00000030: 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f  ................
00000040: 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f  ................
00000050: 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f  ................
00000060: 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f  ................
00000070: 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f  ................
00000080: 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f  ................
00000090: 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f  ................

アプローチ:formatのエスパー

xxdの結果からwidth=0x05cf, height=0x0288であることが確認できます.
また,最初のPixelが#7F7F7Fであることから22byte以降はPixel値で構成されていると考えることができます.

これらの情報をもとにPNGを復元すると次のようになります.

f:id:satto1237:20200312184921p:plain

utflag{j139adfo_93u12hfaj}

以下は復元に利用したコードです.

from PIL import Image
from Crypto.Util.number import *

# width=0x05cf, height=0x0288
with open('pic.png2', 'rb') as f:
    data = f.read()

header = data[:21]
pixels = data[21:]

flag_img = Image.new('RGB', (0x05cf, 0x0288))

x = 0
y = 0
for i in range(0, len(pixels)-3, 3):
    rgb = pixels[i:i+3]
    flag_img.putpixel((x,y), (rgb[0],rgb[1],rgb[2]))
    x += 1
    if x == 0x05cf:
        x = 0
        y += 1

flag_img.save('./flag.png')

Forensics

Observe Closely

A simple image with a couple of twists...

アプローチ:foremost

.pngなのでzstegを利用してhidden dataを抽出します.

> zsteg Griffith_Observatory.png
[?] 2763 bytes of extra data after image end (IEND), offset = 0x1f30f
extradata:0         .. file: Zip archive data, at least v2.0 to extract
    00000000: 50 4b 03 04 14 00 00 00  08 00 45 81 5b 50 b3 10  |PK........E.[P..|
    00000010: f1 08 1b 0a 00 00 18 41  00 00 0d 00 1c 00 68 69  |.......A......hi|
    00000020: 64 64 65 6e 5f 62 69 6e  61 72 79 55 54 09 00 03  |dden_binaryUT...|
    00000030: 42 3e 58 5e 46 3e 58 5e  75 78 0b 00 01 04 e8 03  |B>X^F>X^ux......|
    00000040: 00 00 04 e8 03 00 00 ed  5b 7d 6c 14 c7 15 9f bb  |........[}l.....|
    00000050: f3 99 e3 c3 e7 03 ec e0  00 89 8f 06 24 d3 d4 c7  |............$...|
    00000060: f9 6c 8c dd c8 e0 b3 7d  f6 ba 3a 03 21 76 4a d5  |.l.....}..:.!vJ.|
    00000070: c0 76 7d 7b e7 5b 71 1f  d6 dd 5e 6b d3 56 a1 72  |.v}{.[q...^k.V.r|
    00000080: 42 73 22 4e 50 3f a4 a6  52 55 fe 44 55 a5 80 2a  |Bs"NP?..RU.DU..*|
    00000090: 21 2b 6a 25 23 23 92 a8  51 0a 7f b4 a5 45 55 dd  |!+j%##..Q....EU.|
    000000a0: 28 1f 26 4a 13 87 86 c8  4d 03 db 99 dd 79 7b 3b  |(.&J....M....y{;|
    000000b0: 73 77 85 b4 aa aa 4a fb  93 f6 de ce 6f de 7b f3  |sw....J.....o.{.|
    000000c0: 76 76 76 3d eb 99 f7 64  24 3a e8 74 38 10 c0 85  |vvv=...d$:.t8...|
    000000d0: f6 22 52 3a e8 33 ca bd  94 bf d6 6d aa 60 ae 0b  |."R:.3.....m.`..|
    000000e0: ad c5 bf 0f a0 ad a8 16  97 6b 2c 7a bc 4c 3a 59  |.........k,z.L:Y|
    000000f0: e9 31 db 31 ec ce 52 9e  97 5b 11 2b 1d 16 59 83  |.1.1..R..[.+..Y.|
b1,rgb,lsb,xy       .. text: "This is one of the twists: there is no flag here!"
b2,r,msb,xy         .. text: "PUUDADTP"
b2,bgr,lsb,xy       .. text: "*sj 51\t}Z"
b3,g,msb,xy         .. text: "@C$\tS\"LR"
b3,rgb,lsb,xy       .. text: "@`0B-0R("
b4,r,msb,xy         .. text: "11a 6pFdPWP"
b4,g,msb,xy         .. text: "R@W5pc&7DU3GF\"`sF"
b4,b,msb,xy         .. text: "ud&!qcFu"
b4,rgb,msb,xy       .. text: "#pFEp&`c"
b4,bgr,msb,xy       .. text: "' Cv@%vc"

zipが埋め込まれていることが分かったので,foremostを利用してzipを抽出します.

> foremost Griffith_Observatory.png
foremost: /usr/local/etc/foremost.conf: No such file or directory
Processing: Griffith_Observatory.png
|foundat=hidden_binaryUT
*|

圧縮されていたhidden_binaryを実行すればflagを取得できます.

> ./hidden_binary 
Ah, you found me!
utflag{2fbe9adc2ad89c71da48cabe90a121c0}

utflag{2fbe9adc2ad89c71da48cabe90a121c0}

Spectre

I found this audio file, but I don't think it's any song I've ever heard... Maybe there's something else inside?

> file song.wav
song.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, mono 44100 Hz

アプローチ:Spectrogramの確認

Sonic VisualiserSpectrogramを確認するとflagを確認できます.

f:id:satto1237:20200312195746p:plain

utflag{sp3tr0gr4m0ph0n3}

The Legend of Hackerman, Pt. 1

My friend Hackerman tried to send me a secret transmission, but I think some of it got messed up in transit. Can you fix it?

> file hackerman.png
hackerman.png: data

アプローチ:headerの書き換え

xxdすると.pngファイルシグネチャの上位4byteが0x00で上書きされていることが分かるので,バイナリエディタなどを利用してheaderを8950 4e47に書き換えることでflagを取得できます.

> xxd hackerman.png | head
00000000: 0000 0000 0d0a 1a0a 0000 000d 4948 4452  ............IHDR
00000010: 0000 04a8 0000 029e 0806 0000 0081 2e23  ...............#
00000020: af00 0028 257a 5458 7452 6177 2070 726f  ...(%zTXtRaw pro
00000030: 6669 6c65 2074 7970 6520 6578 6966 0000  file type exif..
00000040: 78da ad9c 6992 1c37 9285 ffe3 1473 04ec  x...i..7.....s..
00000050: cb71 e058 cce6 067d fcf9 1e32 4991 92ba  .q.X...}...2I...
00000060: a7db ac45 1349 5565 4520 e0ee 6f71 78c8  ...E.IUeE ..oqx.
00000070: 9d7f fcef 75ff c33f 2394 ec72 69bd 8e5a  ....u..?#..ri..Z
00000080: 3dff e491 479c fca5 fbcf 3fe3 fd1e 7c7e  =...G.....?...|~
00000090: bfbf 7f66 7fff a5ff feed eb6e 1c1f dfdf  ...f.......n....

f:id:satto1237:20200312200758p:plain

utflag{3lit3_h4ck3r}

The Legend of Hackerman, Pt. 2

Ok, I've received another file from Hackerman, but it's just a Word Document? He said that he attached a picture of the flag, but I can't find it...

> file Hacker.docx
Hacker.docx: Microsoft Word 2007+

アプローチ:unzip

画像ファイルを探しやすくするために.docxunzipします.

unzip Hacker.docx -d Hacher
Archive:  Hacker.docx
  inflating: Hacher/_rels/.rels
  inflating: Hacher/word/fontTable.xml
  inflating: Hacher/word/styles.xml
  inflating: Hacher/word/_rels/document.xml.rels
  inflating: Hacher/word/settings.xml
  inflating: Hacher/word/media/image97.png
  inflating: Hacher/word/media/image102.png
[snip]
  inflating: Hacher/word/media/image25.png
  inflating: Hacher/word/media/image24.png
  inflating: Hacher/word/media/image169.jpeg
  inflating: Hacher/word/media/image37.png
  inflating: Hacher/word/numbering.xml
  inflating: Hacher/docProps/core.xml
  inflating: Hacher/docProps/app.xml
  inflating: Hacher/[Content_Types].xml
  inflating: Hacher/word/document.xml

Hacher/word/media内の.pngを確認するとflagを見つけることができます.

f:id:satto1237:20200312202346p:plain

utflag{unz1p_3v3ryth1ng}

Crypto

[basics] crypto

Can you make it through all of the encodings?

binary.txt

01010101 01101000 00101101 01101111 01101000 00101100 00100000 01101100 01101111 01101111 01101011 01110011 00100000 01101100 01101001 01101011 01100101 00100000 01110111 01100101 00100000 01101000 01100001 01110110 01100101 00100000 01100001 01101110 01101111 01110100 01101000 01100101 01110010 00100000 01100010 01101100 01101111 01100011 01101011 00100000 01101111 01100110 00100000 01110100 01100101 01111000 01110100 00101100 00100000 01110111 01101001 01110100 01101000 00100000 01110011 01101111 01101101 01100101 00100000 01110011 01101111 01110010 01110100 00100000 01101111 01100110 00100000 01110011 01110000 01100101 01100011 01101001 01100001 01101100 00100000 01100101 01101110 01100011 01101111 01100100 01101001 01101110 01100111 00101110 00100000 01000011 01100001 01101110 00100000 01111001 01101111 01110101 00100000 01100110 01101001 01100111 01110101 01110010 01100101 00100000 01101111 01110101 01110100 00100000 01110111 01101000 01100001 01110100 00100000 01110100 01101000 01101001 01110011 00100000 01100101 01101110 01100011 01101111 01100100 01101001 01101110 01100111 00100000 01101001 01110011 00111111 00100000 00101000 01101000 01101001 01101110 01110100 00111010 00100000 01101001 01100110 00100000 01111001 01101111 01110101 00100000 01101100 01101111 01101111 01101011 00100000 01100011 01100001 01110010 01100101 01100110 01110101 01101100 01101100 01111001 00101100 00100000 01111001 01101111 01110101 00100111 01101100 01101100 00100000 01101110 01101111 01110100 01101001 01100011 01100101 00100000 01110100 01101000 01100001 01110100 00100000 01110100 01101000 01100101 01110010 01100101 00100000 01101111 01101110 01101100 01111001 00100000 01100011 01101000 01100001 01110010 01100001 01100011 01110100 01100101 01110010 01110011 00100000 01110000 01110010 01100101 01110011 01100101 01101110 01110100 00100000 01100001 01110010 01100101 00100000 01000001 00101101 01011010 00101100 00100000 01100001 00101101 01111010 00101100 00100000 00110000 00101101 00111001 00101100 00100000 01100001 01101110 01100100 00100000 01110011 01101111 01101101 01100101 01110100 01101001 01101101 01100101 01110011 00100000 00101111 00100000 01100001 01101110 01100100 00100000 00101011 00101110 00100000 01010011 01100101 01100101 00100000 01101001 01100110 00100000 01111001 01101111 01110101 00100000 01100011 01100001 01101110 00100000 01100110 01101001 01101110 01100100 00100000 01100001 01101110 00100000 01100101 01101110 01100011 01101111 01100100 01101001 01101110 01100111 00100000 01110100 01101000 01100001 01110100 00100000 01101100 01101111 01101111 01101011 01110011 00100000 01101100 01101001 01101011 01100101 00100000 01110100 01101000 01101001 01110011 00100000 01101111 01101110 01100101 00101110 00101001 00001010 01010100 01101101 01010110 00110011 01001001 01000111 01001110 01101111 01011001 01010111 01111000 01110011 01011010 01010111 00110101 01101110 01011010 01010011 01000101 01100111 01010001 00110010 01000110 01110101 01001001 01001000 01101100 01110110 01100100 01010011 01000010 01101101 01100001 01010111 01100100 00110001 01100011 01101101 01010101 01100111 01100010 00110011 01010110 00110000 01001001 01001000 01100100 01101111 01011001 01011000 01010001 01101110 01100011 01111001 01000010 01101110 01100010 00110010 01101100 01110101 01011010 01111001 01000010 01110110 01100010 01101001 01000010 01101111 01011010 01011000 01001010 01101100 01010000 01111001 01000010 01001010 01100100 01000011 01000010 01110011 01100010 00110010 00111001 01110010 01100011 01111001 01000010 01110011 01100001 01010111 01110100 01101100 01001001 01001000 01010010 01101111 01011010 01010011 01000010 01110011 01011010 01011000 01010010 00110000 01011010 01011000 01001010 01111010 01001001 01000111 01000110 01111001 01011010 01010011 01000010 01111010 01100001 01000111 01101100 01101101 01100100 01000111 01010110 01101011 01001001 01000111 01001010 00110101 01001001 01001000 01001110 01110110 01100010 01010111 01010101 01100111 01011001 00110010 00111001 01110101 01100011 00110011 01010010 01101000 01100010 01101110 01010001 01110101 01001001 01000011 01101000 01101111 01100001 01010111 00110101 00110000 01001111 01101001 01000010 00110101 01100010 00110011 01010101 01100111 01100010 01010111 01101100 01101110 01100001 01001000 01010001 01100111 01100100 00110010 01000110 01110101 01100100 01000011 01000010 00110000 01100010 01111001 01000010 01111010 01100100 01000111 01000110 01111001 01100100 01000011 01000010 01110011 01100010 00110010 00111001 01110010 01100001 01010111 00110101 01101110 01001001 01001000 01010110 01110111 01001001 01000110 01001010 01110110 01100010 01010111 01000110 01110101 01001001 01001000 01000010 01101100 01100010 00110011 01000010 01110011 01011010 01010011 01101011 01110101 01000011 01101101 01110100 00110010 01011001 01101110 01001110 01111000 01100011 01101101 01010001 01110011 01001001 01000111 01101100 00110101 01011010 01010011 01100100 01101001 01100010 01111001 01000010 01110010 01100100 01101110 01100100 00110101 01011001 00110010 01010001 01100111 01011010 01001000 01001010 01110110 01011001 01101101 00111000 01101000 01001001 01000110 01101000 00110101 01011010 01111001 01000010 01110111 01100101 01010111 01001001 01100111 01011010 01001000 01001010 01110110 01001001 01001000 01000010 01111010 01100101 01000111 01110100 00110010 01001001 01000011 01101000 01110010 01100101 01000111 00110100 01100111 01100100 00110010 01110100 01110000 01100010 01000111 00111000 01100111 01011010 01001000 01001010 01110110 01001001 01001000 01001010 01110010 01011001 01101101 00110101 01110110 01011001 00110010 01010001 01110101 01001100 01101001 00110100 01110000 01001001 01001000 01110000 01110010 01011001 01101101 01010001 00110110 01001001 01000111 01110011 01100111 01011001 00110010 01010110 01110011 01011001 00110010 01010010 01111010 01011010 01000111 01010110 01101011 01100011 00110011 01101100 00110100 01001001 01000111 00110001 01111010 01100101 01101110 01001010 01110110 01011001 01101001 00110100 01100111 01010101 00110011 01100111 01100111 01011010 01001000 01001010 01110110 01001001 01001000 01000010 00110101 01100100 01101110 01011010 00110101 01011010 00110011 01001110 00110100 01100011 01010011 01000010 01101011 01100010 00110010 01101000 01101011 01001100 01000011 01000010 01010100 01001010 00110010 01011010 01110110 01001001 01000111 01010010 01110010 01100100 01010111 00111001 00110100 01001001 01001000 01100100 01110000 01001001 01001000 01100100 01110110 01011001 00110010 01001110 01110010 01100011 01010111 00111000 01100111 01100001 00110011 01101000 01110101 01001001 01000111 01001010 01110110 01100101 01101110 01011010 01110010 01100010 01010111 00111001 01110101 01001001 01000111 00111001 01101101 01100010 00110010 01001010 01110000 01001001 01000111 01110100 00110010 01100101 01101110 01001010 01110010 01100010 01000111 00111001 01101011 01100011 00110010 00110000 01100111 01100010 01011000 01001010 01110010 01011001 01101101 01110100 01110100 01011010 01000111 00111001 01101001 01001001 01000111 01100100 01111010 01011010 01001000 01001001 01100111 01100001 01111001 01000010 01110100 01100101 01010111 01001010 01101001 01100010 00110010 01001110 00110110 01100101 01011000 01101000 01110101 01100010 00110011 01101000 01110100 01100010 01111001 01000010 01101011 01100101 01010011 01000010 01110010 01001001 01000111 00110101 01111010 01100011 01001000 01000010 01110110 01011001 01101101 00111001 00110100 01011010 01000011 01000010 01110100 01100011 01101101 01110100 01101001 01100001 00110010 00110001 01101011 01100010 00110010 01001001 01100111 01001100 01010011 01000010 00110001 01100101 01001000 01101100 01101110 01100101 01000011 01000010 01110010 01011001 01111001 01000010 01110010 01001001 01000111 01001110 01101100 01100010 01000111 01001110 01101011 01100011 00110010 01010010 01101100 01011010 01001000 01001110 00110101 01100101 01000011 01000010 01110100 01100011 00110011 01110000 01111001 01100010 00110010 01001001 01110101 01001001 01000101 00110001 01110010 01100101 01000011 01000010 01110000 01100101 01010111 01010101 01100111 01100011 01001000 01001110 00110100 01100010 01101001 01000010 01101011 01100011 01101101 00111000 01100111 01100011 01001000 01001110 00110100 01100001 00110011 01011001 01100111 01100011 01001000 01011010 01110010 01100011 01010100 00111000 01100111 01100011 01101110 01001110 00110100 01011010 01000100 01101111 01100111 01010010 00110010 00111000 01100111 01100100 01011000 01101000 00110101 01011010 01111001 01000010 01101011 01100011 01101101 01110100 01101011 01001001 01000111 01010010 01111001 01100010 01111001 01000010 01110111 01100100 01101101 01110100 01111000 01001001 01001000 01001110 01101010 01001001 01001000 01000110 00110101 01100011 00110011 01101000 01111000 01001001 01000111 01010010 00110101 01001001 01000111 01111000 01110110 01001001 01001000 01101100 01110111 01001001 01000111 01010010 01111001 01100010 01111001 01000010 01110111 01100101 01010111 01001010 00110011 01100001 00110010 01010001 01100111 01011010 01010111 01010010 01110111 01100100 01101101 01110100 01111000 01100101 01111001 00110100 01110101 01001100 01101110 00110000 01100111 01001100 01010011 01000010 01101110 01100011 01101110 01001110 01110100 01100011 01101001 01000010 00110011 01100010 00110010 01110100 00110100 01011001 01111001 01000010 01101011 01100011 01101101 01110100 01101011 01001001 01001000 01001110 01110111 01001001 01000111 01101100 00110101 01011010 01010011 01000010 01101010 01100010 00110010 00111000 01100111 01011010 01001000 01001010 01110010 01011010 01000011 01000010 00110110 01100001 00110010 01010010 01101011 01100010 00110010 01001010 00110100 01001100 01000011 01000010 01110000 01100101 01010111 01010101 01100111 01100100 01011000 01101000 00110101 01011010 01111001 01000010 01101110 01100011 01101101 01110100 01101011 01001001 01000111 01010010 01111001 01100010 01111001 01000010 01110100 01100101 01010111 01001010 01101001 01100010 00110010 01001110 00110110 01100101 01011000 01101000 01110101 01100010 00110011 01101000 01110100 01100010 00110010 01001101 01100111 01100011 01001000 01101100 01101001 01001001 01000111 01010101 01110011 01001001 01000111 01010001 01110011 01001001 01001000 01000001 01110011 01001001 01001000 01011001 01100111 01100001 01111001 01110111 01100111 01100001 00110011 01101000 01110101 01001001 01001000 01000101 01100111 01100001 00110010 01001010 01110110 01001100 01101001 01000010 01001010 01100101 01010111 01010101 01100111 01100010 01010111 01110100 00110100 01001001 01001000 01110000 01101001 01100101 01010111 01111000 01110010 01100010 01001000 01011010 01110000 01001001 01000111 01100100 00110101 01011001 01101110 01010101 01100111 01100101 01010111 01010110 01101011 01001001 01000111 01010010 01111001 01100010 01111001 01000010 01101001 01100010 00110011 01100100 01110010 01100011 00110011 01101000 01111010 01100101 01001000 01000101 01100111 01100010 01011000 01001010 01110010 01011001 01101101 01110100 01110100 01011010 01000111 00111001 01101001 01011001 01111001 01000010 01110011 01100001 01010011 01000010 01101001 01100010 00110011 01110000 00110010 01100001 00110010 00110001 01111010 01100101 01001000 01000101 01100111 01011010 01001000 01001010 01110110 01100100 01111001 01000010 01110010 01100101 01000111 00110100 01100111 01100011 00110011 01101000 01110111 01100010 00110010 01001010 01101001 01100011 00110011 01101000 01111000 01001001 01000111 00110001 00110101 01100100 00110011 01100100 00110101 01100101 01000011 01000010 01101110 01100101 01010111 01001010 01110101 01011001 01111001 01000010 01111010 01100101 01000011 01000010 01101011 01100011 01101101 00111000 01100111 01010100 00110011 01101000 01111000 01100100 01101110 01001110 01101010 01100011 01101001 01000010 00110010 01100001 00110011 01101000 01111000 01011010 01010111 01110100 01111000 01100010 01111001 00110100 01100111 01010011 00110011 01101000 00110101 01011010 01001000 01001010 01110110 01011001 01101001 01000010 01111000 01011001 01101101 00111001 01110010 01011010 01000011 01000010 00110011 01100010 00110010 01010010 01111001 01100101 01010111 00110100 01100111 01100011 00110010 01001101 01100111 01011010 01001000 01101011 01100111 01011010 01010111 01001110 01110110 01001001 01001000 01000010 01101001 01100010 00110010 01000110 01101100 01100010 00110011 01101000 01110100 01100001 01010011 01000010 01110010 01100101 01000111 01110100 00110010 01100001 01010111 01001110 01111010 01011001 01111010 01101111 01100111 01011010 00110010 00111000 01100111 01100100 01011000 01101000 00110101 01011010 01111001 01000010 01101011 01100011 01101101 01110100 01101011 01001001 01000011 01100100 01110110 01001010 01111001 01000010 01101010 01100011 01101110 01101100 01101110 01011001 01111001 01000010 01101100 01100101 01101001 01000010 00110011 01100101 01010111 01001110 01101011 01001001 01001000 01101100 01110111 01011010 01000111 00111001 00110100 01001001 01001000 01001110 00110100 01001001 01000111 01010010 01111001 01100010 01111001 01000010 01110010 01100100 01101110 01110000 01111001 01100001 00110010 01111000 01110110 01011010 01000011 01110111 01100111 01011001 00110011 01101011 01100111 01011010 01001000 01001010 01110010 01011010 01000011 01100100 01101010 01001001 01001000 01110000 01101001 01100101 01010111 01111000 01110010 01100010 01001000 01011010 01110000 01001001 01000111 01010010 01111001 01100010 01111001 01000010 00110011 01100101 01010111 01001110 01101011 01001001 01000111 00110001 00110101 01100100 00110011 01100100 00110101 01100101 01000011 01000010 01110100 01100011 01101101 01110100 01101001 01100001 00110010 00110001 01101011 01100010 00110010 01001001 01100111 01100011 00110011 01100111 01100111 01011010 01001000 01001010 01110110 01001001 01000111 01010010 01110110 01100001 01000111 01010001 01110011 01001001 01001000 01000010 00110101 01100100 01101110 01011010 00110101 01011010 00110010 00111001 01110101 01001001 01000111 01111000 01110000 01001001 01000011 01100100 01101011 01001010 01111001 01110111 01100111 01100001 00110011 01101000 01110101 01001001 01000111 01001110 00110101 01001001 01001000 01101100 00110100 01001100 01101001 01000010 01011010 01100101 01000111 00110001 01110110 01001001 01000111 01101100 00110101 01011010 01010011 01000010 00110001 01100101 01001000 01101100 01101110 01001001 01000111 01110011 01100111 01100011 01000111 00111001 01101110 01001001 01000111 00110001 01111001 01100001 00110010 01001010 01110010 01100010 01010111 01010010 01110110 01011001 01101101 01001101 01110011 01001001 01000111 01101100 00110101 01011010 01010011 01000010 01110100 01100001 00110011 01100111 01100111 01100011 00110011 01101000 01110111 01100010 00110010 01001001 01100111 01011010 01001000 01001010 01110110 01001001 01000111 01001010 01110110 01011001 00110010 01010001 01100111 01100101 01011000 01000001 01100111 01011010 01001000 01001010 01110110 01001001 01000111 01100100 00110101 01011001 01101101 00110101 01101010 01001001 01000111 01111000 01110010 01011001 00110010 00111001 01110101 01001001 01001000 01101100 00110100 01001001 01000111 00110001 00110101 01100100 00110011 01100100 00110101 01100101 01000011 01000010 01101110 01100101 01010111 01001010 01110101 01011001 01111001 01000010 01101011 01100011 01101101 01110100 01101011 01001001 01000111 01001110 01111001 01100101 01010111 01100011 01100111 01011010 01011000 01101111 01100111 01100011 00110011 01100111 01100111 01011010 01001000 01001010 01110110 01001001 01000101 00111001 00110100 01100011 01011000 01011010 01111010 01011001 00110011 01001001 01100111 01100100 01101101 01110100 00110100 01100011 01010111 01010110 01110010 01100011 01010111 00111000 01110101 01000011 01101110 01001010 01101110 01100001 01000111 00110101 00110100 01100011 00110010 01010010 01101101 01100101 01011000 01001110 01101011 01100100 01000111 01100100 01101111 01100100 01010011 01000101 01100111 01100011 01010111 01100100 01101101 01001001 01000111 01101100 01111010 01011001 01010111 01110011 01100111 01011001 00110011 01010010 01101111 01100100 01001000 01010110 01110000 01100001 00110010 01010101 01100111 01011010 01000111 01101100 01110010 01001001 01001000 01110000 01110010 01100010 01101110 01010010 01101111 01100001 01000111 01110100 00110100 01001001 01001000 01001010 00110100 01100011 01010111 01111000 01101011 01011010 00110010 00110101 00110100 01100011 00110010 01111000 01110000 01100011 01010011 01000010 01111001 01100001 01011000 01001110 00110101 01100101 01010111 01110100 01101111 01100010 01101101 01110011 01110101 01001001 01000111 01101100 01110010 01100101 01000111 01110011 01100111 01100100 01001000 01010101 01100111 01100011 01111001 01000010 01101010 01100101 01011000 01001110 01110101 01001001 01000111 01001110 01101110 01100101 01000011 01000010 01111010 01100101 01011000 01101011 01100111 01100011 01010111 01100100 01101101 01100101 01000011 01000010 01110000 01100011 00110011 01101000 01101100 01001001 01000111 01110100 01101010 01011001 00110010 01100100 00110100 01011010 01001000 01010101 00110110 01001001 01000111 01011010 01101011 01011001 00110011 01101100 01111010 01100010 01101110 01110100 01101111 01001101 01001000 01011010 01100110 01011010 01000111 01101011 00110000 01011010 01001000 01010110 01100110 01100100 01101101 01101011 00110000 01011010 01000110 00111001 00110000 01011000 00110011 01001001 00110000 01100101 01011000 01101100 01100110 01100011 01101110 01101000 01111000 01100010 01000111 01010001 01110111 01100110 01010011 00110100 01100111 01100011 01010111 01100100 01101101 01001001 01001000 01011010 00110000 01100101 01011000 01101011 01100111 01011001 00110011 01010010 01101111 01011010 01010011 01000010 01101011 01100001 01011000 01001110 01101011 01001001 01001000 01001101 01100111 01100101 01010111 01100100 01101011 01001001 01000111 01100100 01101010 01001001 01001000 01001010 00110100 01100011 01010111 01111000 01101011 01011010 00110010 00110101 00110100 01100011 00110010 01111000 01110000 01100011 01010011 01000010 00110000 01100100 01010011 01000010 01110111 01011010 01101110 01010110 01101011 01001001 01001000 01110000 01101101 01100100 01001000 01101100 01101100 01100100 01000111 01101000 01110101 01001001 01000111 01100100 01101010 01011001 01111001 01000010 01101011 01100001 01011000 01010010 00110001 01001001 01001000 01010110 01101110 01100101 01000111 01010001 01100111 01011010 00110010 01001101 01100111 01100101 01101110 01001110 00110001 01100100 01001000 01001001 01100111 01011001 01101101 01101000 01101110 01100100 01101110 01101100 01110010 01011010 01010111 00110101 01110010 01001100 01000011 01000010 01111010 01100001 01000111 01010101 01100111 01100100 01000111 01010001 01100111 01100101 01000111 01110100 01111010 01100101 01011000 01101100 01111000 01001001 01001000 01010010 00110001 01001001 01000111 01101000 01101110 01011010 01000011 01000010 00110001 01011010 01111001 01000010 00110110 01100011 00110010 01010101 01100111 01100011 00110010 01001110 01101011 01100001 00110011 01100111 01100111 01100011 00110011 01101100 00110101 01001100 01101001 01000010 01110000 01011010 00110010 01111000 01110010 01001001 01001000 01000110 01101110 01011010 01101001 01000010 01110010 01100001 01001000 01000010 01101110 01100011 01010111 01110100 01101100 01001001 01000111 01010010 01110000 01100001 01111001 01000010 01111001 01100001 01011000 01001110 00110101 01100101 01010111 01110100 01101111 01100010 01101101 01110011 01101000

アプローチ:binary -> base64 -> rot16 -> substitution cipher

CyberChefを使って変換していきます.

From Binary

Uh-oh, looks like we have another block of text, with some sort of special encoding. Can you figure out what this encoding is? (hint: if you look carefully, you'll notice that there only characters present are A-Z, a-z, 0-9, and sometimes / and +. See if you can find an encoding that looks like this one.)
TmV3IGNoYWxsZW5nZSEgQ2FuIHlvdSBmaWd1cmUgb3V0IHdoYXQncyBnb2luZyBvbiBoZXJlPyBJdCBsb29rcyBsaWtlIHRoZSBsZXR0ZXJzIGFyZSBzaGlmdGVkIGJ5IHNvbWUgY29uc3RhbnQuIChoaW50OiB5b3UgbWlnaHQgd2FudCB0byBzdGFydCBsb29raW5nIHVwIFJvbWFuIHBlb3BsZSkuCmt2YnNxcmQsIGl5ZSdibyBrdnd5Y2QgZHJvYm8hIFh5ZyBweWIgZHJvIHBzeGt2IChreG4gd2tpbG8gZHJvIHJrYm5vY2QuLi4pIHprYmQ6IGsgY2VsY2RzZGVkc3l4IG1zenJvYi4gU3ggZHJvIHB5dnZ5Z3N4cSBkb2hkLCBTJ2ZvIGRrdW94IHdpIHdvY2NrcW8ga3huIGJvenZrbW9uIG9mb2JpIGt2enJrbG9kc20gbXJrYmttZG9iIGdzZHIgayBteWJib2N6eXhub3htbyBkeSBrIG5zcHBvYm94ZCBtcmtia21kb2IgLSB1eHlneCBrYyBrIGNlbGNkc2RlZHN5eCBtc3pyb2IuIE1reCBpeWUgcHN4biBkcm8gcHN4a3YgcHZrcT8gcnN4ZDogR28gdXh5ZyBkcmtkIGRybyBwdmtxIHNjIHF5c3hxIGR5IGxvIHlwIGRybyBweWJ3a2QgZWRwdmtxey4uLn0gLSBncnNtciB3b2t4YyBkcmtkIHNwIGl5ZSBjb28gZHJrZCB6a2Rkb2J4LCBpeWUgdXh5ZyBncmtkIGRybyBteWJib2N6eXhub3htb2MgcHliIGUsIGQsIHAsIHYgaywga3huIHEga2JvLiBJeWUgbWt4IHpieWxrbHZpIGd5YnUgeWVkIGRybyBib3drc3hzeHEgbXJrYmttZG9iYyBsaSBib3p2a21zeHEgZHJvdyBreG4gc3hwb2Jic3hxIG15d3d5eCBneWJuYyBzeCBkcm8gT3hxdnNjciB2a3hxZWtxby4gS3h5ZHJvYiBxYm9rZCB3b2RyeW4gc2MgZHkgZWNvIHBib2Flb3htaSBreGt2aWNzYzogZ28gdXh5ZyBkcmtkICdvJyBjcnlnYyBleiB3eWNkIHlwZG94IHN4IGRybyBrdnpya2xvZCwgY3kgZHJrZCdjIHpieWxrbHZpIGRybyB3eWNkIG15d3d5eCBtcmtia21kb2Igc3ggZHJvIGRvaGQsIHB5dnZ5Z29uIGxpICdkJywga3huIGN5IHl4LiBZeG1vIGl5ZSB1eHlnIGsgcG9nIG1ya2JrbWRvYmMsIGl5ZSBta3ggc3hwb2IgZHJvIGJvY2QgeXAgZHJvIGd5Ym5jIGxrY29uIHl4IG15d3d5eCBneWJuYyBkcmtkIGNyeWcgZXogc3ggZHJvIE94cXZzY3Igdmt4cWVrcW8uCnJnaG54c2RmeXNkdGdodSEgcWdmIGlzYWsgY3RodHVpa2UgZGlrIHprbnRoaGt4IHJ4cWxkZ254c2xpcSByaXN5eWtobmsuIGlreGsgdHUgcyBjeXNuIGNneCBzeXkgcWdmeCBpc3hlIGtjY2d4ZHU6IGZkY3lzbntoMHZfZGk0ZHVfdmk0ZF90X3I0eXlfcnhxbGQwfS4gcWdmIHZ0eXkgY3RoZSBkaXNkIHMgeWdkIGdjIHJ4cWxkZ254c2xpcSB0dSBwZnVkIHpmdHlldGhuIGdjYyBkaXR1IHVneGQgZ2MgenN1dHIgYmhndnlrZW5rLCBzaGUgdGQgeGtzeXlxIHR1IGhnZCB1ZyB6c2Ugc2Nka3ggc3l5LiBpZ2xrIHFnZiBraHBncWtlIGRpayByaXN5eWtobmsh

From Base64

New challenge! Can you figure out what's going on here? It looks like the letters are shifted by some constant. (hint: you might want to start looking up Roman people).
kvbsqrd, iye'bo kvwycd drobo! Xyg pyb dro psxkv (kxn wkilo dro rkbnocd...) zkbd: k celcdsdedsyx mszrob. Sx dro pyvvygsxq dohd, S'fo dkuox wi wocckqo kxn bozvkmon ofobi kvzrklodsm mrkbkmdob gsdr k mybboczyxnoxmo dy k nsppoboxd mrkbkmdob - uxygx kc k celcdsdedsyx mszrob. Mkx iye psxn dro psxkv pvkq? rsxd: Go uxyg drkd dro pvkq sc qysxq dy lo yp dro pybwkd edpvkq{...} - grsmr wokxc drkd sp iye coo drkd zkddobx, iye uxyg grkd dro mybboczyxnoxmoc pyb e, d, p, v k, kxn q kbo. Iye mkx zbylklvi gybu yed dro bowksxsxq mrkbkmdobc li bozvkmsxq drow kxn sxpobbsxq mywwyx gybnc sx dro Oxqvscr vkxqekqo. Kxydrob qbokd wodryn sc dy eco pboaeoxmi kxkvicsc: go uxyg drkd 'o' crygc ez wycd ypdox sx dro kvzrklod, cy drkd'c zbylklvi dro wycd mywwyx mrkbkmdob sx dro dohd, pyvvygon li 'd', kxn cy yx. Yxmo iye uxyg k pog mrkbkmdobc, iye mkx sxpob dro bocd yp dro gybnc lkcon yx mywwyx gybnc drkd cryg ez sx dro Oxqvscr vkxqekqo.
rghnxsdfysdtghu! qgf isak cthtuike dik zknthhkx rxqldgnxsliq risyykhnk. ikxk tu s cysn cgx syy qgfx isxe kccgxdu: fdcysn{h0v_di4du_vi4d_t_r4yy_rxqld0}. qgf vtyy cthe disd s ygd gc rxqldgnxsliq tu pfud zftyethn gcc ditu ugxd gc zsutr bhgvykenk, she td xksyyq tu hgd ug zse scdkx syy. iglk qgf khpgqke dik risyykhnk!

ROT16

alright, you're almost there! Now for the final (and maybe the hardest...) part: a substitution cipher. In the following text, I've taken my message and replaced every alphabetic character with a correspondence to a different character - known as a substitution cipher. Can you find the final flag? hint: We know that the flag is going to be of the format utflag{...} - which means that if you see that pattern, you know what the correspondences for u, t, f, l a, and g are. You can probably work out the remaining characters by replacing them and inferring common words in the English language. Another great method is to use frequency analysis: we know that 'e' shows up most often in the alphabet, so that's probably the most common character in the text, followed by 't', and so on. Once you know a few characters, you can infer the rest of the words based on common words that show up in the English language.
hwxdnitvoitjwxk! gwv yiqa sjxjkyau tya padjxxan hngbtwdnibyg hyiooaxda. yana jk i soid swn ioo gwvn yinu asswntk: vtsoid{x0l_ty4tk_ly4t_j_h4oo_hngbt0}. gwv ljoo sjxu tyit i owt ws hngbtwdnibyg jk fvkt pvjoujxd wss tyjk kwnt ws pikjh rxwloauda, ixu jt naioog jk xwt kw piu istan ioo. ywba gwv axfwgau tya hyiooaxda!

換字式暗号はquipqiupでサクッと解きます.

congratulations! you have finished the beginner cryptography challenge. here is a flag for all your hard efforts: utflag{n0w_th4ts_wh4t_i_c4ll_crypt0}. you will find that a lot of cryptography is just building off this sort of basic knowledge, and it really is not so bad after all. hope you enjoyed the challenge!

utflag{n0w_th4ts_wh4t_i_c4ll_crypt0}

One True Problem

Two of my friends were arguing about which CTF category is the best, but they encrypted it because they didn't want anyone to see. Lucky for us, they reused the same key; can you recover it?

Here are the ciphertexts:

213c234c2322282057730b32492e720b35732b2124553d354c22352224237f1826283d7b0651

3b3b463829225b3632630b542623767f39674431343b353435412223243b7f162028397a103e

アプローチ:ciphertext同士のXOR

問題名と問題文からOne Time Pad keyの使いまわしをしたときに生じる問題を問われていることが分かります.

同一の keyを用いて,One Time Pad m_1, m_2を暗号化すると次のようになります.

 c_1 = key \oplus m_1 \\
c_2 = key \oplus m_2

そのため, c_1, c_2同士のXORが

 c_1 \oplus c_2 = m_1 \oplus m_2

となることを利用し, m_1, m_2を復元することで, key求めることができます.

 m_1, m_2に関してですが,問題文でカテゴリについて議論しているとあるので,カテゴリと m_1 \oplus m_2のXORをとることで m_1, m_2の一部を復元することができます.

以下のコードを用いてカテゴリと m_1 \oplus m_2のXORをとるとCRYPTOGRAPHYBINARY EXPLOITATION m_1, m_2に含まれていることが分かります.

from Crypto.Util.number import *

c1 = 0x213c234c2322282057730b32492e720b35732b2124553d354c22352224237f1826283d7b0651
c2 = 0x3b3b463829225b3632630b542623767f39674431343b353435412223243b7f162028397a103e

categorys = [b'CRYPTOGRAPHY', b'BINARY EXPLOITATION', b'REVERSE ENGINEERING', b'NETWORKING', b'WEB', b'FORENSICS', b'MISC']

xor_msg = long_to_bytes(c1 ^ c2)
for category in categorys:
    print('-'* 30)
    print(category)
    for i in range(len(xor_msg) - len(category) + 1):
        msg = bytearray()
        for c,m in zip(category, xor_msg[i:]):
            msg.append(c ^ m)
        print(msg)
------------------------------
b'CRYPTOGRAPHY'
[snip]
bytearray(b'B+:GUO_ROVH]')
bytearray(b':1NQTWG\\GPLX')
bytearray(b' EXPLOITATIO')
------------------------------
b'BINARY EXPLOITATION'
[snip]
bytearray(b'V&^Q<Q!<;GMOQTORIKO')
bytearray(b'-Y^/ZXY&OQLWIZGTMNX')
bytearray(b'RY IS CRYPTOGRAPHY!')
[snip]

EXPLOITATIO, RY IS CRYPTOGRAPHY!をもとに手作業で確定文字列を増やしていくことで m_1, m_2を全文復元することができます.

THE BEST CTFONE IS BINARY EXPLOITATION
NO THE BEST  CATEGORY IS CRYPTOGRAPHY!

あとは keyを求めるだけです.

msg = b'NO THE BEST  CATEGORY IS CRYPTOGRAPHY!'
c1 = long_to_bytes(c1)
flag = bytearray()
for c, m in zip(c1, msg):
    flag.append(c ^ m)
print(flag)
bytearray(b'os\x03\x18kg\x08b\x12 _\x12im3_p4ds}utflag{tw0_tim3_p')

utflag{tw0_tim3_p4ds}

Random ECB

nc crypto.utctf.live 9003

server.py

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import get_random_bytes
from Crypto.Random.random import getrandbits
from secret import flag

KEY = get_random_bytes(16)


def aes_ecb_encrypt(plaintext, key):
    cipher = AES.new(key, AES.MODE_ECB)
    return cipher.encrypt(plaintext)


def encryption_oracle(plaintext):
    b = getrandbits(1)
    plaintext = pad((b'A' * b) + plaintext + flag, 16)
    return aes_ecb_encrypt(plaintext, KEY).hex()


if __name__ == '__main__':
    while True:
        print("Input a string to encrypt (input 'q' to quit):")
        user_input = input()
        if user_input == 'q':
            break
        output = encryption_oracle(user_input.encode())
        print("Here is your encrypted string, have a nice day :)")
        print(output)
> nc crypto.utctf.live 9003
Input a string to encrypt (input 'q' to quit):
1
Here is your encrypted string, have a nice day :)
0810a77dd0c57f828820ef102fc7269378b7a3b1f807537d5bb3f29cf3206aed
Input a string to encrypt (input 'q' to quit):
1
Here is your encrypted string, have a nice day :)
8fe2fded61cef1f605e890b7eaabc8d082c21c2c5d3b89fbda9c556f8ea1d767a14f439f7202eac2d4a5bff21a8f7ed3
Input a string to encrypt (input 'q' to quit):
1
Here is your encrypted string, have a nice day :)
8fe2fded61cef1f605e890b7eaabc8d082c21c2c5d3b89fbda9c556f8ea1d767a14f439f7202eac2d4a5bff21a8f7ed3
Input a string to encrypt (input 'q' to quit):
1
Here is your encrypted string, have a nice day :)
8fe2fded61cef1f605e890b7eaabc8d082c21c2c5d3b89fbda9c556f8ea1d767a14f439f7202eac2d4a5bff21a8f7ed3
Input a string to encrypt (input 'q' to quit):
1
Here is your encrypted string, have a nice day :)
0810a77dd0c57f828820ef102fc7269378b7a3b1f807537d5bb3f29cf3206aed

アプローチ:選択平文攻撃

AES-ECBに対する典型的な選択平文攻撃が可能ですが, encryption_oracleで入力文字列に50%の確率でAがprefixとして追加されるので,期待通りのplaintextを暗号化できているか何度か確認する必要があります.

以下のソルバではencrypt結果の一致判定を5回行って,prefixによって生じる問題を回避しています (5回しか一致判定をしていないので3.125%の確率でflag1byte分の情報を見逃してしまいます).
また,17byte以降のflagはencrypt結果の17~32byteと49~64byteの一致判定及び1~16byteと33~48byteの一致判定を行うことで復元可能です.

自動化が面倒だったので手動で1文字ずつflagを確定させていきました

import string
from socket import *

sock = socket(AF_INET, SOCK_STREAM)
sock.connect(('crypto.utctf.live', 9003))

confirmed_flag = b'utflag{3cb_w17h_' #16byte
flag = b'r4nd0m_pr3f1x'

rec = sock.recv(1024).decode('utf-8')

for c in '_}' + string.digits + string.ascii_lowercase:
    print(c)
    found = False
    for i in range(5):
        # msg = b'A' * (15 - len(flag)) + flag + c.encode()
        # msg += b'A' * (15 - len(flag)) + b'\n'
        msg = b'A' * (15 - len(flag)) + confirmed_flag[:len(flag)+1]
        msg += confirmed_flag[len(flag)+1:] + flag + c.encode()
        msg += b'A' * (15 - len(flag)) + b'\n'
        sock.send(msg)
        enc = sock.recv(1024).decode('utf-8').split('\n')[1]
        # print(enc)
        if enc[32:64] == enc[96:128] and enc[0:32] == enc[64:96] and len(enc) != 0:
            print('found')
            print(c)
            found = True
            break
    if found:
        print(confirmed_flag.decode() + flag.decode() + c)
        break

utflag{3cb_w17h_r4nd0m_pr3f1x}

Hill

I found these characters on top of a hill covered with algae ... bruh I can't figure it out can you help me?
wznqca{d4uqop0fk_q1nwofDbzg_eu}

アプローチ:行列サイズのエスパー

出題者はencrypt.pyを配布して

問題名からHill Cipherを用いてflagを暗号化したと推測できます.

ここで行列サイズを2行2列, \bmodを26と仮定し,暗号化に用いた行列を Xとします.

f:id:satto1237:20200312235442p:plain

このとき,flag format からHill Cipherによる暗号化は次のようになっていると考えることができます.

f:id:satto1237:20200312235413p:plain

したがって, X^{-1}を求めることで,flagを得ることができます.

 X^{-1}は次のようになります.

f:id:satto1237:20200313005902p:plain

以下,ソルバです.

import binascii
import numpy as np
from Crypto.Util.number import inverse

def transform_matrix(text):
    mats = []

    for i in range(0, len(text), 4):
        mats.append([
            [text[i] - ord('a'), text[i + 1] - ord('a')],
            [text[i + 2] - ord('a'), text[i + 3] - ord('a') ],
        ])

    return mats

def decrypt(inv_key_mat, mats):
    flag = ''
    for mat in mats:
        # flag_mat = np.round(np.dot(inv_key_mat, mat)) % 26
        flag_mat = np.round(np.dot(mat, inv_key_mat)) % 26
        print(flag_mat)
        for row in flag_mat:
            for x in row:
                flag += chr(int(x) + ord('a'))
    print(flag)

# enc = b'wznqca{d4uqop0fk_q1nwofDbzg_eu}'
enc = b'wznqcaduqopfkqnwofdbzgeu'
enc_mat = transform_matrix(enc)

target_mat = [[20, 19],[ 5, 11]]
inv_target_mat = np.round(np.linalg.inv(target_mat) * np.linalg.det(target_mat))
inv_target = inverse(round(np.linalg.det(inv_target_mat)), 26)
inv_target_mat = inv_target_mat * inv_target % 26
key_mat = np.round(np.dot(inv_target_mat, enc_mat[0]))
inv_key_mat = np.round(np.linalg.inv(key_mat) * np.linalg.det(key_mat))
inv_key = inverse(round(np.linalg.det(inv_key_mat)), 26)
inv_key_mat = np.round(inv_key_mat * inv_key) % 26

decrypt(inv_key_mat, enc_mat)
> python solve.py
[[20. 19.]
 [ 5. 11.]]
[[ 0.  6.]
 [ 3. 13.]]
[[ 6.  4.]
 [17. 20.]]
[[18.  2.]
 [15.  7.]]
[[ 4. 17.]
 [19.  4.]]
[[23. 19.]
 [16. 16.]]
utflagdngeruscphertextqq

utflag{d4nger0us_c1pherText_qq}

preタグ使わないと行列書けないはてなmarkdownくん…
preタグ使ったあとにシンタックスハイライト使うとpreタグ内の数式崩壊するの何故?
結局TeXclipで数式を画像化しちゃった

Galois

nc crypto.utctf.live 9004

server.py

import sys
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from secret import flag

KEY = get_random_bytes(16)
NONCE = get_random_bytes(16)


def aes_gcm_encrypt(plaintext):
    cipher = AES.new(KEY, AES.MODE_GCM, nonce=NONCE)
    ciphertext, tag = cipher.encrypt_and_digest(plaintext)
    return ciphertext.hex(), tag.hex()


def aes_gcm_decrypt(ciphertext, tag):
    cipher = AES.new(KEY, AES.MODE_GCM, nonce=NONCE)
    plaintext = cipher.decrypt_and_verify(ciphertext, tag)
    return plaintext


if __name__ == '__main__':
    options = '''Welcome to the AES GCM encryption and decryption tool!
        1. Encrypt message
        2. Decrypt message
        3. Quit
    '''

    def encrypt_msg():
        print("Input a string to encrypt (must be at least 32 characters):")
        user_input = input()
        if len(user_input) < 32:
            sys.exit()
        output = aes_gcm_encrypt(user_input.encode())
        print("Here is your encrypted string & tag, have a nice day :)")
        print(output)


    def decrypt_msg():
        print("Input a hex string and its tag to decrypt:")
        user_input = bytearray.fromhex(input())
        tag = bytearray.fromhex(input())
        try:
            output = aes_gcm_decrypt(user_input, tag)
        except ValueError:
            print("Decryption failed :(")
            return
        print("Here is your decrypted string, have a nice day :)")
        print(output)


    def quit():
        sys.exit()

    menu = {
        '1' : encrypt_msg,
        '2' : decrypt_msg,
        '3' : quit
    }
    
    i = 0
    print('flag', aes_gcm_encrypt(flag)[0])
    while i < 10:
        print(options)
        print('Select option: ')
        choice = input()
        if choice not in menu.keys():
            print("Not a valid choice...")
            sys.exit()
        menu[choice]()
        i += 1
> nc crypto.utctf.live 9004
flag ecdf4c528049b4eec2099b0644ad67075253cfaeb3e4efb4200c5b37393ef99e
Welcome to the AES GCM encryption and decryption tool!
        1. Encrypt message
        2. Decrypt message
        3. Quit

Select option:
1
Input a string to encrypt (must be at least 32 characters):
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Here is your encrypted string & tag, have a nice day :)
('d8ea6b7fa06f8e99e0258521359e44777776bd81ad9199c2552e71294f488fa2', '623748220dc33b03577ab40ce0edd737')
Welcome to the AES GCM encryption and decryption tool!
        1. Encrypt message
        2. Decrypt message
        3. Quit

Select option:
3

アプローチ:AES-GCMにおける同一KEY及び同一NONCEを用いたEncryptの脆弱性

AES-GCM,初めて知った

AES-GCMについて調べるとAES-GCMは暗号化としてCTRモードを利用し,認証としてGaloisモードを組み合わせたモードであることが分かりました(それはそうでしょ).
つまり,AES-GCMにおける同一KEY及び同一NONCEを用いたEncryptによる問題はAES-CTRを利用した場合でも発生します.

AES-CTRで同一KEY及び同一NONCEを用いたEncrypt行った場合,以下のような問題が発生します.

 Enc(flag) \oplus Enc(msg) = flag \oplus msg

したがって,以下のソルバでflagを求めることができます.

from Crypto.Util.number import *

enc_flag = long_to_bytes(0xecdf4c528049b4eec2099b0644ad67075253cfaeb3e4efb4200c5b37393ef99e)
enc_msg = long_to_bytes(0xd8ea6b7fa06f8e99e0258521359e44777776bd81ad9199c2552e71294f488fa2)

msg = b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'

msg_xor_flag = [m ^ f for m,f in zip(enc_msg, enc_flag)]

flag = [chr(m ^ mxf) for m,mxf in zip(msg,msg_xor_flag)]

print(''.join(flag))
> python solve.py
utflag{6cm_f0rb1dd3n_4774ck_777}

utflag{6cm_f0rb1dd3n_4774ck_777}

以下のページが参考になりました.

github.com

Curveball

My friend Shamir was trying to share the flag with me and some of the other problem writers, but he wanted to make sure it didn't get intercepted in transmission, so he split it up. He said that the secrets that he shared will help us find the flag, but I can't figure it out! These are the secrets I've gathered so far:

(C81E728D9D4C2F636F067F89CC14862C, 31E96A93BF1A7CE1872A3CCDA6E07F86)
(ECCBC87E4B5CE2FE28308FD9F2A7BAF3, ADF6E4F1052BDE978344743CCDCF5771)
(E4DA3B7FBBCE2345D7772B0674A318D5, 0668FBCFE4098FEA0218163AC21E6531)

flags.txt

wc -l flags.txt
 14776336 flags.txt
> head -n 5 flags.txt
utflag{aaaa}
utflag{aaab}
utflag{aaac}
utflag{aaad}
utflag{aaae}
> tail -n 5 flags.txt
utflag{9995}
utflag{9996}
utflag{9997}
utflag{9998}
utflag{9999}

アプローチ:ラグランジュ補間

問題文からSecret Sharingであることが分かります.
また,16進数で表された座標はMD5であることも確認できます.

(2, 5398141)
(3, 5398288)
(5, 5398756)

上記の座標を用いて,ラグランジュ補間を行うことでsecretを求めることができます.
ここでのsecretflags.txtsecret番目の文字列がflagであることを表していると考えられます.

以下,ソルバになります.

from Crypto.Util.number import long_to_bytes

points = [(2, 5398141), (3, 5398288), (5, 5398756)]

lag0 = (points[0][1] * points[1][0] * points[2][0]) // ((points[0][0]-points[1][0]) * (points[0][0]-points[2][0]))
lag1 = (points[1][1] * points[0][0] * points[2][0]) // ((points[1][0]-points[0][0]) * (points[1][0]-points[2][0]))
lag2 = (points[2][1] * points[1][0] * points[0][0]) // ((points[2][0]-points[1][0]) * (points[2][0]-points[0][0]))
secret = lag0 + lag1 + lag2

print(secret)

with open('flags.txt') as f:
    flags = [line.strip() for line in f.readlines()]

print(flags[secret - 1])
> python solve.py 
5398021
utflag{wOq0}

まとめ

  • 久しぶりにWrite-up書けるくらい解けたので嬉しかった
  • 裏でやってたzer0pts CTFほとんどできなかったので悲しかった
  • 中級者レベルのCrypto問が安定して解けるようになったらRev, Pwnに手を出したい(これずっと言ってるじゃん)

チームメンバのWrite-up

hackmd.io