mirror of
https://github.com/github/codeql.git
synced 2026-04-24 08:15:14 +02:00
Merge pull request #16771 from porcupineyhairs/js2py
Python : Arbitrary code execution due to Js2Py
This commit is contained in:
24
python/ql/src/experimental/Security/CWE-094/Js2Py.qhelp
Normal file
24
python/ql/src/experimental/Security/CWE-094/Js2Py.qhelp
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
Passing untrusted inputs to a JavaScript interpreter like `Js2Py` can lead to arbitrary
|
||||
code execution.
|
||||
</p>
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p> This vulnerability can be prevented either by preventing an untrusted user input to flow
|
||||
to an <code>eval_js</code> call. Or, the impact of this vulnerability can be
|
||||
significantly reduced by disabling imports from the interepreted code (note that in a <a
|
||||
href="https://github.com/PiotrDabkowski/Js2Py/issues/45#issuecomment-258724406">
|
||||
comment</a> the author of the library highlights that Js2Py is still insecure with this
|
||||
option).</p>
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>In the example below, the Javascript code being evaluated is controlled by the user and
|
||||
hence leads to arbitrary code execution.</p>
|
||||
<sample src="Js2pyBad.py" />
|
||||
<p>This can be fixed by disabling imports before evaluating the user passed buffer.</p>
|
||||
<sample src="Js2pyGood.py" />
|
||||
</example>
|
||||
</qhelp>
|
||||
38
python/ql/src/experimental/Security/CWE-094/Js2Py.ql
Normal file
38
python/ql/src/experimental/Security/CWE-094/Js2Py.ql
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @name JavaScript code execution.
|
||||
* @description Passing user supplied arguments to a Javascript to Python translation engine such as Js2Py can lead to remote code execution.
|
||||
* @problem.severity error
|
||||
* @security-severity 9.3
|
||||
* @precision high
|
||||
* @kind path-problem
|
||||
* @id py/js2py-rce
|
||||
* @tags security
|
||||
* experimental
|
||||
* external/cwe/cwe-94
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.ApiGraphs
|
||||
import semmle.python.dataflow.new.TaintTracking
|
||||
import semmle.python.dataflow.new.RemoteFlowSources
|
||||
import semmle.python.Concepts
|
||||
|
||||
module Js2PyFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
API::moduleImport("js2py").getMember(["eval_js", "eval_js6", "EvalJs"]).getACall().getArg(_) =
|
||||
node
|
||||
}
|
||||
}
|
||||
|
||||
module Js2PyFlow = TaintTracking::Global<Js2PyFlowConfig>;
|
||||
|
||||
import Js2PyFlow::PathGraph
|
||||
|
||||
from Js2PyFlow::PathNode source, Js2PyFlow::PathNode sink
|
||||
where
|
||||
Js2PyFlow::flowPath(source, sink) and
|
||||
not exists(API::moduleImport("js2py").getMember("disable_pyimport").getACall())
|
||||
select sink, source, sink, "This input to Js2Py depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
4
python/ql/src/experimental/Security/CWE-094/Js2pyBad.py
Normal file
4
python/ql/src/experimental/Security/CWE-094/Js2pyBad.py
Normal file
@@ -0,0 +1,4 @@
|
||||
@bp.route("/bad")
|
||||
def bad():
|
||||
jk = flask.request.form["jk"]
|
||||
jk = eval_js(f"{jk} f()")
|
||||
6
python/ql/src/experimental/Security/CWE-094/Js2pyGood.py
Normal file
6
python/ql/src/experimental/Security/CWE-094/Js2pyGood.py
Normal file
@@ -0,0 +1,6 @@
|
||||
@bp.route("/good")
|
||||
def good():
|
||||
# disable python imports to prevent execution of malicious code
|
||||
js2py.disable_pyimport()
|
||||
jk = flask.request.form["jk"]
|
||||
jk = eval_js(f"{jk} f()")
|
||||
Reference in New Issue
Block a user