Lord of BOF_10_Skeleton

핵심 알고리즘은 다음과 같다.

  • argv를 받는다. argv의 48번째 바이트가 0xbf가 아닐 경우 종료한다. 이는 스택의 주소이다.
  • 버퍼에 argv[1]의 내용을 복사한다.
  • buffer를 지운다.
  • 스택 프레임에서, main 함수의 return address을 제외한 위쪽 값을 지운다.

스택은 0x2c(44)만큼 확보하지만, 배열의 시작 주소는 ebp-40이다. 따라서 스택 destroyer로 지워지지 않는 위치는 return address 뿐이다. 즉, 컨트롤 하여 이용할 수 있는 것은 return address이다.

다만, return address는 스택의 주소가 와야 한다. 문제는 스택을 이용하기를 요구하고 있다.

시도

so injection으로 스택을 크게 확보한 뒤, 셸 코드를 저장한다. 이후 return address 조작을 통해 이동하는 방법이다. 이는 실패했다. 테스트 결과 셸 코드를 넣은 스택에 다른 값이 들어가 정리된다. 왜인지는 모르겠다. 

정리되지는 않지만 출력한 주소에 있지도 않다. 스택에 뿌려놓는 작업이 가능하고, 이를 이용할 수도 있다. 하지만, cp한 프로그램에서는 셸을 땄지만 원본 프로그램에서는 invalid instruction 에러가 떴다. nop sled를 이용해도 마찬가지였는데, 주소가 바뀐 게 아닌가 한다. 

이상한 점은 라이브러리에서 stdout으로 출력한 결과물이 argv로 들어간다는 점이다. 간단한 인자 출력 프로그램을 작성하고 실험해 보니 거기서는 그런 현상이 보이지 않는 것 같았다.

참고

바로 풀리지 않아 구글링을 해 보았다. LD_PRELOAD로 라이브러리를 올린다는 접근은 같았지만, 셸 코드를 스택에 직접 밀어넣는 게 아니라 프로그램 이름으로 넣는다는 점은 달랐다.

LD_PRELOAD 환경변수에 등록되는 이름만 생각했기에 안 될 거라고 생각했는데, 다른 위치에도 라이브러리 이름이 올라가는 것 같다. main 함수에서 이용하는 스택보다 낮은 주소에 라이브러리 이름이 적재된다고 한다.

간단한 라이브러리 파일을 만들고, 그 이름을 셸코드로 바꾸었다. 단, 이 셸코드에는 /가 들어가서는 안 된다. 이를 경로로 등록해야 하기 때문이다. 

LD_PRELOAD에 위 라이브러리를 등록하였다. 이를 통해 파일 이름이 스택 어딘가 올라오게 된다. 

메모리를 뒤져 파일 이름을 찾아내었다. main에서의 esp보다 아래쪽에 위치한다.

심볼릭 링크로 원본 파일을 실행하도록 하였다.

위에서 찾은 주소를 이용하여 셸 코드를 실행하도록 하였다. golem의 비밀번호는 cup of coffee 이다.


tags: writeup, pwnable, buffer overflow, stack overflow, memory corruption, ld_preload, library, elf file, linux, c lang, x86asm