Write-Up/FTZ

FTZ:Level 19

NONE_31D 2019. 11. 28. 20:29

1. hint 로 attackme 소스코드 확인

stdin에서 값을 입력받아 buf 배열에 저장한 후, printf 함수를 이용하여 출력한다.

쉽게 생각하면  RTL 기법을 이용하여 system("/bin/sh"); 를 ret 부분에 넣으면 될 것 같지만 코드 내부에 권한 상승을 시켜주는 setreuid() 함수가 없어 총 두번의 함수를 강제로 호출시켜주어야 하는 문제이다. 

=> RTL Chaining 기법 필요. 

 

 

2. RTL Chaining

 

RTL 기법은 ret에 공유 라이브러리의 함수 주소를 넣어 임의의 함수 호출을 한번만 진행한다. 하지만 RTL Chaining 기법에서는 새로 호출한 함수의 RET 부분에 지속적으로 RTL 기법을 이용하며 스택의 포인터를 다음 함수로 보내는 방법을 사용할 수 있다.

이 기법을 사용하기 위해서는 RET, 그리고 함수에 들어갈 파라미터의 순서를 기억해야 원활한 페이로드 작성이 가능하다. 

 

Gadget : RET로 종료되는 명렁어 순서. 스택 포인터를 다음 함수의 주소로 이동시켜줌. 

 

 

3. 스택 구상

어셈블리를 분석하면 현재 스택이 다음과 같이 이루어져있는 것을 확인할 수 있다. 우리는  buf 내부에 44바이트를 nop슬레드로 넘기고, RET 위치부터 setreuid()의 주소, 그에 사용될 인자, system()의 주소, "/bin/sh"의 주소를 알아낸 후 엮을 것이다. 

 

4. 필요 원소

a. buf - RET 의 거리 : 44바이트

b. system(), setreuid()의 주소 : RTL 기법 사용

c. "/bin/sh" 문자열의 주소

- memcmp를 이용하여 system() 함수 내부에 저장된 "/bin/sh" 의 주소를 찾아냄.

 

d. setreuid() 에 인자로 사용할 level20의 uid

- 페이로드는 hex로 사용되기 때문에 3100의 16진수 표기법인 0x00000C1C 로 표기. 

 

e. chaining 에 사용될 pop-pop-ret gadget

setreuid()는 함수의 원형이 다음과 같이 이루어져 있다. 

setreuid(ruid, euid);

ruid : 실제 UID, euid: 프로세스에서 이용할 UID

그렇기 때문에 2번 스택에서 pop을 진행하여 인자값을 받고 리턴하는 부분이 필요하여 ppr gadget을 찾는다.

- 표기된 0x08048418 이용

** 표기된 부분을 사용하면 세그먼트 폴트 오류만 뜨고 진행이 되지 않음. 단순한 pop-pop-ret 뿐만 아니라 사용하는 레지스터도 중요 부분인듯 (이에 따라 명령어 코드도 바뀜) 

 

5. 최종 페이로드 및 스택 

(python -c 'print "\x90"*44+"\x20\x79\x0d\x42"+"\x9c\x84\x04\x08"+"\x1c\x0c\x00\x00"+"\x1c\x0c\x00\x00"+"\xc0\xf2\x03\x42"+"\x90"*4+"\xa4\x7e\x12\x42"' ; cat) | ./attackme

크게 NOP sled + setreuid() + ppr gadget + euid + ruid + system() + NOP sled(argc로 채워질 부분) + "/bin/sh" 로 이루어진 페이로드를 제작했다. 

우 : 공격 후 스택 도식화

다음과 같이 페이로드를 보내면 정상적으로 비밀번호를 얻을 수 있다.

 

 

'Write-Up > FTZ' 카테고리의 다른 글

FTZ: Level17  (0) 2019.11.20
FTZ: Level15  (0) 2019.11.20
FTZ: Level11  (0) 2019.11.13
FTZ: Level 10 - writeup 수정중 (해결완료)  (0) 2019.11.12
FTZ: Level 9  (0) 2019.11.12