1.1 challenge
1.2 file & checksec
1.3 Source code
1.3.1 코드 설명
scanf로 %ld 형식지정자 3개를 사용해서 각각 v4, v5, v6에 값을 넣고,
if 문에서 각각 입력받은 값들이 정수형태로 정확히 받아졌는지 검사하고
v7[v6] = v4 + v5를 통해서 v7 배열에 값을 넣는다.
1.3.2 문제 추측
Out of bound 문제 같다.
즉 v7에서 주어진 12개의 배열이 아닌, 해당 범위를 벗어나
return address 변조할 수 있는 것처럼 보인다.
2. Analysis
2.1 main
이번 문제 같은 경우는 not-stripped 되어 있어 symbol들이 존재 했다.
확인을 해보면,
[rbp-0x78] => v4
[rbp-0x70] => v5
[rbp-0x68] => v6
[rbp-0x60] => v7
이렇게 매핑이 될 수 있겠다.
그리고 main+178 부분을 확인해 보면
[rbp+rax*8-0x60] 을 보아 rax에 13을 넣게 되면
[rbp+8] , 즉, return address를 건드릴 수 있게 된다.
2.2 win
win이라는 함수에
system("cat /flag")라는 함수가 있다.
3. Design
3.1 Out of bound
일단 main에서 Out of bound 취약점이 있는 것을 확인했고,
Return Address를 Overwrite할 수 있다.
3.2 Return Address Overwrite
v7[v6] 부분을 Return Address에 놓으려면, v6를 "13"을 넣으면 된다.
또한 v4, v5의 값이 v4+v5가 되니, 이 값들을 win함수의 주소로 하게 된다면,
Return Address를 Overwrite해서 system('cat /flag')를 할 준비는 끝났다.
3.3 scanf
이제 main함수에서 저 while문을 빠져나와야하는데,
break 조건이 scanf("%ld %ld %ld", &v4, &v5, &v6); != 3
이여야 한다.
scanf의 리턴값은, 형식지정자에 알맞게 매핑이 되었는지
예를 들어, 위의 경우 "1 1 1"을 넣게 되면,
scanf의 return 값은 형식지정자가 알맞게 매핑이 되었기 때문에 3을 리턴한다.
하지만, "1 1 s" 같이 하나가 형식지정자에 맞지 않게 되면, 2를 리턴을 한다.
그래서 break 문을 빠져나오기 위한 종료 조건까지 알아냈다.
4. Exploit
from pnw import *
p = remote('svc,pwnable.xyz', 30002)
p.sendlineafter('Input: ', '0 4196386 13')
p.sendlineafter('Input: ', '1 3 a')
p.interactive()
5. Result
성공적으로 FLAG 를 얻어냈다.
6. 알아낸점
scanf의 리턴값이 형식지정자에 알맞게 매핑이 되었을 경우 모두 리턴하고,
그게 아니라면, 알맞게 매핑된 값들의 수만, 리턴을 한다는 사실을 알았다.