Skip to content

Python : Add Flask sinks for path injection query #6330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 28, 2021

Conversation

ghost
Copy link

@ghost ghost commented Jul 19, 2021

Flask's send_file and send_from_directory calls can allow a remote attacker to potentially access any file stored on the system if the path is controlled by them.

This query modifies the existing Python path injection query to add support for the same.

@ghost
Copy link
Author

ghost commented Jul 19, 2021

Just a small note : https://github.com/cksgf/ServerManagement/blob/49491cc6f94980e6be7791d17be947c27071eb56/route/file.py#L93 should be a true positive for this case but since add a flow to track that may add a lot of FP's, I am in two minds here. @RasmusWL Any thoughts on this?

@RasmusWL
Copy link
Member

I think having additional taint steps for os.path.dirname, os.path.split and so on sound like a good improvement for path injection.

We've added these things like this in the past:

/** An additional taint step for calls to `os.path.normpath` */
private class OsPathNormpathCallAdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
exists(OsPathNormpathCall call |
nodeTo = call and
nodeFrom = call.getPathArg()
)
}
}
so please follow that style as well 😊

Would also be great if you can implement the new sink by using FileSystemAccess::Range, like in

/**
* A call to the builtin `open` function.
* See https://docs.python.org/3/library/functions.html#open
*/
private class OpenCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
OpenCall() { this = getOpenFunctionRef().getACall() }
override DataFlow::Node getAPathArgument() {
result in [this.getArg(0), this.getArgByName("file")]
}
}

@ghost ghost force-pushed the pyPathTraversal branch 2 times, most recently from a476229 to c1c1d89 Compare October 21, 2021 22:40
Copy link
Member

@RasmusWL RasmusWL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the creation of this PR, we have added support for os.path.dirname (see below), so please merge in newest main, and remove that part.

/** An additional taint step for path computations. */
private class OsPathComputationAdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
exists(OsPathComputation call |
nodeTo = call and
nodeFrom = call.getPathArg()
)
}
}

If you can add your new modeling to this file instead https://github.com/github/codeql/blob/main/python/ql/lib/semmle/python/frameworks/Flask.qll (and adjust QLDoc accordingly), I would be happy to merge this PR 👍 I'm not sure how I did not spot this on my last review, sorry about that 🤷‍♂️

@RasmusWL
Copy link
Member

Having a test that shows off the new modeling would also be very good, and should be added somewhere within this folder: https://github.com/github/codeql/tree/main/python/ql/test/library-tests/frameworks/flask

it should use the format expected by our ConceptsTest, so something like the one below, highlight all the interesting different variations that we handle (that is, using both normal arguments and keyword arguments)

flask.send_from_directory("filepath")  # $ getAPathArgument="filepath"

@ghost ghost force-pushed the pyPathTraversal branch from c1c1d89 to 4fd3f21 Compare October 27, 2021 20:42
@ghost
Copy link
Author

ghost commented Oct 27, 2021

@RasmusWL I need some help fixing the tests here. the tests fail with the output I attach below. The arguments are detected by CodeQL on real projects otherwise. So, this looks like an issue with the test runner.

--- expected
+++ actual
@@ -1,1 +1,8 @@
-
+| save_uploaded_file.py:12:51:12:105 | Comment # $ getAPathArgument="filepath" getAPathArgument="file" | Missing result:getAPathArgument="file" |
+| save_uploaded_file.py:12:51:12:105 | Comment # $ getAPathArgument="filepath" getAPathArgument="file" | Missing result:getAPathArgument="filepath" |
+| save_uploaded_file.py:13:30:13:56 | Comment # $ getAPathArgument="file" | Missing result:getAPathArgument="file" |
+| save_uploaded_file.py:15:60:15:114 | Comment # $ getAPathArgument="filepath" getAPathArgument="file" | Missing result:getAPathArgument="file" |
+| save_uploaded_file.py:15:60:15:114 | Comment # $ getAPathArgument="filepath" getAPathArgument="file" | Missing result:getAPathArgument="filepath" |
+| save_uploaded_file.py:16:59:16:113 | Comment # $ getAPathArgument="filepath" getAPathArgument="file" | Missing result:getAPathArgument="file" |
+| save_uploaded_file.py:16:59:16:113 | Comment # $ getAPathArgument="filepath" getAPathArgument="file" | Missing result:getAPathArgument="filepath" |
+| save_uploaded_file.py:17:45:17:71 | Comment # $ getAPathArgument="file" | Missing result:getAPathArgument="file" |

I don't have a clue what's wrong here. Can you please take a look?

@RasmusWL
Copy link
Member

@RasmusWL I need some help fixing the tests here. the tests fail with the output I attach below. The arguments are detected by CodeQL on real projects otherwise. So, this looks like an issue with the test runner.

it was a simple mistake, I fixed it in 358663f

Copy link
Member

@RasmusWL RasmusWL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM now, thanks for updating it 👍

@RasmusWL RasmusWL merged commit 6d09334 into github:main Oct 28, 2021
@RasmusWL RasmusWL self-assigned this Oct 28, 2021
@ghost ghost deleted the pyPathTraversal branch October 28, 2021 10:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant