MawaLog

一日一日、楽しく生きる。技術と音楽が好き。

CTF for Beginners 2018 で CTF問題演習 Crypto [Warmup] Veni, vidi, vici を解く

セキュリティコンテストチャレンジブック -CTFで学ぼう! 情報を守るための戦い方-

セキュリティコンテストチャレンジブック -CTFで学ぼう! 情報を守るための戦い方-

経緯

こういう感じで、 k-mawa.hateblo.jp

とりあえず、CTFにてもっと解けるように残った問題で手習い開始。

Crypto [Warmup] Veni, vidi, vici

1:問題をダウンロードする。

次のような文字列のファイルが見える

#part1
Gur svefg cneg bs gur synt vf: pgs4o{a0zber
#part2
Lzw kwugfv hsjl gx lzw xdsy ak: _uDskk!usd_u
#part3
{ʎɥdɐɹɓ0ʇdʎᴚ :sı ɓɐlɟ ǝɥʇ ɟo ʇɹɐd pɹıɥʇ ǝɥ⊥

ふーん。経験値が少なすぎてなんじゃこりゃ・・・って感じ。part3は可読だね。逆さになってるだけだ。逆さになってる文字列を180度回転するモジュールとかあるんかしら・・・

2逆さにした文字を戻す

rot180って通称で呼ばれているようだ。原理は下記のような感じ。W→Mに変換と似ている文字を探して置換しているだけ。

id.fnshr.info

pythonよく使うからpythonでできないかな。これ・・・で、ありました^^/

How to rotate a character or string by 90 or 180 degree in python? - Stack Overflow

upsidedownってモジュールかやってみよ。

$pip install upsidedown==0.3
#!python3.x系はエラー!
#python2.7.10でインストール成功

$python
Python 2.7.10
>>> import upsidedown
>>> print upsidedown.transform('hello world!')
¡pꞁɹoʍ oꞁꞁǝɥ

よしできた!やってみよう。

UnicodeDecodeError: 'ascii' codec can't decode byte 0xca in position 1: ordinal not in range(128)

ん〜もうこの辺は核心部分じゃないから、いいや。多分アルファベットくらいの対応表しか用意してなくて、十分な対応表がないんじゃないかな・・・そのメンテナンスが遊びの割に面倒だから、pythonモジュールあんまなかったのかも。ふつうにWebのツールでやろう。

Lunicode

一瞬でできた、楽やな^^

#part3 解決後
The third part of the flag is: Rypt0graphy}

3

part1,part2は、意味不明な文字列・・・The third part of the flag is: Rypt0graphy} をからすると、The first part of the flag is: … The second part of the flag is: …と、なりそうかなと当たりをつけることはできる。それで、文字自体は対応してないけど、区切りごとの文字数は同じ・・・つまりシーザー暗号かもね。ということで、調べてみた。

wikiわかりやすい。なるほど。アルファベットを半分にして、逆に対応させるのか。それでROT13か。なんかカッコイイな^^ ROT13 - Wikipedia

そのためのツールがpythonにはあると。今度こそpythonで解きたいよね。

blog.amedama.jp

#part1を解く
>>> import codecs
>>> str = "Gur svefg cneg bs gur synt vf: pgs4o{a0zber"
>>> codecs.decode(str, 'rot13')
'The first part of the flag is: ctf4b{n0more'

行けたやん!

4 part2を解く

>>> import codecs
>>> str = "Lzw kwugfv hsjl gx lzw xdsy ak: _uDskk!usd_u!"
>>> codecs.decode(str, 'rot13')
'Ymj xjhtsi ufwy tk ymj kqfl nx: _hQfxx!hfq_h!'

意味不明だなァ

ここでpythonの文字列の比較演算子の挙動をチェックしてみる…

>>> "a" > "b"
False
>>> "a" < "b"
True
>>> "a" < "a"
False
>>> "a" < "z"
True
>>> "a" < "B" <"z"
False
>>> "a" < "b" <"z"
True
>>> "z" < "b" <"z"
False

うーむつまり、単純に文字列がアルファベット順になっていればTrueというわけか。ふーん。

さらに調べると、アスキーコードの数字の大小で調べていることがわかった。つまりこういうこと。ordは組み込みメソッド

>>> ord('A')
65
>>> ord('B')
66
>>> ord('C')
67
>>> ord('a')
97
>>> ord('b')
98
>>> ord('c')
99

つまり1文字ずらすというのは

>>> chr(ord('A') + 1)
'B'
>>> chr(ord('Z') + 1)
'['
おっと循環しているわけではないか。
>>> ord('A')
65
>>> ord('Z')
90

解説を読みながらテスト

>>> str="J"
>>> chr((ord(str) - ord('A') + 13) % 26 + ord('A'))
'W'

OK、じゃあこれで1文字〜13文字までずらした結果を導く関数をつくってみるか。コード書こう。自分でもツールを作りたいからね^^

と、いうわけで小1時間くらい書いてできた!!

#str_rot_n.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re

def str_rot_n(strings):
    strlist = list(strings)
    answer_list =[]

    for i in range(13):
        print("[+]Info:strings rot {}...".format(i+1))
        
        for j in strlist:

            if 'A' <= j and j <= 'Z':
                roted_str = chr((ord(j) - ord('A') + i+1) % 26 + ord('A'))
                answer_list.append(roted_str)

            if 'a' <= j and j <= 'z':
                roted_str = chr((ord(j) - ord('a') + i+1) % 26 + ord('a'))
                answer_list.append(roted_str)

            m = re.match(r"[a-z,A-Z]", j)
            
            if not m:
                answer_list.append(j)

        answer_list = ','.join(answer_list)
        answer_list = answer_list.replace(",","")

        print("[+]Info:strings rot {}: decode strings is '{}'".format(i+1,answer_list))

        answer_list =[]

これを動かすと・・・

>>> import str_rot_n
>>> str = "Lzw kwugfv hsjl gx lzw xdsy ak: _uDskk!usd_u"
>>> str_rot_n.str_rot_n(str)
[+]Info:strings rot 1...
[+]Info:strings rot 1: decode strings is 'Max lxvhgw itkm hy max yetz bl: _vEtll!vte_v'
[+]Info:strings rot 2...
[+]Info:strings rot 2: decode strings is 'Nby mywihx juln iz nby zfua cm: _wFumm!wuf_w'
[+]Info:strings rot 3...
[+]Info:strings rot 3: decode strings is 'Ocz nzxjiy kvmo ja ocz agvb dn: _xGvnn!xvg_x'
[+]Info:strings rot 4...
[+]Info:strings rot 4: decode strings is 'Pda oaykjz lwnp kb pda bhwc eo: _yHwoo!ywh_y'
[+]Info:strings rot 5...
[+]Info:strings rot 5: decode strings is 'Qeb pbzlka mxoq lc qeb cixd fp: _zIxpp!zxi_z'
[+]Info:strings rot 6...
[+]Info:strings rot 6: decode strings is 'Rfc qcamlb nypr md rfc djye gq: _aJyqq!ayj_a'
[+]Info:strings rot 7...
[+]Info:strings rot 7: decode strings is 'Sgd rdbnmc ozqs ne sgd ekzf hr: _bKzrr!bzk_b'
[+]Info:strings rot 8...
[+]Info:strings rot 8: decode strings is 'The second part of the flag is: _cLass!cal_c'
[+]Info:strings rot 9...
[+]Info:strings rot 9: decode strings is 'Uif tfdpoe qbsu pg uif gmbh jt: _dMbtt!dbm_d'
[+]Info:strings rot 10...
[+]Info:strings rot 10: decode strings is 'Vjg ugeqpf rctv qh vjg hnci ku: _eNcuu!ecn_e'
[+]Info:strings rot 11...
[+]Info:strings rot 11: decode strings is 'Wkh vhfrqg sduw ri wkh iodj lv: _fOdvv!fdo_f'
[+]Info:strings rot 12...
[+]Info:strings rot 12: decode strings is 'Xli wigsrh tevx sj xli jpek mw: _gPeww!gep_g'
[+]Info:strings rot 13...
[+]Info:strings rot 13: decode strings is 'Ymj xjhtsi ufwy tk ymj kqfl nx: _hQfxx!hfq_h'
>>> 

おお![+]Info:strings rot 8... [+]Info:strings rot 8: decode strings is 'The second part of the flag is: _cLass!cal_c'

というわけで、最後のパーツもそろった!

The first part of the flag is: ctf4b{n0more
The second part of the flag is: _cLass!cal_c
The third part of the flag is: Rypt0graphy}

あわせて、 ctf4b{n0more_cLass!cal_cRypt0graphy}

f:id:k_mawa:20180529003743p:plain

解けたぁ!!

解説

これを読みつつ復習中 ^^/

SECCON Beginners CTF 2018 Write-up