ipwn
[pwnable.kr] input 본문
이번에 쓸 라업은 input문제이다.
보아하니 여러가지 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; } |
나는 이 문제를 python을 사용해서 풀었다.
뭐가 좀 길어보이긴 하지만 되게 간단한 문제이다.
그냥 stage별로 5개만 클리어하면 플래그를 읽어와준다.
일단 stage1을 보도록 하겠다.
argv의 갯수가 딱 100개여야 하며, argv['A'], argv['B']의 값이 각각 "\x00", "\x20\x0a\x0d"의 값을 지녀야 한다.
import os from pwn import * 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) |
이런식으로 값을 넘겨준다면 가볍게 stage1을 clear할 수 있을 것이다.
이제 stage2문제이다.
stdio의 값으로 "\x00\x0a\x00\xff"의 값을 넘겨주고, stderr의 값으로 "\x00\x0a\x02\xff"을 넘겨주면 해결 될 것이다.
stderr의 변경은 fd를 stderr에 보내줘야 하는 값이 들어있는 파일의 fd로 바꿔줬다.
import os from pwn import * argvs = [str(i)for i in range(100)] argvs[ord('A')] = '\x00' argvs[ord('B')] = '\x20\x0a\x0d' a = open("./stderr_f", 'w+') a.write("\x00\x0a\x02\xff") a.close() a = open('./stderr_f', 'r+') stderr_f = a.fileno() log.info('stderr fd : ' + str(stderr_f)) send_v = '\x00\x0a\x00\xff' p = process(executable='/home/input2/input', argv=argvs, stderr=stderr_f) p.send(send_v) a.close() |
이렇게 값을 넘겨주면 stage1, stage2가 클리어 되는 것을 확인할 수 있다.
이번엔 환경변수 문제이다.
그냥 이름 맞춰서 딕셔너리로 값 넘겨주면 된다.
import os from pwn import * argvs = [str(i)for i in range(100)] argvs[ord('A')] = '\x00' argvs[ord('B')] = '\x20\x0a\x0d' a = open("./stderr_f", 'w+') a.write("\x00\x0a\x02\xff") a.close() a = open('./stderr_f', 'r+') stderr_f = a.fileno() log.info('stderr fd : ' + str(stderr_f)) send_v = '\x00\x0a\x00\xff' env_v = {"\xde\xad\xbe\xef" : "\xca\xfe\xba\xbe"} p = process(executable='/home/input2/input', argv=argvs, stderr=stderr_f, env=env_v) p.send(send_v) a.close() |
이렇게 만들고 값을 넘겨주면 stage3까지 클리어 되는 것을 확인할 수 있다.
이제 거의 다 했다.
4번 문제는 "\x0a"라는 file명을 가진 file을 만들어서 "\x00\x00\x00\x00"의 값을 넘겨주기만 하면 된다.
이거 직접 만들어도 만들어지는지는 모르겠는데 아마 안만들어지니까 문제로 냈겠지 아무튼 python으로 만들어주는 것 까지 한 번에 짰다.
import os from pwn import * argvs = [str(i)for i in range(100)] argvs[ord('A')] = '\x00' argvs[ord('B')] = '\x20\x0a\x0d' a = open("./stderr_f", 'w+') a.write("\x00\x0a\x02\xff") a.close() a = open('./stderr_f', 'r+') stderr_f = a.fileno() b = open("./\x0a", 'w+') b.write("\x00\x00\x00\x00") b.close() log.info('stderr fd : ' + str(stderr_f)) send_v = '\x00\x0a\x00\xff' env_v = {"\xde\xad\xbe\xef" : "\xca\xfe\xba\xbe"} p = process(executable='/home/input2/input', argv=argvs, stderr=stderr_f, env=env_v) p.send(send_v) a.close() |
이제 이렇게 값을 넘겨주면 stage4까지 클리어 되는 것을 확인할 수 있다.
이제 정말루다가 다 했다.
마지막 stage5는 argv['C']에 넘겨진 값을 atoi해서 나온 값으로 port를 열어서 recv한 값과 "\xde\xad\xbe\xef"와 같기만 하면 된다.
argv['c']의 값에다가 "1234"를 넘겨주어 1234번 포트가 열리게 만들어주고 동시에 nc로 접속해서 값을 넘겨주면 클리어가 되고 플래그를 읽어줄 것이다.
한 번 작성해보겠다.
import os from pwn import * argvs = [str(i)for i in range(100)] argvs[ord('A')] = '\x00' argvs[ord('B')] = '\x20\x0a\x0d' argvs[ord('C')] = '1234' a = open("./stderr_f", 'w+') a.write("\x00\x0a\x02\xff") a.close() a = open('./stderr_f', 'r+') stderr_f = a.fileno() log.info('stderr fd : ' + str(stderr_f)) b = open("./\x0a", 'w+') b.write("\x00\x00\x00\x00") b.close() send_v = '\x00\x0a\x00\xff' env_v = {'\xde\xad\xbe\xef' : '\xca\xfe\xba\xbe'} p = process(executable='/home/input2/input', argv=argvs, stderr=stderr_f, env=env_v) p.send(send_v) a.close() con = remote('localhost', 1234) con.send("\xde\xad\xbe\xef") con.close() sleep(0.1) print p.recv() |
flag를 성공적으로 읽어왔다
굳
'Write up > Pwnable.kr' 카테고리의 다른 글
[pwnable.kr] memcpy (0) | 2018.07.21 |
---|---|
[pwnable.kr] leg (0) | 2018.07.13 |
[pwnable.kr] coin1 (0) | 2018.03.12 |
[pwnable.kr] uaf (0) | 2018.02.19 |
[pwnable.kr] shellshock (0) | 2018.01.06 |