diff --git a/python/debugging/README.md b/python/debugging/README.md new file mode 100644 index 00000000..51d0cef0 --- /dev/null +++ b/python/debugging/README.md @@ -0,0 +1,17 @@ +# Python - Debugging + +This Pack is a collection of Python debugging tips and tricks. + +## Basics + +- [`Sources.ql`](./basics/Sources.ql) + - List of the sources in the Application +- [`Sinks.ql`](./basics/Sinks.ql) + - List of the sinks in the Application + +## Partials + +- [`PartialPathsFromSource.ql`](./partials/PartialPathsFromSource.ql) + - List of partial paths from a sources to nodes in the Application +- [`PartialPathsFromSink.ql`](./partials/PartialPathsFromSink.ql) + - List of partial paths from a sink to nodes in the Application diff --git a/python/debugging/basics/Sinks.ql b/python/debugging/basics/Sinks.ql new file mode 100644 index 00000000..309bd11b --- /dev/null +++ b/python/debugging/basics/Sinks.ql @@ -0,0 +1,21 @@ +/** + * @name Sinks + * @kind problem + * @problem.severity warning + * @security-severity 1.0 + * @sub-severity low + * @precision low + * @id py/debugging/sinks + * @tags debugging + */ + +import python +import semmle.python.dataflow.new.DataFlow +// Helpers +private import ghsl.Helpers + +from DataFlow::Node sinks +where + dangerousSinks(sinks) and + sinks.getScope().inSource() +select sinks, "sink" diff --git a/python/debugging/basics/Sources.ql b/python/debugging/basics/Sources.ql new file mode 100644 index 00000000..bdab8111 --- /dev/null +++ b/python/debugging/basics/Sources.ql @@ -0,0 +1,29 @@ +/** + * @name Sources + * @kind problem + * @problem.severity warning + * @security-severity 1.0 + * @sub-severity low + * @precision low + * @id py/debugging/sources + * @tags debugging + */ + +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.RemoteFlowSources +// Helpers +private import ghsl.Helpers +private import ghsl.LocalSources + +class Sources extends DataFlow::Node { + Sources() { + this instanceof RemoteFlowSource + or + this instanceof LocalSources::Range + } +} + +from Sources sources +where sources.getScope().inSource() +select sources, "source" diff --git a/python/debugging/codeql-pack.lock.yml b/python/debugging/codeql-pack.lock.yml new file mode 100644 index 00000000..a73e38a6 --- /dev/null +++ b/python/debugging/codeql-pack.lock.yml @@ -0,0 +1,24 @@ +--- +lockVersion: 1.0.0 +dependencies: + codeql/dataflow: + version: 1.0.1 + codeql/mad: + version: 1.0.1 + codeql/python-all: + version: 1.0.1 + codeql/regex: + version: 1.0.1 + codeql/ssa: + version: 1.0.1 + codeql/tutorial: + version: 1.0.1 + codeql/typetracking: + version: 1.0.1 + codeql/util: + version: 1.0.1 + codeql/xml: + version: 1.0.1 + codeql/yaml: + version: 1.0.1 +compiled: false diff --git a/python/debugging/diagnostics/SinksDatabases.ql b/python/debugging/diagnostics/SinksDatabases.ql new file mode 100644 index 00000000..d2f1326b --- /dev/null +++ b/python/debugging/diagnostics/SinksDatabases.ql @@ -0,0 +1,16 @@ +/** + * @name Database Sinks Diagnostic + * @id ghsl/diagnostics/database-sinks + * @description List all database sinks + * @kind diagnostic + */ + +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.security.dataflow.SqlInjectionCustomizations + +from SqlInjection::Sink s, Expr n +where + s.getScope().inSource() and + n = s.asExpr() +select n, "" diff --git a/python/debugging/diagnostics/SourcesLocal.ql b/python/debugging/diagnostics/SourcesLocal.ql new file mode 100644 index 00000000..304c0e17 --- /dev/null +++ b/python/debugging/diagnostics/SourcesLocal.ql @@ -0,0 +1,17 @@ +/** + * @name Local Sources Diagnostic + * @id ghsl/diagnostics/local-sources + * @description List all local sources + * @kind diagnostic + */ + +import python +import semmle.python.dataflow.new.DataFlow +// Helpers +import ghsl.LocalSources + +from LocalSources::Range s, Expr n +where + s.getScope().inSource() and + n = s.asExpr() +select n, "" diff --git a/python/debugging/diagnostics/SourcesRemotes.ql b/python/debugging/diagnostics/SourcesRemotes.ql new file mode 100644 index 00000000..6f1ec090 --- /dev/null +++ b/python/debugging/diagnostics/SourcesRemotes.ql @@ -0,0 +1,16 @@ +/** + * @name Remote Sources Diagnostic + * @id ghsl/diagnostics/remote-sources + * @description List all remote sources + * @kind diagnostic + */ + +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.RemoteFlowSources + +from RemoteFlowSource s, Expr n +where + s.getScope().inSource() and + n = s.asExpr() +select n, "" diff --git a/python/debugging/partials/PartialPathsFromSink.ql b/python/debugging/partials/PartialPathsFromSink.ql new file mode 100644 index 00000000..08ffc9cd --- /dev/null +++ b/python/debugging/partials/PartialPathsFromSink.ql @@ -0,0 +1,59 @@ +/** + * @name Partial Path Query from Sink + * @kind path-problem + * @problem.severity warning + * @security-severity 1.0 + * @sub-severity low + * @precision low + * @id py/debugging/partial-path-from-sink + * @tags debugging + */ + +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.TaintTracking +import semmle.python.Concepts +import semmle.python.dataflow.new.RemoteFlowSources +import semmle.python.dataflow.new.BarrierGuards +import semmle.python.ApiGraphs +// Helpers +private import ghsl.Helpers + +// Manual Sinks +class ManualSinks extends DataFlow::Node { + ManualSinks() { this = API::moduleImport("any").getMember("any").getACall() } +} + +/** + * Partial Graph module interface + */ +module RemoteFlowsConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { none() } + + predicate isSink(DataFlow::Node sink) { + // List of dangerous sinks (SQL Injection, Command Injection, etc.) + dangerousSinks(sink) + or + // List of manually added sinks (above) + sink instanceof ManualSinks + } +} + +// Set the limit of the exloration depth +int explorationLimit() { result = 10 } + +module RemoteFlows = DataFlow::Global; + +module RemoteFlowsPartial = RemoteFlows::FlowExplorationRev; + +import RemoteFlowsPartial::PartialPathGraph + +from RemoteFlowsPartial::PartialPathNode source, RemoteFlowsPartial::PartialPathNode sink +where RemoteFlowsPartial::partialFlow(source, sink, _) +/// Filter by location +// and findByLocation(source.getNode(), "app.py", 20) +// +/// Filter by Function Parameters +// and functionParameters(source.getNode()) +// +select sink.getNode(), source, sink, "Partial Graph $@.", source.getNode(), "user-provided value" diff --git a/python/debugging/partials/PartialPathsFromSource.ql b/python/debugging/partials/PartialPathsFromSource.ql new file mode 100644 index 00000000..2bdb6c7f --- /dev/null +++ b/python/debugging/partials/PartialPathsFromSource.ql @@ -0,0 +1,50 @@ +/** + * @name Partial Path Query from Source + * @kind path-problem + * @problem.severity warning + * @security-severity 1.0 + * @sub-severity low + * @precision low + * @id py/debugging/partial-path-from-source + * @tags debugging + */ + +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.TaintTracking +import semmle.python.Concepts +import semmle.python.dataflow.new.RemoteFlowSources +import semmle.python.dataflow.new.BarrierGuards +import semmle.python.ApiGraphs +// Helpers +private import ghsl.Helpers +private import ghsl.LocalSources + +// Partial Graph +module RemoteFlowsConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { + source instanceof RemoteFlowSource + or + // Local Sources + source instanceof LocalSources::Range + } + + predicate isSink(DataFlow::Node sink) { none() } +} + +int explorationLimit() { result = 10 } + +module RemoteFlows = DataFlow::Global; + +module RemoteFlowsPartial = RemoteFlows::FlowExplorationFwd; + +import RemoteFlowsPartial::PartialPathGraph + +from RemoteFlowsPartial::PartialPathNode source, RemoteFlowsPartial::PartialPathNode sink +where RemoteFlowsPartial::partialFlow(source, sink, _) +/// Filter by location +// and findByLocation(source.getNode(), "app.py", 50) +/// Filter by Function Parameters +// and functionParameters(sink.getNode()) +// +select sink.getNode(), source, sink, "Partial Graph $@.", source.getNode(), "user-provided value" diff --git a/python/debugging/qlpack.yml b/python/debugging/qlpack.yml new file mode 100644 index 00000000..e5685212 --- /dev/null +++ b/python/debugging/qlpack.yml @@ -0,0 +1,8 @@ +library: false +name: githubsecuritylab/codeql-python-debugging +version: 0.1.0 +suites: suites +defaultSuiteFile: suites/default.qls +dependencies: + codeql/python-all: '^1.0.0' + githubsecuritylab/codeql-python-libs: "${workspace}" diff --git a/python/debugging/suites/default.qls b/python/debugging/suites/default.qls new file mode 100644 index 00000000..2d3a722e --- /dev/null +++ b/python/debugging/suites/default.qls @@ -0,0 +1,12 @@ +- description: "GitHub's Community Packs Python Debugging Suite" + +# Field query pack with some audit queries +- queries: "." + from: githubsecuritylab/codeql-python-debugging + +- include: + kind: + - problem + - path-problem + - metric + - diagnostic