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