오늘은 mistake를 풀어봤습니다.
input, passcode 문제를 풀이하려고 했는데 어렵네요..
쉬운 1pt 문제입니다.
We all make mistakes, let's move on.
(don't take this too seriously, no fancy hacking skill is required at all)
This task is based on real event
Thanks to dhmonkey
hint : operator priority
Operator priority 즉 연산자 우선순위가 힌트로 주어졌습니다.
ssh 접속 후 파일 목록을 확인하면 아래와 같습니다.
mistake@ubuntu:~$ ls -al
total 44
drwxr-x--- 5 root mistake 4096 Oct 23 2016 .
drwxr-xr-x 87 root root 4096 Dec 27 2017 ..
d--------- 2 root root 4096 Jul 29 2014 .bash_history
-r-------- 1 mistake_pwn root 51 Jul 29 2014 flag
dr-xr-xr-x 2 root root 4096 Aug 20 2014 .irssi
-r-sr-x--- 1 mistake_pwn mistake 8934 Aug 1 2014 mistake
-rw-r--r-- 1 root root 792 Aug 1 2014 mistake.c
-r-------- 1 mistake_pwn root 10 Jul 29 2014 password
drwxr-xr-x 2 root root 4096 Oct 23 2016 .pwntools-cache
mistake@ubuntu:~$
mistake.c 파일을 열어 mistake이 어떤 바이너리인지 확인을 해보면 아래와 같습니다.
mistake@ubuntu:~$ cat mistake.c
#include <stdio.h>
#include <fcntl.h>
#define PW_LEN 10
#define XORKEY 1
void xor(char* s, int len){
int i;
for(i=0; i<len; i++){
s[i] ^= XORKEY;
}
}
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;
}
printf("do not bruteforce...\n");
sleep(time(0)%20);
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;
}
char pw_buf2[PW_LEN+1];
printf("input password : ");
scanf("%10s", pw_buf2);
// xor your input
xor(pw_buf2, 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;
}
mistake@ubuntu:~$
flag 파일을 열기 위해서는 pw_buf[PW_LEN]과 pw_buf2[PW_LEN]의 값이 같아야합니다.
여기서 저는 보통 파일을 열때 fopen() 이라는 함수를 사용하는데 왜 여기서는 open() 함수를 사용했는지에 대해 의문을 가졌고 문제 이름이 mistake인 만큼 좀 더 자세히 알 필요가 있다고 생각했습니다.
그래서 제 로컬 linux에서 똑같은 환경을 구성해주고 아래와 같이 바이너리 하나를 만들어줬습니다.
⚡ root@ubuntu /home/mistake pwd
/home/mistake
⚡ root@ubuntu /home/mistake ls
mistake mistake.c password
⚡ root@ubuntu /home/mistake cat mistake.c
#include <stdio.h>
#include <fcntl.h>
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;
}
printf("fd : %d\n", fd);
return 0;
}
⚡ root@ubuntu /home/mistake
이렇게 했을 때 fd에는 0이 들어가더군요.
⚡ root@ubuntu /home/mistake ./mistake
fd : 0
왜 그런지 확인해보면 연산자 우선순위에 대한 실수가 존재하는 것을 알 수 있습니다.
⚡ root@ubuntu /home/mistake cat mistake.c
#include <stdio.h>
#include <fcntl.h>
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;
}
printf("fd : %d\n", fd);
return 0;
}
위에서 연산자 우선순위에 대한 실수가 있는데 비교연산자 '<' 는 대입연산자 '=' 보다 우선순위가 높기 때문에 open()의 반환값은 양수이고 양수 < 0 을 비교하는데 이 조건은 flase가 되고 fd에는 0이 들어가게 됩니다.
그렇다면 read(fd, pw_buf, PW_LEN) 에서 pw_buf에 10자 입력을 받게 되는데 fd값이 당연히 0이기 때문에 가능합니다.
이를 이용하여 pw_buf에도 입력을 할 수 있고, pw_buf2에도 입력을 할 수 있게 되어 xor 연산을 해도 참값이 나오도록
pw_buf 에는 '1' 10개 , pw_buf2에는 '0' 10개를 넣어준다면 flag파일을 열어볼 수 있습니다.
mistake@ubuntu:~$ ./mistake
do not bruteforce...
1111111111
input password : 0000000000
Password OK
flag~~~~
flag값은 가려두었습니다.
이상 풀이를 마칩니다.