PHP - Deserialization + Autoload Classes
먼저, Autoloading Classes가 무엇인지 확인해야 합니다.
PHP 역직렬화 + spl_autoload_register + LFI/Gadget
웹 앱에서 PHP 역직렬화를 발견했지만 phpggc
내부에 가젯에 취약한 라이브러리가 없는 상황에 있습니다. 그러나 동일한 컨테이너에는 취약한 라이브러리가 있는 다른 컴포저 웹 앱이 있습니다. 따라서 목표는 다른 웹 앱의 컴포저 로더를 로드하고, 역직렬화에 취약한 웹 앱에서 가젯을 이용하여 해당 라이브러리를 악용하는 것입니다.
단계:
역직렬화를 발견했고, 현재 앱 코드에는 가젯이 없습니다
다음과 같은
spl_autoload_register
함수를 악용하여.php
확장자를 가진 로컬 파일을 로드할 수 있습니다.이를 위해 클래스 이름이 **
$name
**에 들어있는 역직렬화를 사용합니다. 직렬화된 객체의 클래스 이름에는 "/" 또는 "."을 사용할 수 없지만, 코드는 밑줄("_")을 슬래시("/")로 대체합니다. 따라서tmp_passwd
와 같은 클래스 이름은/tmp/passwd.php
로 변환되고 코드에서 로드를 시도합니다. 가젯 예시는 다음과 같습니다:O:10:"tmp_passwd":0:{}
파일 업로드가 가능하고 .php
확장자를 가진 파일을 업로드할 수 있다면, 이 기능을 직접 악용하여 이미 RCE를 얻을 수 있습니다.
저의 경우에는 그런 것이 없었지만, 동일한 컨테이너 내에 phpggc
가젯에 취약한 라이브러리가 있는 다른 컴포저 웹 페이지가 있었습니다.
이 다른 라이브러리를 로드하기 위해서는, 먼저 해당 다른 웹 앱의 컴포저 로더를 로드해야 합니다. (현재 애플리케이션의 로더는 다른 앱의 라이브러리에 접근할 수 없습니다.) 애플리케이션의 경로를 알고 있다면, 다음과 같이 매우 쉽게 할 수 있습니다:
O:28:"www_frontend_vendor_autoload":0:{}
(저의 경우, 컴포저 로더는/www/frontend/vendor/autoload.php
에 있었습니다.)이제, 다른 앱의 컴포저 로더를 로드할 수 있으므로,
phpggc
페이로드를 생성해야 합니다. 저의 경우, **Guzzle/FW1
**을 사용하여 파일 시스템 내에 임의의 파일을 작성할 수 있었습니다.참고: 생성된 가젯은 작동하지 않았습니다. 작동하려면, phpggc의
chain.php
페이로드를 수정하여 생성된 객체의 속성을 모두 private에서 public으로 설정해야 합니다. 그렇지 않으면, 문자열을 역직렬화한 후 생성된 객체의 속성에는 어떤 값도 없습니다.이제 다른 앱의 컴포저 로더를 로드할 수 있는 방법과 작동하는 phpggc 페이로드가 있지만, **가젯이 사용될 때 로더가 로드되도록 이를 같은 요청에서 수행해야 합니다. 이를 위해 다음과 같이 두 개의 객체를 직렬화된 배열로 보냈습니다:
먼저 로더가 로드되고 그 다음에 페이로드가 나타납니다.
이제 파일을 생성하고 작성할 수 있지만, 사용자는 웹 서버 내의 어떤 폴더에도 쓸 수 없습니다. 그래서 페이로드에서 볼 수 있듯이, **
/tmp/a.php
**에 생성된 **system
**과 함께 base64를 호출하는 PHP가 생성됩니다. 그런 다음, 다른 웹 앱의 컴포저 로더를 로드하기 위해 LFI로 사용한 첫 번째 유형의 페이로드를 생성된/tmp/a.php
파일을 로드하는 데 재사용할 수 있습니다. 그냥 이를 역직렬화 가젯에 추가하면 됩니다:
페이로드 요약
동일한 컨테이너 내의 다른 웹앱의 컴포저 자동로드 로드
다른 웹앱의 라이브러리를 악용하기 위해 phpggc 가젯 로드 (직렬화 취약점이 있는 초기 웹앱에는 가젯이 없음)
가젯은 악성 명령을 포함한 PHP 페이로드가 있는 /tmp/a.php에 파일을 생성합니다 (웹앱 사용자는 다른 웹앱의 어떤 폴더에도 쓸 수 없음)
페이로드의 마지막 부분은 명령을 실행할 생성된 php 파일을 로드합니다.
이 직렬화를 두 번 호출해야 했습니다. 테스트에서 첫 번째 호출에서는 /tmp/a.php
파일이 생성되지만 로드되지 않았으며, 두 번째 호출에서는 올바르게 로드되었습니다.
Last updated