일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- Python
- pwnable.kr
- 인공지능
- logistic regression
- Linear_regression
- Softmax classification
- programmers
- tensorflow
- leg
- Algorithm
- AI
- 기능개발
- 텐서플로
- Today
- Total
나혼자 공부장
[FTZ] Level 15 write-up 본문
cat 파일을 조회해보면, check 변수가 가리키고 있는 주소의 값이 0xdeadbeef이면 풀리는 문제임을 알 수 있다.
일단 처음 생각난건 fgets 에서 stdin으로 buf값 입력을 받고 있으니, buf 주소에서 시작해서 check 까지 오버플로우를 일으키면 되는 문제라고 생각이 들었다.
하지만 check가 포인터 변수이기 때문에 불가능하다. check 자체의 값이 문제가 아니라 check가 가리키고 있는 주소의 값이 무엇이냐가 문제기 때문에, 값 보다는 주소를 가지고 놀아야하는 레벨이 되겠다.
일단 gdb로 컴파일해서 대충 스택이 어떻게 구성될런지 분석해보자.
간단하게 main 지역변수들의 스택 구성을 구현해보면 위와 같다.
이제 이 구성을 토대로 문제를 풀것이다.
방법 1. check가 buf 주소값을 포인팅
check 가 가리키고 있는 주소의 값이 0xdeadbeef면 되는거라면,
1. buf에 0xdeadbeef를 넣고
2. buf의 주소를 check 에게 넘겨주면
3. 결과적으로 check 가 가리키고 있는 주소의 값은 0xdeadbeef가 된다는 논리이다.
일단 이대로 진행하려면 buf의 주소값을 정확하게 알아야 한다.
위 과정을 거쳐서 0xbfffe120 이 buf의 주소값이라는 사실을 알아냈다.
왜 저 시점에서 esp가 buf의 주소에 위치해 있느냐? main+32 번째 줄은 if문을 진행하는 라인인데, 그 전 명령이 fgets 함수였다. 함수 콜을 하고 작업을 수행한 후 다시 main 으로 돌아오고 나서 스택에 남아있는 fgets의 파라미터 변수들을 정리하고 나면, 가장 마지막에 선언한 지역변수가 buf이므로 제일 윗단에 있는게 buf의 주소가 되기 때문이다.
스택 구성을 참조했을 때, buf의 시작 주소부터의 데이터를 0xdeadbeef 로 만들며 40 byte를 채운 후, check 영역에 buf의 주소를 넣어주는 형태로 페이로드를 짜면 되겠다.
(python -c 'print "\xef\xbe\xad\xde"*10 + "\x20\xe1\xff\xbf"'; cat) | ./attackme
근데 영.. 잘 안 된다. 이것도 Level 11에서 다뤘던 ASLR 라는 기법 때문에, 주소가 계속 랜덤하게 달라져서 물리적 주소를 명확히 정해서 넣어주는 형태는 불안정하다.
물론 주소값이 계속 변하긴 하지만 어느 정도 일정하게 반복되는 형태가 존재하기 때문에 계속 페이로드를 입력해주면 풀 수 있긴 하다. 하지만 이건 어디까지나 주소값을 구하는 과정이 공격대상인 attackme 파일이였을 때 얘기고, 따로 임시 파일에서 구한 주소값이기 때문에 아예 패턴에서 어긋나있는 주소일 수도 있다. 권한이 막혀있어서 임시 파일에서 밖에 주소값을 구할 수 밖에 없었는데도 말이다. 따라서 이건 성공을 보장하는 방법이라고 보긴 어렵다.
방법 2. 0xdeadbeef 문자열 자체의 주소값을 포인팅
방법 1의 문제를 커버하면서 문제를 풀 수 있는 방법 중 하나다. 바로 buf의 주소값을 박아주는게 아니라 프로그램 내부에 있는 0xdeadbeef 문자열 자체의 주소를 check 에 넣어주는 것이다. 0xdeadbeef 는 따로 변수에 들어있지 않고 하드코딩된 형태, 즉 데이터 영역에 위치하기 때문에 ASLR로 변하는 요소가 아니므로, 방법 1과 달리 한번에 풀 수 있는 보장된 방법이다.
eip를 조사해서 if 조건문을 실행하기 전 상태에서, 다음에 실행할 어셈블리 코드를 읽은 것이다.
자세히 보면 dead랑 beef가 보인다. 0x80484b0부터 1씩 증가시켜가면서 0xdeadbeef의 위치를 찾아보자
0x8048b2라는 주소값을 얻었다.
그럼 이제 위에서 그린 스택 구성을 참고하여 페이로드를 짜보자.
40 byte를 NOP Sled를 태워준 다음 check 영역에 0xdeadbeef 주소값을 넣어주면 된다.
(python -c 'print "\x90"*40+"\xbe\x48\x04\x08"';cat) | ./attackme
방법 3. 0xdeadbeef를 환경변수로 지정
다음과 같이 환경변수의 주소를 구하는 코드를 짜준다.
이 때 ptr += (strlen . . . 이 라인은 어떤 의미인가 하면, 환경변수가 항상 무조건적으로 고정되어있는 주소값을 가지고 있는게 아니기 때문이다. 프로그램의 변수 개수나 디렉토리의 경로 길이 등에 따라 환경변수의 주소가 밀린다는 새로운 사실을 알게 되었다. 따라서 위와 같이 밀린 바이트 수까지 반영해주는 라인이 필요하다.
맥락은 이해가 가는데 저 연산에서 2를 왜 곱해주는게 왜 필요한지 정확히는 모르겠다.. 아직 조사가 부족한 것 같다.
BEEF라는 환경변수로 0xdeadbeef를 지정했다.
0xbffffcb6이라는 주소를 얻었다.
password : about to cause mass
'pwnable > FTZ' 카테고리의 다른 글
[FTZ] Level 17 write-up (0) | 2019.11.20 |
---|---|
[FTZ] Level 11 풀이 (0) | 2019.11.13 |
[FTZ] Level 9 풀이 (0) | 2019.11.13 |