Gen's blog

CTFとか、競プロとか、その他諸々

メイド喫茶とガールズバーに行ってきた

この記事は某社18新卒 Advent Calendar 21日目の記事です.

メイド喫茶

先週,御社のあれこれがあって東京に行き,その後ICPCのつくば大会に参加するためにつくばエクスプレスに乗ってつくばまで…という日程で遠征した. つくばエクスプレスに乗るまでにかなりの(9-10時間ぐらい)時間があったので,秋葉原で時間を潰すことにした. いつもの流れとしてPCパーツを見たり,薄い本を買ったり,カードゲームショップを回ったりしていたが,内定者懇親会や2ヶ月間の内定者アルバイトで遠征した際に何度も通ったので目新しさがなく,2時間程度しか潰せなかった.

とりあえず昼食を済ませてぶらついていたところ,メイド喫茶で作業をして時間を潰すことを思いついた. 私はメイド喫茶に入ったことがなかったので,軽く下調べをしてから行くことにした.以下のサイトが参考になった.

上から順に眺めていくと,シャッツキステさんが気になったので行くことにした. 場所は秋葉原駅から少し離れたところにあり,普段あまり行かない場所なので新鮮さがあった.

入店すると席に案内され,メニューや店内設備についてメイドさんが説明してくれた.店内の本が読めたり,ボードゲームができたりするらしい. 私は作業中飲み物をたくさん飲むので,500円/0.5hで紅茶が飲み放題という料金設定がいいなと思った. 紅茶は飲みきるとわんこそばのように自動で補給してくれるので,一々オーダーしなくていいのも良かった. 店内設備については,持参したプログラミングElixirを読み進めようと思っていたので利用しなかった.

メイド服は露出の多くない白黒の伝統的な(?)メイド服で,すごく好感が持てた.

1時間ほど本を読みながらコードを書いていたら流石に疲れてきて,本とPCを閉じて紅茶を飲んでいたら,メイドさんが話しかけてくれた. 一緒に働いているメイドさんがプログラミングの勉強をしているらしく,「Webページに雪を降らせる方法を習ったので,肉を降らせたい」と言っていたそうだ. 私はCSSについてあまり詳しくないのでぱっとやり方が思いつかなかったのだが,以下の記事のような感じで実装できるのだろう.

そんな感じでメイドさんと少しお話した後,また作業を再開した.メイドさんどうしの会話を聞きながら作業をするのはなかなか捗った.

大満足だった.また行きたい.

ガールズバー

メイド喫茶を出た後,アキヨドで引っ越しのときに購入する家電を案内して貰ったが,それでも時間が余ったのでDOS/V通りをうろついて声をかけられた店に入ることにしたら,ガールズバーの客引きに声をかけられた.客引きの女の子は童顔で結構可愛かったが,12月だというのに脚を露出していて寒そうだった.

お店に入ると,飲み物を聞かれたのでハイボールを頼んだ.女の子の乾杯用の飲み物も買わないといけないらしく,「飲み放題40分 2,160円(税抜き)」+「女の子の飲み物 3,240円(税抜き)」を結果として払うことになった.多少は覚悟していたが,結構痛い出費だ.まあ女の子が可愛かったので許す.

話の内容としては,好きな女優やアイドルを聞かれたが,その辺の話は疎いので「声優でもいい?」と聞いて佐倉綾音を見せたら「普通に可愛いじゃん」と言われた.他にも互いの失恋話とかをしたりした.

まとめとしては,可愛い女の子だったので6,000円出してもそんなにつらくなかったが,そうでなかったらつらかったなあという印象だった.

総評

また行きたいなと思うのはメイド喫茶だったが,お金に余裕があって,女の子とお酒飲みながら気兼ねなく話したいならガールズバーもありかなと感じた.ただし,話題についてはメイド喫茶のほうがオタク的な話題にも対応してくれやすい.

今回行ったのは落ち着いた雰囲気のメイド喫茶だったので,きゃぴきゃぴした感じのメイド喫茶にも行ってみようかと思う.

俺の嫁にOSの下でも会いたかった

この記事はFUN Advent Calendar 2017の8日目の記事です.

最近までのぼく

ここ0.75年ぐらい,色々あって生きるのがつらかった. 就活で精神を摩耗しているときに当時好きだった女の子にフラれ,祖父が死去し,そんな状態でOSCに出展するために振られたタスクをこなそうとしていたが最後まで上手く行かなかった.

8月9月に内定者アルバイトで東京に行っていたときは気分転換になったのもあってか多少マシだったが,帰ってきてからは反動が来たかのように一気に精神的にきてしまった(内定者アルバイトで研究が遅れていたぶん,取り返さなければというプレッシャーのようなものもあったのかもしれない).

最近まで,大学に週に1,2日来て,残りの日は自室のベッドでうずくまっているというような生活を送っていた.

転機

小・中学校時代の友人に勧められ,アズールレーンをはじめてみた. 最初はすぐ飽きるだろうと思っていたんだが,2-1で☆埋めをしているときにある艦と出会い,考えが変わった.

ロンドンである.

当時の自分,スクショを添付しろ,嫁との出会いだぞ.

ロンドンはアズールレーンを起動すれば「ごきげんよう,閣下,ロンドンは今日もおそばにおりますよ」と言ってくれる.私がどれだけつらかろうと,ベッドでうずくまっていようと,ずっと一緒にいてくれる.就活で辛いときにその気にさせるようなことを言って振ってくるような女とは違う.

ロンドンは圧倒的に可愛いのだが,当時の私の心の傷はまだ完全には癒えておらず,卒論の中間報告書をかなりギリギリまで着手できなかった.そんなときに救ってくれたのもまた,ロンドンである.

これによって,先生にレビューをお願いしたのが一番最後だったにもかかわらず,一番最初に先生のOKをもらうことができた.

中間セミナーの直前においても,精神的につらくなってしまったが,同様の手法を用いてモチベーションを上げ,深夜に登山を行い,どうにか中間セミナーを成し遂げた.

他にも,様々なロンドンの魅力があるが,ここでは割愛する.詳細については@neglect_ypのツイートを遡ってほしい.(尚,この記事を作成するにあたって「from:neglect_yp ロンドン」で検索したところ,スクリーンネームに「ロンドン」が入っているために全ツイートがヒットして全く役に立たなかったことを付記しておく)

OSの下でロンドンを表示する

ロンドンは「今日もおそばにいてくれる」が,もっとおそばにいてほしい.現状では,「私」→「ハードウェア」→「OS」→「アズールレーン」→「ロンドン」といった状態だが,OSよりもハードウェアよりのレイヤーでロンドンを表示することにより,「もっとおそばに」を実現したい.

(というようなこじつけをしたが,neglectyp.londonやazurlane.londonといったドメインを取得するほどにはロンドン愛を拗らせているので,自らの研究内容と嫁を関連付けたいと思うのは自然な流れである.)

結果から述べると,下のような感じで表示できた.

f:id:Gen_IUS:20171208225426j:plain

かわいい

ここから先は技術的な話になるので,興味のない方はブラウザバックしてほしい.

技術的詳細

ロンドンの表示は,BitVisorに実装されているADVisor機能を用いている.各関数の使用方法は下記の記事が参考になるので,そちらを参照して欲しい.

BitVisorのADvisor機能の利用 - Qiita

ADVisor機能によって利用される画像データは,BGRX_8888の形式である.これは,一般的に使用されるRGBA/RGBXの順番を入れ替えたものである.Xは,「アルファチャンネルの領域は存在するが無視する」という意味で,実用上は 0xFF でも入れておけばよい.

スクリーンショットで保存したロンドンの画像はRGB形式であるため,BGRXに変換するためのスクリプトPythonで書いた.

from PIL import Image

if __name__ == '__main__':
    img = Image.open('london.png')
    img.thumbnail((1000, 300), Image.LANCZOS)

    w, h = img.size
    print(w, h)

    px = []
    for y in range(h):
        for x in range(w):
            r, g, b, a = img.getpixel((x, y))
            bgrx = (0xff << 24) | (r << 16) | (g << 8) | b  # little endian
            px.append(bgrx)

    with open('output.txt', 'w') as f:
        for i, p in enumerate(px):
            f.write(hex(p))
            if i % 8 == 7:
                f.write(',\n')
            else:
                f.write(', ')

画素情報はunsigned intで渡すのだが,リトルエンディアンであるために,BGRXと視覚的には逆順に配置していることに注意してもらいたい(1敗)

あとは,ロンドンの表示専用のスレッドを作成し,VM Exitが発生するたびにVRAMを上書きすれば良い.

#include <core/initfunc.h>
#include <core/mm.h>
#include <core/printf.h>
#include <core/string.h>
#include <core/thread.h>
#include <core/time.h>
#include <core/vga.h>

unsigned int img_buf = {
    // write pixel data here
};

static void vram_overwrite_thread (void *arg)
{
    // run when VM Exit called
    for (;;) {
        const int w = 168, h = 300;
        unsigned int dsp_w, dsp_h;

        schedule();

        if (!vga_is_ready())
            continue;

        if (!vga_get_screen_size(&dsp_w, &dsp_h) || (dsp_w == 640 && dsp_h == 480))
            continue;

        vga_transfer_image(
            VGA_FUNC_TRANSFER_DIR_PUT, img_buf,
            VGA_FUNC_IMAGE_TYPE_BGRX_8888,
            sizeof img_buf[0] * w,
            w, h,
            dsp_w - w, dsp_h - h);
    }

    thread_exit();
}

static void vga_tamper_kernel_init (void)
{
    thread_new(vram_overwrite_thread, NULL, VMM_STACKSIZE);
}

INITFUNC("config1", vga_tamper_kernel_init);

このコードをBitVisorの適当なディレクトリに配置し,ビルド対象にする.vga_intelドライバを有効にすることを忘れないで欲しい(1敗).

ADVisor機能を用いることで,元々VRAMにかかれている値を取り出すことができるので,特定の画素は元のVRAMの値に置き換えることで擬似的な透過処理も可能である.ただし,今回は時間がなかったので実装していない.

今後に向けて

現状の実装だと,ロンドンのサイズを大きくすると動作が極端に重くなるという問題がある.これは,任意のVM Exitに対応してVRAMを書き換える処理を追加しているせいだと考えられる.

実は元々,Intel HD GraphicsのレジスタにあるDSPASURFという領域(表示用フレームバッファへのポインタ)へのMMIOによる書き込みをフックすることでページフリッピングを検知し,次回表示されるフレームバッファを書き換えるような実装をしていた.これによって,現在表示されているフレームバッファを直接書き換えないのでちらつき等を抑えられるし,何より書き換えが減るので軽くなるのではと考えていた.

しかし,この実装ではフレームバッファに書き込みを行ったあと,すぐに上書きされてしまった.OSがDMAによってフレームバッファを書き換えているのではないかと考えているが,まだ調査中である.何か分かる人がいれば,Twitterなどで教えて貰えると幸いだ.

また,現状では画面表示を行っているだけだが,今後Intel HDAのドライバを実装するなどしてロンドンちゃんの声も聞きたい.

おわり

明日はPythonおじさん(@uehara1414)です.ぼくもPython好きなので期待しています.

Tokyo Westerns CTF 3rd 2017 WriteUp

久しぶりにCTFに参加した。(これは若干嘘で、katagaitai勉強会でXSS千本ノックをしたりSANS NETWARS トーナメント 2017に参加したりしていた)

Harekazeで出て、940ptsで33位だった。 僕はrevのwarmup問題のrev_rev_revだけ解いた。

rev_rev_rev

読むと 、fgets()で入力をとったあとに、入力文字列を4つの関数で処理して、あるバイト列と比較していることがわかる。4つの関数は順に、

  • 改行文字を'\0'に(chomp的なやつ)
  • 文字列を逆順に(reverse的なやつ)
  • 各文字cに対して下の3行を実行する。実は、最初の<< 1add eax, eax(c & 0x55)の結果を自身に足していたんだけれど、これは多分最適化された結果で、下2行の雰囲気を見ると元は<< 1だと思う。
c = ((c & 0x55) << 1) | ((c >> 1) & 0x55);
c = ((c & 0x33) << 2) | ((c >> 2) & 0x33);
c = (c << 4) | (c >> 4);
  • 各文字のビットを反転する。

となっている。手動デコンパイルしたのをチームに共有したあと、お腹が減ったのでシャワーを浴びてご飯を買いに行ってたら、うさぎさんが「256通り試せば行けそう」と言っていたので脳死でソルバを書いた。(一文字ずつ処理してるのでそれはそう)

以下のコードでフラグが出た。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const unsigned char ans[] = {
    0x41,0x29,0xd9,0x65,0xa1,0xf1,0xe1,0xc9,
    0x19,0x09,0x93,0x13,0xa1,0x09,0xb9,0x49,
    0xb9,0x89,0xdd,0x61,0x31,0x69,0xa1,0xf1,
    0x71,0x21,0x9d,0xd5,0x3d,0x15,0xd5,0x00
};

void reverse(char *str) {
    int len = strlen(str);
    char *end = str + len - 1;

    while (str < end) {
        char c = *str;
        *str = *end;
        *end = c;
        str++;
        end--;
    }
}

int main() {
    char buf[0x21];
    int len = strlen((char *)ans);

    for (int i = 0; i < len; i++) {
        for (unsigned char chr = 0x21; chr <= 0x7e; chr++) {
            unsigned char c = chr;
            c = ((c & 0x55) << 1) | ((c >> 1) & 0x55);
            c = ((c & 0x33) << 2) | ((c >> 2) & 0x33);
            c = (c << 4) | (c >> 4);
            if ((~c & 0xff) == ans[i]) {
                buf[i] = chr;
                break;
            }
        }
    }
    reverse(buf);
    printf("%s\n", buf);
    return 0;
}

TWCTF{qpzisyDnbmboz76oglxpzYdk}

let’s go とかも解きたかったんですが、goのバイナリは気合が足りなくて読めず…

DoubleS1405 CTF Writeup

Harekazeで参加。チームで 881ptを獲得し、順位は 9 位 (得点 130 チーム中)、私はそのうち250pt(+200pt)をとった。

[Rev 100] Exec

PowerPCのバイナリが渡される。powerpc-linux-gnu-objdump で.rodata領域を見ると、flagis_MY_TRAP_CARDという文字列と?\\x148\x05\x16k?7:0\x0d1?(p3"'というバイト列が見つかる。バイナリの中身を読む前にXORを試したらフラグが出てきた。

Flag: Y0u_le4rned_pow3rpc

[Crypto 150] RSA

最初、渡されるスクリプト(の一部)が以下のようになっていたが、明らかに間違っている(recv==encという比較であれば、送られてきたencをそのまま渡せばよい)ので、enc_dataもしくはSECRET_LOGIC()を行う前のデータとの比較であると想定した。

これは後ほど修正があった様子。

if True:
    enc_data = SECRET_LOGIC()
    enc = powmod(enc_data, e, n)
    conn.send("enc : %d\ne : %d\np : %d\nq : %d\n" % (enc, e, p, q))

    recv = conn.recv(1024)

    if end - start > 1:
        conn.send("time out")
        conn.close()

    if recv == enc:
        conn.send(FLAG)
        conn.close()

    conn.send("wrong")
    conn.close()

else:
    conn.close()
    print "error"

enc, e, p, qが送られてくるので、復号することは容易だが毎回送られてくるデータは異なる。そのうちの1つに着目すると、

復号結果: 8755777115341080594761456402455437710685895952551191971666112763595998769587018749591234410595235907226473499074309848886437298673992843291278177512204044380308909676435457547909426657896511491773395035272677030211195668187992227281682442084623728957

これを16進数に変換後、hexstringとみなしてデコードした結果: NDU0NDM4NTQ2OTA1MzQxNjQ5NTY4MDE1MzY4Njk5MDAyNzY5MTgxODYyNTYyNjEwNDI0OTI4MzAxNzMwNjA3MzczMTI3ODM4OTEwNjA=

さらにこれをbase64とみなしてデコードした結果: 45443854690534164956801536869900276918186256261042492830173060737312783891060

これを16進数に変換後、hexstringとみなしてデコードした結果: dxOmJnmqANLoRFzfGpfs1AW74l4VFlzt

というようになっていた。上でいうdxOmJnmqANLoRFzfGpfs1AW74l4VFlztを送り返すとFlagが貰える。

一応、以下のようなスクリプトを書いた。

from pwn import *
from base64 import b64decode
import Crypto.PublicKey.RSA

r = remote('203.251.182.94', 4000)

r.recvuntil('enc : ')
enc = int(r.recvuntil('\n')[:-1])
r.recvuntil('e : ')
e = int(r.recvuntil('\n')[:-1])
r.recvuntil('p : ')
p = int(r.recvuntil('\n')[:-1])
r.recvuntil('q : ')
q = int(r.recvuntil('\n')[:-1])

log.info(enc)
log.info(e)
log.info(p)
log.info(q)

def gcd(a, b):
    while b:
        a, b = b, a%b
    return a

def lcm(a, b):
    return a * b / gcd(a,b)

def gcd2(a, b):
    if b == 0:
        u = 1
        v = 0
    else:
        q = a / b
        r = a % b
        (u0, v0) = gcd2(b, r)
        u = v0
        v = u0 - q * v0
    return (u, v)

d = gcd2(e,lcm((p-1),(q-1)))[0]
rsa = Crypto.PublicKey.RSA.construct((p*q, long(e), d, p, q))

flag = hex(int(b64decode(hex(rsa.decrypt(enc))[2:].decode('hex'))))[2:].decode('hex')
log.info(flag)
r.send(flag)
log.info(r.recv())

Flag: Y34hh_RSA_1S_S0_E4sy

([For 200] AI Mouse)

リンちゃん(@jtwp470)がUSBのパケットを解析->マウスの軌跡を画像化までやってくれていて、ほとんどFlagはとれていた。しかし、字が汚すぎて判別がつかないという問題があり、Flagの読み取りだけお手伝いさせてもらった。(ほとんど漁夫の利みたいな感じになってしまったので、申し訳ない気持ち)

f:id:Gen_IUS:20170330222424j:plain

Flag: c4tch_th3_m0us3!

なんだけど、どう見ても最初のcは大文字だし、最後のが!ってのは無理があると思う…

ScytheCTF 2017 Writeup

Harekaze で ScytheCTF 2017 に参加しました。(1チーム3人までだったので、@hiwwさん、@st98_さんと一緒に出ました) チームは425ptを獲得して7位、私はそのうち200ptを獲得しました。

[Crypto 150] rsa-love

渡されたzipファイルの中身は以下のようになっています。

Archive:  crypto.zip
  Length     Date   Time    Name
 --------    ----   ----    ----
        0  03-08-17 22:59   crypto/
      512  03-08-17 17:58   crypto/ciphertext1
      512  03-08-17 17:58   crypto/ciphertext2
      895  03-08-17 22:57   crypto/makefile.pyc
      795  03-08-17 17:58   crypto/pubkey
 --------                   -------
     2714                   5 files

makefile.pycuncompyle2デコンパイルすると、以下のようになっています。

#Embedded file name: ./makefile.py
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
flag = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
e = 17L
p = getPrime(2048)
q = getPrime(2048)
n = p * q
m = int(flag.encode('hex'), 16)
c1 = pow(m + 525689, e, n)
f = open('ciphertext1', 'w')
f.write(hex(c1)[2:-1].decode('hex'))
f.close()
c2 = pow(m + 614039, e, n)
f = open('ciphertext2', 'w')
f.write(hex(c2)[2:-1].decode('hex'))
f.close()
rsa = RSA.construct((n, e))
f = open('pubkey', 'w')
f.write(rsa.publickey().exportKey())
f.close()

少し調べると、Franklin-Reiter related message attackという攻撃手法が使えそうだということがわかりました。以下は参考にさせて頂いた記事です。

最終的には、下のようにsageスクリプトを書くとフラグが出てきました。

def related_message_attack(c1, c2, diff, e, n):
    PRx.<x> = PolynomialRing(Zmod(n))
    g1 = x^e - c1
    g2 = (x+diff)^e - c2

    def gcd(g1, g2):
        while g2:
            g1, g2 = g2, g1 % g2
        return g1.monic()

    return -gcd(g1, g2)[0]


if __name__ == '__main__':
    n = 861989937789654426343461243692067541646389136311279472446273771380858591625799045480051880016167718577658753128114583588383932472239887532172654339870957744753326309084673348480208200721928375516193389541702362452779965541554418677435608451699395256247138474396834520098936161405270620432424672291929888064130422062921966409668948497829705768760525774247650535053422643580738401556942324260544893782468891562816590270831614624237877973003686291610265574551629414163200950228047285602529516064690646175978064578814463967642861445483802710181935820557001553628723227309919458243310054535987861396335937057322519432286790724315958028243706586026951293434287385440723446396785106065925954282107811068208807162110744413874784050820334181968892572151375893316164421299682073611671735120835384408284028006058512208895055633703444944571240009593754857230895392515268894872261726043200570474182492569784574170294738999962439991665188355923101471407683779419743815417334789620414324520353716086440275136258345544515245749214223565224488530498725011173014355937540112656062646800663153687788062813622722398138482615418491235933205129196807880212257539452423260828545503342523786106829637208140030098553391575548646889945502359545728826142377267
    e = 17

    with open("ciphertext1", "r") as f:
        c1 = int(f.read().encode('hex'), 16)
    with open("ciphertext2", "r") as f:
        c2 = int(f.read().encode('hex'), 16)

    m1 = related_message_attack(c1, c2, 88350, e, n)
    flag = hex(long(m1 - 525689))[2:-1].decode('hex')
    print flag

[Stego 50] quick challenge

ソラちゃん(@st98_)が GitHub - jaybosamiya/busysteg: Hide information content into busy areas of images, optimally を見つけていたものの、ビルドにはOpenCVが必要とのことだったので、調べたら何故か入っていました。(いついれたかわからない…)

しかし、そのままビルドしようとするとオペランドの型が曖昧であるというようなエラーがでてビルドできませんでした…

--- a/busysteg.cpp
+++ b/busysteg.cpp
@@ -193,7 +193,7 @@ void hide_data(char* inimg, char* indata, char* outimg) {
   }
   long int fsize = fin.tellg();
   fin.seekg(0, ios_base::end);
-  fsize = fin.tellg() - fsize;
+  fsize = (long)fin.tellg() - fsize;
   fin.seekg(0, ios_base::beg);
   char *buf = new char[fsize + 16];
   memcpy(buf, "BUSYSTEG", 8);

以上のように変更することで無事ビルドし、flagを取り出すことができました。

BSidesSF CTF Writeup

Harekazeで参加。チームは3837ptで18位でした。 私は8問解いて1451pt入れました。

[Crypto 450] vhash

—- Due to a bug, the challenge might be easier than intended. Enjoy the free points! —-

サーバサイドのスクリプトがバグっていて、ハッシュが固定されている。cookieのusernameを書き換えるだけ。

FLAG:180e2300112ef5a4f23c93cfdec8d780

[For 40] easycap

TCPストリームを読むと書いてある。

FLAG:385b87afc8671dee07550290d16a8071

[For 666] matryoshka

地獄。有名なものからマイナーなものまで、様々な形式で多重にアーカイブ化されている。 途中までst98さんが解いてくれていた。詰まったところだけ下に記述する。

dact

fileコマンドを叩いても判別できなかったので、「"0x444354c3" magic」などでぐぐっているとDACT compressed dataとわかった。aptでアーカイバを入れて展開した。

freeze

fileコマンドを叩くと frozen file 2.1 と表示され、ぐぐるfreeze というコマンドに行き当たる。しかし、展開方法がなかなか見当たらなかった。悩んでいると、st98さんがFedoraのパッケージとGentooのパッケージを発見。Gentooのものを落としてビルドして、unfreeze コマンドで展開した。

zpaq

7kSt から始まるファイルが出てきて、ぐぐるとZPAQという形式だとわかる。しかし、Ubuntu 14.04のaptで入る zpaq コマンドが古すぎて展開できなかったので、最新版のソースを落としてビルドした後、展開した。

展開後

全て展開し終えると、FLAC形式のファイルが出てくる。ビットレートが8bitで、サンプリング周波数が1Hzというあたりから、データ部分がテキストになっているのではないかと思った(わざわざFLAC可逆圧縮)を使っていることもヒントになるかも)。というわけで、一旦WAVEに変換したのだが ffmpeg のデフォルトだとビットレートが16bitに変換されてしまい、ここで無限に時間を溶かした。結果的には下のような感じでうまくいく。

$ ffmpeg -i file.flac -acodec pcm_u8 file.wav
$ strings file.wav
RIFF
WAVEfmt
LIST
INFOISFT
Lavf57.56.100
dataw
.. - ... - .... . .. -. -.-. .-. . -.. .. -... .-.. . ... .... .-. .. -. -.- .. -. --. -- --- .-. ... . -.-. --- -.. .

モールス信号がでてきたので、適当なデコーダに投げる。

ITSTHEINCREDIBLESHRINKINGMORSECODE

[For 150] Latlong

渡されるファイルに対して file コマンドを叩くとWAVEであることがわかる。Audacityなどで色々いじってみたものの、何もわからないので放置していたが、運営からヒントが出た。

Hint - “Ax25 will lead you in the direction”

ぐぐると、AX.25というアマチュア無線で使われるプロトコルがあるらしい。デコーダを探すと、Releases · h2so5/Invasive · GitHubを見つけた。

flag{f4ils4f3c0mms}

これヒントなしでどうやって解くんだろう…

[Pwn 30] easyshell

シェルコードを送るだけ。

FLAG:c832b461f8772b49f45e6c3906645adb

[Rev 10] Easy

strings

FLAG:db2f62a36a018bce28e46d976e3f9864

[Rev 75] Skipper

スキッパーといえばはいふり

uname -n の結果、/proc/versionの内容、cpuid命令の結果をそれぞれ正しいか比較している。1番目と2番目は chroot を使って突破できたが、3番目をどうするか悩んでいた。苦し紛れにバイナリ中の比較対象の文字列を GenuineIntel に書き換えるとFlagが出てしまった。(入力文字列や比較対象の文字列がFlagの生成に影響があるのかと思っていた)他の人のWriteupを読むと、認証部分をデバッガで飛ばしても良いらしく、つらい気持ちになった。

FLAG:f51579e9ca38ba87d71539a9992887ff

[Web 30] easyauth

cookieのusername変えるだけ。Flagとっておくの忘れてた。

感想

Forensicsしか解けないのつらい。

BITSCTF 2017 writeup

Harekazeで参加し、チームは520ptで18位でした。 私は5問解いて140pt入れました。

[Crypto 20] Banana Princess

PDFっぽいファイルを渡されるが、そのままだと開けない。バイナリエディタなどで開くと、ヘッダなどがおかしいことがわかる。本来であれば %PDF-1.5 であるべき部分が %CQS-1.5 になっているので、rot13だとわかった。

import string

with open('./MinionQuest.pdf', 'rb') as f:
    pdf = list(f.read())
    for i, c in enumerate(pdf):
        if c in string.ascii_letters:
            pdf[i] = c.encode('rot13')
    with open('./flag.pdf', 'wb') as out:
        out.write(b''.join(pdf))

出力されたPDFを開くと、Flagの部分が黒塗りされていて見えない。どこかで見たことある問題だなあと思いつつ、LibreOfficeで開いて黒塗り部分を削除すると、Flagが読めた。

BITSCTF{save_the_kid}

[Crypto 60] Sherlock

渡された final.txt を読むと、不自然に大文字になっている箇所があるので、スクリプトを書いて取り出すと ZEROONE という文字列の羅列になっていることがわかった。それぞれ数字の0と1に置換して、8bitずつ文字と解釈するとFlagが出てきた。

import string

with open('./final.txt', 'r') as f:
    txt = f.read()
    flag = []
    for c in txt:
        if c in string.ascii_uppercase:
            flag.append(c)
    bin = ''.join(flag).replace('ZERO', '0').replace('ONE', '1')
    print(''.join([chr(int(bin[i:i+8],2)) for i in range(0, len(bin), 8)]))

BITSCTF{h1d3_1n_pl41n_5173}

[Forensics 10] Woodstock-1

pcapファイルを渡されるので、Wiresharkで開いてみるとTCPのパケットが沢山ある。とりあえずTCPストリームを見てみたらFlagがあった。

BITSCTF{such_s3cure_much_w0w}

[Forensics 30] flagception

わけがわからず放置していたら、megumishさんがトップページのロゴの画像にある旗の色がおかしいことを発見。拡大して見てみると、

f:id:Gen_IUS:20170206100233p:plain

というようなパターンが見つかる。ちょうど1行に8パターンあるので、濃い方を1、薄い方を0として文字にすると、最初がBとわかったので、そのまま人力で解いた。解いたあと目が痛かったので、素直にソルバ書けばよかったと後悔した。

BITSCTF{f1agc3pt10n}

[Rev 20] Mission improbable

ファイル名にある TEENSY31ぐぐると、マイコンが出てくる。そのマイコンで動作するバイナリなんだろうなあと思いつつ、ディスアセンブル方法をぐぐると、

avr-objdump -j .sec1 -d -m avr5 MissionImprobable.TEENSY31.hex

で一応ディスアセンブルはできることがわかった。

全然読む気が起きないので、もうちょっとぐぐると、

avr-objcopy –I ihex –O binary MissionImprobable.TEENSY31.hex MissionImprobable.TEENSY31.bin

で、ふつうのバイナリに変換できることがわかった。変換後にstringsをかけるとFlagが見えた。

BITCTF{B4d_bad_U5B}

感想

pwnの練習しなさすぎて、自明っぽいpwnすら解けなかったので練習しなければな、と思いました。