2011-09-17 2 views
3

나는 이것에 대해서 궁금해. strtol은 처리 할 바이트 수를 지정하지 않아도되므로 이론적으로는 소비 할 끝없는 숫자의 숫자가 포함 된 문자열이 제공되어 서비스 거부 공격이 발생할 수 있습니다. 물론, 한 번에 long의 정밀도가 고갈되었다는 사실을 깨닫게되면 쉽게 좌절됩니다 (실제로 65 진수의 2 진수는 될 수 없습니다). 더 이상 읽을 점이 없습니다.`strtol`의 구현은 무엇입니까?

그러나 strtol은 첫 번째 비 공백 문자가 발생할 때까지 필요한만큼 많은 공백 문자를 삭제해야합니다. 따라서 숫자를 읽는 것이 현명하더라도 끝이없는 공백 문자로 공격 당할 수 있습니까?

+5

"끝이없는"공백 문자열에는 끝이없는 메모리가 필요합니다. [Here] (ftp://ftp.irisa.fr/pub/OpenBSD/src/sys/lib/libsa/strtol.c)는 구현의 한 예입니다. 너무 많은 숫자를 읽지 않는 것이 현명합니다. – user786653

+0

대부분의 라이브러리 함수에서와 마찬가지로 strtol에 제공 한 인수를 확인해야합니다. 예 : 1. 인수는 문자열이어야합니다 (즉, 종료되어야합니다). 그리고 그것이 당신에 관한 것이라면, 당신이 무한한 긴 문자열을주지 않았는지 확인하십시오. – nos

+0

사용자 입력을 읽기 위해'fgets()'(와'sscanf()')를 사용하십시오! – pmg

답변

3

의 대학이 볼 수있는 strtol 함수를보고 싶어 음 경우, strtol 함수는 공백이 아닌 첫 번째 문자까지 필요한만큼의 공백 문자를 폐기해야합니다 마주 친다. 따라서 숫자를 읽는 것이 현명하더라도 끝이없는 공백 문자로 공격 당할 수 있습니까? 도에 공급하기 전에 문자열에 strtol 작품이 이미 메모리에 당신이 저장했을 것이다 (그리고 공격자로부터 읽기) 공백의 "끝"양으로

(또는를 잊어 버린 당신의 문자열을 NUL - 종료) strtol.

구현시 최대 유효 자릿수를 계산할 수 있으므로 올바른 문자열에있을 수 있습니다. 의심되는대로 계속 진행할 필요가 없습니다.

DOS 공격은 결함이있는 구현에서 발생할 수 있지만 this 관련 사례를 확인하십시오 (이것은 double을 읽는 경우 java 및 PHP에서 발생하지만 C 또는 C++ 구현에서 발생할 수 있음).

1

strtol의 구현은 없습니다. 모든 구현이 당신이 설명하는 종류의 공격에 취약하다는 점은 의심 스럽습니다. 분명한 구현은 숫자를 한 번에 저장하지 않고 숫자 시퀀스를 순회하는 것입니다. (일련의 숫자로 인해 주요 0 s의 임의의 길이 될 수 있습니다.)

당신이 구현에 대한 코드를보고 싶다면, 당신은의 glibc 버전 here을 다운로드 할 수 있습니다; strtol()stdlib/strtol.c입니다.

0

는 당신이 캘리포니아 그러나

/* 
* strtol.c -- 
* 
* Source code for the "strtol" library procedure. 
* 
* Copyright (c) 1988 The Regents of the University of California. 
* All rights reserved. 
* 
* Permission is hereby granted, without written agreement and without 
* license or royalty fees, to use, copy, modify, and distribute this 
* software and its documentation for any purpose, provided that the 
* above copyright notice and the following two paragraphs appear in 
* all copies of this software. 
* 
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR 
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT 
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF 
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
* 
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO 
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 
*/ 
static const char rcsid[] = "$Header$ SPRITE (Berkeley)"; 

#include <ctype.h> 

extern unsigned long int strtoul(char *string, char **endPtr, int base); 

/* 
*---------------------------------------------------------------------- 
* 
* strtol -- 
* 
* Convert an ASCII string into an integer. 
* 
* Results: 
* The return value is the integer equivalent of string. If endPtr 
* is non-NULL, then *endPtr is filled in with the character 
* after the last one that was part of the integer. If string 
* doesn't contain a valid integer value, then zero is returned 
* and *endPtr is set to string. 
* 
* Side effects: 
* None. 
* 
*---------------------------------------------------------------------- 
*/ 

long int 
strtol(
    char *string,  /* String of ASCII digits, possibly 
       * preceded by white space. For bases 
       * greater than 10, either lower- or 
       * upper-case digits may be used. 
       */ 
    char **endPtr,  /* Where to store address of terminating 
       * character, or NULL. */ 
    int base   /* Base for conversion. Must be less 
       * than 37. If 0, then the base is chosen 
       * from the leading characters of string: 
       * "0x" means hex, "0" means octal, anything 
       * else means decimal. 
       */ 
) 
{ 
    register char *p; 
    int result; 

    /* 
    * Skip any leading blanks. 
    */ 
    p = string; 
    while (isspace(*p)) { 
    p += 1; 
    } 

    /* 
    * Check for a sign. 
    */ 
    if (*p == '-') { 
    p += 1; 
    result = -1*(strtoul(p, endPtr, base)); 
    } else { 
    if (*p == '+') { 
     p += 1; 
    } 
    result = strtoul(p, endPtr, base); 
    } 
    if ((result == 0) && (endPtr != 0) && (*endPtr == p)) { 
    *endPtr = string; 
    } 
    return result; 
} 
+1

이'strtol()'은 C 스펙에 명시된 것처럼 오버플로에 대해 INT_MAX와 INT_MIN을 반환하지 않습니다. – chux

+4

쓸데없는 대답,이 코드는'strtoul'을 호출합니다. – izabera

0

내 개인 구현. 나는 어떤 미리보기 (p[1] 또는 그와 비슷한 것)를 사용하지 않았기 때문에, 이론적으로 이것을 스트림에서 읽는 것으로 변환 할 수 있습니다 (예 : get_long() 문자로 getc()).

#include <errno.h> 
#define LONG_MAX ((long)(~0UL>>1)) 
#define LONG_MIN (~LONG_MAX) 
int isspace(int c); /* <-- Forward declare from <ctype.h> */ 

long strtol(const char *restrict nptr, char **restrict endptr, int base) { 
    const char *p = nptr, *endp; 
    _Bool is_neg = 0, overflow = 0; 
    /* Need unsigned so (-LONG_MIN) can fit in these: */ 
    unsigned long n = 0UL, cutoff; 
    int cutlim; 
    if (base < 0 || base == 1 || base > 36) { 
#ifdef EINVAL /* errno value defined by POSIX */ 
     errno = EINVAL; 
#endif 
     return 0L; 
    } 
    endp = nptr; 
    while (isspace(*p)) 
     p++; 
    if (*p == '+') { 
     p++; 
    } else if (*p == '-') { 
     is_neg = 1, p++; 
    } 
    if (*p == '0') { 
     p++; 
     /* For strtol(" 0xZ", &endptr, 16), endptr should point to 'x'; 
     * pointing to ' ' or '0' is non-compliant. 
     * (Many implementations do this wrong.) */ 
     endp = p; 
     if (base == 16 && (*p == 'X' || *p == 'x')) { 
      p++; 
     } else if (base == 0) { 
      if (*p == 'X' || *p == 'x') { 
       base = 16, p++; 
      } else { 
       base = 8; 
      } 
     } 
    } else if (base == 0) { 
     base = 10; 
    } 
    cutoff = (is_neg) ? -(LONG_MIN/base) : LONG_MAX/base; 
    cutlim = (is_neg) ? -(LONG_MIN % base) : LONG_MAX % base; 
    while (1) { 
     int c; 
     if (*p >= 'A') 
      digit = ((*p - 'A') & (~('a'^'A'))) + 10; 
     else if (*p <= '9') 
      digit = *p - '0'; 
     else 
      break; 
     if (c < 0 || c >= base) break; 
     endp = ++p; 
     if (overflow) { 
      /* endptr should go forward and point to the non-digit character 
      * (of the given base); required by ANSI standard. */ 
      if (endptr) continue; 
      break; 
     } 
     if (n > cutoff || (n == cutoff && c > cutlim)) { 
      overflow = 1; continue; 
     } 
     n = n * base + c; 
    } 
    if (endptr) *endptr = (char *)endp; 
    if (overflow) { 
     errno = ERANGE; return ((is_neg) ? LONG_MIN : LONG_MAX); 
    } 
    return (long)((is_neg) ? -n : n); 
} 
관련 문제