LFI2RCE via Eternal waiting

Support HackTricks

기본 정보

기본적으로 PHP에 파일이 업로드되면 (예상하지 않더라도) **php[a-zA-Z0-9]{6}**와 같은 이름의 임시 파일이 /tmp에 생성됩니다. 그러나 일부 도커 이미지에서는 생성된 파일에 숫자가 포함되지 않는 경우도 보았습니다.

로컬 파일 포함에서 업로드된 파일을 포함할 수 있다면 RCE를 얻을 수 있습니다.

기본적으로 PHP는 단일 요청에서 20개의 파일만 업로드할 수 있도록 허용합니다 (설정은 /etc/php/<version>/apache2/php.ini에 있습니다):

; Maximum number of files that can be uploaded via a single request
max_file_uploads = 20

또한, 잠재적인 파일 이름의 수는 62*62*62*62*62*62 = 56800235584입니다.

다른 기술들

다른 기술들은 PHP 프로토콜을 공격하는 데 의존합니다(경로의 마지막 부분만 제어할 경우에는 불가능합니다), 파일의 경로를 노출시키거나, 예상되는 파일을 악용하거나, PHP가 세그멘테이션 오류를 겪도록 하여 업로드된 임시 파일이 삭제되지 않게 만드는 것입니다. 이 기술은 마지막 기술과 매우 유사하지만 제로 데이를 찾을 필요가 없습니다.

영원한 대기 기술

이 기술에서는 상대 경로만 제어하면 됩니다. 파일을 업로드하고 LFI가 끝나지 않도록 만들면, 우리는 "충분한 시간"을 가지게 되어 업로드된 파일을 브루트 포스하고 찾을 수 있습니다.

이 기술의 장점:

  • 포함된 내부의 상대 경로만 제어하면 됩니다.

  • nginx나 로그 파일에 대한 예상치 못한 접근 수준이 필요하지 않습니다.

  • 세그멘테이션 오류를 일으키기 위해 0일이 필요하지 않습니다.

  • 경로 노출이 필요하지 않습니다.

이 기술의 주요 문제는 다음과 같습니다:

  • 특정 파일이 존재해야 합니다(더 있을 수 있습니다).

  • 미친 양의 잠재적 파일 이름: 56800235584

  • 서버가 숫자를 사용하지 않는다면 총 잠재적 양은: 19770609664

  • 기본적으로 단일 요청에서 20개 파일만 업로드할 수 있습니다.

  • 사용된 서버의 최대 병렬 작업자 수.

  • 이 제한은 이전의 제한들과 함께 이 공격이 너무 오래 지속되게 만들 수 있습니다.

  • PHP 요청의 타임아웃. 이상적으로는 이 요청이 영원해야 하거나 임시로 업로드된 파일을 삭제하지 않고 PHP 프로세스를 종료해야 합니다. 그렇지 않으면 이것도 문제가 될 것입니다.

그렇다면, 어떻게 PHP 포함을 끝나지 않게 만들 수 있을까요? 파일 **/sys/kernel/security/apparmor/revision**을 포함하기만 하면 됩니다 (불행히도 Docker 컨테이너에서는 사용할 수 없습니다...).

그냥 호출해 보세요:

php -a # open php cli
include("/sys/kernel/security/apparmor/revision");

Apache2

기본적으로 Apache는 150개의 동시 연결을 지원하며, https://ubiq.co/tech-blog/increase-max-connections-apache/에 따르면 이 숫자를 최대 8000까지 늘릴 수 있습니다. 이 모듈과 함께 PHP를 사용하려면 다음을 따르세요: https://www.digitalocean.com/community/tutorials/how-to-configure-apache-http-with-mpm-event-and-php-fpm-on-ubuntu-18-04.

기본적으로, (내 테스트에서 확인한 바에 따르면) PHP 프로세스는 영원히 지속될 수 있습니다.

수학을 해봅시다:

  • 149개의 연결을 사용하여 149 * 20 = 2980개의 임시 파일을 생성할 수 있습니다.

  • 그런 다음, 마지막 연결을 사용하여 브루트 포스를 수행합니다.

  • 10 요청/초의 속도로 시간은 다음과 같습니다:

  • 56800235584 / 2980 / 10 / 3600 ~= 530시간 (265시간에 50% 확률)

  • (숫자 없이) 19770609664 / 2980 / 10 / 3600 ~= 185시간 (93시간에 50% 확률)

이전 예제에서 우리는 다른 클라이언트를 완전히 DoS하고 있다는 점에 유의하세요!

Apache 서버가 개선되고 4000개의 연결을 남용할 수 있다면, 3999*20 = 79980 파일을 생성할 수 있으며, 시간은 약 19.7시간 또는 6.9시간으로 줄어들 것입니다 (10시간, 3.5시간 50% 확률).

PHP-FMP

정상적인 php 모듈 대신 웹 페이지가 PHP-FMP를 사용하여 PHP 스크립트를 실행하는 경우 (이것은 웹 페이지의 효율성을 향상시키므로 일반적으로 발견됩니다), 기술을 개선하기 위해 할 수 있는 다른 것이 있습니다.

PHP-FMP는 **/etc/php/<php-version>/fpm/pool.d/www.conf**에서 request_terminate_timeout 매개변수를 구성할 수 있게 해줍니다. 이 매개변수는 PHP에 대한 요청이 종료되어야 하는 최대 초 수를 나타냅니다 (기본값은 무한하지만, 매개변수가 주석 해제되면 30초). PHP가 요청을 처리하는 동안 지정된 초 수가 지나면, 요청이 종료됩니다. 이는 요청이 임시 파일을 업로드하고 있었던 경우, php 처리가 중단되었기 때문에, 해당 파일이 삭제되지 않을 것을 의미합니다. 따라서 요청이 그 시간을 지속할 수 있다면, 삭제되지 않는 수천 개의 임시 파일을 생성할 수 있으며, 이는 파일을 찾는 과정을 가속화하고 모든 연결을 소모하여 플랫폼에 대한 DoS 확률을 줄입니다.

따라서 DoS를 피하기 위해 공격자가 동시에 100개의 연결만 사용할 것이라고 가정해 보겠습니다. php-fmp의 PHP 최대 처리 시간은 30초입니다. 따라서 초당 생성할 수 있는 임시 파일의 수는 100*20/30 = 66.67입니다.

그런 다음, 10000개의 파일을 생성하기 위해 공격자는: **10000/66.67 = 150초**가 필요합니다 ( 100000개의 파일을 생성하는 데는 25분이 소요됩니다).

그런 다음 공격자는 이 100개의 연결을 사용하여 브루트 포스 검색을 수행할 수 있습니다. **** 300 req/s의 속도를 가정할 때, 이를 활용하는 데 필요한 시간은 다음과 같습니다:

  • 56800235584 / 10000 / 300 / 3600 ~= 5.25시간 (2.63시간에 50% 확률)

  • (100000개의 파일로) 56800235584 / 100000 / 300 / 3600 ~= 0.525시간 (0.263시간에 50% 확률)

예, EC2 중간 크기 인스턴스에서 100000개의 임시 파일을 생성하는 것이 가능합니다:

타임아웃을 트리거하기 위해서는 취약한 LFI 페이지를 포함하는 것만으로도 충분하므로, 영원한 포함 루프에 들어갑니다.

Nginx

기본적으로 Nginx는 동시에 512개의 병렬 연결을 지원하는 것으로 보이며 (이 숫자는 개선될 수 있습니다).

HackTricks 지원하기

Last updated