[pwnable.kr] fd - 1 pt [Toddler's Bottle]
pwnalbe.kr 시작합니다~~~
먼저 fd라는 1pt문제부터 시작.
Mommy! what is a file descriptor in Linux? * try to play the wargame your self but if you are ABSOLUTE beginner, follow this tutorial link: https://youtu.be/971eZhMHQQw ssh fd@pwnable.kr -p2222 (pw:guest) |
file descriptor에 대한 문제같다. 먼저 ssh로 저 주소로 접속해보자.
와우... 접속이 되고 기본적인 설명이 되어있다. 일단 파일이 무엇이 있는지 살펴보자.
저런것들이 있고, CTF나 Wargame류에서 흔히 그러듯 flag가 있다.
하지만 flag의 읽기권한이 우리에겐 없으므로 읽는 것은 불가능하다.
여기서 fd를 보면 setuid가 걸려있어 프로그램을 실행하면 fd_pwn의 권한으로 일을 하게된다.
저 fd가 무엇을 하는지 알기 위해 fd.c를 보자.
(그전에 https://youtu.be/971eZhMHQQw에서 scp를 이용해서 파일을 내 서버로 가져오는 법을 배웠다.)
scp -P2222 fd@143.248.249.64:fd .
scp -P2222 fd@143.248.249.64:fd.c .
만약 바이너리파일만 주어지면 이렇게 내 서버로 가져와서 사용해보는 것도 나쁘지않아보인다.
그럼 한번 fd.c의 내용을 보자
#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; } | cs |
buf를 전역변수로 두고, 첫번째 인자로 받은 값을 atoi로 정수로 바꾸어 -0x1234를 한후 fd에 넣어준다.
그리고 read(fd, buf, 32);를 수행하여 32값을 읽어와 buf에 저장해준다. 먼저 read에 대해 알아보자.
man read
함수원형
#include <unistd.h>
ssize_t read(int fd, void *buff, size_t nbytes);
리턴값
반환 값: 읽어온 바이트 수, 실패 시 -1, 파일의 끝에서 시도하면 0
여기서 read의 첫번째 인자 fd : 파일 서술자
두번째 인자는 *buff : 읽어와서 저장할 버퍼
새번째 인자는 nbytes : 읽을 수 있는 최대 byte의 수
이다. 첫번째 인자로 들어가는 fd는 int형인데, 이는 파일 디스크립터가 C int 타입으로 표현되기 때문이다. (최대값은 1024이지만 1048576번까지 설정가능하다한다)
이 때, 0,1,2 번은 사전에 배정되어 있고 각각 아래와 같다.
0 : 표준 입력 (stdin) / 1 : 표준 출력 (stdout) / 2 : 표준 오류 (stderr)
따라서 실제 하나의 파일을 생성하게 되면 “3번” 부터 File Descriptor가 부여된다고한다.
보통 사용할때 fd = open("path/", option)으로 먼저 fd에 번호를 부여한후에 read로 읽는게 대부분이다.
그러므로 fd값을 0으로 주면 stdin을 이용하여 buf에 우리가 원하는 값을 입력할 수 있게된다.
#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; } | cs |
자 이제 문제로 돌아와서 코드를 한번 살펴보자.
fd를 설정한 후, len = read(fd, buf, 32); 를 통해 buf에 최대 32자를 받은후
strcmp를 통해 "LETMEWIN"이라는 문자열과 비교한다. 만약 같다면 0을 리턴하므로 if문이 실행되고
good job이라는 메세지와 함께 system("/bin/cat flag");를 수행하는 모습을 볼 수 있다.
fd는 setuid가 걸려 fd_pwn권한으로 실행되어 flag를 볼 수 있을 것이다.
그러므로 우리는 fd=0으로 만들어주기만하면 된다.
fd = atoi(argv[1]) - 0x1234이고, 0x1234는 4660이므로 ./fd 4660을 실행하면 우리가 원하는 값을 buf에 표준입력(stdin)으로 넣어줄수 있다.
mommy! I think I know what a file descriptor is!!
굿!!
'Wargame > Pwnable.kr' 카테고리의 다른 글
[pwnable.kr] blackjack - 1 pt (0) | 2018.05.01 |
---|---|
[pwnable.kr] cmd1 - 1 pt (0) | 2018.05.01 |
[pwnable.kr] shellshock - 1 pt (0) | 2018.05.01 |
[pwnable.kr] mistake - 1 pt (0) | 2018.04.27 |
[pwnable.kr] random - 1 pt [Toddler's Bottle] (0) | 2018.04.25 |