_
ls로 hint와 처음 보는 attackme 파일을 찾았다.
hint 파일은 소스코드로 구성 되었고 이외의 말은 없었다.
attackme 파일을 실행해보았지만 Segmentation fault 오류가 나고
cat으로 읽어보니 깨진 내용이 출력되어 새로운 뭔가를 얻을 수 없었다.
* Segmentation Fault
- 프로그램이 동작 중 잘못된 주소를 참조할 때 발생하는 오류 (메모리 관련 오류)
- 읽기 전용 메모리 영역에 데이터를 쓰려고 할 때 (read-only)
- 운영체제 메모리 영역 또는 보호된 메모리 데이터를 쓰려고 할 때
- 잘못된 메모리 영역에 접근하려고 할 때 (NULL, -1 등등)
hint의 내용이 attackme의 소스코드인 것 같으니 분석해보자.
먼저 char로 선언된 배열의 크기는 256byte이다.
seteuid를 사용하여 프로그램 권한을 level12로 정의했다.
입력값을 함수 실행 시 받아오는데 256byte 크기의 str에 넣으면서 크기의 제한을 두지 않았다.
여기서 Buffer over flow가 발생할 수 있다.
마지막으로 str의 내용을 출력하며 main 함수는 종료된다.
함수 안에서 권한이 level12로 상승되므로 도중에 my-pass를 사용할 수 있으면 패스워드를 얻을 수 있을것 같다.
입력한 내용을 동일하게 출력해 주는 것을 보니 hint의 내용은 attackme가 맞는 듯 하다.
attackme 파일은 setuid 권한을 가지고 있고 유저는 level12이다.
attackme 파일을 tmp로 복사해두려 했는데
복사후 ls 명령어를 사용해도 아무것도 없다고 나온다. 왜지 ?
어쨌든 tmp 앞에 /를 빼고 tmp로 복사했다.
attackme라는 파일을 분석하기 위해 gdb 명령어를 사용했다.
이 내용을 소프트웨어 보안에서 공부했었는데
gdb 명령어도 쉘코드도 오랜만에 보니 새로워서 수업 필기를 다시 공부했다.
소스코드에서 str을 256byte로 할당했다.
현재 sub 명령을 수행하는 esp에는 0x108(16진수) 즉 264byte가 할당되어있다.
이를 통해 264byte 안에 sub 256byte와 더미 8byte가 포함되어있음을 알 수 있다.
입력값을 받는 eax는 <main+41> / 0xfffffef0(16진수) 의 주소값을 가진다.
현제 main함수의 메모리 구조를 정리해보자면 아래와 같다.
buffer [256 byte] + dummy [8 byte] + SFP [4 byte] + RET [4 byte] = 272 byte
str에 변수 크기인 256byte를 초과하여 오버플로우를 발생시키기 위해서는
buffer + dummy + SFP에 아무 코드나 채워주고 return 주소인 마지막 4byte에 권한을 얻을 수 있는 쉘코드를 입력하면 된다.
쉘코드로 my-pass를 입력할 수는 없으니 bash 쉘을 실행하는 코드를 입력해야 하는데 구성하는 방법을 모르겠어서 구글링했다.
shell code ->
\x31\xc0\x31\xdb\xb0\x46\xcd\x80\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\x31\xc0\xb0\x01\xcd\x80
* GDB(GNU Debugger)'
- 디버거의 목적은 프로그램 수행 중에 내부에서 무슨 일이 일어나는지 잘못되고 있는지 보여주는 것
- -q: gab를 시작할 때 버전 정보 등을 출력하지 않도록 해줌
- -args: 파일과 함께 인자를 전달할 수 있도록 해줌
- run: gdb로 로드한 프로그램을 실행함, 이 역시 인자값을 넘겨줄 수 있음
- disas: 명시한 함수에 대한 disassemble을 수행함
- break: *address를 뒤에 명시하거나 *main+0 등으로 하여 브레이크포인트를 설정함
- continue: 다음 브레이크포인트 전까지 코드를 실행함
- x: 주어진 주소 내의 메모리 값이 무엇인지를 확인하는 용도
출력형식 [ x(16진수) s(문자열) I (명령어)]
범위의 단위 [ b(1byte) h(2byte) w(4byte) g(8byte)]
-n / 몇개의 메모리 유닛을 보여줄 것인지 지정하며 디폴트 값은 1
-f / 읽은 메모리 값을 어떻게 해석할 것인지를 지정하며 디폴트 값은 x
-u / 읽을 메모리의 유닛 사이즈를 결정함 (b, h, w, g)
* 메모리 변수
- RET : return 주소값 (함수 실행을 마치고 돌아갈 주소)
- SFP : 함수가 실행될 때 이전 Break Point의 주소
쉘코드를 환경변수로 등록하기 위해 export 명령어를 사용했다.
* export
- 쉘 변수를 환경변수로 저장할 수 있음
export water="삼다수"
export TEMP_DIP=/tmp
export BASE_DIR=$TEMP_DIP/backup // 동적경로도 환경변수로 할당이 가능함
SHELLCODE란 이름으로 환경변수를 등록했고
다시 export 명령어를 사용하여 제대로 등록이 되었는지 확인하였다.
SELLCODE 환경변수의 주소를 확인하기 위해 semple 코드를 작성했다.
getenv 함수를 사용하여 주소를 얻어냈다.
SELLCODE 환경변수의 주소는 0xbffffef0이다.
이제 RET의 자리에 이 환경변수의 주소를 넣고, 버퍼의 자리에는 x90으로 채워서 공격을 시도해보려 했는데
명령을 잘못 입력한 것인지 계속해서 Segmentation fault가 난다.
환경변수를 잘못 할당한 것인가 싶어서 그 자리에 bash를 얻어내는
쉘코드를 직접 대입해봤는데 역시 동일한 오류가 난다.
뭔가 잘못 이해하고 있는 것 같다. 다시 처음부터 해보려고 한다.
다시 SHELLCODE를 환경변수로 등록을 했다.
내용은 아까랑 동일한데 쉘변수로 등록을 안한게 문제인가 싶어서
이번엔 쉘 변수로 등록한다는 내용을 포함하여 환경변수로 설정했다.
semple 파일을 지우고 바뀐 변수명에 맞추어서 다시 컴파일했다.
여기서 다시 segmentation fault가 나서 진짜 막막했는데
가만히 보니 16진수로 된 주소를 거꾸로 입력해놨다 :D.. ㅎㅎ
uid가 아직 level 11이다. 계획했던 버퍼 오버플로우에 성공했으면 level12로 바뀌어야 하는데.
여기까지 넘어온걸 보면 이 방식은 맞는데 왜 권한을 얻지 못할까 !!!!!!!!!
_
어렵다 level11부터 난이도가 확 올라간 느낌이다.
다시 풀어보고 게시글 밑에 추가해야겠다 !! ✊🏻
_
풀었다 !!!!!!!!!!!!!!!!!!!!!!!
정말 이 문제로 대체 며칠을 끙끙거렸는지.