[toddler's bottle] input

폭풍저그머성찡 ㅣ 2018. 11. 30. 22:17

pwn 공부가 필요하다..


졸라 갓모듈이다 진짜루;;


int main(int argc, char* argv[], char* envp[]){

        printf("Welcome to pwnable.kr\n");

        printf("Let's see if you know how to give input to program\n");

        printf("Just give me correct inputs then you will get the flag :)\n");


        // argv

        if(argc != 100) return 0;

        if(strcmp(argv['A'],"\x00")) return 0;

        if(strcmp(argv['B'],"\x20\x0a\x0d")) return 0;

        printf("Stage 1 clear!\n");


        // stdio

        char buf[4];

        read(0, buf, 4);

        if(memcmp(buf, "\x00\x0a\x00\xff", 4)) return 0;

        read(2, buf, 4);

        if(memcmp(buf, "\x00\x0a\x02\xff", 4)) return 0;

        printf("Stage 2 clear!\n");


        // env

        if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0;

        printf("Stage 3 clear!\n");


        // file

        FILE* fp = fopen("\x0a", "r");

        if(!fp) return 0;

        if( fread(buf, 4, 1, fp)!=1 ) return 0;

        if( memcmp(buf, "\x00\x00\x00\x00", 4) ) return 0;

        fclose(fp);

        printf("Stage 4 clear!\n");


        // network

        int sd, cd;

        struct sockaddr_in saddr, caddr;

        sd = socket(AF_INET, SOCK_STREAM, 0);

        if(sd == -1){

                printf("socket error, tell admin\n");

                return 0;

        }

        saddr.sin_family = AF_INET;

        saddr.sin_addr.s_addr = INADDR_ANY;

        saddr.sin_port = htons( atoi(argv['C']) );

        if(bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0){

                printf("bind error, use another port\n");

                return 1;

        }

        listen(sd, 1);

        int c = sizeof(struct sockaddr_in);

        cd = accept(sd, (struct sockaddr *)&caddr, (socklen_t*)&c);

        if(cd < 0){

                printf("accept error, tell admin\n");

                return 0;

        }

        if( recv(cd, buf, 4, 0) != 4 ) return 0;

        if(memcmp(buf, "\xde\xad\xbe\xef", 4)) return 0;

        printf("Stage 5 clear!\n");


        // here's your flag

        system("/bin/cat flag");

        return 0;

}


각각의 스테이지들을 깨고나면 플래그를 먹을 수 있는 구조이다.


문제풀이는 사실상 pwn모듈 설명이 전부다


차근차근 한 스테이지씩 풀이해보겠다.


++ 홈디렉터리 말고 /tmp에 자기 소유의 폴더를 하나 파고 거기서 스크립트를 짜야 권한 문제가 발생하지 않는다.



[Stage 1]

from pwn import *

p = [str(i) for i in range(100)]

p[65] = '\x00'

p[66] = '\x20\x0a\x0d'


s = process(executable = '/home/input2/input', argv = p)


print s.recvuntil('Stage 1 clear!')


첫 스테이지는 쉽다. ( 근데 펄로 하면 안되더라 )


인자 100개에 65, 66번째 인자를 특정값으로 바꿔주면 된다.


[Stage 2]


from pwn import *

p = [str(i) for i in range(100)]

p[65] = '\x00'

p[66] = '\x20\x0a\0d'


fi = open('./in', 'a')

fi.write('\x00\x0a\x00\xff')

fe = open('./err', 'a')

fe.write('\x00\x0a\x02\xff')


s = process(executable = '/home/input2/input', argv = p, stderr = open('./err'), stdin = open('./in'))


print s.recvuntil('Stage 2 clear!')


표준 입출력 관련 입력이다.


파일에 쓰고 해당 파일의 서술자를  넘겨줘야한다. (솔찍히 좀 불편함 걍 문자열로 받으면 안되남 ㅇㅅㅇ)



[Stage 3]


from pwn import *

p = [str(i) for i in range(100)]

p[65] = '\x00'

p[66] = '\x20\x0a\x0d'


fi = open('./in', 'a')

fi.write('\x00\x0a\x00\xff')

fe = open('./err', 'a')

fe.write('\x00\x0a\x02\xff')

e = {"\xde\xad\xbe\xef" : "\xca\xfe\xba\xbe"}


s = process(executable = '/home/input2/input', argv = p, stderr = open('./err'), stdin = open('./in'), env = e)


print s.recvuntil('Stage 3 clear!')


환경변수 입출력이다. 사실 pwn공부하기 전까지 이런건 처음봤다. c에도 setenv어쩌구로 있는거같다.


[Stage 4]


from pwn import *

p = [str(i) for i in range(100)]

p[65] = '\x00'

p[66] = '\x20\x0a\x0d'


fi = open('./in', 'a')

fi.write('\x00\x0a\x00\xff')

fe = open('./err', 'a')

fe.write('\x00\x0a\x02\xff')


ff = open('./\x0a', 'a')

ff.write("\x00\x00\x00\x00")


e = {"\xde\xad\xbe\xef" : "\xca\xfe\xba\xbe"}


s = process(executable = '/home/input2/input', argv = p, stderr = open('./err'), stdin = open('./in'), env = e)


print s.recvuntil('Stage 4 clear!')


16진수 이름의 파일 만들고 내용 입력하기




[Stage 5]


from pwn import *

p = [str(i) for i in range(100)]

p[65] = '\x00'

p[66] = '\x20\x0a\x0d'

p[67] = '21212'


fi = open('./in', 'a')

fi.write('\x00\x0a\x00\xff')

fe = open('./err', 'a')

fe.write('\x00\x0a\x02\xff')


ff = open('./\x0a', 'a')

ff.write("\x00\x00\x00\x00")


e = {"\xde\xad\xbe\xef" : "\xca\xfe\xba\xbe"}


s = process(executable = '/home/input2/input', argv = p, stderr = open('./err'), stdin = open('./in'), env = e)


r = remote('127.0.0.1', 21212)


r.sendline("\xde\xad\xbe\xef")


print s.recvuntil('Stage 5 clear!')


s.interactive();


소켓 입출력


여기까지 하고나서 interactive()썼을 때 깔끔하게 나오면 좋겠지만 우리가 현재 작업하는 경로는 /tmp폴더이고 flag파일은 /home/input2에 있기 때문에 플래그를 출력하지 못하는 문제가 발생한다.


그냥 tmp폴더에 심볼릭 링크 하나 만들면 된다.


ln -s /home/input2/flag ./flag


하고 실행시키면 플래그 잘 나온다.
















'write-up > pwnable.kr' 카테고리의 다른 글

[toddler's bottle] cmd2  (0) 2018.12.03
[toddler's bottle] cmd1 풀이  (0) 2018.12.03
[toddler's bottle] mistake  (0) 2018.11.30
[toddler's bottle] random  (0) 2018.11.30
[toddler's bottle] passcode  (0) 2018.11.30