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