python: rewrite models using subscripts

more rewrites could be done to these models
for instance, I think the extra taint configuration could be removed,
but here I just wanted to illustrate the benefits of the new API graph.
This commit is contained in:
Rasmus Lerchedahl Petersen
2022-10-11 16:49:54 +02:00
parent 0b8e908823
commit db616a526a
2 changed files with 36 additions and 66 deletions

View File

@@ -26,7 +26,7 @@ private module Sendgrid {
}
/** Gets a reference to a `SendGridAPIClient` instance call with `send` or `post`. */
private DataFlow::CallCfgNode sendgridApiSendCall() {
private API::CallNode sendgridApiSendCall() {
result = sendgridApiClient().getMember("send").getACall()
or
result =
@@ -62,7 +62,7 @@ private module Sendgrid {
* * `getFrom()`'s result would be `"from@example.com"`.
* * `getSubject()`'s result would be `"Sending with SendGrid is Fun"`.
*/
private class SendGridMail extends DataFlow::CallCfgNode, EmailSender::Range {
private class SendGridMail extends API::CallNode, EmailSender::Range {
SendGridMail() { this = sendgridApiSendCall() }
private DataFlow::CallCfgNode getMailCall() {
@@ -118,40 +118,28 @@ private module Sendgrid {
or
result = this.sendgridWrite("html_content")
or
exists(KeyValuePair content, Dict generalDict, KeyValuePair typePair, KeyValuePair valuePair |
content.getKey().(StrConst).getText() = "content" and
content.getValue().(List).getAnElt() = generalDict and
// declare KeyValuePairs keys and values
typePair.getKey().(StrConst).getText() = "type" and
typePair.getValue().(StrConst).getText() = ["text/html", "text/x-amp-html"] and
valuePair.getKey().(StrConst).getText() = "value" and
result.asExpr() = valuePair.getValue() and
// correlate generalDict with previously set KeyValuePairs
generalDict.getAnItem() in [typePair, valuePair] and
[this.getArg(0), this.getArgByName("request_body")].getALocalSource().asExpr() =
any(Dict d | d.getAnItem() = content)
exists(API::Node contentElement |
contentElement =
this.getKeywordParameter("request_body").getSubscript("content").getASubscript()
|
contentElement.getSubscript("type").getAValueReachingSink().asExpr().(StrConst).getText() =
["text/html", "text/x-amp-html"] and
result = contentElement.getSubscript("value").getAValueReachingSink()
)
or
exists(KeyValuePair footer, Dict generalDict, KeyValuePair enablePair, KeyValuePair htmlPair |
footer.getKey().(StrConst).getText() = ["footer", "subscription_tracking"] and
footer.getValue() = generalDict and
// check footer is enabled
enablePair.getKey().(StrConst).getText() = "enable" and
exists(enablePair.getValue().(True)) and
// get html content
htmlPair.getKey().(StrConst).getText() = "html" and
result.asExpr() = htmlPair.getValue() and
// correlate generalDict with previously set KeyValuePairs
generalDict.getAnItem() in [enablePair, htmlPair] and
exists(KeyValuePair k |
k.getKey() =
[this.getArg(0), this.getArgByName("request_body")]
.getALocalSource()
.asExpr()
.(Dict)
.getAKey() and
k.getValue() = any(Dict d | d.getAKey() = footer.getKey())
)
exists(API::Node html |
html =
this.getKeywordParameter("request_body")
.getSubscript("tracking_settings")
.getSubscript("subscription_tracking")
or
html =
this.getKeywordParameter("request_body")
.getSubscript("mail_settings")
.getSubscript("footer")
|
html.getSubscript("enable").getAValueReachingSink().asExpr() instanceof True and
result = html.getSubscript("html").getAValueReachingSink()
)
}

View File

@@ -101,33 +101,6 @@ module SmtpLib {
)
}
/**
* Gets a message subscript write by correlating subscript's object local source with
* `smtp`'s `sendmail` call 3rd argument's local source.
*
* Given the following example with `getSMTPSubscriptByIndex(any(SmtpLibSendMail s), "Subject")`:
*
* ```py
* message = MIMEMultipart("alternative")
* message["Subject"] = "multipart test"
* server.sendmail(sender_email, receiver_email, message.as_string())
* ```
*
* * `def` would be `message["Subject"]` (`DefinitionNode`)
* * `sub` would be `message["Subject"]` (`Subscript`)
* * `result` would be `"multipart test"`
*/
private DataFlow::Node getSmtpSubscriptByIndex(DataFlow::CallCfgNode sendCall, string index) {
exists(DefinitionNode def, Subscript sub |
sub = def.getNode() and
DataFlow::exprNode(sub.getObject()).getALocalSource() =
[sendCall.getArg(2), sendCall.getArg(2).(DataFlow::MethodCallNode).getObject()]
.getALocalSource() and
sub.getIndex().(StrConst).getText() = index and
result.asCfgNode() = def.getValue()
)
}
/**
* Gets a reference to `smtplib.SMTP_SSL().sendmail()`.
*
@@ -153,7 +126,7 @@ module SmtpLib {
* * `getFrom()`'s result would be `sender_email`.
* * `getSubject()`'s result would be `"multipart test"`.
*/
private class SmtpLibSendMail extends DataFlow::CallCfgNode, EmailSender::Range {
private class SmtpLibSendMail extends API::CallNode, EmailSender::Range {
SmtpLibSendMail() {
this = smtpConnectionInstance().getReturn().getMember("sendmail").getACall()
}
@@ -163,15 +136,24 @@ module SmtpLib {
override DataFlow::Node getHtmlBody() { result = getSmtpMessage(this, "html") }
override DataFlow::Node getTo() {
result in [this.getArg(1), getSmtpSubscriptByIndex(this, "To")]
result = this.getParameter(1, "to_addrs").asSink()
or
result = this.getMsg().getSubscript("To").asSink()
}
override DataFlow::Node getFrom() {
result in [this.getArg(0), getSmtpSubscriptByIndex(this, "From")]
result = this.getParameter(0, "from_addr").asSink()
or
result = this.getMsg().getSubscript("From").asSink()
}
override DataFlow::Node getSubject() {
result in [this.getArg(2), getSmtpSubscriptByIndex(this, "Subject")]
override DataFlow::Node getSubject() { result = this.getMsg().getSubscript("Subject").asSink() }
private API::Node getMsg() {
result.getAValueReachableFromSource() = this.getParameter(2, "msg").asSink()
or
result.getMember("as_string").getReturn().getAValueReachableFromSource() =
this.getParameter(2, "msg").asSink()
}
}
}