일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- RCE
- rev-basic-3
- sint
- rev-basic-5
- 코드엔진 베이직 13
- rev-basic-2
- L15
- 코드엔진 베이직
- CodeEngn
- rev-basic-0
- sd카드 리더기
- pwnable.kr
- rev-basic-7
- basic_exploitation_000
- Pwnable
- basic_exploitation_001
- 드림핵
- rev-basic-1
- Basic
- 포너블
- off_by_one_000
- L16
- off_by_one_001
- L17
- out_of_bound
- rev-basic-4
- coin1
- L18
- rev-basic-6
- Dreamhack
- Today
- Total
서브웨이
pwnable.kr 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;
}
대충 보아하니 여러가지 입력 방법에 대해 익히는 문제인듯 합니다. 주어진 스테이지를 모두 통과하면 플래그를 볼 수 있네요.
참고로 문제 디렉토리에선 파일 생성이 불가능하니 /tmp 디렉토리에 아무 디렉토리나 만들어서 거기서 작업합니다.
자 일단 스테이지1을 봅시다.
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");
간단하게 인자가 100개고 아스키코드로 A, B번째 인자가 \x00, \x20\x0a\x0d여야 하네요.
간단하게 pwntools를 사용합시다.
from pwn import *
argvs = ["A" for i in range(100)]
argvs[65] = "\x00"
argvs[66] = "\x20\x0a\x0d"
r = process(executable="/home/input2/input" ,argv=argvs)
r.interactive()
스테이지2를 봅시다.
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");
간단하게 stdin에서 4바이트를 읽어와서 내용이 \x00\x0a\x00\xff인지 확인하고 stderr에서 4바이트를 읽어와서 내용이 \x00\x0a\x02\xff인지 확인합니다.
그럼 간단하게 파일에 stderr로 넘겨줄 내용을 써서 stderr로 지정해주고, stdin에 쓸 내용을 send해주면 해결할 수 있습니다.
with open("./stderr", "a") as f:
f.write("\x00\x0a\x02\xff")
r = process(executable="/home/input2/input", argv=argvs, stderr=open("./stderr"))
r.send("\x00\x0a\x00\xff")
스테이지3를 봅시다.
if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0;
printf("Stage 3 clear!\n");
그냥 \xde\xad\xbe\xef라는 환경변수의 값을 \xca\xfe\xba\xbe로 지정해주면 됩니다.
envirn = {"\xde\xad\xbe\xef":"\xca\xfe\xba\xbe"}
r = process(executable="/home/input2/input", argv=argvs, stderr=open("./stderr"), env=envirn)
간단합니다.
스테이지4를 봅시다.
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);
뭐 간단합니다. 그냥 \x0a라는 이름을 가진 파일에 4바이트를 0으로 채우면 됩니다.
with open("./\x0a", "a") as f:
f.write("\x00\x00\x00\x00")
스테이지5를 봅시다.
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;
뭐 그냥 간단한 소켓 코드입니다. 그냥 아스키코드로 C, 즉 67번째 인자에 넘겨준 값을 포트번호로 하는 로컬 서버에 4바이트를 보내서 그 값이 \xde\xad\xbe\xef인지 확인합니다.
argvs[67] = "12345"
client = remote("127.0.0.1", 12345)
client.send("\xde\xad\xbe\xef")
끝~~~!~!!~!~~!
하지만 아직 플래그를 열 수 없습니다. 해당 폴더에 플래그가 없으므로 플래그파일의 소프트링크를 하나 생성해줍니다.
ln -s /home/input2/flag flag
이 명령어를 쓰면 됩니다.
전체 페이로드는 다음과 같습니다.
from pwn import *
#Stage1
argvs = ["A" for i in range(100)]
argvs[65] = "\x00"
argvs[66] = "\x20\x0a\x0d"
#Stage2
with open("./stderr", "a") as f:
f.write("\x00\x0a\x02\xff")
#Stage3
envirn = {"\xde\xad\xbe\xef":"\xca\xfe\xba\xbe"}
#Stage4
with open("./\x0a", "a") as f:
f.write("\x00\x00\x00\x00")
#Stage5
argvs[67] = "12345"
r = process(executable="/home/input2/input", argv=argvs, stderr=open("./stderr"), env=envirn)
#Stage2
r.send("\x00\x0a\x00\xff")
#Stage5
client = remote("127.0.0.1", 12345)
client.send("\xde\xad\xbe\xef")
r.interactive()
'Pwnable > pwnable.kr' 카테고리의 다른 글
pwnable.kr mistake 풀이 (0) | 2020.08.14 |
---|---|
pwnable.kr leg 풀이 (0) | 2020.08.13 |
pwnable.kr random 풀이 (0) | 2020.08.11 |
pwnable.kr passcode 풀이 (0) | 2020.07.21 |
pwnable.kr flag 풀이 (0) | 2020.02.18 |