2024. 7. 19. 17:26ㆍInformation Security 정보보안/Vulnerability Analysis 취약점 분석
배울내용:
시스템 해킹
단위공격 기술
포맷스트링 공격 발생 원리
포맷스트링 공격 실습
포맷스트링 공격 취약점 방지 방법
메모리 취약점
포맷스트링 공격 이란?
Format String Attack
포맷스트링 공격이란?
포맷스트링 공격은 프로그램에 입력된 문자열 데이터가 명령으로 해석될 때 발생한다. 이러한 방식으로 공격자는 코드를 실행하거나 스택 메모리 일부를 읽거나 실행중인 프로그램에 Segmentation Fault를 발생시켜 시스템에 의도되지 않은 동작을 일으킬 수 있다
이 공격은 주로 C와 C++과 같은 저수준 프로그래밍 언어에서 발생하며, printf()와 같은 형식 문자열을 사용하는 함수에서 자주 발견된다.
공격 방식
포맷 스트링 공격은 다음과 같은 경우 발생한다
- 입력값을 직접 형식 문자열로 사용: 사용자의 입력값을 형식 문자열 함수(예: printf())의 인자로 직접 사용할 때 발생하는데 이 경우, 사용자가 특별히 조작된 입력값을 제공하면 시스템 메모리에 대한 임의 접근이 가능해진다.
#include <stdio.h>
int main() {
char buf[512];
fgets(buf,512,stdin);
printf(buf);
return 0;
}
위에 코드를 보면 printf 에 buf 뒤에 인자값이 나와야하지만 나오지 않았음으로 이걸실행했을떄
Printf 함수에 %를 만날떄마다 뒤에있는문자 방식을보고 뒤에 인자가 있으면 하나씩 끌어다 옮기는게 안되게 된다.
%x %x %x %x %x %x %x
이떄, 위와 같이 입력값에 입력 해주면
이런식으로 나온다
그러면 200뒤에 이후에는 print 함수가 실행되기 직전의 esp 상태를 나타내게 된다
즉 , 이는 포인터(esp)와 관련이 있으며, printf가 실행되기 전에 스택에 저장된 값들을 출력하는 것이다
또하나 데이터를 쓰는 format string 이 있다
%n 라는 친구는 지금까지 출력된 글자의 개수를 뒤에 포인터에 저장한다
이는 printf와 같은 함수에서 %n은 현재까지 출력된 문자 수를 해당 위치의 인자로 전달된 정수형 변수에 저장한다.
이 기능을 악용하면 메모리의 특정 위치에 원하는 값을 쓸 수 있게 된다.
예시를 들면
#include <stdio.h>
int main() {
int val = 0;
printf("12345%n\n", &val);
printf("val: %d\n", val);
return 0;
}
이렇게 val 이 0 으로 할당되고 아래에 val 을 출력하는게 있는데 중간에 12345%n 이 있으면
어떻게 출력이 될까?
12345
val: 5
바로 이런식으로 출력이 된다
그러한이유는 위에서 알려주었다시피 지금까지 출력된 글자의 개수를 뒤에 포인터에 저장하기 떄문이다
이를이용해서 특정위치에 원하는 값또한 바꿀수있다.
실습
코드작성
format_1.c
/*
gcc -m32 -no-pie format_1.c -o format_1
*/
#include <stdio.h>
int answer = 0x9047;
void main(){
char buf[512] = {0,};
fgets(buf, 511, stdin);
printf(buf);
if(answer == 0xbeef){
printf("You Win!\n");
}
}
위에는 보기에는 간단하다 그러나 answer 가 0x9047 인데 format string 공격으로 이를 beef 로 바꿔주기만 하면된다.
우선 gdb 를 실행해서 answer 를 확인해보면 주소( p &answer ) 와 값(p answer) 이 들어가있는걸 볼수있다
answer 주소: 0x804c028
answer 주소 값: 0x9047
이제 pd main 으로해서 메인코드를 전체적으로 훌터보면
print 되는 b *main+116 에서 브레이크 포인트 걸고 run(시작) 시키고 puts에 AAAA 넣어본다
(beef 비교하기 직전 printf 에서 멈춰서 본다 )
r → AAAA → x/16/wx $esp
그리고 esp 를 확인해보면
위에 ESP 레지스터에도 AAAA 가 들어간게 보이고
x/16wx 로 esp 에 잘들어갔는지 보면
8번째에 위치하는곳에 0x41414141 (AAAA) 가 들어가있는걸 볼수가있다
그런데 정확히는 7번쨰의 위치라고 할수가 있다
그이유는 1번쨰에는 0xffffce4c 이다 그런데 이주소는
arg[0] 인덱스가 0으로부터 시작되니 0이고 1번은 0x00001ff 부터해서 7번쨰 주소는 0x41414141 이 되는 것이다.
그럼이제 여기위치에 무슨값이든지 넣을수있다는 뜻인데 0x804c028 를 표현할수없어서 새로운 명령어로 넣어줘야한다
r <<< `perl -e ‘print “\x01\x02\x03\x04”’
주어진 명령어는 Unix-like 시스템에서 사용되는 명령어로, Perl을 이용해 특정 바이트 문자열을 생성하고 실행하는 것이다.
그러면 저걸 실행한 뒤에 다시보자
이렇게 값이들어간걸 볼수있고
7번째의 위치에 0x04030201 이 들어가있는걸 볼수있다
\x01\x02\x03\x04 이렇게 입력했는데 저렇게 들어가는거는 리틀 엔디언과 빅엔디언의 이해하면 알수있다
리틀 엔디언과 빅 엔디언: 컴퓨터 시스템은 데이터를 저장할 때 리틀 엔디언(작은 바이트가 먼저 저장됨)이나 빅 엔디언(큰 바이트가 먼저 저장됨) 방식으로 데이터를 저장할 수 있다. 만약 리틀 엔디언 방식으로 데이터를 해석했다면, 바이트 순서가 바뀔 수 있다
아래에서 좀더 자세히 볼수있다
https://sarimus.tistory.com/85
그러면 위에걸 이용해서 answer 에 주소를 넣으면 된다 , 아까 봤던 asnwer 의 주소는 아래와 같이 확인 헀었다
answer 주소: 0x804c028
answer 주소 값: 0x9047
이제 이걸 이용해서
answer 의 주소인 0x8004c028 을 아까 perl 명령문 에다가 넣어주면 된다 그런데 7번쨰의 위치에다가 넣어준다.
`perl -e ‘print “\x28\xc0\x04\x08”, “%p%p%p%p%p%p%n”’`
그리고 asnwer 이 비교하는게 0xbeef 이란걸 볼수있는데 이는 HEX 값으로 DEC (정수값)으로 바꾸면 아래와 같이 된다
계산기로 HEX 값에 BEEF 넣으면 DEC로 48879 가 나온다 그래서 %n 앞에 1개의 %p 대신에 %48879c 를 넣어주고 실행하면 b1f1 으로 바뀐다
그이유는 %n의 특성을 이해하면 알수있다 \x28\xc0\x04\x08 이것의 앞에 있던 길이또한 더해줘야하니 Bf1F 에서 BEEF 를 뺴주면 된다 그러면 그값이 48 ( HEX로는 30 , DEX 로는 48 ) 인걸 알수있다
이값을 더해서 다시 명령어 입력해주면
`perl -e ‘print “\x28\xc0\x04\x08”, “%p%p%p%p%p %48831c%n”’`
하면 성공적으로 answer 에 beef 에 넣을수있다 그리고 실행하면 성공할것이다.
'Information Security 정보보안 > Vulnerability Analysis 취약점 분석' 카테고리의 다른 글
시스템 해킹 실습 -8 . Buffer OverFlow (버퍼 오버플로우) [2] (0) | 2024.07.21 |
---|---|
시스템 해킹 실습 -7 . Format String Attack 포맷스트링 공격 [ 2 ] (7) | 2024.07.20 |
시스템 해킹 실습 -5 . Type Confusion 데이터 유형 혼동 (1) | 2024.07.19 |
시스템 해킹 실습 -4 . Uninitialized 미초기화 취약점 (0) | 2024.07.18 |
시스템 해킹 실습 -3. Integer Overflow 정수 오버플로우 (0) | 2024.07.17 |