Portswigger-Arbitrary object injection in PHP

problem link

풀이

이 웹사이트에서는 직렬화 기반 세션 메커니즘을 사용하며, 결과적으로 임의의 객체 주입에 취약하다. 문제를 해결하려면 Carlos의 홈 디렉토리에 morale.txt 파일을 삭제하는 악성 직렬화된 객체를 생성하고 주입하라. wiener:peter 계정을 이용할 수 있다.

웹페이지를 크롤링하면 /libs/CustomTemplate.php라는 소스코드 경로를 얻을 수 있다.

레퍼런스를 찾아보면 HTML의 주석에서 찾은 것을 알 수 있다. 하지만 이 경로로 접속하면 아무 내용도 오지 않는다.

Repeater에 넣어 이것 저것 백업 파일 형식의 이름으로 테스트해보면 /libs/CustomTemplate.php~ 경로에 에디터가 생성한 백업 파일이 있다.

<?php
class CustomTemplate {
    private $template_file_path;
    private $lock_file_path;
 
    public function __construct($template_file_path) {
        $this->template_file_path = $template_file_path;
        $this->lock_file_path = $template_file_path . ".lock";
    }
 
    private function isTemplateLocked() {
        return file_exists($this->lock_file_path);
    }
 
    public function getTemplate() {
        return file_get_contents($this->template_file_path);
    }
 
    public function saveTemplate($template) {
        if (!isTemplateLocked()) {
            if (file_put_contents($this->lock_file_path, "") === false) {
                throw new Exception("Could not write to " . $this->lock_file_path);
            }
            if (file_put_contents($this->template_file_path, $template) === false) {
                throw new Exception("Could not write to " . $this->template_file_path);
            }
        }
    }
 
    function __destruct() {
        // Carlos thought this would be a good idea
        if (file_exists($this->lock_file_path)) {
            unlink($this->lock_file_path);
        }
    }
}
?>

CustomTemplate 클래스는 생성할 때 경로를 입력받는다. 이 경로로 파일을 생성하는 기능을 하는데, 파일을 생성할 때 동일 이름에 확장자로 .lock을 붙인 lock 파일을 생성한다. 이후 동일 이름으로 파일을 쓸 때 이미 생성된 lock 파일이 있는 경우 쓰지 않는다. 즉, 이미 생성된 lock 파일이 있는 경우 이를 삭제해야 새로운 내용을 쓸 수 있다.

__construct__destruct 메소드는 생성자와 소멸자이다. CustomTemplate 클래스의 인스턴스를 생성/삭제할 때 호출된다. CustomTemplate 인스턴스를 삭제하면 문제에서 원하는 특정 파일을 삭제하는 목표에 도달할 수 있을 것 같다.

로그인을 하고 돌아다니다보면 Burpsuite의 이슈에 눈에 띄는 이슈가 있다. Serialized object in HTTP message에 대한 경고를 하고 있다. 오브젝트를 직렬화하여 이용하는 것을 발견한 것이다. 공격자는 입력값을 조작해 직렬화된 값을 조작할 수 있고, 이를 통해 공격자는 이 개체를 처할 때 호출되는 서버 측 기능을 제어하여 무단으로 코드를 실행을 유발할 수 있다. 일반적으로 이 취약점을 악용하려면 소스코드에 액세스 할 수 있어 어떻게 입력값을 조작할 지 알 수 있어야 한다고 한다.

또한 이슈로 Base64로 인코드된 파라미터가 있다고 한다. 이는 Serialized object in HTTP message 경고와 동일한 파라미터에 대한 경고였다. 즉, 이 Base64로 인코딩된 데이터가 직렬화된 객체라는 의미이다.

Base64로 인코딩된 문구를 디코딩하면 O:4:"User":2:{s:8:"username";s:6:"wiener";s:12:"access_token";s:32:"t1s1x7h05h1dcuje1regrscwto4t3f4w";} 와 같은 데이터가 나왔다. 여기 username과 access_token 이 보인다. s:n:“문자열” 형식으로 되어있는데, 아마 string이 n글자 있다는 의미같다. O:4:“User”는 아마 오브젝트의 이름을 의미하는 것 같다. 이 데이터는 User 클래스 인스턴스의 변수를 의미하며, 이 인스턴스를 직렬화하여 보낸 것 같다.

PHP serialize 를 이용하면 이런 형태가 나오는 듯 하다.

O:4:"User":2:{s:8:"username";s:6:"carlos";s:12:"access_token";s:32:"t1s1x7h05h1dcuje1regrscwto4t3f4w";} 로, username의 값을 carlos로 변경해 직렬화, 세션 토큰으로 지정해 My Account 페이지에 접근하니 위와 같은 스택 트레이스가 나타났다. 액세스 토큰의 값이 잘못 되었다는 의미의 오류 메시지를 출력하며 기존의 토큰 값을 보여주었다.

이 토큰을 이용해 다시 O:4:"User":2:{s:8:"username";s:6:"carlos";s:12:"access_token";s:32:"eudyc1a7qu8gg76qb23mb8li2flih65o";}를 직렬화해 세션 토큰으로 지정하니 carlos의 My Account 페이지에 접근할 수 있었다.

<<<쉬었다 하여 문제가 초기화, URL이 변경되었음>>>

문제를 해결하기 위해 굳이 carlos 계정으로 로그인할 필요는 없었다. 단순히 CustomTemplate 인스턴스를 만들었다가 삭제하도록 하면 된다. 이를 위해 deserialization 함수에 User에 대한 serialize된 문자열 대신 CustomTemplate의 문자열을 넣는다. O:14:"CustomTemplate":2:{s:18:"template_file_path";s:4:"test";s:14:"lock_file_path";s:10:"morale.txt";} 와 같은 형식으로 만들어 base64인코딩하고, 특수문자는 URL 인코딩한다. lock_file_path로 지우고자 하는 파일 경로를 입력한다.

응답으로 에러 메시지가 오지만, 실제로 deserialization을 했기 때문에 CustomTemplate 인스턴스가 생성된다. 그리고 기존의 원래 User 인스턴스가 필요했던 코드가 실패하며 프로그램이 에러가 나 종료되고, 그 과정에 CustomTemplate 인스턴스가 삭제되어 morale.txt을 삭제한다.

(원래 문제 의도는 /home/carlos/morale.txt 위치의 파일을 삭제하는 것인듯 하다.)

이 취약점은 serialize 데이터를 사용자가 조작할 수 있는 위치에 두고 아무 보호 없이 이용했기 때문에 발생했다. 민감한 데이터를 암호화하지 않고 사용자가 조작할 수 있게 두었다. 또한 내부 파일 구조에 대한 주석을 삭제하지 않아 결론적으로 백업 파일에 접근할 수 있던 것이 문제였다. 백업 파일에 어떠한 액세스 컨트롤로 없었으며, 애초에 퍼블릭 서버의 접근 가능한 위치에 백업 파일을 방치한 것이 문제였다.


tags: writeup, information disclosure vulnerability, wstg-info-05, wstg-info-06, wstg-conf-04, insecure-deserialization, web hacking