はじめに
CTF学習のため、Cpawというサイトの問題を解いていく記事です。
今回はCpaw最終回ということでLevel3の残り2問を解いていきます。
この記事の対象者
- CTF超初心者
- Cpawの問題を解いてみたい人
問題一覧
Q23. [Reversing] またやらかした!
ELFファイル
Level2のQ21でもあったELFファイル
なるものを解析して、
暗号を解くプログラムを実行しましょう。
取り組んだ手順
Step1. WSL環境でコマンドの実行 (ファイルの種類確認)
Step2. WSL環境でコマンドの実行 (アセンブラ眺める)
Step3. Python または C++で暗号解く
実行するコマンド(WSL)
拡張子なしはとりあえずfileコマンド
で種類確認を行いましょう。
file rev200
rev200: ELF 32-bit ... for GNU/Linux 2.6.24
案の定Q21と同じく32bit ELFファイルでしたね。
次にobjdumpコマンド -dオプション
で逆アセンブル情報を見てみます。
objdump -d rev200
たくさんの文字列が出てきますが注目したいのは以下の部分です。
80483f5: c7 45 88 7a 00 00 00 movl $0x7a,-0x78(%ebp)
80483fc: c7 45 8c 69 00 00 00 movl $0x69,-0x74(%ebp)
8048403: c7 45 90 78 00 00 00 movl $0x78,-0x70(%ebp)
804840a: c7 45 94 6e 00 00 00 movl $0x6e,-0x6c(%ebp)
8048411: c7 45 98 62 00 00 00 movl $0x62,-0x68(%ebp)
8048418: c7 45 9c 6f 00 00 00 movl $0x6f,-0x64(%ebp)
804841f: c7 45 a0 7c 00 00 00 movl $0x7c,-0x60(%ebp)
8048426: c7 45 a4 6b 00 00 00 movl $0x6b,-0x5c(%ebp)
804842d: c7 45 a8 77 00 00 00 movl $0x77,-0x58(%ebp)
8048434: c7 45 ac 78 00 00 00 movl $0x78,-0x54(%ebp)
804843b: c7 45 b0 74 00 00 00 movl $0x74,-0x50(%ebp)
8048442: c7 45 b4 38 00 00 00 movl $0x38,-0x4c(%ebp)
8048449: c7 45 b8 38 00 00 00 movl $0x38,-0x48(%ebp)
8048450: c7 45 bc 64 00 00 00 movl $0x64,-0x44(%ebp)
8048457: c7 45 84 19 00 00 00 movl $0x19,-0x7c(%ebp)
movl
:32bitの処理をする命令
movl $0x7a,-0x78(%ebp)
:0x7a(ASCII文字 'z')を−0x78アドレスに格納
これらからrev200ではこの辺が結果として得られてそうなことがわかります。
しかしこれの後に出力命令call
がないため、flagがわからない状態です。
flag求めるソースコード
【やること】
- 0x~を配列に格納する
- keyを0x19として設定する
- forで配列の長さまでループ
- keyと配列のi番目でXORしたものを出力
a = []
a.append(0x7a)
a.append(0x69)
a.append(0x78)
a.append(0x6e)
a.append(0x62)
a.append(0x6f)
a.append(0x7c)
a.append(0x6b)
a.append(0x77)
a.append(0x78)
a.append(0x74)
a.append(0x38)
a.append(0x38)
a.append(0x64)
key = 0x19
for i in a:
# XORする
print(chr(key^i))
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> a;
a.reserve(100);
a.push_back(0x7a);
a.push_back(0x69);
a.push_back(0x78);
a.push_back(0x6e);
a.push_back(0x62);
a.push_back(0x6f);
a.push_back(0x7c);
a.push_back(0x6b);
a.push_back(0x77);
a.push_back(0x78);
a.push_back(0x74);
a.push_back(0x38);
a.push_back(0x38);
a.push_back(0x64);
int key = 0x19;
for (size_t i = 0; i < a.size(); ++i) {
cout << static_cast<char>(key ^ a[i]);
}
cout << endl;
return 0;
}
これによってflagが得られました!
flag
cpaw{vernam!!}
Q26. [PPC] Remainder theorem
Common Modulus Attackをする問題
Common Modulus Attackについてはこのサイトがわかりやすいと思います。
ざっくり言うと、RSA公開鍵(e1,N), (e2,N)と平文 m がある時、
Nに同じ鍵を使っているとできる攻撃です。
(e, N) = (11, 236934049743116267137999082243372631809789567482083918717832642810097363305512293474568071369055296264199854438630820352634325357252399203160052660683745421710174826323192475870497319105418435646820494864987787286941817224659073497212768480618387152477878449603008187097148599534206055318807657902493850180695091646575878916531742076951110529004783428260456713315007812112632429296257313525506207087475539303737022587194108436132757979273391594299137176227924904126161234005321583720836733205639052615538054399452669637400105028428545751844036229657412844469034970807562336527158965779903175305550570647732255961850364080642984562893392375273054434538280546913977098212083374336482279710348958536764229803743404325258229707314844255917497531735251105389366176228741806064378293682890877558325834873371615135474627913981994123692172918524625407966731238257519603614744577)
80265690974140286785447882525076768851800986505783169077080797677035805215248640465159446426193422263912423067392651719120282968933314718780685629466284745121303594495759721471318134122366715904
これは...と書いてある箇所からは問題のNと中身が同じhint.txt
をDLできるようです。
(e, N) = (13, 236934049743116267137999082243372631809789567482083918717832642810097363305512293474568071369055296264199854438630820352634325357252399203160052660683745421710174826323192475870497319105418435646820494864987787286941817224659073497212768480618387152477878449603008187097148599534206055318807657902493850180695091646575878916531742076951110529004783428260456713315007812112632429296257313525506207087475539303737022587194108436132757979273391594299137176227924904126161234005321583720836733205639052615538054399452669637400105028428545751844036229657412844469034970807562336527158965779903175305550570647732255961850364080642984562893392375273054434538280546913977098212083374336482279710348958536764229803743404325258229707314844255917497531735251105389366176228741806064378293682890877558325834873371615135474627913981994123692172918524625407966731238257519603614744577)
14451037575679461333658489727928902053807202350950440400755535465672646289383249206721118279217195146247129636809289035793102103248547070620691905918862697416910065303500798664102685376006097589955370023822867897020714767877873664
求めるソースコードと解説
拡張ユークリッドの互除法はこのサイトとかを参考にしてみてください。
# 拡張ユークリッド互除法関数
def excgcd(a, b):
if(b != 0):
# 最大公約数gcd求める
gcd, y, x = excgcd(b, a % b)
# ax + by = d を満たす係数 (x, y) を計算
y -= (a // b) * x
return gcd, x, y
return a, 1, 0
# Common Modulus Attack
def commonModulusAttack(N, e_1, c_1, e_2, c_2):
gcd, s_1, s_2 = excgcd(e_1, e_2)
return (pow(c_1, s_1 ,N) * pow(c_2, s_2,N)) % N
# 公開鍵と暗号文定義
N = 236934049743116267137999082243372631809789567482083918717832642810097363305512293474568071369055296264199854438630820352634325357252399203160052660683745421710174826323192475870497319105418435646820494864987787286941817224659073497212768480618387152477878449603008187097148599534206055318807657902493850180695091646575878916531742076951110529004783428260456713315007812112632429296257313525506207087475539303737022587194108436132757979273391594299137176227924904126161234005321583720836733205639052615538054399452669637400105028428545751844036229657412844469034970807562336527158965779903175305550570647732255961850364080642984562893392375273054434538280546913977098212083374336482279710348958536764229803743404325258229707314844255917497531735251105389366176228741806064378293682890877558325834873371615135474627913981994123692172918524625407966731238257519603614744577
e_1 = 11
c_1 = 80265690974140286785447882525076768851800986505783169077080797677035805215248640465159446426193422263912423067392651719120282968933314718780685629466284745121303594495759721471318134122366715904
e_2 = 13
c_2 = 14451037575679461333658489727928902053807202350950440400755535465672646289383249206721118279217195146247129636809289035793102103248547070620691905918862697416910065303500798664102685376006097589955370023822867897020714767877873664
m = commonModulusAttack(N, e_1, c_1, e_2, c_2)
print(m)
flag
cpaw{424311244315114354}
おわりに
Cpaw最終回はLevel3の2問について解説しました。
CTFだけでなく競プロでもそうでしたが知識とアルゴリズムへの理解がないとなかなか厳しいことを痛感しました...。
最後までお付き合いただきありがとうございました!