min8282

[취약점분석] Type Confusion, Format String Bug(시스템 해킹 실습 3일차) 본문

K-Shield.Jr

[취약점분석] Type Confusion, Format String Bug(시스템 해킹 실습 3일차)

min8282 2024. 7. 18. 17:36

이전 내용)

uninitialized

포인터가 가리키는 것? or 포인터로 해석되는 곳이

초기화 되지 않은 더미 데이터가 있어서 여기로 접근하려다가 크래시 일어난 것임


Type Confusion

컴파일 하면 seg fault가 남.

메모리 관점에서 생각 해봐야 됨

죽는 지점은 printf에서 죽음

 

여기서 에러가 날거임. 디버거 실행 ㄱㄱ

 

 

[] 안에 있는 값을 쓰려고 하는 것

rdi 0x4d2를 인식해서 그 안을 보려고 하는 것

 

메모리 할당을 보기 위해 

이전에 bp 지우고 main+17부터 다시 보려 한다.

r 을 누르면 malloc에 멈추고

ni를 누르면 malloc 함수가 끝남

 

 

rax에 힙의 주소가 담겨 있을거임

 

문자열은 반드시 주소라고 생각

어떤 값이라기 보다는 어떤 값을 가리키는 주소를 뜻함.

int 형정수는 4D2라는 값 자체가 되는데. *string은 포인터로 접근하는 것임. 그래서 반드시 주소로 읽을 수 있는 값을 전달 해줘야 함. 주소와 값을 구분할 줄 알아야 한다.

따라서 int타입의 num을 str의 인자로 받기 때문에 타입이 안 맞아서? type error?

 

여기서 format을 %s가 아닌 %d로 하면 에러가 발생x.

why? str->string의 값을 포인터로 인식하는데 %d로 하면 그 값 그자체가 되기 때문?


type confusion 예제 시작

 

목표)

강제종료 시키는 것이 목표  - 크래서

 

union이라고 하면 아래에 작성되는 둘 중하나의 구조로 해석됨. 여기서 보면 adult, child 둘 중 하나로 선정됨.

나이를 받을 때만 바로 넣지 않고 if문으로 조건에 맞는 것을 넣음.

 

p *(struct person*)0x555555559ac0 이렇게ㅏㅎ면 코드 struct 볼 수 있음

gdb 분석)

^C하면 멈출 수 있음

이때 만든 0x555555559ac0 의 메모리 구조 확인. 이때 만든건 20살이기 때문에 adult의 구조를 보임

해당 구조는 adult

adult의 typeflag는 0x2인 것을 알 수 있음

멈춘 거 진행하고 child 객체 하나 생성.

메모리 구조와 확인 

p *(struct child*)0x555555559b30이아니라

person으로 구조를 확인 해야함

child type flag 0x1

 


메모리 커럽션 취약점 시작(race condition 제외) - format string bug

포못 스트링 - 형식 지정자

사실상 현재는 발생하지 않는다. 만에 하나 식별되면 이 친구는 exploit 될 확률이 너무너무너무(아이오아이) 많다.

32 비트는 인자 전달 스택, push 로 한다.

call 하면 돌아갈 주소가 들어가게 된다.

인자

인자

복귀주소

프롤로그에서 만들어 지는 거 = ebp

지역변수는 마이너스로 접근

인자는 베이스 플러스로 접근하면 되죠.

목표는 answer 값을 0xbeef로 만들어서 you win을 띄우는 것.

 

현재 제가 넣은 입력이 전부 포맷스트링으로 활용될 여지가 있다.

$ ./poc를 하고 input에 %x %x %x %x %x %x 6개 입력하면? 주소가 여러 개 나옴

gdb -q poc

pd main

bp *main+116

전역변수 answer의 값을 바꾸는 것.

제일 먼저 알야아 할 것은 answer 주소를 알아야 함

p &answer을 하면 answer의 영역 주소가 나옴. 심볼 사용한 것임.

bp 걸고 실행(r) 후, %n 했더니 segfault.

 

printf는 %n을 만나면 글자수만큼 저장된 주소 저장.

 

다시 실행해서 main+113(printf 부분)에 bp 걸고

32비트는 x/wx=4바이트 / 64비트는 x/gx=8바이트

확인하면 됨. 첫번째 값이 AAAA\n으로 확인가능

r <<<`perl -e 'print "\x01\x02\x03\x04"'`

이걸 쓰는 이유? 일반적인 키보드 입력으로는 불가능 하기 때문.

이전과 비교했을 때 입력한 순서의 반대로 들어감.

그래서 answer의 주소를 넣고 싶기 때문에 1바이트씩 끊어서 거꾸로 입력해보면?

8번째에 들어간거 확인

0x00009047 은 초기값

ni 후 answer 값 확인하기

0x00000039가 왜 나온걸까?

ni 했을 때의 아래 나온 값?

%50c

 

이렇게 넣으면 0xbf1f가 나오는 오차가 발생함

 

여기서 0xbf1f를 beef만큼 빼면 48831이 넣어야 함. -> 직접해보기

bf1f-beef = 0x30이 나오는데 0x30은 10진수로 48이기 때문에 48879-48=48831을 넣는 것.

48831c도 퍼센트로 치고 %n이 앞에 만큼 넣어서 beef가 나오는 것.

 

아래는 다른 방식

beef는 48879인데 앞에 4바이트가 붙기 때문에 beef를 만들기 위해서는 4바이트를 뺀 48875를 넣어야 한다. 48875를 7번째 인자에 넣겠다는 의미고, \\를 사용한 이유는 $를 다른 문자로 인식하는 경우가 있어서 변수로 인식하지 않게 escape 시키기 위해서 \\를 쓴다.

ni를 해서 answer 값을 보면?

you win

 

wow!


해당 게시글은 복습을 위한 실습 내용 필기이므로 올바르지 않은 정보가 포함되어 있습니다.