버퍼 언더 플로가 어떻게 64 비트에서 원격 코드 실행으로 이어질 수 있습니까?

나는 git‑shell (/bin/bash는 실행할 프로그램으로 대체되었으므로 다른 작업을 수행 할 수 없습니다.) :

struct _raw_uncapped_ssh_string { // no limit on the size of the string; uint32_t len; char non_null_terminated_string[]; // by protocol design it have a minimum length of 1 }; typedef struct _raw_uncapped_ssh_string raw_ssh_string; union buffer { void * uncapped_zlib_decompressed_network_data; // yes, the size is uncapped, so it’s possible to put 4Gb of // data in it that would be copied later into memory. zlib // allow easily to turn some Mb in Gb of data, but it’s not // the point of the question. raw_ssh_string st; }; get_command (compressed_network_data) { size_t len; char * command; buffer string=uncompress_to_buffer(compressed_network_data); len=ntohl(string.st.len)+1; command=malloc(len+1); command[len]=0; // here’s the point, both the string length and content as // well it’s supplied size is controlled by the attacker. memcpy(command,string.st.data,len); return command; } 

다음은 나중에 명령이 실행되는 방식 (문자열 command 이후에 변경되지 않음 get_command()) .

const char *args[]={"/bin/bash",command,NULL}; // /bin/bash isn’t the shell, it has been replaced by git‑shell. // redirect the program output to the network. dup2(stdin, 0); dup2(stdout,1); dup2(stdout,2); close(stdin); close(stdout); //if this return execution failed and print an error message return execv(args[0],(char * const *)args); // I don’t know which is the system, so I can’t know about the libc behaviour. 

memcpy(command,string.st.data,0) memcpy의 세 번째 멤버가 최소 크기는 1이고 내 컨텍스트에서는 size_t 64 비트 정수를 사용하므로 버퍼 오버플로를 수행 할 수 없습니다. len.

할 수있는 일은 len 할당 된 값보다 큰 값으로 string.st.data 설정하는 것입니다. 이것은 할당되지 않은 메모리를 읽을 수 있도록하는 버퍼 언더 플로입니다.
서버 메모리는 읽을 수 있지만 공용 ssh 서버가 저장할 수있는 민감한 데이터를 볼 수 없습니다. (제 경우에는 ssh is public을 수행 할 수 있음) .

또한 memcpy 원격 허용 코드 실행?

설명

  • 코드가 실제로 길이가 len 인 버퍼의 최대 인덱스가 len-1이기 때문에 이는 버퍼 오버 플로우입니다. 또는 실제 코드가 malloc(len) 대신 malloc(len+1)를 수행하는 경우

    값을 0xFFFFFFFF로 설정합니다.

  • @ThomasPornin : 이건 내 부분의 오류입니다. 사실 여러 함수를 호출하여 이. 나머지가 사실이라고 가정합니다.
  • @ThomasPornin : 64 비트에 대해 이야기하고 있습니다. len은 size_t이므로 64 비트 정수를 사용합니다. 따라서 정수 오버플로에 대한 방법이 없습니다.
  • @ThomasPornin len+1를 할당하므로 0 설정이 유효해야합니다.
  • @ RoraΖ : 그는 string.st.len를 -1로 설정하는 것에 대해 이야기하고있었습니다.

답변

일반적으로, 원격 코드 실행에는 버퍼 언더 플로를 사용할 수 없습니다. 공격자가 제어하는 데이터는 할당 된 공간을 벗어나지 않으므로 프로그램의 실행 흐름을 장악 할 수 없습니다.

버퍼 언더 플로는 다음과 같은 다른 유형의 공격에 대한 가능성을 가지고 있습니다. 정보 공개 (프로그램이 버퍼의 원래 내용이 새 데이터에 의해 삭제되는 것을 고려하는 경우)

댓글

  • 또는 I 최근에 git에서 보았지만 나중에 버퍼 오버플로로 바뀝니다.

답변

처음에이 응답을 작성했을 때 , 나는 당신이 가지고있는 오해에 대해 비판 한 것 같습니다. 이러한 오해로 인해 내 대답을 이해하지 못할 수 있습니다. 명확하게 말하면, 저는이 텍스트를 무례하지 않도록 강조하기 위해 크게 만들 것입니다.

사용하는 많은 용어가 의미한다고 생각하는 것을 의미하지 않습니다.

예 :

  • memcpy의 세 번째 구성원은 memcpystruct 또는 union가 아닌 함수입니다.
  • len가 있기 때문에 버퍼 오버플로를 수행 할 수없고 휘발유가 있기 때문에 휘발유가 부족할 수 없습니다. 질문이 있으십니까? 특히 이론적으로 말하면 코드가 버퍼 오버 플로우를 호출 할 수 있을 수 있기 때문에 나에게 적합한 비유처럼 보입니다.
  • “내가 할 수있는 일은 lenstring.st.data에 할당 된 값보다 큰 값으로 설정합니다. 이것은 버퍼 언더 플로입니다 … “ 아니요, 이것은 버퍼 언더 플로의 정의가 아닙니다. 버퍼 언더 플로는 음의 인덱스를 사용하여 배열을 벗어난 배열에 액세스 할 때 발생합니다. 포인터 산술 래핑이 발생할 수 있습니다. 후자는 일부 구성 ( “64 비트 시스템”에서도 가능합니다. 그 의미가 무엇이든간에)에 대해 가능할 수 있지만이 단어를 작성할 때 이것이 의미하는 바는 의심 스럽습니다. with :
  • “… 할당되지 않은 메모리를 읽을 수있게 해줍니다.” “초기화되지 않은 메모리”를 의미하는 것 같습니다. 명확하게 말하면 “ 초과를 할당하고 초과분을 초기화하지 않은 상태로 두었습니다 . 이에 대해 조치를 취하고 싶을 수도 있습니다 (calloc 또는 memset).

char *fubar = NULL;를 잠시 생각해 보겠습니다. 이런 종류의 포인터는 일반적으로 0 값.역 참조는 널 포인터 역 참조 로 간주되지만 0["hello"]와 같은 것을 작성하면 "hello"[0] (즉, "h"). 따라서 공격자가 대괄호 사이의 표현식을 제어 할 때 공격에서 널 포인터 역 참조를 사용할 수 있습니다 (현재 상황에서와 같이).

다시 fubar 사물; memset(&fubar, UCHAR_MAX, sizeof fubar);를 가정 해 보겠습니다. 이제 fubar가 모두 1 비트입니다. 즉, 주소가 있을 수 있습니다 이것이 우리 시스템이 (이론적으로) 수용 할 수있는 가장 큰 주소입니다. fubar[1]에 액세스하면 어떻게됩니까? 가장 큰 주소 뒤에 요소에 액세스하려면 어떻게해야합니까? 기술적으로이 모든 것은 정의되지 않은 동작이지만 공통 아키텍처에서 의 이름을 지정하면 다음과 같습니다.

  1. 포인터, 이어지는 …
  2. 널 포인터 역 참조 및 / 또는 잠재적으로 버퍼 언더 플로 .

memcpy의 버퍼 언더 플로가 원격 코드 실행을 허용합니까?

버퍼 언더 플로는 공격자가 해당 배열 이전의 메모리 영역에있는 함수 포인터를 덮어 쓸 수 있도록합니다. 이러한 함수 포인터가 쉘 코드를 가리 키도록 만들면 해당 쉘 코드는 “나중에 호출 될 때 실행됩니다.

이 다소 모호한 코드에서는 int가 더 넓은 범위를 가질 때 버퍼 언더 플로의 위험이 있습니다. ntohl(string.st.len)+1uint32_t보다 uint32_t 값이 int 유형. 예를 들어 INT_MIN-4294967296 (0 - UINT32_MAX보다 1 개 작음) 인 경우를 생각해보십시오. 그리고 INT_MAX4294967295 … 이것은 기본적으로 33 비트 int입니다. 바이트 너비까지 채울 패딩; 드물지만 가능합니다. 이 상황에서 ntohl(string.st.len)+1 표현식은 uint32_t 유형이 아닙니다. 유형이 int이며 부호없는 정수 오버플로 가 발생할 때 0으로 다시 래핑하는 대신 -4294967296 부호있는 정수 오버플로 가 발생할 때

버퍼 언더 플로 에 대한 보증을 찾고 있다면 U 정수 리터럴 접미사 (예 : ntohl(string.st.len)+1U). 그런 다음이 상황에서 표현식은 uint32_t 또는 unsigned int (가장 큰 유형에 따라 도메인).

ntohl(string.st.len)가 서명되지 않은 유형 (무엇이든)에 대한 최대 값보다 작은 값을 반환 할 수 있다고 생각하면 len=ntohl(string.st.len)+1는 최대 값을, malloc(len+1) 서명되지 않은 래핑 을 발생 시키므로 결국 다음에 command[len]=0는 배열의 끝을 넘어서 잘 그리고 진정으로 작성합니다. 그러면 당연히 또한 memcpy(command,string.st.data,len); (버퍼 오버 플로우)에 문제가 생깁니다.

버퍼 언더 플로우 및 오버플로가 유일한 위험은 아닙니다. malloc

NULL를 반환 한 다음 null 포인터 역 참조를 사용하여 임의의 코드를 실행할 수 있습니다. 이는

오류가 발신자에게 돌아갑니다. 또한 동일한 방법을 사용하여 래핑 문제를 확인하고 발신자에게 다시 전달할 수 있음을 의미합니다.

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다