Problem
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)
Exploration
먼저 디렉토리를 탐색하면 flag는 fd_pwn 권한을 얻어야 읽을 수 있었다. fd 파일을 통해 fd_pwn 권한을 얻어 flag를 읽는 방향으로 접근하였다.
fd@pwnable:~$ id
uid=1002(fd) gid=1002(fd) groups=1002(fd)
fd@pwnable:~$ ls -lahr
total 40K
drwxr-xr-x 2 root root 4.0K Oct 23 2016 .pwntools-cache
dr-xr-xr-x 2 root root 4.0K Dec 19 2016 .irssi
-rw------- 1 root root 128 Oct 26 2016 .gdb_history
-r--r----- 1 fd_pwn root 50 Jun 11 2014 flag
-rw-r--r-- 1 root root 418 Jun 11 2014 fd.c
-r-sr-x--- 1 fd_pwn fd 7.2K Jun 11 2014 fd
d--------- 2 root root 4.0K Jun 12 2014 .bash_history
drwxr-xr-x 116 root root 4.0K Oct 30 2023 ..
drwxr-x--- 5 root fd 4.0K Aug 31 16:09 .
fd.c 파일을 살펴보면 fd 라는 4 byte 정수형 변수에 argv[1] 을 ASCII 코드로 변환하고 0x1234를 뺀 값을 저장한다.
그리고 fd에 32byte를 읽어 buf 에 저장하고 "LETMEWIN\n" 이라는 문자열과 비교하여 같으면 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;
}
File descriptor와 read 함수에 대해 알아보면 File descriptor는 system으로부터 할당받을 file(socket)을 식별하는 정수값이다. file 을 열거나 socket을 생성하거나 pipe를 만들 때 os는 process에 file descriptor를 반환한다. 예를 들어 open system call을 사용하여 파일을 열 때 반환되는 값이 file descriptor 이다. file descriptor 는 최대 1024까지 생성 가능하다.
프로세스가 메모리에 올라갈 때 프로세스마다 fd 의 번호가 미리 배정되어있는데 0, 1, 2가 사전 배정되어있다.
standard file descriptor
- 0: stdin
- 1: stdout
- 2: stderr
read() 함수는 file descriptor로부터 data를 읽어들이는데 사용되는 system call이다. 이 함수는 file, socket, pipe 등 과 같은 다양한 file descriptor로 부터 data를 읽어들일 수 있다. read() 함수의 prototype은 다음과 같다.
READ(2) Linux Programmer's Manual READ(2)
NAME
read - read from a file descriptor
SYNOPSIS
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
- fd: read 작업을 수행할 file descriptor
- buf: data를 저장할 buffer의 pointer
- count: read할 최대 byte 수
Solution
fd에서 input stream을 열어 'LETMEWIN\n' 문자열을 입력하면 flag값을 얻을 수있다.
file descriptor로 입력을 받으려면 보통 socket과 같은 system call을 통해 i/o stream 을 열어야한다.
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
// TCP 소켓 생성
int sockfd = socket(AF_INET, SOCK_STREAM, 0); // IPv4, TCP 프로토콜
if (sockfd == -1) {
perror("socket failed");
return 1;
}
printf("TCP socket created with fd: %d\n", sockfd);
// 추가적인 소켓 연결 및 데이터 송수신 코드가 필요합니다.
close(sockfd); // 소켓 닫기
return 0;
}
#include <unistd.h>
#include <stdio.h>
int main() {
int fds[2];
if (pipe(fds) == -1) {
perror("pipe failed");
return 1;
}
printf("Pipe created with read fd: %d, write fd: %d\n", fds[0], fds[1]);
// fds[0]: 읽기 끝, fds[1]: 쓰기 끝
close(fds[0]);
close(fds[1]);
return 0;
}
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("open failed");
return 1;
}
// 파일 내용을 메모리에 매핑
void *map = mmap(NULL, 4096, PROT_READ, MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED) {
perror("mmap failed");
close(fd);
return 1;
}
printf("Memory mapped at address %p\n", map);
munmap(map, 4096);
close(fd);
return 0;
}
#include <sys/eventfd.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int efd = eventfd(0, 0); // 초기값 0, 기본 플래그 사용
if (efd == -1) {
perror("eventfd failed");
return 1;
}
printf("Eventfd created with fd: %d\n", efd);
close(efd);
return 0;
}
하지만 코드 상으로는 fd를 여는 부분이 없기 때문에 system 표준 입출력인 0, 1, 2를 제외한 값으로 열었을 경우 유효하지 않은 file descriptor이기 때문에 입력을 받을 수 없다.
fd 는 입력값에 0x1234(10진수로 4660)을 뺀 값의 file descriptor를 연다. 따라서 fd 4660을 실행하면 stdin(0) stream을 열 수 있게 된다.
fd@pwnable:~$ ./fd 4659
learn about Linux file IO
fd@pwnable:~$ ./fd 4658
learn about Linux file IO
fd@pwnable:~$ ./fd 4660
LETMEWIN
good job :)
mommy! I think I know what a file descriptor is!!
fd@pwnable:~$ ./fd 4662
LETMEWIN
good job :)
mommy! I think I know what a file descriptor is!!
fd@pwnable:~$ ./fd 4661
LETMEWIN
good job :)
mommy! I think I know what a file descriptor is!!
'네트워크 보안 > CTF' 카테고리의 다른 글
pwnable bof (0) | 2024.10.06 |
---|---|
[pwnable] pwnable.kr collision (hash function, hash collision, md5 hash collision) (0) | 2024.09.11 |
[HTB/Crypto] Weak RSA (1) | 2024.03.24 |
[Web] webhacking.kr 3번 (0) | 2022.05.27 |
[Web] webhacking.kr 1번 (0) | 2022.05.27 |