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], 81, fp);
        fclose(fp);
 
        printf("OTP generated.\n");
 
        unsigned long long passcode=0;
        FILE* fp2 = fopen(fname, "r");
        if(fp2==NULL){ exit(-1); }
        fread(&passcode, 81, fp2);
        fclose(fp2);
 
        if(strtoul(argv[1], 016== 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과 관련된 문제라는 힌트가 있었다.



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

+ Recent posts