[어설픈] 해커스쿨 FTZ level 11 문제풀이

2019. 1. 22. 21:45System Hacking/FTZ

안녕하세요!

오늘은 FTZ Level 11을 

풀어볼게요!


제가 여기서 

모르는 게 좀 많았어서

공부하느라 

시간이 좀 오래걸렸네요!


문제를 보니

char형의 str버퍼 256byte를 할당하네요!

그리고 setreuid를 3092로 설정하네요!

권한 상승 시켜준다는 거죠

(※ Why? 찾아보니 3092의 uid level 12의 것이에요)


그 다음에 strcpy로 저희의 argv[1]을 복사해오는데

일단 여기서 취약점이 있죠!

얼마나 복사해오는지 크기 안정했으니까요!


그리고 그 복사해온 것이

str에 있는데 이걸 출력하네요

printf함수로요!



뭐 버퍼 오버플로우 계속 해왔던 대로 

풀면서 드는 생각!


버퍼크기(256byte)+ (더미가 존재하면 더미 크기 ???byte)+ EBP(4byte) 


쉽게 설명해서 RET ADDR 전까지 

저희가 메모리를 꽉 채우고!

RET ADDR을 조작하면 되겠네?


근데 일단 더미의 크기가 존재할까?

있다면 얼마일까?


확인해보러 gdb attackme 한 다음

disas main 해보니까

sub 0x108이네요


공학용 계산기 0x108= 264이네요

즉 264- 256 = 8byte가 더미네요!


버퍼크기(256byte)+ (더미 크기 8byte)+ EBP(4byte)  = 268 byte


 


뭔가 너무 쉽게 쉽게 풀리는데?

그러면 이제 우리가 RET_ADDR을 조작해야겠죠?

RET_ ADDR은 저희가 shell code를 268byte안에

주입하고 RET_ADDR 주소에

shell code의 주소를 넣으면 되겠네요?


그러면 저희가 입력한 문자열이

어디서부터 시작하는지 알아봅시다!


run `python -c'print "A"*268'`

버퍼에 268개의 A를 꽉꽉 채웠습니다!


그런 다음에 스택 상황을 확인하려고

strcpy 함수 뒷부분에 

breakpoint를 걸고

(str에 복사를 한 다음의 스택상황을 봐야하잖아요 아니면 str이 비어있으니..)


x/100x $esp를 입력해서 스택 상황을 보니

0xbfffdcc0에서 저희가 넣은 A가 시작하네요

(0x41=A)



오케이 그러면 뭐 다 끝났네요!


exploit code 짜볼까요? 

저는 25byte shellcode를 사용하려고 해요!

인터넷에서 가져와서 복사했습니다


대략적으로 먼저 어떻게 짤 건지 보여드리면

쉘코드(25) + 아무 값(243) + RET_ADDR에 쉘코드(25)의 시작주소

그래서 아래와 같이 코드를 완성했습니다!


잘 안 보이실까봐

`python -c 'print \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" 쉘코드 +"A"*243 아무값+ "\xc0\xdc\xff\xbf"'`복귀주소



그래서 다시 이렇게 명령어를 입력하고

gdb상에서 실행시켰습니다!


그래서 input이 잘들어갔나 

확인 차 stack상황을 확인했는데....

아니 저기요?!


쉘코드의 시작주소가 바뀌었는데요?

원래 저희가 작성할 때 주소는 0xbfffdcc0이였는데

지금은 0xbffff5c0으로 바뀌었는데요?


그러면 RET_ADDR이 이상한 메모리 주소로 복귀하는데요?

그러면 exploit 실패하는데요?

그래서 제가 어이가 없어서 그럼 혹시나  계속 돌리면

나오나 될까 싶어서....


코드 계속 실행해 봤는데 죽어도 안되더라구요

이건 \x90 (NOP) 243개넣고 그뒤에 쉘코드 25byte 넣고 짠 코드에요....


그래서 인터넷에서 온갖 검색이란 검색을 다 해봤습니다!


다른 분들은 나와 같이 했는데 풀렸다!

어떤 사람들은 나와 같이 했는데 안풀렸다!


결국에 찾아보니 옛날에 이 문제를 푸신 분들은 (FTZ 서버에 접속하셔서 푸신 분들)

ASLR이라는 보호기법이 적용 안되어 있엇고


저처럼 FTZ 파일을 다운받아서 직접 구축한다음에 문제를 푸신분들은

ASLR이 적용되어 있다네요...


※ASLR?

(Address Space Layout Randomization)

간단하고 직관적이게 설명드리자면 

스택과 힙 영역의 메모리 주소를 

실행 할때마다 랜덤하게 바꾸는 거에요!


ex) 처음 실행될땐 뭐 0xbfef1358  

다음에 실행될 땐 0xbcefa485

그냥 랜덤하게 바뀜


그러니 저희가 백날 RET_ADDR에 shellcode가 담긴 주소를 넣어놔도 

그 shellcode가 담긴 주소가 실행 될때마다 매번 바뀌니 

문제가 풀릴리가 없죠...


그래서 저는 어떻게 이 문제를 해결했냐?

우선 구글링을 해보니 RTL이라는 기법을 사용하라해서

RTL(Return to Library)로 풀었습니다!


RET_ADDR이 스택영역이 아니라 공유라이브러리 영역으로

리턴하게 만드는 거에요!

(물론 공유 라이브러리 영역에도 ASLR걸려있으면 노답)


그래서 저는 기본적으로 

공유 라이브러리영역의 주소를

알아내고자 이러한 커맨드들을 입력했습니다!


여기서 궁금 하실 수 있는 커맨드 3개

 

1. what is ldd?

런타임때 프로그램 실행에 필요한

공유 라이브러리 목록을 보여준다!


즉, 실행 파일이 동적으로 어떤 라이브러리를 필요로 하는지 보여준다!

저희는 저 두 개중에 /lib/tls/libc.so.6(0x42000000)를 이용 할 거에요!


2. what is nm?

라이브러리나 실행파일에 

어떤 심볼 혹은 함수가 있는지

알기위해 실행시키는 것!


그래서 저는 /lib/tls/libc.so.6 라이브러리에서

system 함수가 있습니까? 라고 grep을 통해서 찾은거죠!


3. what is strings?

오브젝트 파일 혹은 라이브러리 파일 or 바이너리 파일의 내용을 

vi 나 cat 명령어로 확인을 못하죠?


그래서 strings [파일명]을 입력하면 

(오브젝트, 라이브러리, 바이너리)파일에 있는 모든 인쇄 가능한

문자들을  화면에 출력해줘요!


-tx는 뭐야?

줄 수 있는 옵션 중에

이 문자열이 어느 위치에 있는지도

출력해! 16진수로(hex)!


그리고 grep을 써서 /bin/sh의 문자열을 검색해!

그러니 바로 출력되었죠


그래서 바로 저는 위와 같이 커맨드를 짜보았습니다!

A가 268개+ ret addr에 시스템 함수 주소 0x4203f2c0 (little endian)+ 임의의 4byte값+ /bin/sh 주소 0x42127ea4(little endian)

이렇게 되면 복귀를 시스템 함수로 하게 되고!

system(""); (이 상태)


시스템 함수의 인자로 /bin/sh을 주면

 (/bin/sh가 저장된 주소를 저장해 놨으니)

system("/bin/sh"); (이 상태)


즉 쉘이 실행되는거죠!


RTL은 여기서 다루기는 양이 너무 많아서 

방법만 소개해드리자면 

원래 RET_ADDR에서 8byte떨어진 위치에 스택을 인자 값으로 인식해요!

EBP| RET ADDR | (4byte)=다음 함수의 RET_ADDR | 인자로 인식(4byte)


원래 stack에서 

함수 인자가 있을 때

함수 인자가 제일 먼저 쌓이고

그 다음에 ret addr

EBP 쌓이잖아요!


어찌됐든 결국

저렇게 커맨드를 완성하면

shell이 실행이 되고


이렇게 exploit이 완성됩니다!

고생하셨습니다!