Skip to content
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

Fully qualified names #16352

Closed
OrenGitHub opened this issue Apr 28, 2024 · 13 comments
Closed

Fully qualified names #16352

OrenGitHub opened this issue Apr 28, 2024 · 13 comments
Labels
JS question Further information is requested

Comments

@OrenGitHub
Copy link

I'm looking for fully qualified name calls for express.post1 :

const express = require('express')
const app = express()

app.post('/vuln', (req, res) => { ... } // <--- here is a call example I'm after

I can get all calls containing the word post:

import javascript

from CallExpr c
where c.getCalleeName().matches("%post%")
select c, c.getLocation(), c.getCalleeName()

And it works great:

$ .\codeql\codeql database analyze --rerun example-repo C:\Users\tuna_\GitHub\codeql\javascript\ql\examples\queries\dataflow\EvalTaint\EvalTaint.ql --sarif-category=javascript-typescript --format=sarif-latest --output=output.sarif
$ .\codeql\codeql bqrs decode .\example-repo\results\codeql\javascript-examples\queries\dataflow\EvalTaint\EvalTaint.bqrs --format=text --output=output.txt
$ type .\output.txt
|           c           |    col1    | col2 |
+-----------------------+------------+------+
| app.pos ... `);\r\n}) | main.js:16 | post |
| app.pos ... `);\r\n}) | main.js:16 | post |
| app.pos ... `);\r\n}) | main.js:10 | post |
| app.pos ... `);\r\n}) | main.js:16 | post |

When I try to use the fully qualified name predicate it doesn't work:

import javascript

from CallExpr c
where c.getCallee().hasQualifiedName("express.post")
select c, c.getLocation(), c.getCalleeName()

Here is the error that I get:

$ .\codeql\codeql database analyze --rerun example-repo C:\Users\tuna_\GitHub\codeql\javascript\ql\examples\queries\dataflow\EvalTaint\EvalTaint.ql --sarif-category=javascript-typescript --format=sarif-latest --output=output.sarif
ERROR: hasQualifiedName(string) cannot be resolved for type Expr::Expr

1 The complete code is here

@OrenGitHub OrenGitHub added the question Further information is requested label Apr 28, 2024
@ginsbach
Copy link
Contributor

Thank you for the question!

The error message is correct - Expr simply does not declare such a hasQualifiedName method. However, you can use PropAccess::getQualifiedName instead:

from CallExpr c
where c.getCallee().(PropAccess).getQualifiedName().matches("app.post")
select c, c.getLocation(), c.getCalleeName()

@OrenGitHub
Copy link
Author

@ginsbach thanks ! Is there an option to match "express.post" instead of the nominal "app.post" ?
I need that to identify javascript express post handlers

@asgerf
Copy link
Contributor

asgerf commented Apr 30, 2024

Try this

API::moduleImport("express").getMember("post")

The JavaScript analysis does not operate with fully qualified names, instead we rely on identifying the of access paths that lead to the desired endpoint.

@OrenGitHub
Copy link
Author

I can't make a properly typed query 😬
attempt 1:

from CallExpr c
where c.getCalleeName() = API::moduleImport("express").getMember("post")
select c, c.getLocation(), c.getCalleeName()

yields the following error:

ERROR: string is incompatible with ApiGraphs::API::Node (C:\Users\tuna_\GitHub\codeql\javascript\ql\examples\queries\dataflow\EvalTaint\EvalTaint.ql:16,25-26)

Attempt 2:

from CallExpr c
where c.getCallee() = API::moduleImport("express").getMember("post")
select c, c.getLocation(), c.getCalleeName()

Yields this error:

ERROR: Expr::Expr is incompatible with ApiGraphs::API::Node (C:\Users\tuna_\GitHub\codeql\javascript\ql\examples\queries\dataflow\EvalTaint\EvalTaint.ql:16,21-22)

What am I missing ?

@OrenGitHub
Copy link
Author

When I look at the docs, there isn't anything similar, though
the scenario is very useful, so I may be looking in the wrong place (?)

@sidshank sidshank added the JS label Apr 30, 2024
@asgerf
Copy link
Contributor

asgerf commented Apr 30, 2024

Try API::moduleImport("express").getMember("post").getACall().asExpr()

@OrenGitHub
Copy link
Author

Still no go - no type errors, but I get an empty table:

from CallExpr c
where c.getCallee() = API::moduleImport("express").getMember("post").getACall().asExpr()
select c, c.getLocation(), c.getCalleeName()

and the table I get is:

$ .\codeql\codeql bqrs decode .\example-repo\results\codeql\javascript-examples\queries\dataflow\EvalTaint\EvalTaint.bqrs --format=text --output=output.txt
$ type .\output.txt
| c | col1 | col2 |
+---+------+------+

And there is a call for express.post: source

@asgerf
Copy link
Contributor

asgerf commented Apr 30, 2024

The getACall().asExpr() part returns the call itself, but you were comparing it against the callee of that call (i.e. a function).

Try comparing it to the call expression itself

from CallExpr c
where c = API::moduleImport("express").getMember("post").getACall().asExpr()
select c, c.getLocation(), c.getCalleeName()

Or just

select API::moduleImport("express").getMember("post").getACall()

@OrenGitHub
Copy link
Author

Guys, thanks. I'm still getting an empty table though 😬
I even fixed metadata problems, so they don't somehow interfere (they didn't)
Here is my final query:

import javascript

from CallExpr c
where c = API::moduleImport("express").getMember("post").getACall().asExpr()
select c.getLocation(), "moish"

And here is my output:

$ .\codeql\codeql database analyze --rerun example-repo C:\Users\tuna_\GitHub\codeql\javascript\ql\examples\queries\dataflow\EvalTaint\EvalTaint.ql --sarif-category=javascript-typescript --format=sarif-latest --output=output.sarif
Running queries.
Compiling query plan for C:\Users\tuna_\GitHub\codeql\javascript\ql\examples\queries\dataflow\EvalTaint\EvalTaint.ql.
[1/1 comp 8.8s] Compiled C:\Users\tuna_\GitHub\codeql\javascript\ql\examples\queries\dataflow\EvalTaint\EvalTaint.ql.
Starting evaluation of codeql\javascript-examples\queries\dataflow\EvalTaint\EvalTaint.ql.
[1/1 eval 531ms] Evaluation done; writing results to codeql\javascript-examples\queries\dataflow\EvalTaint\EvalTaint.bqrs.
Shutting down query evaluator.
Interpreting results.

$ .\codeql\codeql bqrs decode .\example-repo\results\codeql\javascript-examples\queries\dataflow\EvalTaint\EvalTaint.bqrs --format=text --output=output.txt

$ type .\output.txt
| col0 | col1 |
+------+------+

@asgerf
Copy link
Contributor

asgerf commented May 1, 2024

Sorry, I misread you example code, we need a getReturn() after moduleImport("express") because post is not called on the express package itself, but on the value returned from express().

select API::moduleImport("express").getReturn().getMember("post").getACall()

I'd suggest trying to quick-eval the individual pieces of the above CodeQL expression to get some intuition about what it does.

@OrenGitHub
Copy link
Author

It works ! Thanks for all the guidance !

@OrenGitHub
Copy link
Author

@asgerf should I close this issue ?

@asgerf
Copy link
Contributor

asgerf commented May 3, 2024

Yes, closing issue

@asgerf asgerf closed this as completed May 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
JS question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants