Pwnable.kr [Toddler's Bottle]의 7번째 문제인 input입니다.

문제한테 털릴거 같은..
C코드 파일이 있네요

 

C코드 파일이 있으니 한번 뜯어 보도록 하겠습니다.

 

#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단계로 각각의 5가지 조건을 충족시켜줘야지 /bin/cat flag를 출력 하는 것 같습니다.

 

// argv 1 stage
	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");

 

첫번째 스테이지입니다.

 

조건은 인자의 개수는 100개가 되어야하고 argv A,B에 각각 \x00과 \x20\x0a\x0d를 채워줘야합니다.

 

// stdio 2 stage
	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");

 

두번째 스테이지입니다. 

 

1번문제인 fd에서 File Descriptor에 대해서 공부한 적이 있었는데 이걸 이용해서 풀어야겠군요.

 

stdin으로 \x00\x0a\x00\xff을 주고 sterr로 \x00\x0a\x02\xff을 주면 되는 것 같습니다.

 

// env 3 stage
	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 값을 넣어주면 되네요.

 

// file 4 stage
	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");

네번째 스테이지입니다.

 

\x0a라는 파일을 연 다음 읽은 첫 4바이트가 \x00\x00\x00\x00값이면 클리어입니다.

 

// network 5 stage
	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");

 

5번째 스테이지입니다.

atoi(argv['C']) = argv['C']의 정수형으로 변환한 값을 포트번호로 소켓서버 열고 \xde\xad\xbe\xef 보내면 클리어

 

이 5가지 조건을 한 코드로 합쳐야겠죠? python으로 코드를 작성하겠습니다. 

 

from pwn import *
 
#stage1
argvs = [str(i) for i in range(100)]
argvs[ord('A')] = '\x00'
argvs[ord('B')] = '\x20\x0a\x0d'
 
#stage2
with open('./stderr', 'a') as f:
    f.write('\x00\x0a\x02\xff')
#stage3
envVal = {'\xde\xad\xbe\xef':'\xca\xfe\xba\xbe'}
 
#stage4
with open('./\x0a', 'a') as f:
    f.write('\x00\x00\x00\x00')
 
#stage5 
argvs[ord('C')] = '40000'
 

target = process(executable='/home/input2/input', argv=argvs, stderr=open('./stderr'), env=envVal)
 

target.sendline('\x00\x0a\x00\xff')
 

conn = remote('localhost', 40000)
conn.send('\xde\xad\xbe\xef')
target.interactive() 

 

참고로 이 코드는 권한이 있는 /tmp를 이용해 작성하고 실행해야합니다.

 

하지만 /tmp에는 플래그 파일이 없기때문에 심볼릭 링크를 걸어줘야 합니다.

 

ln -s /home/input2/flag flag 명령어를 이용하여 심볼릭 링크를 걸어주면 됩니다.

 

성공적으로 Flag가 출력되었습니다!

 

FLAG: Mommy! I learned how to pass various input in Linux :)

반응형
복사했습니다!