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) 환영입니다 !! 😊☺️👍 |