tmxklab

[pwnable.kr] otp 본문

War Game/pwnable.kr

[pwnable.kr] otp

tmxk4221 2021. 6. 7. 14:36

 

 

1. 문제 확인

otp@pwnable:~$ ls -l
total 20
-r--r----- 1 otp_pwn root   65 Jun 14  2014 flag
-r-sr-x--- 1 otp_pwn otp  9052 Jun 14  2014 otp
-rw-r--r-- 1 root    root  820 Jun 14  2014 otp.c

 

1) mitigation 확인

 

2) 문제 확인

 

3) 코드 흐름 확인

3-1) otp.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

int main(int argc, char* argv[]){
	char fname[128];
	unsigned long long otp[2];

	if(argc!=2){
		printf("usage : ./otp [passcode]\n");
		return 0;
	}

	int fd = open("/dev/urandom", O_RDONLY);
	if(fd==-1) exit(-1);

	if(read(fd, otp, 16)!=16) exit(-1);
	close(fd);

	sprintf(fname, "/tmp/%llu", otp[0]);
	FILE* fp = fopen(fname, "w");
	if(fp==NULL){ exit(-1); }
	fwrite(&otp[1], 8, 1, fp);
	fclose(fp);

	printf("OTP generated.\n");

	unsigned long long passcode=0;
	FILE* fp2 = fopen(fname, "r");
	if(fp2==NULL){ exit(-1); }
	fread(&passcode, 8, 1, fp2);
	fclose(fp2);
	
	if(strtoul(argv[1], 0, 16) == passcode){
		printf("Congratz!\n");
		system("/bin/cat flag");
	}
	else{
		printf("OTP mismatch\n");
	}

	unlink(fname);
	return 0;
}
  • 로직은 생각보다 간단하다.
  • 난수 값(/dev/urandom)16byte 가져와 /tmp/"난수값" 파일을 생성한다.
  • 그리고 거기다가 난수 값의 상위 8byte를 저장하고 ptr변수에 값을 가져온다.
  • 마지막으로 argv[1]과 난수 값 8byte를 비교한다.

딱히, 취약점이라고 보일만한 것은 보이질 않는다.

 


2. 접근 방법

 

위에서 코드를 보면 굉장히 쓸데없이 긴 것을 알 수 있다. 걍 랜덤 값 가져와서 비교하면 될 것을 /tmp/에 난수 값 파일을 만들고 난수 값 저장하고 난수 값을 가져오고....

 

중요한 부분은 파일이 만들어지고 fwrite()를 통해 해당 파일에 난수 값을 쓰는 것인데 여기서 ulimit라는 명령어를 사용하면 최대 파일 사이즈 크기를 지정할 수 있다는 것이다.

 

미리 ulimit로 파일 사이즈를 0으로 제한을 두고 otp프로그램이 실행되고 fwrite()를 통해 난수 값을 쓸 때 파일 사이즈가 제한되었기 때문에 프로세스가 종료하게 된다. (ulimit : 프로세스의 자원 한도를 설정하는 명령어)

 


3. 문제 풀이

ulimit로 파일 사이즈 제한을 0으로 걸어두고 otp를 실행시킬 때 널 값을 넣는다.

'War Game > pwnable.kr' 카테고리의 다른 글

[pwnable.kr] ascii_easy  (0) 2021.06.07
[pwnable.kr] simple login  (0) 2021.06.07
[pwnable.kr] md5 calculator  (0) 2021.01.15
[pwnable.kr] brain fuck  (0) 2021.01.14
[pwnable.kr] horcruxes  (0) 2020.12.02
Comments