level 18 로그인 후 hint를 본다.
엄청나게 긴 hint가 나온다.
코드가 긴 만큼 gdb 분석도 길어서 겁먹기에 십상이다.
모르는 함수들이 많고 코드가 길어도 시스템 해킹에서는 언제나 "root의 권한으로 쉘을 실행시킨다"라고 생각하면 쉽다.
위와 같이 생각하고 코드를 보게 되면 변수들이 선언되고 변수 check 값이 0xdeadbeef면 shellout 함수가 실행되는 아주 간단한 코드가 된다.
여기서 알아야 할 것은 "먼저 선언된 변수가 높은 메모리 주소를 가진다"는 것이다.
이것을 알면 스택 구조도 쉽게 파악할 수 있다. 스택 구조를 보게 되면 아래와 같다.
스택 구조
fds 4byte |
count 4byte |
x 4byte |
check 4byte |
string[100] 100byte |
SFP 4byte |
RET 4byte |
dummy가 140byte로 위 스택 구조와 함께 256byte를 채우게 된다.
gdb를 보면 dummy는 아마도 count와 fds 사이에 들어가는 것으로 보인다. 정확하진 않다.
스택 구조를 보게 되면 check가 더 낮은 주소에 있다. 그래서 string에 BOF를 하면 SFP, RET에 값이 들어가지만, check에 값을 넣기는 힘들다. 그래서 BOF가 아닌 다른 방법을 찾아야 한다.
gdb가 길게 나오기 때문에 필요한 부분만 잘라서 본다.
main+3에서 0x100(256)byte를 확보한다.
main+12, main+19에서 0으로 초기화 하는데 위 코드에서 0으로 초기화 하는 변수는 "x, count"이므로 이 둘이라고 볼 수 있다.
main+91에서 0xdeadbeef와 비교하는 거로 봐서는 check의 주소가 "ebp-104"라는 걸 알 수 있다.
이렇게 보면 "ebp-100"은 배열 string 시작 주소, "ebp-104"는 변수 check 시작 주소, "ebp-108"은 변수 x 시작 주소, "ebp-112"는 변수 count 시작 주소를 알 수 있고 이들 사이에 dummy가 들어가지 않는다는 것도 알 수 있다.
주소들을 보게 되면 먼저 선언된 변수가 더 높은 주소를 가지고 있다는 것도 알 수 있다.
주소를 알았으면 공격을 위한 다음 코드를 본다.
처음에 코드를 보고 fgets 함수 같은 받아주는 함수가 없어서 코드가 어떻게 돌아가는지 파악하기 힘들었다.
그 해답은 else 문에 있다.

else 문을 정말로 아주 간략하게 분석하게 되면 이렇게 된다.
FD_SET 부분에서 fds 파일 디스크립터를 STDIN이랑 연결해서 select로 다중화시켜주고 read로 읽어온다.
else 부분의 fd(File Descriptor, 파일 디스크립터)에 대해서는 공부를 하지 않았고 질문을 통해 들은 간단한 분석이다.
위 fgets 함수와 비슷한 부분은 read 함수로 나온 것이다.
read 함수를 분석하게 되면 표준 입력(stdin)으로 들어온 데이터를 1바이트씩 "&x"에 넣는 것이다.
그럼 그 "&x"는 swhitch(x) 문의 x로 들어가게 된다.
주소를 보게 되면 check는 ebp-104가 되는데 check에 0xdeadbeef를 넣어야 한다.
표준 입력으로 데이터를 쓸 수 있는 주소는 string의 주소 ebp-100이다.
여기서 switch 문을 사용하면 check의 주소에 들어가 check에 입력할 수 있게 된다.
그 방법은 case 0x08을 이용하면 된다. 왜냐하면 string[-4]를 만들어야 하기 때문이다.
x에 0x08을 넣으면 "count--;"가 되는데 그렇게 되면 count는 "-1, -2, -3, -4"로 나아가게 된다.
-4까지 넣고 case에 없는 문자를 입력했을 경우 default로 이동해 string[-4]가 된다.
처음에는 이 부분이 이해가 되지 않았다.
count의 변수만 바뀌었는데 string ebp가 움직인다고 생각했다. 이 생각이 잘못된 생각이었다.
string 자체 ebp는 움직이는 게 아니다.
예를 들어 p[a]가 있을 때 p[a]는 *(p +a)의 문법적 설탕이기 때문에 string[-4]는 *(string -4)의 문법적 설탕이 된다.
string[-4]가 되면 string ebp보다 4작은 주소를 가져오게 되는 것이다. string ebp보다 4작은 주소는 ebp-104 즉 check의 주소가 된다.
공격 코드를 보면서 다시 확인해 본다.

공격 코드를 간단하게 분석하면 이렇게 된다.
공격 코드로 "\x08\x08\x08\x08\xef\xbe\xad\ed"를 입력한다.
입력하면 read 함수에서 표준 입력(stdin)으로 들어온 데이터를 1바이트씩 읽어 &x에 저장한다.
처음 입력한 \x08이 &x에 들어가고 &x는 switch(x) 이곳에 들어가게 되어 switch(\x08)가 된다.
그렇게 되면 세 번째 case인 0x08에 걸려 "count--;"가 되고 "count = -1;"이 되어 다시 while 루프가 실행된다.
그렇게 \x08이 세 번 더 돌면 "count = -4;"가 된다.
이후에는 "\x08"이 아닌 "\ef"가 들어가기 때문에 default로 이동하고 "count = -4;"이므로 string[-4]가 오게 된다.
"0xdeadbeef"가 들어갈 때까지 루프가 실행되고 "0xdeadbeef"가 다 들어가게 되면 다음 루프가 실행할 때 두 번째 if 문에서 check와 비교하게 되어 쉘이 실행되는 것이다.
이 문제는 C언어를 깊게 공부하지 않았다면 위 hint 분석처럼 아주 간단하게 분석하고 넘어가서 뒤에서 막히게 된다.
종일 이 문제만 보고 있었는데 검색만으로는 이해할 수 없는 부분이 많았다.
대부분의 문제 설명들이 코드가 어떻게 실행되는지에 대한 자세한 설명이 없어서 이해하지 못했다고 생각했다.
그래서 질문을 통해 hint 코드와 공격 코드가 어떻게 실행되는지 정확히 파악하고 질문을 통해 얻은 답변, hint 코드와 공격 코드의 실행을 자세히 적으려 노력했다.
'System Hacking > 해커스쿨 F.T.Z Hacking Zone' 카테고리의 다른 글
해커스쿨 F.T.Z Level 20 (0) | 2020.03.02 |
---|---|
해커스쿨 F.T.Z Level 19 (0) | 2020.02.29 |
해커스쿨 F.T.Z Level 17 (0) | 2020.02.27 |
해커스쿨 F.T.Z Level 16 (0) | 2020.02.27 |
해커스쿨 F.T.Z Level 15 (0) | 2020.02.26 |
댓글