sec.js ( not javascript )

CTFのwriteupってキレイに解けたスクリプトだけが載っているけど、実際は泥臭い作業が沢山あるよね

SECCON 2016 オンライン予選に参加しました(1)

会社のチームで参加して37位でした。 私はどうでもよい問題しか解けませんでした(x_x)

(Forensics:100) VoIP

Wiresharkでpcap開いて、[Telephony]->[RTP]->[RTP Stream]で再生して聴き取るだけ。 VとRの発音聴き取れるかだけの問題だった。

VはBなの?とか、Rは「アー」としか聴き取れず愕然とした。

SECCON{9001IVR}

9001IVRて何ですか???


(Crypto:100) Vigenere

解いたと思ったら、チームメイトに先を越されてた(第一弾)。 問題中の?文字の数は信じずに解いた。

問題

Vigenere
k: ????????????
p: SECCON{???????????????????????????????????}
c: LMIG}RPEDOEEWKJIQIWKJWMNDTSR}TFVUFWYOCBAJBQ

k=key, p=plain, c=cipher, md5(p)=f528a6ab914c1ecf856a1d93103948fe

 |ABCDEFGHIJKLMNOPQRSTUVWXYZ{}
-+----------------------------
A|ABCDEFGHIJKLMNOPQRSTUVWXYZ{}
B|BCDEFGHIJKLMNOPQRSTUVWXYZ{}A
C|CDEFGHIJKLMNOPQRSTUVWXYZ{}AB
(省略)

write-up

vigenere.py

# -*- coding: utf-8 -*-

# see https://ja.wikipedia.org/wiki/%E3%83%B4%E3%82%A3%E3%82%B8%E3%83%A5%E3%83%8D%E3%83%AB%E6%9A%97%E5%8F%B7

def shift(char, key, chars, rev=False):
    if not char in chars:
        return char
    if rev:
        return chars[(chars.index(char) - chars.index(key)) % len(chars)]
    else:
        return chars[(chars.index(char) + chars.index(key)) % len(chars)]

def encrypt(plain, key, chars="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
    return ''.join([shift(plain[i], key[i % len(key)], chars) for i in range(len(plain))])

def decrypt(encrypted, key, chars="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
    return ''.join([shift(encrypted[i], key[i % len(key)], chars, rev=True) for i in range(len(encrypted))])

writeup.py

# -*- coding: utf-8 -*-
import vigenere
import itertools
import hashlib

chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ{}"
crypt = "LMIG}RPEDOEEWKJIQIWKJWMNDTSR}TFVUFWYOCBAJBQ"
plain = "SECCON{"

#-----------
# 前半のキーを既知の平文"SECCON{"を元に求める
key = []
for index, c in enumerate(crypt):
    if index >= len(plain):
        break
    for k in chars:
        p = vigenere.decrypt(c, k, chars)
        if p == plain[index]:
            key.append(k)
            continue

front_key = "".join(key)
print "front_key => %s" % front_key
#-----------
# 後半のキーの組み合わせを平文のmd5sumを手がかりに考える 
# itertoolを使った直積の求め方 see : http://qiita.com/junkls/items/10384950963056cc8e08
def solve(lengthmax, md5sum):
    for i in range(1,lengthmax+1):
        keys = list(itertools.product(chars,repeat=i))
        for k in keys:
            true_key = "%s%s" % (front_key, "".join(k))
            p = vigenere.decrypt(crypt, true_key, chars)
            if p[-1] == '}' and md5sum == hashlib.md5(p).hexdigest():
                return p
    return "unsolve"

print "solve!!! => %s" % solve(5, md5sum = "f528a6ab914c1ecf856a1d93103948fe")

実行結果(writeup.py)

~/D/c/vigenere ❯❯❯ time python writeup.py
front_key => VIGENER
solve!!! => SECCON{ABABABCDEDEFGHIJJKLMNOPQRSTTUVWXYYZ}
python writeup.py  162.40s user 1.10s system 99% cpu 2:43.75 total

悩んだとこ

Vigenere暗号の問題は、今まで[Vigenere][Online]でググって出てきたサイトで適当に解いてました。これらのサイトはA-Za-zな文字列を対象にしていることが多く、今回の問題を解けるサイトが見つからず、[Vigenere][Python]でググって出てきたサイトを参考にスクリプト書きました。

また、前半の鍵(=VIGENER)を求めた後に後半の鍵をどう作るか悩んで、?の数を信じてforで回すのはクソダサいと思って、標準ライブラリでいいのないかなと探してitertoolに辿り着きました。

最初、後半の鍵を直積(=itertools.product)ではなく組み合わせ(=itertools.combinations)や順列(=itertools.permutations)を使ってflagにたどり着かない!!!(鍵はVIGENERECODEです。後半がECODEなので組み合わせではもちろんダメで、順列も惜しくもダメだった)とアホみたいに悩んでました。。。落ち着いてドキュメント読みましょう。

pythonを立ち上げて、下記を入力してみましょう。イテレータとかジェネレータとか知らなくても望んだものが得られます。素晴らしい。

import itertools
list(itertools.product("ABCDE",repeat=3))

(Forensics:100) Memory Analysis

これも解いたと思ったら、チームメイトに先を越されてた(第二弾)。

問題

Memory Analysis
Find the website that the fake svchost is accessing.
You can get the flag if you access the website!!

memoryanalysis.zip
The challenge files are huge, please download it first. 
Hint1: http://www.volatilityfoundation.org/
Hint2: Check the hosts file

password: fjliejflsjiejlsiejee33cnc 

write-up

環境

$ uname -a
Linux ubuntu 4.4.0-53-generic #74-Ubuntu SMP Fri Dec 2 15:59:10 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.1 LTS"

$ sudo apt-get install volatility

Downloadしたメモリイメージがどのプラットフォームの環境のものか確認する。'WinXPSP2x86'か'WinXPSP3x86'のどちらかを選べばよいとわかる。

$ volatility -f forensic_100.raw imageinfo
Volatility Foundation Volatility Framework 2.5
INFO    : volatility.debug    : Determining profile based on KDBG search...
          Suggested Profile(s) : WinXPSP2x86, WinXPSP3x86 (Instantiated with WinXPSP2x86)
                     AS Layer1 : IA32PagedMemoryPae (Kernel AS)
                     AS Layer2 : FileAddressSpace (/mnt/hgfs/juns/Downloads/forensic_100.raw)
                      PAE type : PAE
                           DTB : 0x34c000L
                          KDBG : 0x80545ce0L
          Number of Processors : 1
     Image Type (Service Pack) : 3
                KPCR for CPU 0 : 0xffdff000L
             KUSER_SHARED_DATA : 0xffdf0000L
           Image date and time : 2016-12-06 05:28:47 UTC+0000
     Image local date and time : 2016-12-06 14:28:47 +0900

ヒントにhostsを見ろと書かれているので、hostsファイルを抜き出す。 crattack.tistory.comがhostsファイルに登録されていることがわかる。

$ volatility -f forensic_100.raw --profile=WinXPSP3x86 filescan | grep hosts
Volatility Foundation Volatility Framework 2.5
0x000000000217b748      1      0 R--rw- \Device\HarddiskVolume1\WINDOWS\system32\drivers\etc\hosts

$ volatility -f forensic_100.raw --profile=WinXPSP3x86 dumpfiles -Q 0x000000000217b748 --dump-dir=.
Volatility Foundation Volatility Framework 2.5
DataSectionObject 0x0217b748   None   \Device\HarddiskVolume1\WINDOWS\system32\drivers\etc\hosts

$ cat file.None.0x819a3008.dat 
# Copyright (c) 1993-1999 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host

127.0.0.1       localhost
153.127.200.178    crattack.tistory.com

メモリイメージ中にcrattack.tistory.comが含まれてないかgrepすると、URLが出て来る。

$ fgrep -a http://crattack.tistory.com forensic_100.raw  


Referer: http://crattack.tistory.com/entry/Data-Science-import-pandas-as-pd
(省略)

hostsファイルに書かれている情報を、自分のPCにも登録して、上記のURLへアクセスするとテキストファイルが落ちてきて、その中にflagが書かれている。

SECCON{_h3110_w3_h4ve_fun_w4rg4m3_}

悩んだとこ

hostsファイルに書かれているcrattack.tistory.comのサイトが実際に韓国語のサイトで存在していること、また153.127.200.178のサイトがnginxで立てられたサイトで存在していため、最後のfgrepする前にこの2つのサイトにflagがあるのでは?と色々とアクセス試してしまいました。funできなかったよ。


Anti-Debuggingもuncomfortable webも先に解かれてたので、チームで取り組む場合はちゃんとチャット見ないとですね。 とはいえ、exploitと100点以上の問題には手出せなかったので精進します。