Gloem의 소스를 먼저 보겠습니다.

코드에 변경점이 좀 있네요.

Egghunter가 사라졌으니 환경변수를 입력 가능합니다.

그리고 프로그램 종료 전에 buffer부터 0xbffffffff까지 ret주소가 들어있는부분을 제외하고는 전부다 0으로 초기화 하네요.

즉 매개변수, 버퍼, 환경변수 다 사용 불가능하다는 얘기 같습니다.

 

그럼 저희가 쉘코드를 넣을수 있는 위치는 buffer 아랫부분에 있는 메모리 영역입니다.

Code, data, bss영역은 코드 컴파일시에 결정이 나고, heap영역은 동적할당으로 잡히는 영역이니 프로그램 실행시에 저희가 임의로 값을 넣어줄 수는 없습니다.

 

그럼 할수 있는 방법이 무엇이 있을 까요?

 

여기서 잠시 생각해 봐야 하는 것은 프로그램이 동작할때 메모리에 실행한 프로그램만 로드하는 것이 아니라는 것입니다. 프로그램 내부에서 사용하는 함수들도 실행을 해야하니 전부 메모리에 로드를 해야곘죠.

 

일반적으로 내부 함수들은 외부 라이브러리에 존재하기때문에 다른 메모리 영역에 존재합니다.

프로그램에서 사용하고 있는 memset이나 strcpy등 다른 함수들은 다 메모리 중 저 위치에 로드가 되어 있는 것입니다.

그래서 실행시에 저기서 가져오게 되는 것이죠.

 

그럼 여기에 등록이 되어 있지 않은 다른 임의 함수를 추가해서 사용할 때는 어떻게 될까요?

메모리 상에 로드를 해야 실행을 할 수 있을테니 프로그램 동작시에 사전에 메모리에 로드하게 될것입니다.

이러기 위한 환경변수가 리눅스에 존재 합니다.

바로 LD_PRELOAD이죠. LD_PRELOAD 환경변수에 파일을 등록 하면 프로그램이 메모리에 로드 되기 전에 환경변수에 등록한 파일을 먼저 메모리에 로드하게 됩니다.

 

그리고 이전 문제에서의 기억을 되짚어 보면 프로그램의 해당 메모리 영역의 끝부분에는 해당 프로그램의 이름이 올라가 있습니다.

 

, 만약 LD_PRELOAD 환경변수에 AA라는 이름의 파일을 등록하고 프로그램을 실행하면 프로그램의 스택 아래쪽에는 AA라는 이름의 파일의 코드가 등록이 되고 그 파일의 이름 또한 스택에 존재하겠죠.

 

코드상에서 0으로 초기화 하는것은 buffer부터 0xbfffffff까지 이므로 LD_PRELOAD로 메모리에 로드한 영역은 초기화 되지 않습니다.

 

이 방법을 이용해 이번 문제를 풀면 됩니다.

 

우선 아무런 동작을 하지 않는 파일을 하나 만들어 쉘코드 이름으로 컴파일 해주도록 하곘습니다.

shared object를 컴파일 하기 위한 명령어는 gcc –fPIC –shared입니다.

 

이제 환경변수 LD_PRELOAD에 이 파일을 등록해 주면 됩니다.

정상적으로 쉘코드를 이름으로 하고 있는 파일이 LD_PRELOAD에 등록이 되었네요.

 

이제 gdb를 통해 이 이름의 위치를 확인하도록 하겠습니다.

golem의 메모리 영역보다 아래쪽에 있을테니 esp-3000부터 확인하도록 하겠습니다.



NOP 슬라이드와 쉘코드가 메모리에 적재되어 있는것이 보이네요. Ret 주소에 대략 0xbffff5a0쯤 넣어주면 될것 같습니다.

 

쉘이 떳네요.

 

이제 원본 파일을 대상으로 공격하도록 하겠습니다.

golem의 쉘을 획득 하였네요.

golem의 패스워드는 cup of coffee라고 합니다.

Skeleton의 소스코드를 한번 확인해 보도록 하겠습니다.



소스코드에 걸려 있는 조건을 확인해 보도록 하겠습니다.

1.    Argv갯수 제한 없음

2.    환경변수 사용 불가능

3.    argv[1][47] == ‘\xbf’

4.    argv[1]의 길이는 48byte

5.    버퍼 사용 불가능

6.    모든 매개변수 사용 불가능

 

모든 매개변수를 초기화 하는 코드가 들어간것이  매우 타격이 크네요.

매개변수도 불가능하고, 환경변수도 사용 불가능하고, 버퍼도 사용 불가능하고, RTL도 불가능하고, 그럼 무엇을 할 수 있을까요?

 

일단 gdb로 프로그램이 끝나기 바로전에 bp를 걸어 모든 메모리를 확인해 보겠습니다.


더 이상 확인 할 수 없을 때 까지 일단 확인해 보도록 하겠습니다.

! 빙고! 메모리의 끝부분에 파일의 경로가 들어가 있는것을 발견했습니다.

그럼 문제가 다 해결됫네요.

쉘코드로 이름이 되어 있는 링크파일을 작성하고 ret주소를 변경해 주면 될것 같습니다.

 

우선 이름이 쉘코드로 된 링크파일을 생성해주겠습니다.

 

파일이 생성이되었으니 이제 gdb로 파일 경로가 들어있는 메모리의 주소를 얻어 내도록 하겠습니다.

0xbfffff51부터 의도한 파일경로가 들어가 있네요.

 

ret주소를 0xbfffff80쯤으로 잡고 실행하도록 하겠습니다.

한번에 쉘이 얻어졌네요.

 

원본 파일을 대상으로 진행하도록 하겠습니다.

skeleton의 쉘을 획득 하였습니다.

Skeleton의 패스워드는 shellcoder이네요.

vampire의 소스코드를 한번 보겠습니다.


.. 소스코드가 매우 짧아졌네요.


모든 제약이 다 풀렸습니다. argv[2]에도 넣을수도 있고 argv[1]의 길이도 상관 없고, 환경변수도 상관없고, 버퍼도 상관없네요.


다만 한가지 제약이 새로 추가되었습니다.

Argv[1][46]\xff면 안되네요.


지금까지 넣었던 메모리의 주소를 생각하면 항상 \xbfff로 시작했었습니다.

\xbffeffff보다 작거나 같은 메모리 위치에 있는 값을 써야 한다는게 핵심이네요.


스택은 구조상 높은 주소로부터 낮은 주소로 자라게 됩니다. 즉 매개변수에 전달되는 값의 크기가 크면 클수록 그만큼 스택은 아래쪽에 자리 잡게 된다는 말입니다.

저희가 사용할 수 있는 ret 주소는 0xbffeffff 이므로 0xbfffffff에서 부터 0x10000만큼 내려 와야 합니다. 0x1000010진수로 65536입니다.


한번 크기가 65536인 입력을 준 뒤 ebp를 확인해 보도록 하겠습니다.

예상대로 ebp의 주소값이 0xbffeffff보다 내려갔습니다.

65536개의 NOP슬라이드를 넣어주고 쉘코드 그 뒤에 넣어준 다음, ret 주소를 적당한 위치로 바꿔주면 될 듯 합니다.

 

ret주소를 0xbffeffff로 하여 입력해 보도록 하겠습니다.

바로 쉘이 떴네요.

NOP슬라이드의 개수가 많다보니 적당히 넣은 값에도 쉘이 떳습니다.

 

이제 원본 파일에 실행하도록 하겠습니다.

성공적으로 vampire의 쉘을 획득 하였네요.

Vampire의 패스워드는 music world입니다.

+ Recent posts