0x02 Study :)/Pwnable

[pwnable.kr][Toddler] input 문제풀이

eli_ez3r 2018. 8. 14. 16:32


input

#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;
}

 


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");

인자 값이 100개 이어야 하며, argv['A'], 즉 arg[61] = "\x00", argv[62] = "\x20\x0a\x0d" 이어야 한다.

from pwn import *

#stage1
argvs = [str(i) for i in range(100)]
argvs[ord('A')] = '\x00'
argvs[ord('B')] = '\x20\x0a\x0d'

p = process(executable='/home/input2/input', argv=argvs)
p.interactive()

 


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");

stdin(0)으로 4Byte만큼 읽어 들여 buf에 저장한다.

그리고 buf의 4Byte가 "\x00\x0a\x00\xff"인지 비교한다.

stderr(2)에서 4Byte만큼 읽어 들여 buf에 저장한다.

그리고 buf의 4Byte가 "\x00\x0a\x02\xff" 인지 비교한다.

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')

p = process(executable='/home/input2/input', argv=argvs, stderr=open('./stderr'))
p.sendline('\x00\x0a\x00\xff')
p.interactive()

 


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"인지 확인한다.

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

p = process(executable='/home/input2/input', argv=argvs, stderr=open('./stderr'), env=envVal)
p.sendline('\x00\x0a\x00\xff')
p.interactive()

 


State 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");

"\x0a"라는 파일이 있어야 하며 첫 4바이트가 "\x00\x00\x00\x00" 이여야 한다.

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')

#state3
envVal = {'\xde\xad\xbe\xef':'\xca\xfe\xba\xbe'}

#stage4
with open("./\x0a", 'a') as f:
	f.write("\x00\x00\x00\x00")


p = process(executable='/home/input2/input', argv=argvs, stderr=open('./stderr'), env=envVal)
p.sendline('\x00\x0a\x00\xff')
p.interactive()

stage5

// 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']의 포트번호로 포트를 열기 때문에 포트번호를 넣어줘야한다.

recv받은 내용의 4바이트가 "\xdeadbeef"이면 클리어가 된다.

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')

#state3
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')] = '77777'

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

#stage2 stdin
p.sendline('\x00\x0a\x00\xff')

#stage5
c = remote('localhost', 77777)
c.send("\xde\xad\xbe\xef")

p.interactive()

 

pwnable.kr에서 ex코드 생성 후 실행되는 위치는 tmp디렉터리 이기 때문에 실행되는 부분에 flag가 있지 않아 flag가 보이지 않는다.

 

따라서 심볼릭 링크로 원래 flag를 가리켜주어야 한다.

 




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




잘못 된 개념을 서술하였거나, 잘못 풀이된 내용이 있으면 댓글 달아주시면 감사합니다 :)

태클 댓글이나 메일(513.eunice@gmail.com) 환영입니다 !! 😊☺️👍