콘텐츠로 건너뛰기

input2

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"}

# python3 -c 'import sys; sys.stdout.buffer.write(b"\x00\x0a\x02\xff")' > /tmp/w4_2/err
# python3 -c 'import sys; sys.stdout.buffer.write(b"\x00\x00\x00\x00")' > /tmp/w4_2/$'\x0a'
# ln -sf /home/input2/flag /tmp/w4_2/flag


# p = process(executable='./input2', argv=arg, stderr = open('/tmp/w4/err'), env=_env)
p = process(executable='/home/input2/input2', argv=arg, stderr = open('/tmp/w4_2/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

태그: