시스템해킹을 하시는 분들이라면 한번쯤 들어봤고, 풀어봤을 법한 pwnable.kr 사이트의
첫번째 문제입니다.
fd 를 클릭하면
이러한 창이 뜹니다. 리눅스에서 파일디스크립터가 무엇인지를 묻는 문제입니다.
아래쪽을 보니 Flag를 찾아 넣고 auth 버튼을 누르면 되겠네요.
Pwnable.kr 접속하기
우선 접속을 해봅시다.
가상머신에 있는 리눅스를 켜서 터미널 창 열고
ssh fd@pwnable.kr -p2222
치고 들어가도 되지만, 저는 그냥 putty로 접속하도록 하겠습니다.
아래와 같이 설정해주고, Open!
password 는 guest
password 까지 치고 들어가면 완료!
Pwnable.kr 1번 fd 문제 풀이
우선 어떠한 파일들이 존재하는지 알아봅시다.
ls -l 을 이용해서 파일에 대한 정보를 출력합니다.
먼저 각 파일들의 권한을 살펴보겠습니다.
fd 라는 파일은 소유자가 fd_pwn 이고 소유그룹이 fd 네요.
우리는 지금 fd 라는 이름으로 접속을 했기 때문에 소유그룹에 해당됩니다.
fd 그룹에 할당된 권한은 r-x 이기 때문에 우리가 읽고 실행할 수 있습니다.
fd.c 파일은 소유자가 root고 소유그룹도 root 입니다. 이 파일에서의 우리는 other의 권한을 가집니다.
other의 권한을 보니 r-- 네요.
우리는 이 파일을 읽을 수 있습니다.
flag는 우리가 읽을 수도, 실행할 수도 없는 것을 확인할 수 있습니다.
우선 fd.c 부터 읽어보도록 하겠습니다.
cat 명령어를 이용하여 fd.c 을 읽을 수 있습니다.
파일 이름에서도 보이지만, c 파일입니다.
대략 살펴보면 32바이트의 buf 를 선언해주고,
그 buf와 "LETMEWIN\n" 을 비교하여 같으면 flag를 실행시켜주는 코드인 것 같습니다.
자주 보이는 main 함수 인자인 argc 와 argv[] 가 보이네요.
- argc : 메인함수에 전달되는 정보의 개수를 의미
- argv[] : 실질적인 정보를 의미
간단하게 정리하자면 이렇습니다. argc 는 개수, argv는 정보(문자열)를 의미합니다.
메인 함수 상단의 if 문은 인자를 하나 이상 더 넣어라. 라는 의미입니다.
헷갈리실 수도 있으니 예를 들어보겠습니다.
리눅스에서 test 라는 실행파일이 있다고 칩니다.
우리는
./test
를 타이핑 해서 test 파일을 실행 시키는데, 이때 ./test 옆에 인자를 더 넣어줄 수 있습니다.
만약 123 이라는 데이터를 인자로 넘겨주고 싶다면
./test 123
을 타이핑해주면 됩니다.
메인함수의 첫번째 if 문은 인자가 없으면 "pass argv[1] a number\n" 를 출력하라는 의미입니다.
인자를 하나 넣어서 argc가 2가 되면 if 문에 걸리지 않고 다음 코드를 읽겠죠?
atoi 라는 함수가 눈에 띕니다.
간단하게 말하자면 atoi는 char 형 데이터를 int 형 데이터로 변환해주는 함수입니다.
우리가 넣은 인자값은 숫자를 넣어도 데이터 형이 char 입니다. char* argv[] 로 받기 때문이죠.
그렇기 때문에 atoi를 이용해서 숫자형 데이터로 변환해주는 것입니다.
우리가 넣은 값에 16진수 1234를 빼서 fd 에 저장합니다.
그 밑을 더 보면 read() 함수가 보이네요.
read()?
read(파일 디스크립터, 저장할 버퍼 포인터, 저장할 버퍼 길이);
의 형식으로 사용되는 함수입니다.
파일 디스크립터에 해당하는 파일을 최대 저장할 버퍼 길이만큼 읽어서
저장할 버퍼 포인터 안에 넣는 역할을 합니다.
반환값으로 읽어낸 바이트의 수를 반환합니다.
그렇다면 파일 디스크립터란 무엇일까요?
File Descriptor(파일 디스크립터)?
: 프로세스가 파일에 접근할 때 사용되는 인덱스. 윈도우 관점에서의 핸들.
프로세스가 파일에 접근할 때, 우리는 파일을 open 한다고 칭합니다.
파일을 open할 때, 파일 디스크립터는 0을 포함한 양의 정수를 배당받습니다.
그 중, 0 과 1,2 는 기본으로 할당되는 파일 디스크립터입니다.
각각 표준 입력, 표준 출력, 표준 에러를 의미합니다.
0 = 표준 입력(키보드)
1 = 표준 출력(모니터)
2 = 표준 에러(모니터)
만약 read 함수에 파일디스크립터의 값이 0이라면 키보드로 입력받은 값을 읽어 저장을 하게 되는 겁니다.
strcmp는 문자열 비교 함수입니다. 인자로 값 2개를 받고, 그 둘을 비교하면서
같다면 0을, 다르다면 1을 반환합니다.
앞에 NOT(부정) 의 의미를 가지고 있는 "!"가 붙었으니 같으면 1이, 다르다면 0이 되겠네요.
if(1)은 항상 참이기에 우리는 "LETMEWIN\n" 과 buf 를 같게 만들어 if문을 참으로 만들면 됩니다.
정리하자면, 만약 파일 디스크립터의 값이 0 이라면
read()함수를 통해 우리는 키보드 입력을 buf에 저장할 수 있습니다.
이 buf가 LETMEWIN\n 과 같다면 우리는 flag의 결과값을 볼 수 있습니다.
거의 다 왔어요!
그렇다면 fd(파일 디스크립터)의 값을 0으로 만들어야합니다.
0x1234 는 10진수 4660 과 같습니다.
인자값으로 4660을 넘겨주도록 하겠습니다.
4660 을 넘겨주니 키보드 입력을 기다리고 있네요.
LETMEWIN을 입력해주겠습니다.
플래그를 알려줍니다.
이걸 복사해서 pwnable.kr 의 fd 문제 플래그 칸에 넣고 auth를 클릭해줍니다.
문제 클리어!
'Archive > Hacking' 카테고리의 다른 글
[ Stack ] Stack & Stack Frame | 스택이란 무엇일까? (0) | 2020.04.19 |
---|---|
[ Register ] 범용 레지스터 종류 & 범용 레지스터 역할 (0) | 2020.04.19 |
[ Assemble ] 어셈블리 곱셈(mul)/ 나눗셈(div) 연산 실습(1byte) (0) | 2020.04.15 |
[ Assemble ] 어셈블리어 덧셈(add)/뺄셈(sub) 실습 (1) | 2020.04.15 |
[ Assemble ] 어셈블리 입력 매크로함수 (2) | 2020.04.15 |