#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
'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 |