pwnable.kr --- mistake
ssh mistake@pwnable.kr 2222 (pw:guest)로 접속하면 mistake 문제를 만날 수 있다.
windows 환경의 cmd로 접속한것이 아니라 xshell5로 접속했다.
windows 환경의 cmd로 접속하려면 ssh mistake@pwnable.kr -p2222와 같이 접속 해야한다.
우선 현재 디렉터리에 어떤 파일이 있는지 확인해보자.
우리가 원하는 파일은 flag이고 현재 id가 mistake이기 때문에 flag를 볼 수 있는 권한이 없다.
password와 mistake라는 elf 파일이 존재하고, password는 read만 가능하고 mistake는 실행 가능하다.
mistake 파일은 setuid가 mistake_pwn의 권한으로 걸려있다.
mistake elf 파일을 통해 mistake_pwn의 권한으로 flag, password를 볼 수 있을것 같다.
mistake.c를 가지고 mistake elf 파일을 만들었을 확률이 높으므로 mistake.c를 분석해보자.
PW_LEN=10, XORKEY=1 치환하는 매크로 함수를 작성한다.
지역 변수 fd를 선언한다.
"/home/mistke/passwd"를 읽기모드로 passwd 파일을 소유자만 읽을 수 있도록 fd를 설정하고,
만일 파일 읽기에 실패하면 "can't open password %d\n"를 출력한다.
open 함수의 원형은 아래와 같다.
int open(const char *FILENAME, int FLAGS[, mode_t MODE])
char *FILENAME : 대상 파일 이름이다.
int FLAGS : 파일에 대한 열기 옵션이다.
[, mode_t MODE]: O_CREAT 옵션 사용시 파일이 생성될 때 지정되는 파일의 권한이다.
반환형은 정상적으로 open 하면 file descriptor의 값을 return하고, 실패하면 -1을 반환한다.
여기서 hint의 중요성을 알게 된다. 처음에 hint를 보지 못해서 애를 먹었는데 mistake의 hint는 operator priority이다.
open("/home/mistake/password",O_RDONLY,0400) 함수는 성공하니 file descriptor를 반환할 것이고 file descriptor는 양수이다.
operator priority 때문에 크기 비교(<)를 먼저하고, file descriptor와 0을 대소비교하니 거짓이나와 0이 return 되어 최종적으로 file descriptor는 0이된다.
1 2 3 4 5 6 7 8 9 10 | #define PW_LEN 10 #define XORKEY 1 int main(int argc, char* argv[]){ int fd; if(fd=open("/home/mistake/password", O_RDONLY, 0400) < 0) { printf("can't open password %d\n", fd); return 0; } | cs |
"do not bruteforce...\n"를 출력하고 sleep() 한다.
1 2 | printf("do not bruteforce...\n"); sleep(time(0)%20); | cs |
11 byte의 char형 배열을 선언하고, int형 len 변수를 선언한다.
file descriptor를 10 byte 읽어들여 11 byte의 char형 배열인 pw_buf에 저장한다.
read함수에 성공하면 읽어들인 길이만큼 len에 저장한다.
read 함수에 실패하면 "read error\n"를 출력하고 file descriptor를 닫고 종료한다.
연산자 우선순위는 "="가 거의 제일 낮기 때문에 마지막으로 판단한다.
1 2 3 4 5 6 7 | char pw_buf[PW_LEN+1]; int len; if(!(len=read(fd,pw_buf,PW_LEN) > 0)){ printf("read error\n"); close(fd); return 0; } | cs |
11 byte의 char형 배열을 선언하고 사용자로부터 10글자의 string을 입력받는다.
xor 함수를 호출한다.
1 2 3 4 5 6 7 | char pw_buf2[PW_LEN+1]; printf("input password : "); scanf("%10s", pw_buf2); // xor your input xor(pw_buf2, 10); | cs |
xor 함수는 각 string 한 문자를 1과 xor한 값을 저장한다.
1 2 3 4 5 6 | void xor(char* s, int len){ int i; for(i=0; i<len; i++){ s[i] ^= XORKEY; } } | cs |
만일 pw_buf와 pw_buf2를 10 byte 비교 했을 때, 같으면 "password OK"를 출력하고 flag를 pwn_mistake의 권한으로 보여준다.
만일 두 문자열이 다르다면 "Wrong Password\n"를 출력하고 종료한다.
file descriptor를 닫고 종료한다.
1 2 3 4 5 6 7 8 9 10 | if(!strncmp(pw_buf, pw_buf2, PW_LEN)){ printf("Password OK\n"); system("/bin/cat flag\n"); } else{ printf("Wrong Password\n"); } close(fd); return 0; | cs |
최종적으로 소스를 정리해보면 아래와 같다.
fd는 0으로 설정되고 사용자로부터 글자를 입력받아 10 byte를 pw_buf에 저장한다.
사용자로부터 입력을 받아 pw_buf2에 저장한다.
pw_buf2는 각 문자가 1과 xor 연산을 해 pw_buf2와 저장한다.
pw_buf와 pw_buf2를 비교해 같으면 flag를 보여준다.
A를 10개 집어넣어 pw_buf에 저장하자.
pw_buf에는 A가 10개 들어가있다.
우리는 이제 입력을 해야하는데 A는 0x41이므로 0x41과 0x1을 xor하면 0x40(@)이다.
아래와 같이 입력하면 공격에 성공 할 수 있다.
'Wargame > pwnable.kr' 카테고리의 다른 글
[pwnable.kr] leg 풀이, write-up (0) | 2018.12.24 |
---|---|
[pwnable.kr] cmd1 풀이, write-up (2) | 2018.11.16 |
[pwnable.kr] shellshock 풀이, write-up (0) | 2018.11.06 |
[pwnable.kr] random 풀이, write-up (0) | 2018.11.06 |
[pwnable.kr] flag 풀이, write-up (1) | 2018.11.02 |