문제 코드

#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");
		setregid(getegid(), getegid());
		system("/bin/cat flag");
		exit(0);
	}
	printf("learn about Linux file IO\n");
	return 0;
 
}

취약한 코드 분석

제일 먼저 어디서 flag를 얻을 수 있는지를 확인하였습니다. 그 결과 16번째줄에서 flag를 출력하는 코드를 확인할 수 있었습니다.

system("/bin/cat flag");

해당 코드를 실행하기 위해서는 다음 조건문을 충족시켜야 하는데 strcmp의 경우 같으면 0 다르면 1을 반환하지만 !를 통해서 반전되므로 ‘LETMEWIN’문자열과 buf라는 변수가 같은 문자열을 같아야지 실행되는 구조였습니다.

if(!strcmp("LETMEWIN\n", buf))

하지만 조건문을 받기 전에 fd라는 argv[1] 입자 값에서 0x1234 즉 4660을 뺸 값으로 read의 첫 번째 인자를 받고 있었습니다.

read함수에 첫 번째 인자에는 3가지 종류의 값을 입력받을 수 있으며, 0,1,2 각각의 뜻이 존재합니다. 3개중 어떤것을 해도 출력값에는 문제없이 출력이 이뤄지므로 저는 0을 만드는 방법으로 접근하기로 했습니다.

Tip

여기서 atoi는 문자열을 integer 정수로 바꿔주는 명령어입니다.

int fd = atoi( argv[1] ) - 0x1234;
	int len = 0;
	len = read(fd, buf, 32);

exploit

./fd 4660
LETMEWIN

배운 내용

FILE Descriptor

  • 유닉스 계열 운영체제에서 프로세스가 파일, 소켓, 파이프 등 입출력 리소스에 접근할 때 사용하는 0 이상의 정수 형태인 추상적 키(식별자)

  • 기본 제공 FD (Standard Streams): 프로세스 생성 시 3개의 기본 FD가 할당됩니다.

    • 0: 표준 입력 (STDIN_FILENO, stdin)
    • **1: **표준 출력 (STDOUT_FILENO, stdout)
    • 2: 표준 오류 (STDERR_FILENO, stderr)

관련 시스템 호출(System Call)

  • open(): 파일을 열고 새로운 FD를 반환
  • read()/write(): FD를 사용하여 데이터 읽기/쓰기
  • close(): FD를 닫고 리소스 반환

참고자료

setregid & getegid

setregid(getegid(), getegid());
  • setregid :
  • getegid :

참고자료