@@ -13,7 +13,12 @@ module InsecureDownload {
1313 /**
1414 * A data flow source for download of sensitive file through insecure connection.
1515 */
16- abstract class Source extends DataFlow:: Node { }
16+ abstract class Source extends DataFlow:: Node {
17+ /**
18+ * Gets a flow-label for this source.
19+ */
20+ abstract DataFlow:: FlowLabel getALabel ( ) ;
21+ }
1722
1823 /**
1924 * A data flow sink for download of sensitive file through insecure connection.
@@ -23,28 +28,67 @@ module InsecureDownload {
2328 * Gets the call that downloads the sensitive file.
2429 */
2530 abstract DataFlow:: Node getDownloadCall ( ) ;
31+
32+ /**
33+ * Gets a flow-label where this sink is vulnerable.
34+ */
35+ abstract DataFlow:: FlowLabel getALabel ( ) ;
2636 }
2737
2838 /**
2939 * A sanitizer for download of sensitive file through insecure connection.
3040 */
3141 abstract class Sanitizer extends DataFlow:: Node { }
3242
43+ /**
44+ * Flow-labels for reasoning about download of sensitive file through insecure connection.
45+ */
46+ module Label {
47+ /**
48+ * A flow-label for file URLs that are both sensitive and downloaded over an insecure connection.
49+ */
50+ class SensitiveInsecureURL extends DataFlow:: FlowLabel {
51+ SensitiveInsecureURL ( ) { this = "sensitiveInsecure" }
52+ }
53+
54+ /**
55+ * A flow-label for a URL that is downloaded over an insecure connection.
56+ */
57+ class InsecureURL extends DataFlow:: FlowLabel {
58+ InsecureURL ( ) { this = "insecure" }
59+ }
60+ }
61+
3362 /**
3463 * A HTTP or FTP URL that refers to a file with a sensitive file extension,
3564 * seen as a source for download of sensitive file through insecure connection.
3665 */
3766 class SensitiveFileUrl extends Source {
67+ string str ;
68+
3869 SensitiveFileUrl ( ) {
39- exists ( string str | str = this .getStringValue ( ) |
40- str .regexpMatch ( "http://.*|ftp://.*" ) and
41- exists ( string suffix | suffix = unsafeExtension ( ) |
42- str .suffix ( str .length ( ) - suffix .length ( ) - 1 ) .toLowerCase ( ) = "." + suffix
43- )
44- )
70+ str = this .getStringValue ( ) and
71+ str .regexpMatch ( "http://.*|ftp://.*" )
72+ }
73+
74+ override DataFlow:: FlowLabel getALabel ( ) {
75+ result instanceof Label:: InsecureURL
76+ or
77+ hasUnsafeExtension ( str ) and
78+ result instanceof Label:: SensitiveInsecureURL
4579 }
4680 }
4781
82+ /**
83+ * Holds if `str` is a string that ends with an unsafe file extension.
84+ */
85+ bindingset [ str]
86+ predicate hasUnsafeExtension ( string str ) {
87+ exists ( string suffix | suffix = unsafeExtension ( ) |
88+ str .suffix ( str .length ( ) - suffix .length ( ) - 1 ) .toLowerCase ( ) = "." + suffix
89+ )
90+ }
91+
4892 /**
4993 * Gets a file-extension that can potentially be dangerous.
5094 *
@@ -58,13 +102,48 @@ module InsecureDownload {
58102
59103 /**
60104 * A url downloaded by a client-request, seen as a sink for download of
61- * sensitive file through insecure connection.a
105+ * sensitive file through insecure connection.
62106 */
63107 class ClientRequestURL extends Sink {
64108 ClientRequest request ;
65109
66110 ClientRequestURL ( ) { this = request .getUrl ( ) }
67111
68112 override DataFlow:: Node getDownloadCall ( ) { result = request }
113+
114+ override DataFlow:: FlowLabel getALabel ( ) {
115+ result instanceof Label:: SensitiveInsecureURL
116+ or
117+ hasUnsafeExtension ( request .getASavePath ( ) .getStringValue ( ) ) and
118+ result instanceof Label:: InsecureURL
119+ }
120+ }
121+
122+ /**
123+ * Gets a node for the response from `request`, type-tracked using `t`.
124+ */
125+ DataFlow:: SourceNode clientRequestResponse ( DataFlow:: TypeTracker t , ClientRequest request ) {
126+ t .start ( ) and
127+ result = request .getAResponseDataNode ( )
128+ or
129+ exists ( DataFlow:: TypeTracker t2 | result = clientRequestResponse ( t2 , request ) .track ( t2 , t ) )
130+ }
131+
132+ /**
133+ * A url that is downloaded through an insecure connection, where the result ends up being saved to a sensitive location.
134+ */
135+ class FileWriteSink extends Sink {
136+ ClientRequest request ;
137+ FileSystemWriteAccess write ;
138+
139+ FileWriteSink ( ) {
140+ this = request .getUrl ( ) and
141+ clientRequestResponse ( DataFlow:: TypeTracker:: end ( ) , request ) .flowsTo ( write .getADataNode ( ) ) and
142+ hasUnsafeExtension ( write .getAPathArgument ( ) .getStringValue ( ) )
143+ }
144+
145+ override DataFlow:: FlowLabel getALabel ( ) { result instanceof Label:: InsecureURL }
146+
147+ override DataFlow:: Node getDownloadCall ( ) { result = request }
69148 }
70149}
0 commit comments