analysis
문제의 내용으로 dhmonkey라는 것과 관련이 있고, 힌트는 연산자 우선 순위이다.
dhmonkey를 구글에 검색했을 때 나오는 것이 없으니 사전에 알아두어야 하는 것이 아니라 ssh를 접속하고 나서 지켜보면 될 것 같다.
#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;
}
C 언어 코드를 분석한다.
홈 화면에는 이 외에도 password라는 파일이 존재한다.
password도 소유자의 root 권한만 걸려있다
코드를 차근차근 분석해보자.
#define PW_LEN 10
#define XORKEY 1
void xor(char* s, int len){
int i;
for(i=0; i<len; i++){
s[i] ^= XORKEY;
}
}
password length를 10으로 지정한다.
xorkey에 1을 넣어두고, 문자열과 길이를 입력받아, 각 문자마다 1을 xor한다.
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;
}
main함수는 인자를 입력받을 수 있다.
그리고 password파일을 열어 file descriptor을 fd로 설정한다.
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;
}
곧바로 브포 때리지 말라고 하며, 현재 시간 % 20 만큼 sleep? 한다.
pw buf는 password에서 읽어들인 파일을 read 함수를 통해 저장된다.
char pw_buf2[PW_LEN+1];
printf("input password : ");
scanf("%10s", pw_buf2);
// xor your input
xor(pw_buf2, 10);
그리고 패스워드를 입력, 우리가 원하는 값을 넣는다. 그 뒤에는 곧바로 위 함수에서 정의한 xor연산을 마친다.
if(!strncmp(pw_buf, pw_buf2, PW_LEN)){
printf("Password OK\n");
system("/bin/cat flag\n");
}
else{
printf("Wrong Password\n");
}
우리가 입력한 패스워드의 xor 이후 값이 password와 일치하면 flag를 준다. 브루트포스를 맘 먹으면 돌릴 수 있을 것 같지만 문제에서는 연산자 우선순위가 힌트라고 하니..
발생 가능한 우선순위 부분을 살펴본다.
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;
}
여기서 연산자가 여러개 사용된 것으로 보아 우선순위를 확인해야겠다.
대입 연산자는 웬만하면 우선순위가 낮다. 즉 다른 연산자들보다 나중에 사용되는데,
그러면 여기서는 open에서 에러가 있는지를 보고 에러가 없다면 0을 반환한다. 그 반환값이 fd에 들어가면
fd는 0이 들어간다. if문은 그냥 넘어간다.
실제로 실행해보면 뭔가 값을 입력해야 다음 scanf문으로 넘어갔었는데, 이게 fd가 0이어서 그랬나보다.
read를 통해 stdin으로 10자를 입력받는다. read의 비교를 통해서 len이 1이 들어갈 것이다.
그러나 실제 strncmp 비교문에서는 PW_LEN을 사용하기에 가치가 없는 듯.
Solution
이제 우리가 입력으로 password, 그리고 각각 password의 문자를 1로 xor한 값을 넣으면 됨을 알았다.
처음에는 각각 0, 1을 넣었는데 안 되길래 생각해보니 고정적으로 10의 길이만큼 xor하여 null로 끝나지 않는다.
null로 끝내고 싶으면 \x01을 넣으면 되지만 그냥 10개를 넣으면 될 일이기 때문에
0 10개
1 10개를 넣어서 맞춰준다.