Layer7 21과제 -F.T.Z level 20 풀이-

2019. 7. 12. 05:51FTZ

FSB(format string bug)

 fsb는  format stirng(서식 문자)를 사용하는 함수 딴에서 인자 전달을 확실하게 하지 않았을 경우에 

 발생하는 취약점이다.

 

먼저 format string이란 무엇일까?

다음과 같은 것들이 포맷 스트링이다.

아마 c언어를 한번 해본 독자라면 "%d, %f, %c, %s"와 같은 format string(서식문자)

많이 접해보았을 것이다.

 

하지만 이 표에는 없는 "%n" "%hn"이라는 포맷 스트링이 존재한다.

이 포맷 스트링은 현재 (esp+4+포맷 스트링에 따라 더해질 byte 수)가 가리키고 있는 값을 

주소로 인식하고 이전에 출력했던 byte수 만큼 그 주소값에 대입을 하겠다는 포맷 스트링이다.

 

이 두 포맷 스트링의 차이점은

%n 같은 경우에는 4byte 메모리 공간을 가진 주소로 인식해서 4byte 만큼의 값을 대입할 수 있고,

%hn은 2byte 메모리 공간을 가진 주소값으로 인식을 해 2byte의 값을 대입을 할 수 있는 것이다. 

 

일단 포맷스트링의  사용의 예를 한 번 봐 보자.

 

 

이렇게 프로그램을 만들고 실행하면 

출력값이 제대로 12345678이라는 값이 출력이 될 것이다.

 

그런데 다음과 같이 코딩하면 어떻게 될까?

BUF에  ".%x.%x.%x.%x\n"라는 문자열 define 해놓았고 

printf로 BUF를 출력해주었다.

다시 말해 포맷 스트링(format string)만 출력을 해준것이다.

결과

그렇게 하면 메모리의 주소를 가져온다.

이게 바로 FSB(Format String Bug)이다.

 

원리

printf(변수);라고 해도 문자열의 화면 출력에는 문제가 없다.

그런데 변수 안에 서식 문자가 들어있을 때 문제가 된다.

위와 같이 사용하게 되면 문자열을 출력하다가 변수 안에서 %d나 %x, %s 드을 

만나면 이들을 출력해야할 문자열로 보지 않고 서식 문자로 인식해버리는 것이다.

이렇게 문자열을 출력하다가 서식문자를 만나면 메모리의 다음 4바이트를 참조해서 출력하는 등 

그 기능을 수행 해버린다.


ftz 20번 풀이

ftz 20번이 바로 fsb(format string bug)를 이용하여 푸는 문제이다.

왜냐하면 지금까지는 오버플로우의 버그 위험이 있는 함수인 gets() 함수를 사용해 

입력을 받았기 때문에 입력한 값이 입력 받는 변수의 메모리 크기보다 크면 오버플로우가 일어나서

ret 위치나 이런 곳에 쉘을 넣어 해킹을 할 수 있었다.

 

하지만. 

 

fgets() 함수는 가운데 인자에 지정된 만큼만 크기를 받는다. 그러므로 오버플로우가 일어나지 않는다.

하지만 printf(bleh);이라고 되어있기 때문에 overflow는 일어나지 않지만 

fsb를 이용하여 문제를 풀 수 있다.


포맷 스트링의 취약점 대로 포맷 스트링 문자열을 보내주면

메모리에 있는 값이 차례대로 출력된다.

 

더 정확히 말하자면 FSB 취약점이 있는 프로그램에서 %c, %s, %x 등의 포맷을 입력하면

esp가 4byte씩 +되면서 현재의 esp의 주소에 포맷 스트링이 표현 가능한  byte 수 만큼 esp+4에서

더해서 그 위치의 값을 맞는 출력 방식에 따라 출력한다는 것을 알 수 있다.

 

Ex) printf("%d%x%s%c", 12345678, 0x12345678, "asdf", 'c'); 와 같은 코드가 있다면

스택 상태는 아래와 같은 상태가 될 것이다.

 

esp -> "%d%x%s%c"의 주소

esp + 0x4 -> 0x00bc614e

esp + 0x8 -> 0x12345678

esp + 0xc -> "asdf"의 주소

esp + 0x10 -> 0x78

 

만약 bleh에 "AAAA%x"를 입력한다면 어떻게 될까?

처음에는 AAAA를 출력하겠지만, 서식문자 %x를 만나는 순간 현재 esp에서 4바이트 증가한 부분의 메모리

내용을 16진수로 출력하게 되는 것이다. 

 

이제 AAAA%x를 입력했을 때 실제 프로그램에서 서식문자 몇 개를 넣었을 때 비로소 bleh[80]이 읽히는지

알아보자.

%x를 4개 썼을 때 `16진수 A의 값이 나온다는 것을 알 수 있다.

 

따라서

bleh[80]

dummy[12]

printf

와 같은 형태임을 예상할 수 있다.

 

 (2)우리에게 필요한 서식문자 %n

레벨 20을 해결하는데 가장 중요한 서식 문자 %n이 있다. 여태껏 printf(blef) 이런식으로 사용하면

문자열 중에 %d등과 같은 서식문자를 만나면 스택에서 다음 4바이트를 읽어서 출력한다고 했다.

 

그런데  %n은 독특한 기능을 한다.

%n은 %n이 나오기 전에 출력된 자릿수를 계산하여 스택 다음 4바이트에 있는 내용을 주소로 여기고 

그 주소에 계산한 자리수, 즉 숫자를 입력한다.

그 예로 

%100c%n이라고 한다면 100이라는 숫자를 넣는것이다.

여기서 keeppoint는 우리가 원하는 메모리 주소에 원하는 내용을 쓸 수 있다는 것이다.


오버플로우가 어렵기 때문에 이로 ret을 건들기가 상당히 힘들다.

때문에 우리는 .dtors(destructor[소멸자])라는 것을 사용할 것이다.

FSB은 보통 .dtors 영역을 수정하는 것으로 공격이 이루어진다. 

이는 gcc 컴파일러의 특징이라고 한다.

 

ret은 함수가 끝나면 실행되는 것이고, 프로그램이 끝나면 .dtors(소멸자)가 실행되는데,

이제 그 주소를 확인해보자.

 

참고로 이렇게 나온 주소를 그냥 쓰면 안돼고 FBS에[서 .dtors를 사용할 때는  주소값에 +4 더해야 한다.

.dtors+4는 보통 0으로 세팅되어 있다. 하지만 이 값이 0이 아니라면, 프로그램을 종료하고 그 부분을 실행한다.

그래서 .dtors+4를 하는 것이다.

 

08049594+4가 ret이다. 즉 08049598

 

이제 우리는 여기를 쉘코드로 덮어주면 된다.

조금 정리를 해보자면 08049598에 쉘코드를 따서 덮어주면 된다.


개념잡기

.dtors()

.dtors(소멸자[destructor])

: 리눅스 gcc로 컴파일 한 프로그램은 main 함수를 호출하기 전에 .ctors 속성의 함수를 실행하게 되고,

  main 함수가 종료된 직후 .dtors  속성의 함수를 실행한다.

 

objdump 

objdump는 GNU 바이너리 유틸리티의 일부로서, 라이브러리, 컴파일된 오브젝트 모듈, 공유 오브젝트 파일, 

독립 실행 파일등의 바이너리 파일들의 정보를 보여주는 프로그램이다.

이를 써서 .dtors의 시작주소를 볼 수 있다.

 


위와 같이 환경 변수의 주소를 얻는 프로그램을 만들어준다.

 

 

0xbffffc9a

bfff(49,151‬)

fc9a(64,666‬)

 

49151에서 64,666를 빼면 음수이기 때문에 보수 처리

114887-64,666=50,221‬

 

입력값을 .dtors %x %x %x %x %x %x %x %x.... 처럼하면?

언젠간 스택에 남아있는 .dtors의 주소가 출력될것이다. 

몇변 %x를 했을때 dtors의 주소가 나오는지 확인하고, %n으로 .dtor에 eggshell의 주소값을 쓰면 된다.

 

그런데 주소의 크기가 너무 커서 메모리를 덮어 쓸 수가 없다. 그래서 2byte 씩 나눠서

반반씩 넣어야한다.

쉘코드의 주소 8자리를 한 번에 넣으려면 자릿수가 8개 이상이 필요하다

근데 일반적인 x86(32bit) 시스템에서는 이렇게 8개씩 넣을수가 없다.

그래서 낮은 주소/ 높은주소 절반을 나눠서 반절씩 갚을 전달해주는 것이다.

 

3) 페이로드 구성
<기본 구성>

즉 페이로드는 (python -c 'print "AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%64412c%n%50221c%n"';cat)|./attackme 이다.

 

파일을 만들고 쉘코드의 주소를 땄다.

 

리틀렌디안 방식을 사용하여

 

최종적으로

(python -'print "AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%62096c%n%52551c%n"';cat)|./attackme

이 됩니다.

 

 

i will come in a munute