チーム Harekaze で AlexCTF に参加しました。
最終的にチームで 1990 点を獲得し、順位は 68 位 (得点 1029 チーム中) でした。うち、私は 11 問を解いて 1000 点を入れました。
以下、解いた問題の write-up です。
ltrace ./re2 ABCDEFGH
と ltrace ./re2 ALEXCTF{
の結果を比較すると、後者は _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE3endEv
が何度も呼ばれていました。
フラグのフォーマットは ALEXCTF{[A-Za-z0-9_]*}
と指定されていたので、あとはシェルスクリプトで適当に。
#!/bin/bash
for c in 0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z _
do
echo -n "$c ";
ltrace ./re2 $1$c 2>&1 | grep -c endEv
done
ALEXCTF{W3_L0v3_C_W1th_CL45535}
4 人がかりで解きました。rev は気合いです。
まず username のチェック処理を確認します。0x400c9a
からの処理を読むと、どうやら username は 8 文字か 12 文字だろうということが分かります。続いて 0x400cdd
からの処理を読むと、どうやら username を 4 文字ずつに区切っていろいろいじって比較していると分かります。
from z3 import *
a, b, c = Ints('a b c')
solve(a-b+c==0x5c664b56, a*3+c*3+b==0x2e700c7b2, b*c==0x32ac30689a6ad314)
このスクリプトを実行すると username が catalyst_ceo
と分かります。
次に password のチェック処理を確認します。0x400977
からの処理を読むと、srand(username をこねくり回した値)
してから (password を切ったもの) - rand()
と謎の数値とを何度も比較しています。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int seed, i, a, b;
int nums[10] = {
0x55eb052a,
0xef76c39,
0xcc1e2d64,
0xc7b6c6f5,
0x26941bfa,
0x260cf0f3,
0x10d4caef,
0xc666e824,
0xfc89459c,
0x2413073a
};
seed = 0x61746163;
seed += 0x7473796c;
seed += 0x6f65635f;
srand(seed);
printf("seed: %x\n", seed);
for (i = 0; i < 10; i++) {
a = nums[i] + rand();
b = ((a & 0xff000000) >> 24) |
((a & 0xff0000) >> 8) |
((a & 0xff00) << 8) |
((a & 0xff) << 24);
printf("%x", b);
}
putchar('\n');
return 0;
}
で password が sLSVpQ4vK3cGWyW86AiZhggwLHBjmx9CRspVGggj
と分かります。あとは得られた username と password を入力するとフラグが出ました。
ALEXCTF{1_t41d_y0u_y0u_ar3__gr34t__reverser__s33}
s = open('zero_one', 'r').read()
s = s.replace(' ', '').replace('\n', '')
s = s.replace('ZERO', '0').replace('ONE', '1')
print hex(int(s, 2))[2:-1].decode('hex').decode('base64')
を実行するとモールス信号が出てきます。
.- .-.. . -..- -.-. - ..-. - .... .---- ..... --- .---- ... --- ..... ..- .--. ...-- .-. --- ..... . -.-. .-. ...-- - --- - -..- -
これをデコードすると ALEXCTFTH15O1SO5UP3RO5ECR3TOTXT
になりますが、このままでは通りませんでした。若干エスパーして ALEXCTF{TH15_1S_5UP3R_5ECR3T_TXT}
を投げると通りました。
ALEXCTF{TH15_1S_5UP3R_5ECR3T_TXT}
暗号文と ALEXCTF{
を xor すると、Dear Fri
という文字列が冒頭に出てきました。暗号文は何らかの文章とフラグが xor されているようです。
s = '''0529242a631234122d2b36697f13272c207f2021283a6b0c7908
2f28202a302029142c653f3c7f2a2636273e3f2d653e25217908
322921780c3a235b3c2c3f207f372e21733a3a2b37263b313012
2f6c363b2b312b1e64651b6537222e37377f2020242b6b2c2d5d
283f652c2b31661426292b653a292c372a2f20212a316b283c09
29232178373c270f682c216532263b2d3632353c2c3c2a293504
613c37373531285b3c2a72273a67212a277f373a243c20203d5d
243a202a633d205b3c2d3765342236653a2c7423202f3f652a18
2239373d6f740a1e3c651f207f2c212a247f3d2e65262430791c
263e203d63232f0f20653f207f332065262c3168313722367918
2f2f372133202f142665212637222220733e383f2426386b'''
s = ''.join(s.splitlines()).decode('hex')
t = 'Dear Friend, This time I u'
print repr(''.join(chr(ord(c) ^ ord(t[i % len(t)])) for i, c in enumerate(s)))
何らかの文章の方をエスパーで当てていくとフラグが出ました。
ALEXCTF{HERE_GOES_THE_KEY}
RSA のようですが、p と q が既に与えられているので計算するだけです。
ALEXCTF{RS4_I5_E55ENT1AL_T0_D0_BY_H4ND}
strings に投げるとメールアドレスとパスワードらしき文字列が出てきます。
alexctf@example.com
をメールアドレスに、strings
で出てきた dksgkpdjg;kdj;gkje;gj;dkgv a enpginewognvln owkge noejne
をパスワードに入力するとフラグが出てきました。
ALEXCTF{Mu77_Th3_CoRe}
binwalk に投げると PNG があるのが分かります。あとは取り出して、数字に気を付けながら読むだけです。
ALEXCTF{SN1FF_TH3_FL4G_0V3R_U58}
Hint: It scripting because we need a python library to solve the challenge, one that is made in japan.
というヒントから PyPI で jp stegano
と検索すると、steganography というライブラリがヒットしました。
steganography-script.py -d cat_with_secrets.png
でフラグが出てきました。
ALEXCTF{CATS_HIDE_SECRETS_DONT_THEY}
IRC のトピックにフラグが設定されていました。
ALEXCTF{W3_w15h_y0u_g00d_luck}
もはやちょっと懐かしい脆弱性。
heartbleed
証明書を確認すると、どうやら Let’s Encrypt を使っている様子。指定された形式に直します。
letsencrypt
[Reverse Engineering 150] RE3: Catalyst system は手でデコンパイルしながら解きました。ハンドデコンパイルはほとんど経験がありませんでしたが、結構楽しいですね。
st98.github.io / st98 の日記帳