Skip to content

Commit c961340

Browse files
authored
Merge pull request #260 from microsoft/powershell-unsafe-deserialization
Powershell Unsafe Deserialize query
2 parents 03a7d3d + d78280e commit c961340

File tree

10 files changed

+224
-0
lines changed

10 files changed

+224
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* Provides default sources, sinks and sanitizers for reasoning about
3+
* unsafe deserialization vulnerabilities, as well as extension points for
4+
* adding your own.
5+
*/
6+
7+
private import semmle.code.powershell.dataflow.DataFlow
8+
import semmle.code.powershell.ApiGraphs
9+
private import semmle.code.powershell.dataflow.flowsources.FlowSources
10+
private import semmle.code.powershell.Cfg
11+
12+
module UnsafeDeserialization {
13+
/**
14+
* A data flow source for SQL-injection vulnerabilities.
15+
*/
16+
abstract class Source extends DataFlow::Node {
17+
/** Gets a string that describes the type of this flow source. */
18+
abstract string getSourceType();
19+
}
20+
21+
/**
22+
* A data flow sink for SQL-injection vulnerabilities.
23+
*/
24+
abstract class Sink extends DataFlow::Node {
25+
/** Gets a description of this sink. */
26+
abstract string getSinkType();
27+
28+
}
29+
30+
/**
31+
* A sanitizer for Unsafe Deserialization vulnerabilities.
32+
*/
33+
abstract class Sanitizer extends DataFlow::Node { }
34+
35+
/** A source of user input, considered as a flow source for unsafe deserialization. */
36+
class FlowSourceAsSource extends Source instanceof SourceNode {
37+
override string getSourceType() { result = SourceNode.super.getSourceType() }
38+
}
39+
40+
class BinaryFormatterDeserializeSink extends Sink {
41+
BinaryFormatterDeserializeSink() {
42+
exists(DataFlow::ObjectCreationNode ocn, DataFlow::CallNode cn |
43+
cn.getQualifier().getALocalSource() = ocn and
44+
ocn.getExprNode().getExpr().(CallExpr).getAnArgument().getValue().asString() = "System.Runtime.Serialization.Formatters.Binary.BinaryFormatter" and
45+
cn.getLowerCaseName() = "deserialize" and
46+
cn.getAnArgument() = this
47+
)
48+
}
49+
50+
override string getSinkType() { result = "call to BinaryFormatter.Deserialize" }
51+
52+
}
53+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Provides a taint tracking configuration for reasoning about
3+
* deserialization vulnerabilities (CWE-502).
4+
*
5+
* Note, for performance reasons: only import this file if
6+
* `UnsafeDeserializationFlow` is needed, otherwise
7+
* `UnsafeDeserializationCustomizations` should be imported instead.
8+
*/
9+
10+
import powershell
11+
import semmle.code.powershell.dataflow.flowsources.FlowSources
12+
import semmle.code.powershell.dataflow.DataFlow
13+
import semmle.code.powershell.dataflow.TaintTracking
14+
import UnsafeDeserializationCustomizations::UnsafeDeserialization
15+
16+
module Config implements DataFlow::ConfigSig {
17+
predicate isSource(DataFlow::Node source) { source instanceof Source }
18+
19+
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
20+
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo){
21+
exists(InvokeMemberExpr ime |
22+
nodeTo.asExpr().getExpr() = ime and
23+
nodeFrom.asExpr().getExpr() = ime.getAnArgument()
24+
)
25+
}
26+
}
27+
28+
module UnsafeDeserializationFlow = TaintTracking::Global<Config>;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
7+
<p>Using <code>BinaryFormatter</code> to deserialize an object from untrusted input may result in security problems, such
8+
as denial of service or remote code execution.</p>
9+
10+
</overview>
11+
<recommendation>
12+
13+
<p>Avoid using <code>BinaryFormatter</code>.</p>
14+
15+
</recommendation>
16+
<example>
17+
18+
<p>In this example, a string is deserialized using a
19+
<code>BinaryFormatter</code>. <code>BinaryFormatter</code> is an easily exploited deserializer.</p>
20+
21+
<sample src="examples/BinaryFormatterDeserialization.ps1" />
22+
23+
</example>
24+
<references>
25+
26+
<li>
27+
Mu&ntilde;oz, Alvaro and Mirosh, Oleksandr:
28+
<a href="https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf">JSON Attacks</a>.
29+
</li>
30+
31+
<li>
32+
Microsoft:
33+
<a href="https://learn.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide">Deserialization risks in use of BinaryFormatter and related types</a>.
34+
</li>
35+
36+
</references>
37+
</qhelp>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @name Use of Binary Formatter deserialization
3+
* @description Use of Binary Formatter is unsafe
4+
* @kind problem
5+
* @problem.severity error
6+
* @security-severity 8.8
7+
* @precision high
8+
* @id powershell/microsoft/public/binary-formatter-deserialization
9+
* @tags correctness
10+
* security
11+
* external/cwe/cwe-502
12+
*/
13+
14+
import powershell
15+
import semmle.code.powershell.security.UnsafeDeserializationCustomizations::UnsafeDeserialization
16+
17+
from BinaryFormatterDeserializeSink sink
18+
select sink, "Call to BinaryFormatter.Deserialize"
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
7+
<p>Deserializing an object from untrusted input may result in security problems, such
8+
as denial of service or remote code execution.</p>
9+
10+
</overview>
11+
<recommendation>
12+
13+
<p>Avoid using an unsafe deserialization framework.</p>
14+
15+
</recommendation>
16+
<example>
17+
18+
<p>In this example, a string is deserialized using a
19+
<code>BinaryFormatter</code>. <code>BinaryFormatter</code> is an easily exploited deserializer.</p>
20+
21+
<sample src="examples/BinaryFormatterDeserialization.ps1" />
22+
23+
</example>
24+
<references>
25+
26+
<li>
27+
Mu&ntilde;oz, Alvaro and Mirosh, Oleksandr:
28+
<a href="https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf">JSON Attacks</a>.
29+
</li>
30+
31+
<li>
32+
Microsoft:
33+
<a href="https://learn.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide">Deserialization risks in use of BinaryFormatter and related types</a>.
34+
</li>
35+
36+
</references>
37+
</qhelp>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* @name Unsafe deserializer
3+
* @description Calling an unsafe deserializer with data controlled by an attacker
4+
* can lead to denial of service and other security problems.
5+
* @kind path-problem
6+
* @problem.severity error
7+
* @security-severity 8.8
8+
* @precision high
9+
* @id powershell/microsoft/public/unsafe-deserialization
10+
* @tags correctness
11+
* security
12+
* external/cwe/cwe-502
13+
*/
14+
15+
import powershell
16+
import semmle.code.powershell.security.UnsafeDeserializationQuery
17+
import UnsafeDeserializationFlow::PathGraph
18+
19+
from
20+
UnsafeDeserializationFlow::PathNode source, UnsafeDeserializationFlow::PathNode sink,
21+
Source sourceNode
22+
where
23+
UnsafeDeserializationFlow::flowPath(source, sink) and
24+
sourceNode = source.getNode()
25+
select sink.getNode(), source, sink, "This unsafe deserializer deserializes on a $@.", sourceNode,
26+
sourceNode.getSourceType()
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
$untrustedBase64 = Read-Host "Enter user input"
2+
3+
$formatter = New-Object System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
4+
$stream = [System.IO.MemoryStream]::new([Convert]::FromBase64String($untrustedBase64))
5+
6+
$obj = $formatter.Deserialize($stream)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
edges
2+
| test.ps1:1:20:1:47 | Call to read-host | test.ps1:3:69:3:84 | untrustedBase64 | provenance | Src:MaD:0 |
3+
| test.ps1:3:11:3:86 | Call to new | test.ps1:4:31:4:37 | stream | provenance | |
4+
| test.ps1:3:41:3:85 | Call to frombase64string | test.ps1:3:11:3:86 | Call to new | provenance | Config |
5+
| test.ps1:3:69:3:84 | untrustedBase64 | test.ps1:3:41:3:85 | Call to frombase64string | provenance | Config |
6+
nodes
7+
| test.ps1:1:20:1:47 | Call to read-host | semmle.label | Call to read-host |
8+
| test.ps1:3:11:3:86 | Call to new | semmle.label | Call to new |
9+
| test.ps1:3:41:3:85 | Call to frombase64string | semmle.label | Call to frombase64string |
10+
| test.ps1:3:69:3:84 | untrustedBase64 | semmle.label | untrustedBase64 |
11+
| test.ps1:4:31:4:37 | stream | semmle.label | stream |
12+
subpaths
13+
#select
14+
| test.ps1:4:31:4:37 | stream | test.ps1:1:20:1:47 | Call to read-host | test.ps1:4:31:4:37 | stream | This unsafe deserializer deserializes on a $@. | test.ps1:1:20:1:47 | Call to read-host | read from stdin |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
queries/security/cwe-502/UnsafeDeserialization.ql
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
$untrustedBase64 = Read-Host "Enter user input"
2+
$formatter = New-Object System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
3+
$stream = [System.IO.MemoryStream]::new([Convert]::FromBase64String($untrustedBase64))
4+
$obj = $formatter.Deserialize($stream)

0 commit comments

Comments
 (0)