Pwnable 1번 [fd]

 

http://pwnable.kr/play.php < 이 곳으로 접속해서 진행할 수 있다.

 

http://pwnable.kr/play.php

 

pwnable.kr

 

문제 1번 - [fd]

귀여운 얼굴에 그렇지 못한 태도...

 

English Attack...

엄마! Linux에 있는 file descriptor가 무엇인가요?!

(나도 모른다 아들아....)

 

 

Linux의 파일 디스크립터 관련한 문제인 것 같다.

 

내 OS는 친근한 windows 이므로 문제를 풀기 위해서는 가상머신으로 Linux를 돌려 터미널로 들어가거나 putty를 이용하면 되는데 후자를 택하도록 한다.

 

 

오랜만에 하는 Putty ^_^

 

1) putty 접속

  • 문제 하단에 있는 설정대로 접속하도록 한다.
  • ssh fd@pwnable.kr -p2222 (pw:guest) 

 

 

2) pw 입력

  • guest 를 입력하면 정상적으로 로그인이 된다.

 

3) ls 명령으로 파일, 디렉토리 list 확인

  • ls 를 입력하니 3개의 파일이 나온다.  fd  fd.c  flag

  • 좀더 자세히 보자. ls -l 명령어 입력

  • 각 파일별 소유자, 소유그룹, 파일권한을 살펴보면
    • fd 계정으로 접속한 나는,
    • fd 파일은 소유그룹이 fd이므로 읽기, 실행 가능
    • fd.c 파일은 소유자, 소유그룹이 둘다 root이므로 other의 권한인 읽기만 가능
    • flag 파일은 마찬가지로 other에 속하기 때문에 other의 권한으로 접근이 가능한데 권한이 없다. (당연한소리)

 

4) fd.c 파일 읽기

  • cat 명령어를 사용하여 fd.c 를 읽어보자

5) 코드 분석

첫번째, 상단의 if문 조건식  

을 보면 (argc<2) 가 참이면, pass argv[1] a number\n 라는 문구를 출력하고 프로그램을 종료하도록 되어 있다.

 

여기서 C언어의 main 함수 인자 int argc와 char* argv[]는 인수 갯수와 인수 값을 의미로 쓰인다.

이 부분은 C언어 파트에서 자세히 알아보도록 하자. 갈길이 멀다!

 

리눅스에서는 파일을 실행할 때 ./fd 의 형태로 실행할 수 있는데 옆에 인자값을 줄 수 있다.

./fd 12345 를 입력하게 되면 main 함수가 실행될 때 12345를 argv[]의 값으로 받게 되는 것.

 

즉, fd 파일을 실행할 때 인자값을 주지 않으면 인자값을 입력하라는 문구와 함께 프로그램 강제 종료시켜버리는 코드인 것이다.

 

두번째, int fd = atoi(argv[1]) - 0x1234;  

 atoi 함수 :   ascii to int , ascii 값을 int 값으로 치환해 주는 함수이다.

argv[]는 main에서 char* 타입으로 받게 되어 있어 우리가 숫자를 입력해도 ascii 형태의 숫자값으로 들어오게 된다.

 

atoi 함수를 써서 치환한 argv[1]의 값에 0x1234를 뺀 정수 값을 fd에 대입한다.

 

※16진수 0x1234는 10진수 4660이다.

0001 0010 0011 0100 -> 4096 + 512 + 32 + 16 + 4 = 4660

 

세번째, len = read(fd, buf, 32);  

 read 함수 :  쉽게 말해서 파일을 읽는 함수인데 파일 디스크립터(File Descriptor)가 여기서 등장한다.

read 함수의 인자는 다음 3가지이다.

  • file descriptor(int fd)
  • 파일을 읽어들이고 저장할 공간인 버퍼(void* buf)
  • 최대 읽어들일 바이트 수(size_t byte)
  • read 함수는 파일을 읽고 읽어낸 바이트 수를 정수로 반환한다.

 

여기서 file descriptor란, 윈도우에서의 핸들(Handle)과 동일한 개념으로 

리눅스에서 프로세스가 파일에 접근할 때 사용하기 위한 인덱스라고 볼 수 있다.

 

이 인덱스 값 중 미리 예약된 값이 있는데 다음과 같다.

 0 = 표준 입력(키보드) / 1 = 표준 출력(모니터) / 2 = 표준 에러(모니터) 

 

fd 값이 0이라면, 키보드를 통해 원하는 값을 입력하여 buf 에 저장할 수 있다는 의미이다.

 

네번째, 하단의 if문  

드디어 flag에 대한 코드가 나온다!

 

 strcmp 함수 :  인자로 받은 두 문자열을 비교하여 동일하면 0을 반환, 다르면 1을 반환하는 함수이다.

그러나 위의 코드에서는 if문 실행을 위해 앞에 !(not)이 붙었으므로 동일하면 1을 반환하도록 되어 있다.

 

 LETMEWIN 이라는 문자열과 buf에 저장된 문자열동일해야 flag 파일을 열 수 있다는 뜻!

 

따라서 이 문제의 해결 조건은,

(1) fd 값이 0이 되게 하여 표준 입력을 받을 수 있도록 하기
(2) 그러려면, ./fd 명령어 실행 시 인자값을 주어야 하고 (첫번째 if문 거짓되도록)
(3) ./fd 인자값이 0x1234여야 한다. (0x1234 - 0x1234 = 0)
(4) 마지막으로, LETMEWIN 문자열을 입력하여 !strcmp() 반환값이 1이 되도록 하여야 한다.

 

6) flag 찾아 입력하기

  • 위에서 언급한 0x1234 의 10진 정수값인 4660을 입력해 보자.

  • 입력 대기상태로 바뀐다.
  • 문자열 LETMEWIN을 입력해 보자.

  • good job 이라는 칭찬과 함께 cat flag 가 수행되어 flag가 바로 출력된다~

 

  • 이 문장 그대로 pwnable 사이트의 답란에 쓰고, auth 버튼을 클릭하면 Clear!

포스팅을 위해 한번 더 풀었더니 아래의 메시지가 뜬다;; 1점 이미 받았기에...

'Wargame > pwnable.kr' 카테고리의 다른 글

Pwnable 2번 Collision  (0) 2021.05.12