|
| 1 | +/** |
| 2 | + * Provides classes for modeling the `Twirp` framework. |
| 3 | + */ |
| 4 | + |
| 5 | +private import codeql.ruby.DataFlow |
| 6 | +private import codeql.ruby.CFG |
| 7 | +private import codeql.ruby.ApiGraphs |
| 8 | +private import codeql.ruby.AST as Ast |
| 9 | +private import codeql.ruby.security.ServerSideRequestForgeryCustomizations |
| 10 | +private import codeql.ruby.Concepts |
| 11 | + |
| 12 | +/** |
| 13 | + * Provides classes for modeling the `Twirp` framework. |
| 14 | + */ |
| 15 | +module Twirp { |
| 16 | + /** |
| 17 | + * A Twirp service instantiation |
| 18 | + */ |
| 19 | + class ServiceInstantiation extends DataFlow::CallNode { |
| 20 | + ServiceInstantiation() { |
| 21 | + this = |
| 22 | + API::getTopLevelMember("Twirp").getMember("Service").getASubclass().getAnInstantiation() |
| 23 | + } |
| 24 | + |
| 25 | + /** |
| 26 | + * Gets a local source node for the Service instantiation argument (the service handler). |
| 27 | + */ |
| 28 | + private DataFlow::LocalSourceNode getHandlerSource() { |
| 29 | + result = this.getArgument(0).getALocalSource() |
| 30 | + } |
| 31 | + |
| 32 | + /** |
| 33 | + * Gets the API::Node for the service handler's class. |
| 34 | + */ |
| 35 | + private API::Node getAHandlerClassApiNode() { |
| 36 | + result.getAnInstantiation() = this.getHandlerSource() |
| 37 | + } |
| 38 | + |
| 39 | + /** |
| 40 | + * Gets the AST module for the service handler's class. |
| 41 | + */ |
| 42 | + private Ast::Module getAHandlerClassAstNode() { |
| 43 | + result = |
| 44 | + this.getAHandlerClassApiNode() |
| 45 | + .asSource() |
| 46 | + .asExpr() |
| 47 | + .(CfgNodes::ExprNodes::ConstantReadAccessCfgNode) |
| 48 | + .getExpr() |
| 49 | + .getModule() |
| 50 | + } |
| 51 | + |
| 52 | + /** |
| 53 | + * Gets a handler's method. |
| 54 | + */ |
| 55 | + Ast::Method getAHandlerMethod() { |
| 56 | + result = this.getAHandlerClassAstNode().getAnInstanceMethod() |
| 57 | + } |
| 58 | + } |
| 59 | + |
| 60 | + /** |
| 61 | + * A Twirp client |
| 62 | + */ |
| 63 | + class ClientInstantiation extends DataFlow::CallNode { |
| 64 | + ClientInstantiation() { |
| 65 | + this = API::getTopLevelMember("Twirp").getMember("Client").getASubclass().getAnInstantiation() |
| 66 | + } |
| 67 | + } |
| 68 | + |
| 69 | + /** The URL of a Twirp service, considered as a sink. */ |
| 70 | + class ServiceUrlAsSsrfSink extends ServerSideRequestForgery::Sink { |
| 71 | + ServiceUrlAsSsrfSink() { exists(ClientInstantiation c | c.getArgument(0) = this) } |
| 72 | + } |
| 73 | + |
| 74 | + /** A parameter that will receive parts of the url when handling an incoming request. */ |
| 75 | + class UnmarshaledParameter extends Http::Server::RequestInputAccess::Range, |
| 76 | + DataFlow::ParameterNode { |
| 77 | + UnmarshaledParameter() { |
| 78 | + exists(ServiceInstantiation i | i.getAHandlerMethod().getParameter(0) = this.asParameter()) |
| 79 | + } |
| 80 | + |
| 81 | + override string getSourceType() { result = "Twirp Unmarhaled Parameter" } |
| 82 | + |
| 83 | + override Http::Server::RequestInputKind getKind() { result = Http::Server::bodyInputKind() } |
| 84 | + } |
| 85 | +} |
0 commit comments