White Security
Input 문제풀이 본문
1 2 3 | Mom? how can I pass my input to a computer program? ssh input2@pwnable.kr -p2222 (pw:guest) |
Toddler's Bottle 7번 문제.
설명대로 입출력 제어와 관련된 문제입니다.
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 | #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; } |
소스를 살펴보면
인자 전달, 표준 입력, 환경변수 전달, 파일 입력, 소켓 통신
5개의 스테이지로 나누어져
조건을 만족하지 못하면
system 문에 도달하지 못하고
즉시 return 하도록 되어 있습니다..
1 2 3 4 5 6 7 8 9 10 | import subprocess arg = [ str (i) for i in range ( 1 , 100 ) ] arg[ ord ( 'A' ) - 1 ] = "\x00" arg[ ord ( 'B' ) - 1 ] = "\x20\x0a\x0d" proc = subprocess.Popen([ './input' ] + arg, stdout = subprocess.PIPE) print (proc.pid, proc.wait()) print (proc.communicate()) |
파이썬의 subprocess 모듈로
시도해 보았지만 실패했습니다.
1 2 3 4 5 6 7 | Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.7/subprocess.py", line 711, in __init__ errread, errwrite) File "/usr/lib/python2.7/subprocess.py", line 1343, in _execute_child raise child_exception TypeError: execv() arg 2 must contain only strings |
subprocess 의 Popen 내부에서 사용되는
execv() 에 null 바이트를 넣으면 오류를 뿜기 때문에
다른 방법을 써야만 했습니다.
1 | class pwnlib.tubes.process.process(argv = None , shell = False , executable = None , cwd = None , env = None , stdin = - 1 , stdout = <pwnlib.tubes.process.PTY object >, stderr = - 2 , close_fds = True , preexec_fn = <function < lambda >>, raw = True , aslr = None , setuid = None , where = 'local' , display = None , alarm = None , * args, * * kwargs) |
탐색결과 pwntools 의 process 모듈을 발견했습니다.
위 모듈은 널 바이트가 포함된 인자도 정상적으로 받아들입니다.
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 | <p> #!/usr/bin/env python from pwn import * argv = [ str (i) for i in range ( 100 )] argv[ ord ( 'A' )] = '\x00' argv[ ord ( 'B' )] = '\x20\x0a\x0d' argv[ ord ( 'C' )] = '9999' env = { '\xde\xad\xbe\xef' : '\xca\xfe\xba\xbe' } with open ( '\x0a' , 'wb' ) as f: f.write( '\x00\x00\x00\x00' ) with open ( 'stderr' , 'wb' ) as f: f.write( '\x00\x0a\x02\xff' ) proc = process(executable = '/home/input2/input' , argv = argv, stderr = open ( 'stderr' ), env = env) proc.stdin.write( '\x00\x0a\x00\xff' ) with remote( 'localhost' , argv[ ord ( 'C' )]) as sd: sd.send( '\xde\xad\xbe\xef' ) proc.interactive() < / p><div><br>< / div> |
pwntools 를 이용하여 작성한 파이썬 스크립트입니다,
argv 변수에 argv 인자를
env 변수에 환경번수를 저장하여 전달하였고
pwntools 의 remote 모듈을 이용해 데이터를 전달했습니다.
그러던 중, process 에서 전달하는 인자를 수정해
argv[0] 을 임의대로 변경 가능하다는 것을 깨달았습니다.
argv[0] 은 실행 파일 경로로 정해져 있다고 생각했는데
절대적인 정의는 아니었나 봅니다.
1 2 3 4 | with open ( 'stderr' , 'wb' ) as f: f.write( '\x00\x0a\x02\xff' ) proc = process(executable = '/home/input2/input' , argv = argv, stderr = open ( 'stderr' ), env = env) |
소스를 확인해보면 stage 2에서
stderr 로 전달해야할 데이터를 파일로 저장한 다음
open 을 통해 파일 디스크립터를 별도로 열어
인자로 전달하는 것을 확인할 수 있는데요.
1 | proc.stderr.write( '\x00\x0a\x02\xff' ) |
본래는 위처럼 다이렉트로 전달하려고 했습니다.
1 2 3 4 5 6 7 | >>> proc.stderr < open file '<fdopen>' , mode 'r+' at 0x7f96357c5b70 > >>> proc.stderr.write( 'data' ) >>> proc.stderr.read() Traceback (most recent call last): File "<stdin>" , line 1 , in <module> IOError: [Errno 11 ] Resource temporarily unavailable |
그런데 접근 모드가 r+ 인 탓인지
stderr 에 직접적인 입력은 불가능 했습니다.
1 | input2@ubuntu: /tmp/posix $ ln -s /home/input2/flag flag |
홈 폴더에는 파일을 저장할 권한이 없으므로
저는 /tmp 내에 별도로 디렉토리를 만들어
스크립트를 저장해 주었습니다.
또한 system 문의 flag 가 상대경로로 되어 있기에
심볼링 링크를 만들어 연결해 주었습니다.
1 2 3 4 | input2@ubuntu: /tmp/posix $ ls ? flag solve.py stderr input2@ubuntu: /tmp/posix $ ls -b \n flag solve.py stderr |
스크립트를 통해 \x0a 라는 이름으로 파일을 생성하면
파일명이 정상적으로 표시되지 않는데
ls -b 옵션을 통해 확인할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | input2@ubuntu:/tmp/posix$ ./solve.py [+] Starting local process '/home/input2/input': Done [+] Opening connection to localhost on port 9999: Done [*] Closed connection to localhost port 9999 [*] Switching to interactive mode Welcome to pwnable.kr Let's see if you know how to give input to program Just give me correct inputs then you will get the flag :) Stage 1 clear! Stage 2 clear! Stage 3 clear! Stage 4 clear! Stage 5 clear! Mommy! I learned how to pass various input in Linux :) [*] Process '/home/input2/input' stopped with exit code 0 [*] Got EOF while reading in interactive |
플래그 취득에 성공했습니다.
'Wargame Writeups > pwnable.kr' 카테고리의 다른 글
Mistake 문제풀이 (0) | 2019.02.08 |
---|---|
Leg 문제풀이 (0) | 2019.02.08 |
Random 문제풀이 (0) | 2019.02.06 |
Passcode 문제풀이 (0) | 2019.02.06 |
Flag 문제풀이 (0) | 2019.02.05 |