Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
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
Archives
Today
Total
관리 메뉴

White Security

Input 문제풀이 본문

Wargame Writeups/pwnable.kr

Input 문제풀이

POSIX 2019. 2. 7. 13:29
Mom? how can I pass my input to a computer program?

ssh input2@pwnable.kr -p2222 (pw:guest)


Toddler's Bottle 7번 문제.

설명대로 입출력 제어와 관련된 문제입니다.


#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개의 스테이지로 나누어져

조건을 만족하지 못하면

system 문에 도달하지 못하고

즉시 return 하도록 되어 있습니다..


import subprocess

arg = [ str(i) for i in range(1,100) ]
arg[ord('A') - 1] = "\x00"
arg[ord('B') - 1] = "\x20\x0a\x0d"

proc = subprocess.Popen(['./input'] + arg, stdout = subprocess.PIPE)

print(proc.pid, proc.wait())
print(proc.communicate())


파이썬의 subprocess 모듈로 

시도해 보았지만 실패했습니다.


Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1343, in _execute_child
    raise child_exception
TypeError: execv() arg 2 must contain only strings


subprocessPopen 내부에서 사용되는

execv()null 바이트를 넣으면 오류를 뿜기 때문에

다른 방법을 써야만 했습니다.


class pwnlib.tubes.process.process(argv=None, shell=False, executable=None, cwd=None, env=None, stdin=-1, stdout=<pwnlib.tubes.process.PTY object>, stderr=-2, close_fds=True, preexec_fn=<function <lambda>>, raw=True, aslr=None, setuid=None, where='local', display=None, alarm=None, *args, **kwargs)


탐색결과 pwntoolsprocess 모듈을 발견했습니다.

위 모듈은 널 바이트가 포함된 인자도 정상적으로 받아들입니다.


#!/usr/bin/env python from pwn import * argv = [str(i) for i in range(100)] argv[ord('A')] = '\x00' argv[ord('B')] = '\x20\x0a\x0d' argv[ord('C')] = '9999' env = {'\xde\xad\xbe\xef' : '\xca\xfe\xba\xbe'} with open('\x0a', 'wb') as f: f.write('\x00\x00\x00\x00') with open('stderr', 'wb') as f: f.write('\x00\x0a\x02\xff') proc = process(executable = '/home/input2/input', argv = argv, stderr = open('stderr'), env = env) proc.stdin.write('\x00\x0a\x00\xff') with remote('localhost', argv[ord('C')]) as sd: sd.send('\xde\xad\xbe\xef') proc.interactive()



pwntools 를 이용하여 작성한 파이썬 스크립트입니다,

argv 변수에 argv 인자를

env 변수에 환경번수를 저장하여 전달하였고

pwntoolsremote 모듈을 이용해 데이터를 전달했습니다.


그러던 중, process 에서 전달하는 인자를 수정해

argv[0] 을 임의대로 변경 가능하다는 것을 깨달았습니다.


argv[0] 은 실행 파일 경로로 정해져 있다고 생각했는데

절대적인 정의는 아니었나 봅니다.


with open('stderr', 'wb') as f:
	f.write('\x00\x0a\x02\xff')

proc = process(executable = '/home/input2/input', argv = argv, stderr = open('stderr'), env = env)


소스를 확인해보면 stage 2에서

stderr 로 전달해야할 데이터를 파일로 저장한 다음


open 을 통해 파일 디스크립터를 별도로 열어

인자로 전달하는 것을 확인할 수 있는데요.


proc.stderr.write('\x00\x0a\x02\xff')


본래는 위처럼 다이렉트로 전달하려고 했습니다.


>>> proc.stderr
<open file '<fdopen>', mode 'r+' at 0x7f96357c5b70>
>>> proc.stderr.write('data')
>>> proc.stderr.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 11] Resource temporarily unavailable


그런데 접근 모드가 r+ 인 탓인지

stderr 에 직접적인 입력은 불가능 했습니다.


input2@ubuntu:/tmp/posix$ ln -s /home/input2/flag flag


홈 폴더에는 파일을 저장할 권한이 없으므로

저는 /tmp 내에 별도로 디렉토리를 만들어

스크립트를 저장해 주었습니다.


또한 system 문의 flag 가 상대경로로 되어 있기에

심볼링 링크를 만들어 연결해 주었습니다.


input2@ubuntu:/tmp/posix$ ls
?  flag  solve.py  stderr
input2@ubuntu:/tmp/posix$ ls -b
\n  flag  solve.py  stderr


스크립트를 통해 \x0a 라는 이름으로 파일을 생성하면

파일명이 정상적으로 표시되지 않는데


ls -b 옵션을 통해 확인할 수 있습니다.


input2@ubuntu:/tmp/posix$ ./solve.py
[+] Starting local process '/home/input2/input': Done
[+] Opening connection to localhost on port 9999: Done
[*] Closed connection to localhost port 9999
[*] 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 :)
[*] Process '/home/input2/input' stopped with exit code 0
[*] Got EOF while reading in interactive


플래그 취득에 성공했습니다.




'Wargame Writeups > pwnable.kr' 카테고리의 다른 글

Mistake 문제풀이  (0) 2019.02.08
Leg 문제풀이  (0) 2019.02.08
Random 문제풀이  (0) 2019.02.06
Passcode 문제풀이  (0) 2019.02.06
Flag 문제풀이  (0) 2019.02.05
Comments