cat hint로 hint를 확인해준다.
level11과 유사한 hint인 것 같다.
그럼 이 문제도 BOF를 이용하여 푸는 문제라는 것이다.
한번 attackme를 실행해본다.
위의 코드와 같이 문장을 입력받으면
입력받은 문장을 그대로 출력하는 실행파일이다.
자꾸 이런 BOF문제가 나오는데 BOF에 대해
공부를 한번 해보겠다.
[ Memory Corruption 취약점 ]
예상되지 않은 메모리 값 변경, 참조 등에 의해서 발생한다.
대부분 안전하지 않은 함수의 사용, 잘못 된 함수 사용 등 프로그래밍 실수로 인해 발생한다.
대표적으로 BOF취약점이 있다.
[ BOF 공격 ]
버퍼란 데이터를 일시적으로 저장해두는 메모리 상의 공간을 의미한다.
BOF는 프로세스가 데이터를 버퍼에 저장할 때 원래 크기보다 초과되는 데이터를 입력하면
정상적인 경우에는 사용되지 않아야 할 영역에 데이터가 덮어씌워지는 것을 의미한다.
[ BOF에 취약한 대표적인 함수 ]
strcpy, strcmp, gets, scanf, strcat, getwd, sprintf 등
그럼 level11과 같이 tmp에 attackme 실행파일을 복사한 후
GDB 디버거를 이용하여 한번 살펴 보겠다.
이 문제는 gets함수로 입력을 받아서 printf함수로 출력을 하기 때문에
gets 함수 바로다음(main+61)에 break를 걸어서 주소를 확인해야겠다.
RET가 시작되는 주소는 0xbffff9d0이라는 것을 알 수 있다.
이유는 A가 16진수로 0x41이므로 AAAA는 0x41414141이 되기 때문이다.
GDB 디버거를 종료한 후 vi명령을 통해 파이썬 코드를 한번 짜주자.
일일히 타이핑 해도 괜찮지만 너무 길기 때문에 간편하게 하기 위해 인터넷 검색을 통해
짜는 법을 확인했다.
우선 이 코드를 설명 드리자면
import struct는 struct 뮤듈을 이용한다는 의미이다.
struct 모듈은 C구조체의 값을 파이썬에서 사용하는 데이터 값으로 변경하기 위하여 제공되는 파이썬 모듈이다.
그리고 a의 구조를 Nop + 쉘코드 + Nop + RET로 한 이유는
처음에 Nop + 쉘코드 + RET로 했을 때 안되길래
검색을 해보니 컴퓨터가 가끔 쉘코드 + RET를 그냥 쉘코드 하나로
인식할 때가 있다고 하여서 배치를 저렇게 하였습니다.
lambda x: 의 의미는 x를 이용한 함수를 사용하겠다는 것을 의미한다.
뒤의 struct.pack("<L", x)의 의미는 x를 리틀 엔디안으로 표시한다는 의미이다.
엔디안이란 바이트 순서란 뜻이며
순서에 따라 빅 엔디안과 리틀 엔디안으로 나누어 진다.
빅 엔디안과 리틀 엔디안의 차이는 위 그림을 보면 된다.
파이썬 코드를 완성했으면 이제 공격을 한번 해보자.
하나씩 하는 것이 귀찮아서 4번씩 실행을 시켜보았다.
;로 연결한 이유는 여러개의 명령어를 동시에 실행할 때
&&를 사용하면 앞의 명령어가 실패하면 뒤의 명령어들은 실행이 되지 않지만
;를 사용하면 앞의 명령어의 성공/실패 여부와 상관없이 뒤의 명령어가 실행되기 때문이다.
위의 (python a.py;cat)|./attackme를 풀어주자면
우선 (python a.py;cat)의 결과값을 ./attackme의 입력값으로 주기 위해 | 를 사용하였다.
python a.py는 a.py를 실행하는 것을 의미한다.
;cat을 사용한 이유는 밑의 그림으로 설명하겠다.
하다보면 알겠지만 Segmentation fault가 발생하기도 하는데 이는
ASLR 기법이 적용 되어 있기 때문이라고 한다.
[ ASLR 기법 ]
프로세스의 가상주소공간에 어떤 Object 가 매핑될 때, 그 위치를 프로그램 실행시마다
랜덤하게 변경하는 보안 기법을 의미한다.
또한 Illegal instruction가 발생하기도 하는데 이는
GDB에서의 주소와 실제 실행 시의 주소의 차이 때문에 발생하는 것이므로
주소를 증감 해 가며 올바를 주소를 찾아야 한다.
만약 Illegal instruction가 발생하면 다시 vi a.py를 실행시켜
보이는 RET의 주소를 UP/DOWN하며 일일히 찾아 주어야 된다.
수 많은 노가다 끝에 Enter을 눌렀을 때
오류가 뜨지않으면 id명령어를 입력하여
uid가 level13인지 확인하고 level13이면 my-pass 명령어를 이용하여
다음레벨의 Password를 얻으면 된다.
'코딩 문제 > 해커스쿨' 카테고리의 다른 글
FTZ : level14 (0) | 2019.07.13 |
---|---|
FTZ : level13 (0) | 2019.07.08 |
FTZ : level11 (0) | 2019.06.29 |
FTZ : level10 (0) | 2019.01.22 |
FTZ : level9 (0) | 2019.01.19 |