bruteforce는 하지 말라는게 힌트다.
삽질을 굉장히 많이했고 도저히 모르겠어서 결국 검색을 통해 푼 문제다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | #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; } | cs |
문제의 otp 바이너리의 소스코드이다.
passcode를 입력하고 /dev/urandom을 통해 16 바이트의 난수를 읽어오고, 앞의 8바이트는 파일의 이름으로 임시 파일을 생성,
뒤의 8바이트는 생성한 임시 파일에 쓰고 이걸 후에 다시 읽어와서(passcode) 사용자의 입력(argv[1])과 비교한다.
/tmp 디렉토리에 코드를 복사하여 이런저런 테스트를 해봤다.
도저히 모르겠어서 검색해보니 ulimit과 관련된 문제라는 힌트가 있었다.
user가 생성할 수 있는 resource의 제한을 두는 것을 의미하는데
해당 문제에서는 120000으로 설정되어있었다.
즉, user가 해당 쉘에서 자식 프로세스로 생성되는 프로세스가 생성할 수 있는 파일의 크기가 최대 120000으로 제한한다는 것인데
이걸 user가 변경할 수 있는 것 같다.
만약 user가 이 제한을 0으로 변경하면 실행되는 자식 프로세스는 모두 파일을 생성할 수 없게된다.
이 문제는 이 제한을 변경해서 otp 프로세스가 파일을 생성하지 못하게 하는 문제다.
ulimit을 0으로 설정하면 다음 코드에서 문제가 발생할 것이다.
파일을 생성하고 파일을 쓰는데, 쓸 수 있는 파일의 크기가 0으로 제한되기 때문에 파일에는 아무 값도 쓸 수 없게된다.
이 때 다음과 같이 파일의 크기가 커서 생성이 못하는 의미를 갖는 27번 errno이 설정된다.
1 | #define EFBIG 27 /* File too large */ | cs |
그럼 이 부분에서 문제가 생기는데, 원래 파일에서 읽어야 할 passcode를 파일에 읽을 데이터가 없기 때문에 읽을 수 없게된다.
passcode는 여기서 null이 되고 이후 비교문을 보면
이 부분에서 strtoul 함수의 반환값이 0이 되어야 한다.
즉 argv[1]에 아무 값도 전달하지 않아야 한다는 것인데 터미널에서 실행시키는 방법으론 방법이 생각나지 않는다.
그래서 파이썬 스크립트로 subprocess로 실행시키는 방법을 사용했다.
1 2 | import subprocess subprocess.call(['/home/otp/otp', '']) | cs |
이렇게 인자를 전달하면 argv[1]에는 null이 들어가게 된다.
/tmp 디렉토리에 해당 파이썬 스크립트를 작성하고 다음과 같이 ulimit을 0으로 설정한다.
이제 파이썬 스크립트를 실행하면..
플래그가 출력된다.
1 | Darn... I always forget to check the return value of fclose() :( | cs |
'CTF 공부 > Pwnable.kr' 카테고리의 다른 글
fsb (0) | 2019.01.13 |
---|---|
brain fuck (0) | 2019.01.08 |
21. horcruxes (0) | 2018.12.30 |
13. cmd1 (0) | 2018.10.01 |
13. lotto (0) | 2018.10.01 |