Description
Mom? how can I pass my input to a computer program? ssh [email protected] -p2222 (pw:guest)
Source Code
#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 setregid(getegid(), getegid()); system("/bin/cat flag"); return 0; }
Stage 1
// 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");
argc
는 프로그램에 전달된 인자의 개수로, 100개여야한다.
A는 65의 16진수로, argv[65]
가 "\x00"
와 동일하여야 한다.
B는 66의 16진수로, argv[66]
가 "\x20\x0a\x0d"
와 동일하여야 한다.
Stage 2
// 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");
read 함수의 1번째 매개변수로 각각 들어가는 0과 2는 표준 입력인 stdin과 표준 에러인 stderr을 의미한다.
read(0, buf, 4)
는 표준 입력(stdin, fd 0)에서 4바이트를 읽어 buf
에 저장하는데 "\x00\x0a\x00\xff"
와 동일하여야 한다.
buf
에 표준 에러(stderr, fd 2)에서 4바이트를 읽어 buf
에 저장하는데 "\x00\x0a\x02\xff"
와 동일하여야 한다.
Stage 3
// env if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0; printf("Stage 3 clear!\n");
환경 변수의 이름이 "\xde\xad\xbe\xef"
인 것을 찾았을때 그 값이 "\xca\xfe\xba\xbe"
와 동일하여야 한다.
Stage 4
// 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");
이름이 줄바꿈 문자 (0x0a
) 하나로 된 파일을 읽기 모드로 연다.
얻은 fp
로부터 4바이트
를 buf
에 읽어오는데 "\x00\x00\x00\x00”
와 동일하여야 한다.
Stage 5
// 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");
argv['C']
위치의 문자열을 포트번호로 사용하여 소켓에 바인딩하고 클라이언트가 접속하기를 기다린다.
클라이언트가 접속하면 수신된 데이터 4바이트를 검사하는데, "\xde\xad\xbe\xef"
와 동일하여야 한다.
Solution
사전에 Stage 2, 4를 통과시키고 flag를 읽히기 위해 임시디렉토리를 만들어 몇몇의 명령어를 입력하면 된다.
from pwn import * context.log_level = 'debug' context(arch='amd64', os='linux') warnings.filterwarnings('ignore') import sys _port = "13375" arg = [str(i) for i in range(100)] arg[65] = "\x00" arg[66] = "\x20\x0a\x0d" arg[67] = _port _env = {'\xde\xad\xbe\xef' : "\xca\xfe\xba\xbe"} # Stage 2 # python3 -c 'import sys; sys.stdout.buffer.write(b"\x00\x0a\x02\xff")' > /tmp/w4_a/err # Stage 4 # python3 -c 'import sys; sys.stdout.buffer.write(b"\x00\x00\x00\x00")' > /tmp/w4_a/$'\x0a' # Pass Stage # ln -sf /home/input2/flag /tmp/w4_a/flag # p = process(executable='./input2', argv=arg, stderr = open('/tmp/w4_a/err'), env=_env) p = process(executable='/home/input2/input2', argv=arg, stderr = open('/tmp/w4_a/err'), env=_env) payload = "\x00\x0a\x00\xff" # input() p.recvuntil("Stage 1 clear!\n") p.send(payload) p.recvuntil("Stage 4 clear!\n") p2 = remote("127.0.0.1", _port) p2.send("\xde\xad\xbe\xef") p2.close() p.interactive()
Result
input2@ubuntu:/tmp/w4_a$ nano solve.py Unable to create directory /home/input2/.local/share/nano/: No such file or directory It is required for saving/loading search history or cursor positions. input2@ubuntu:/tmp/w4_a$ python3 -c 'import sys; sys.stdout.buffer.write(b"\x00\x0a\x02\xff")' > /tmp/w4_a/err input2@ubuntu:/tmp/w4_a$ python3 -c 'import sys; sys.stdout.buffer.write(b"\x00\x00\x00\x00")' > /tmp/w4_a/$'\x0a' input2@ubuntu:/tmp/w4_a$ ln -sf /home/input2/flag /tmp/w4_a/flag input2@ubuntu:/tmp/w4_a$ python3 solve.py [x] Starting local process '/home/input2/input2' argv=[b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'10', b'11', b'12', b'13', b'14', b'15', b'16', b'17', b'18', b'19', b'20', b'21', b'22', b'23', b'24', b'25', b'26', b'27', b'28', b'29', b'30', b'31', b'32', b'33', b'34', b'35', b'36', b'37', b'38', b'39', b'40', b'41', b'42', b'43', b'44', b'45', b'46', b'47', b'48', b'49', b'50', b'51', b'52', b'53', b'54', b'55', b'56', b'57', b'58', b'59', b'60', b'61', b'62', b'63', b'64', b'', b' \n\r', b'13375', b'68', b'69', b'70', b'71', b'72', b'73', b'74', b'75', b'76', b'77', b'78', b'79', b'80', b'81', b'82', b'83', b'84', b'85', b'86', b'87', b'88', b'89', b'90', b'91', b'92', b'93', b'94', b'95',[/.......] Starting local process '/home/input2/input2' argv=[b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'10', b'11', b'12', b'13', b'14', b'15', b'16', b'17', b'18', b'19', b'20', b'21', b'22', b'23', b'24', b'25', b'26', b'27', b'28', b'29', b'30', b'31', b'32', b'33', b'34', b'35', b'36', b'37', b'38', b'39', b'40', b'41', b'42', b'43', b'44', b'45', b'46', b'47', b'48', b'49', b'50', b'51', b'52', b'53', b'54', b'55', b'56', b'57', b'58', b'59', b'60', b'61', b'62', b'63', b'64', b'', b' \n\r', b'13375', b'68', b'69', b'70', b'71', b'72', b'73', b'74', b'75', b'76', b'77', b'78', b'79', b'80', b'81', b'82', b'83', b'84', b'85', b'86', b'87', b'88', b'89', b'90', b'91', b'92', b'93', b'94', b'95', b'96', b'97', b'98', b'99'] env={b'\xde\xad\xbe\xef': b'\xca\xfe\xba\xbe'} Starting local process '/home/input2/input2' argv=[b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'10', b'11', b'12', b'13', b'14', b'15', b'16', b'17', b'18', b'19', b'20', b'21', b'22', b'23', b'24', b'25', b'26', b'27', b'28', b'29', b'30', b'31', b'32', b'33', b'34', b'35', b'36', b'37', b'38', b'39', b'40', b'41', b'42', b'43', b'44', b'45', b'46', b'47', b'48', b'49', b'50', b'51', b'52', b'53', b'54', b'55', b'56', b'57', b'58', b'59', b'60', b'61', b'62', b'63', b'64', b'', b' \n\r', b'13375', b'68', b'69', b'70', b'71', b'72', b'73', b'74', b'75', b'76', b'77', b'78', b'79', b'80', b'81', b'82', b'83', b'84', b'85', b'86', b'87', b'88', b'89', b'90', b'91', b'92', b'93', b'94', b'95', b'96', b'97', b'98', b'99'] env={b'\xde\xad\xbe\xef': b'\xca\xfe\xba\xb[+] Starting local process '/home/input2/input2' argv=[b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'10', b'11', b'12', b'13', b'14', b'15', b'16', b'17', b'18', b'19', b'20', b'21', b'22', b'23', b'24', b'25', b'26', b'27', b'28', b'29', b'30', b'31', b'32', b'33', b'34', b'35', b'36', b'37', b'38', b'39', b'40', b'41', b'42', b'43', b'44', b'45', b'46', b'47', b'48', b'49', b'50', b'51', b'52', b'53', b'54', b'55', b'56', b'57', b'58', b'59', b'60', b'61', b'62', b'63', b'64', b'', b' \n\r', b'13375', b'68', b'69', b'70', b'71', b'72', b'73', b'74', b'75', b'76', b'77', b'78', b'79', b'80', b'81', b'82', b'83', b'84', b'85', b'86', b'87', b'88', b'89', b'90', b'91', b'92', b'93', b'94', b'95', b'96', b'97', b'98', b'99'] env={b'\xde\xad\xbe\xef': b'\xca\xfe\xba\xbe'} : pid 3732946 [DEBUG] Received 0x92 bytes: b'Welcome to pwnable.kr\n' b"Let's see if you know how to give input to program\n" b'Just give me correct inputs then you will get the flag :)\n' b'Stage 1 clear!\n' [DEBUG] Sent 0x4 bytes: 00000000 00 0a 00 ff │····│ 00000004 [DEBUG] Received 0x2d bytes: b'Stage 2 clear!\n' b'Stage 3 clear!\n' b'Stage 4 clear!\n' [+] Opening connection to 127.0.0.1 on port 13375: Done [DEBUG] Sent 0x4 bytes: 00000000 de ad be ef │····│ 00000004 [*] Closed connection to 127.0.0.1 port 13375 [*] Switching to interactive mode [DEBUG] Received 0xf bytes: b'Stage 5 clear!\n' Stage 5 clear! [DEBUG] Received 0x2d bytes: b'Mommy_now_I_know_how_to_pa5s_inputs_in_Linux\n' Mommy_now_I_know_how_to_pa5s_inputs_in_Linux [*] Process '/home/input2/input2' stopped with exit code 0 (pid 3732946) [*] Got EOF while reading in interactive $ [*] Interrupted