├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── COPYRIGHT
├── LICENSE
├── README.md
├── semmle-security-cpp
├── .project
├── .qlpath
├── README.md
├── lib
│ └── ghostscript
│ │ ├── CollectionsTracking.qll
│ │ ├── README.md
│ │ ├── Stack.qll
│ │ └── Type.qll
├── queries.xml
└── queries
│ └── ghostscript
│ ├── README.md
│ └── TypeConfusion.ql
└── semmle-security-java
├── .project
├── .qlpath
├── README.md
├── lib
├── dataflow_extra
│ ├── CollectionsEdges.qll
│ ├── ExtraEdges.qll
│ ├── ExtraSources.qll
│ └── Sanitizers.qll
└── struts
│ ├── DataFlow.qll
│ ├── OGNL.qll
│ ├── README.md
│ └── Sanitizers.qll
├── queries.xml
└── queries
└── struts
├── README.md
├── cve_2018_11776
├── README.md
├── final.ql
├── initial.ql
├── ognl_Injection_final.ql
└── ognl_Injection_initial.ql
└── double_evaluation
├── README.md
└── double_eval_final.ql
/.gitignore:
--------------------------------------------------------------------------------
1 | # emacs
2 | *~
3 |
4 | #ql cache
5 | .cache
6 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | This code of conduct outlines expectations for participation in the Semmle open source community, including any open source repositories on GitHub.com, as well as steps for reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all.
4 |
5 | People violating this code of conduct may be banned from the community.
6 |
7 | Our community strives to:
8 | * Be friendly and patient: Remember you might not be communicating in someone else’s primary spoken or programming language, and others may not have your level of understanding.
9 | * Be welcoming: Our community welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, color, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.
10 | * Be respectful: We are a world-wide community of professionals, and we conduct ourselves professionally. Disagreement is no excuse for poor behavior and poor manners. Disrespectful and unacceptable behavior includes, but is not limited to:
11 | * Violent threats or language.
12 | * Discriminatory or derogatory jokes and language.
13 | * Posting sexually explicit or violent material.
14 | * Posting, or threatening to post, people’s personally identifying information (“doxing”).
15 | * Insults, especially those using discriminatory terms or slurs.
16 | * Behavior that could be perceived as sexual attention.
17 | * Advocating for or encouraging any of the above behaviors.
18 | * Understand disagreements: Disagreements, both social and technical, are useful learning opportunities. Seek to understand others’ viewpoints and resolve differences constructively.
19 |
20 | This code is not exhaustive or complete. It serves to capture our common understanding of a productive, collaborative environment. We expect the code to be followed in spirit as much as in the letter.
21 |
22 | # Scope
23 |
24 | This code of conduct applies to all repositories and communities for Semmle open source projects, regardless of whether or not the repository explicitly calls out its use of this code. The code also applies in public spaces when an individual is representing the Semmle open source community. Examples include using an official project email address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
25 |
26 |
27 | # Reporting Code of Conduct Issues
28 | We encourage members of the community to resolve issues on their own whenever possible. This builds a broader and deeper understanding and ultimately a healthier interaction. In the event that an issue cannot be resolved locally, please feel free to report your concerns by contacting code-of-conduct@semmle.com.
29 | In your report please include:
30 | * Your contact information.
31 | * Names (real, usernames or pseudonyms) of any individuals involved. If there are additional witnesses, please include them as well.
32 | * Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public chat log), please include a link or attachment.
33 | * Any additional information that may be helpful.
34 |
35 | All reports will be reviewed by a multi-person team and will result in a response that is deemed necessary and appropriate to the circumstances. Where additional perspectives are needed, the team may seek insight from others with relevant expertise or experience. The confidentiality of the person reporting the incident will be kept at all times. Involved parties are never part of the review team.
36 |
37 | Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the review team may take any action they deem appropriate, including a permanent ban from the community.
38 |
39 | *This text is licensed under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license. It is based on a template established by the [TODO Group](http://todogroup.org/) and variants thereof used by numerous other large communities (e.g., [Microsoft](https://microsoft.github.io/codeofconduct/), [Facebook](https://code.fb.com/codeofconduct/), [Yahoo](https://yahoo.github.io/codeofconduct), [Twitter](https://github.com/twitter/code-of-conduct), [GitHub](https://blog.github.com/2015-07-20-adopting-the-open-code-of-conduct/)) and the Scope section from the [Contributor Covenant version 1.4](http://contributor-covenant.org/version/1/4/).*
40 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Semmle open-source projects
2 |
3 | We welcome contributions to our project. If you have an idea or a bugfix then please go ahead an open a Pull Request!
4 |
5 | Before we accept your pull request, we will require that you have agreed to our Contributor License Agreement. This is not something that you need to do before you submit your pull request, but until you've done so, we will be unable to accept your contribution.
6 |
7 | ## Using your personal data
8 |
9 | If you contribute to this project, we will record your name and email
10 | address (as provided by you with your contributions) as part of the code
11 | repositories, which might be made public. We might also use this information
12 | to contact you in relation to your contributions, as well as in the
13 | normal course of software development. We also store records of your
14 | CLA agreements. Under GDPR legislation, we do this
15 | on the basis of our legitimate interest in creating the QL product.
16 |
17 | Please do get in touch (privacy@semmle.com) if you have any questions about
18 | this or our data protection policies.
19 |
20 | ## Contributor License Agreement
21 |
22 | This Contributor License Agreement (“Agreement”) is entered into between Semmle Limited (“Semmle,” “we” or “us” etc.), and You (as defined and further identified below).
23 |
24 | Accordingly, You hereby agree to the following terms for Your present and future Contributions submitted to Semmle:
25 |
26 | 1. **Definitions**.
27 |
28 | * "You" (or "Your") shall mean the Contribution copyright owner (whether an individual or organization) or legal entity authorized by the copyright owner that is making this Agreement with Semmle. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
29 |
30 | * "Contribution(s)" shall mean the code, documentation or other original works of authorship, including any modifications or additions to an existing work, submitted by You to Semmle for inclusion in, or documentation of, any of the products or projects owned or managed by Semmle (the "Work(s)"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to Semmle or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Semmle for the purpose of discussing and/or improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
31 |
32 | 2. **Grant of Copyright License**. You hereby grant to Semmle and to recipients of software distributed by Semmle a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
33 |
34 | 3. **Grant of Patent License**. You hereby grant to Semmle and to recipients of software distributed by Semmle a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that Your Contribution, or the Work to which You have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
35 |
36 | 4. **Ownership**. Except as set out above, You keep all right, title, and interest in Your Contribution. The rights that You grant to us under this Agreement are effective on the date You first submitted a Contribution to us, even if Your submission took place before the date You entered this Agreement.
37 |
38 | 5. **Representations**. You represent and warrant that: (i) the Contributions are an original work and that You can legally grant the rights set out in this Agreement; (ii) the Contributions and Semmle’s exercise of any license rights granted hereunder, does not and will not, infringe the rights of any third party; (iii) You are not aware of any pending or threatened claims, suits, actions, or charges pertaining to the Contributions, including without limitation any claims or allegations that any or all of the Contributions infringes, violates, or misappropriate the intellectual property rights of any third party (You further agree that You will notify Semmle immediately if You become aware of any such actual or potential claims, suits, actions, allegations or charges).
39 |
40 | 6. **Employer**. If Your employer(s) has rights to intellectual property that You create that includes Your Contributions, You represent and warrant that Your employer has waived such rights for Your Contributions to Semmle, or that You have received permission to make Contributions on behalf of that employer and that You are authorized to execute this Agreement on behalf of Your employer.
41 |
42 | 7. **Inclusion of Code**. We determine the code that is in our Works. You understand that the decision to include the Contribution in any project or source repository is entirely that of Semmle, and this agreement does not guarantee that the Contributions will be included in any product.
43 |
44 | 8. **Disclaimer**. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Except as set forth herein, and unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND.
45 |
46 | 9. **General**. The failure of either party to enforce its rights under this Agreement for any period shall not be construed as a waiver of such rights. No changes or modifications or waivers to this Agreement will be effective unless in writing and signed by both parties. In the event that any provision of this Agreement shall be determined to be illegal or unenforceable, that provision will be limited or eliminated to the minimum extent necessary so that this Agreement shall otherwise remain in full force and effect and enforceable. This Agreement shall be governed by and construed in accordance with the laws of the State of California in the United States without regard to the conflicts of laws provisions thereof. In any action or proceeding to enforce rights under this Agreement, the prevailing party will be entitled to recover costs and attorneys’ fees.
47 |
--------------------------------------------------------------------------------
/COPYRIGHT:
--------------------------------------------------------------------------------
1 | Copyright (c) Semmle Inc and other contributors. All rights reserved.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4 | this file except in compliance with the License. You may obtain a copy of the
5 | License at http://www.apache.org/licenses/LICENSE-2.0
6 |
7 | THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
8 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
9 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
10 | MERCHANTABLITY OR NON-INFRINGEMENT.
11 |
12 | See the Apache Version 2.0 License for specific language governing permissions
13 | and limitations under the License.
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Security queries
2 |
3 | This repository is a place to store and share customized security queries and libraries. This contains queries in [LGTM blog posts](https://lgtm.com/blog), but also project specific libraries. If you find it useful and would like to share some cool queries that you wrote for finding vulnerabilities in open source projects with us, or if you would like to help us to improve the project-specific QL libraries, please feel free to contribute and create a PR!
4 |
5 | These queries should be used with the free [QL for Eclipse plugin](https://help.semmle.com/ql-for-eclipse/Content/WebHelp/home-page.html). To run these queries on an open source project that is available on [LGTM](https://lgtm.com), follow the first two steps in [Basic Usage](https://help.semmle.com/ql-for-eclipse/Content/WebHelp/basic-usage.html) to obtain and import the project snapshot, then go to the specific `.ql` file in this repository that contains the query, [import the parent project into Eclipse](https://help.semmle.com/ql-for-eclipse/Content/WebHelp/import-ql-project.html), open and select the file and press `Ctrl+R`. There are also some links to snapshots for specific versions of certain projects in the `README` files in this repository.
6 |
7 | ## Using the Path Explorer
8 |
9 | Many queries in this repository makes use of the Taint-Tracking library in QL, which allows you to visualize the code path that goes from a tainted source to a dangerous sink. To enable this, click `Window` on the Eclipse menu bar, then click `Show View > Other... > Semmle > Path Explorer` to display the Path Explorer window. This will show you the tainted path when you click on a query result.
10 |
11 |
--------------------------------------------------------------------------------
/semmle-security-cpp/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | semmle-security-cpp
4 |
5 |
6 |
7 |
8 |
9 |
10 | com.semmle.plugin.qdt.core.qlnature
11 |
12 |
13 |
--------------------------------------------------------------------------------
/semmle-security-cpp/.qlpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | com.semmle.code.cpp.library
5 |
6 | com.semmle.code.cpp.dbscheme
7 |
8 | cpp
9 |
10 |
11 |
--------------------------------------------------------------------------------
/semmle-security-cpp/README.md:
--------------------------------------------------------------------------------
1 | # Semmle C++ security queries
2 |
3 | This directory contains QL libraries and queries that are used for finding vulnerabilities in open source C++ projects. The libraries are in the `lib` directory and queries in the `queries` directory. These directories are organized according to the open source project that they are meant to be used with.
4 |
--------------------------------------------------------------------------------
/semmle-security-cpp/lib/ghostscript/CollectionsTracking.qll:
--------------------------------------------------------------------------------
1 | import cpp
2 | import semmle.code.cpp.dataflow.TaintTracking
3 | import lib.ghostscript.Type
4 | import lib.ghostscript.Stack
5 | /** Various dataflow utilities related to collections. */
6 |
7 | /** A method that takes a collection as an input argument, and store the result in the output argument.*/
8 | abstract class FetchMethod extends Function {
9 |
10 | abstract int getInput();
11 |
12 | abstract int getOutput();
13 | }
14 |
15 | /** FetchMethod for array.*/
16 | class ArrayGetMethod extends FetchMethod {
17 | int input;
18 | int output;
19 |
20 | ArrayGetMethod() {
21 | this.hasName("array_get") and input = 1 and output = 3
22 | }
23 |
24 | override int getInput() {
25 | result = input
26 | }
27 |
28 | override int getOutput() {
29 | result = output
30 | }
31 | }
32 |
33 | /** FetchMethod for dictionary.*/
34 | class DictionaryFetchMethod extends FetchMethod {
35 | int input;
36 | int output;
37 |
38 | DictionaryFetchMethod() {
39 | (this.hasName("dict_find_string") and input = 0 and output = 2) or
40 | (this.hasName("dict_find") and input = 0 and output = 2)
41 | }
42 |
43 | override int getInput() {
44 | result = input
45 | }
46 |
47 | override int getOutput() {
48 | result = output
49 | }
50 | }
51 |
52 | class InputSourceConfig extends DataFlow::Configuration {
53 | InputSourceConfig() {
54 | this = "inputSourceConfig"
55 | }
56 |
57 | override predicate isSource(DataFlow::Node source) {
58 | isOSPSource(source)
59 | }
60 |
61 | override predicate isSink(DataFlow::Node sink) {
62 | exists(FetchMethod f, FunctionCall fc | fc.getTarget() = f |
63 | fc.getArgument(f.getOutput()).(RefAccess).getVariable().getAnAccess() = sink.asExpr()
64 | )
65 | }
66 |
67 | override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
68 | isFetchEdge(node1, node2)
69 | }
70 | }
71 |
72 | predicate isFetchEdge(DataFlow::Node node1, DataFlow::Node node2) {
73 | exists(FunctionCall fc, FetchMethod f | fc.getTarget() = f |
74 | node1.asExpr() = fc.getArgument(f.getInput()) and
75 | node2.asExpr() = fc.getArgument(f.getOutput()).(RefAccess).getVariable().getAnAccess() and
76 | node1.getEnclosingCallable() = node2.getEnclosingCallable()
77 | )
78 | }
--------------------------------------------------------------------------------
/semmle-security-cpp/lib/ghostscript/README.md:
--------------------------------------------------------------------------------
1 | #Ghostscript QL libraries
2 |
3 | This contains project specific libraries for Ghostscript You can import these libraries in your custom queries and use them on snapshots of [Ghostscript].(https://downloads.lgtm.com/snapshots/cpp/ghostscript/ghostscript/ghostscript-revision-2018-October-15--10-34-16.zip)
4 |
--------------------------------------------------------------------------------
/semmle-security-cpp/lib/ghostscript/Stack.qll:
--------------------------------------------------------------------------------
1 | import cpp
2 | import semmle.code.cpp.dataflow.DataFlow
3 |
4 | /** An access to an operator stack variable, which are arguments to PostScript functions. */
5 | predicate isOSPAccess(FieldAccess fa) {
6 | exists(FieldAccess opStack, FieldAccess stack |
7 | fa.getTarget().hasName("p")
8 | | fa.getQualifier() = stack and stack.getTarget().hasName("stack") and
9 | stack.getQualifier() = opStack and opStack.getTarget().hasName("op_stack")
10 | )
11 | }
12 |
13 | /** A DataFlow::Node that is an access to an operator stack variable. */
14 | predicate isOSPSource(DataFlow::Node source) {
15 | exists(FieldAccess fa | isOSPAccess(fa) and
16 | source.asExpr() = fa
17 | )
18 | }
--------------------------------------------------------------------------------
/semmle-security-cpp/lib/ghostscript/Type.qll:
--------------------------------------------------------------------------------
1 | import cpp
2 | import semmle.code.cpp.dataflow.TaintTracking
3 | import semmle.code.cpp.dataflow.DataFlow
4 | /** Contains QL classes specific to various structures in Ghostscript. */
5 |
6 | /** Access to a variable of type `ref` or various other equivalent types.*/
7 | class RefAccess extends Expr {
8 | /** The variable of this `ref`*/
9 | Variable v;
10 |
11 | RefAccess() {
12 | (v.getAnAccess() = this or v.getAnAccess() = this.(AddressOfExpr).getAnOperand()) and
13 | exists(string name | v.getType().getName() = name |
14 | v.getType() instanceof PointerType or
15 | name = "os_ptr" or name = "const_os_ptr" or
16 | name = "const os_ptr" or name = "ref" or
17 | name = "const ref"
18 | )
19 | }
20 |
21 | Variable getVariable() {
22 | result = v
23 | }
24 |
25 | /** Convenient predicate to check that two access are to the same variable.*/
26 | predicate isEquivalent(RefAccess other) {
27 | this.getVariable() = other.getVariable()
28 | }
29 | }
30 |
31 | /** An access to a field that requires type checking.*/
32 | class TypeFieldAccess extends FieldAccess {
33 | TypeFieldAccess() {
34 | exists(FieldAccess f | f.getTarget().hasName("value") and
35 | this.getQualifier() = f and this.getTarget().getDeclaringType().hasName("v")
36 | )
37 | }
38 |
39 | RefAccess getRef() {
40 | result = this.getQualifier().(FieldAccess).getQualifier()
41 | }
42 | }
43 |
44 | /** An access to a field that represents the type of a `ref`.*/
45 | class TypeAttrAccess extends FieldAccess {
46 | TypeAttrAccess() {
47 | exists(FieldAccess fa | fa.getTarget().hasName("tas") and
48 | fa = this.getQualifier() and this.getTarget().getName() = "type_attrs"
49 | )
50 | }
51 |
52 | RefAccess getRef() {
53 | result = this.getQualifier().(FieldAccess).getQualifier()
54 | }
55 | }
56 |
57 | /** A comparison statement that is likely to be a type check. */
58 | class TypeCheck extends TypeAttrAccess {
59 | TypeCheck() {
60 | exists(EqualityOperation eq | eq.getAnOperand().getAChild*() = this)
61 | }
62 | }
63 |
64 | /** A switch statement that uses the type of a `ref` as the condition. This is a common pattern for checking types. */
65 | class SwitchCheck extends TypeAttrAccess {
66 | SwitchStmt stmt;
67 | SwitchCheck() {
68 | stmt.getControllingExpr().getAChild*() = this
69 | }
70 |
71 | SwitchStmt getSwitch() {
72 | result = stmt
73 | }
74 | }
75 |
76 | /** A DataFlow::Configuration to see whether a function checks the type of its argument.*/
77 | class CheckTypeConfig extends DataFlow::Configuration {
78 | CheckTypeConfig() {
79 | this = "checkTypeConfig"
80 | }
81 |
82 | override predicate isSource(DataFlow::Node source) {
83 | exists(Parameter p | p = source.asParameter())
84 | }
85 |
86 | override predicate isSink(DataFlow::Node sink) {
87 | exists(TypeAttrAccess tc | tc.getRef() = sink.asExpr() and
88 | (tc instanceof TypeCheck or tc instanceof SwitchCheck)
89 | )
90 | }
91 | }
92 |
93 | /** A function that checks the type of a `ref` when it is passed as parameter `index`. */
94 | class CheckFunction extends Function {
95 | int index;
96 | CheckFunction() {
97 | exists(CheckTypeConfig cfg, DataFlow::Node source | source.asParameter() = this.getParameter(index) and
98 | cfg.hasFlow(source, _)
99 | ) or
100 | //This allocates an array, so the parameter is overwritten and have array type afterwards. (i.e. Not user controlled anymore)
101 | (this.hasName("gs_alloc_ref_array") and index = 1)
102 | }
103 |
104 | int getIndex() {
105 | result = index
106 | }
107 | }
108 |
109 | /** A DataFlow::Node that can only be reached after a type check. */
110 | predicate isTypeCheck(DataFlow::Node node) {
111 | exists(TypeAttrAccess tc, RefAccess e | dominates(tc, e) and
112 | e = node.asExpr() and tc.getRef().isEquivalent(e) and
113 | (tc instanceof TypeCheck or tc instanceof SwitchCheck)
114 | ) or
115 | exists(FunctionCall fc |
116 | dominates(fc, node.asExpr()) and
117 | fc.getArgument(fc.getTarget().(CheckFunction).getIndex()).(RefAccess).isEquivalent(node.asExpr())
118 | )
119 | }
--------------------------------------------------------------------------------
/semmle-security-cpp/queries.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/semmle-security-cpp/queries/ghostscript/README.md:
--------------------------------------------------------------------------------
1 | # Ghostscript specific queries
2 |
3 | This directory contains security queries specific for [Ghostscript](https://www.ghostscript.com/). You can run the queries here on a [Ghostscript snapshot](https://downloads.lgtm.com/snapshots/cpp/ghostscript/ghostscript/ghostscript-revision-2018-October-15--10-34-16.zip). Follow the steps [here](https://help.semmle.com/ql-for-eclipse/Content/WebHelp/basic-usage.html) to import the snapshot and run the queries.
4 |
--------------------------------------------------------------------------------
/semmle-security-cpp/queries/ghostscript/TypeConfusion.ql:
--------------------------------------------------------------------------------
1 | /**
2 | * @name TypeConfusion
3 | * @description Type confusion in GhostScript.
4 | * @kind path-problem
5 | * @id type-confusion-final
6 | * @problem.severity error
7 | */
8 |
9 | import cpp
10 | import lib.ghostscript.CollectionsTracking
11 | import lib.ghostscript.Type
12 | import DataFlow::PathGraph
13 |
14 | class TypeConfusionConfig extends TaintTracking::Configuration2 {
15 | TypeConfusionConfig() {
16 | this = "typeConfusionConfig"
17 | }
18 |
19 | override predicate isSource(DataFlow::Node source) {
20 | exists(InputSourceConfig cfg, DataFlow::Node input | cfg.hasFlow(input, source))
21 | }
22 |
23 | override predicate isSink(DataFlow::Node sink) {
24 | exists(TypeFieldAccess tc | tc.getRef() = sink.asExpr()
25 | )
26 | }
27 |
28 | override predicate isSanitizer(DataFlow::Node node) {
29 | isTypeCheck(node) or
30 | //Manually remove the assignment of this argument inside array_get is safe.
31 | exists(Function f | f.getName() = "array_get" and
32 | f.getParameter(3) = node.asParameter()
33 | )
34 | }
35 | }
36 |
37 | from InputSourceConfig inputCfg, TypeConfusionConfig cfg, DataFlow::Node sink, DataFlow::PathNode inputSource,
38 | DataFlow::PathNode inputSink
39 | where cfg.hasFlow(inputSink.getNode(), sink) and inputCfg.hasFlowPath(inputSource, inputSink)
40 | select inputSink, inputSource, inputSink, "$@ flows to here and is used later without type check.", inputSource, "Function argument"
--------------------------------------------------------------------------------
/semmle-security-java/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | semmle-security-java
4 |
5 |
6 |
7 |
8 |
9 |
10 | com.semmle.plugin.qdt.core.qlnature
11 |
12 |
13 |
--------------------------------------------------------------------------------
/semmle-security-java/.qlpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | com.semmle.code.java.library
5 |
6 | com.semmle.code.java.dbscheme
7 |
8 | java
9 |
10 |
11 |
--------------------------------------------------------------------------------
/semmle-security-java/README.md:
--------------------------------------------------------------------------------
1 | # Semmle Java security queries
2 |
3 | This directory contains QL libraries and queries that are used for finding vulnerabilities in open source Java projects. The libraries are in the `lib` directory and queries in the `queries` directory. These directories are organized according to the open source project that they are meant to be used with.
4 |
--------------------------------------------------------------------------------
/semmle-security-java/lib/dataflow_extra/CollectionsEdges.qll:
--------------------------------------------------------------------------------
1 | import java
2 | import semmle.code.java.dataflow.DefUse
3 | import semmle.code.java.dataflow.DataFlow
4 | /** Contains DataFlow edges for handling access to Collections. These edges usually takes the approach of tainting the entire
5 | * collection when an tainted element is added to the Collection and are considered too aggressive for default QL library.
6 | */
7 |
8 | /** Tracks from a tainted Collection to an element of it iterated in a loop.*/
9 | predicate forLoopEdge(DataFlow::Node node1, DataFlow::Node node2) {
10 | exists(EnhancedForStmt for | for.getExpr() = node1.asExpr() and
11 | defUsePair(for.getVariable(), node2.asExpr().(VarAccess))
12 | )
13 | }
14 |
15 | /** Tracks from a tainted Map entry to the return of its `getKey` or `getValue` methods */
16 | private predicate mapEntryEdge(DataFlow::Node node1, DataFlow::Node node2) {
17 | exists(MethodAccess ma, Method m | m.hasName("getKey") or m.hasName("getValue") |
18 | m.getDeclaringType().getASourceSupertype*().getQualifiedName().matches("java.util.Map<>$Entry%") and
19 | ma.getMethod() = m and ma = node2.asExpr() and ma.getQualifier() = node1.asExpr()
20 | )
21 | }
22 |
23 | /** Tracks from a tainted Map to the return of its `get` or `getOrDefault` method. */
24 | private predicate mapGetEdge(DataFlow::Node node1, DataFlow::Node node2) {
25 | exists(MethodAccess ma, Method m | m.hasName("get") or m.hasName("getOrDefault") |
26 | m.getDeclaringType().getASourceSupertype*().getQualifiedName().matches("java.util.Map%") and
27 | ma.getMethod() = m and
28 | ma = node2.asExpr() and ma.getQualifier() = node1.asExpr()
29 | )
30 | }
31 |
32 | /** Tracks from a tainted List to the return of various methods that outputs its elements or sublist.*/
33 | private predicate listEdge(DataFlow::Node node1, DataFlow::Node node2) {
34 | exists(MethodAccess ma, Method m | ma.getMethod() = m and
35 | m.getDeclaringType().getASourceSupertype*().getQualifiedName().matches("java.util.List%") and
36 | (
37 | m.getName() = "get" or
38 | m.getName() = "elementAt" or
39 | m.getName() = "elements" or
40 | m.getName() = "firstElement" or
41 | m.getName() = "lastElement" or
42 | m.getName() = "listIterator" or
43 | m.getName() = "subList"
44 | ) and
45 | ma = node2.asExpr() and ma.getQualifier() = node1.asExpr()
46 | ) or
47 | exists(MethodAccess ma, Method m | ma.getMethod() = m and
48 | m.getDeclaringType().getASourceSupertype*().getQualifiedName().matches("java.util.List%") and
49 | m.hasName("copyInto") and node1.asExpr() = ma.getQualifier() and node2.asExpr() = ma.getAnArgument()
50 | )
51 | }
52 |
53 | /** Tracks from a tainted Map to various of its internal data.*/
54 | private predicate keyEntryEdge(DataFlow::Node node1, DataFlow::Node node2) {
55 | exists(MethodAccess ma, Method m |
56 | m.hasName("entrySet") or m.hasName("keySet") or m.hasName("values") |
57 | node1.asExpr() = ma.getQualifier() and node2.asExpr() = ma and
58 | ma.getMethod() = m and
59 | m.getDeclaringType().getASourceSupertype*().getQualifiedName().matches("java.util.Map%")
60 | )
61 | }
62 |
63 | /** Tracks from a tainted element into a Map. Note that this taints the whole map and can increase FP significantly.*/
64 | private predicate mapPutEdge(DataFlow::Node node1, DataFlow::Node node2) {
65 | exists(MethodAccess ma, Method m | m = ma.getMethod() and
66 | (
67 | m.hasName("put") or m.hasName("putAll") or m.hasName("replace") or m.hasName("putIfAbsent") or
68 | m.hasName("replaceAll") or m.hasName("compute") or m.hasName("computeIfAbsent") or m.hasName("merge")
69 | )
70 | and
71 | m.getDeclaringType().getASourceSupertype*().getQualifiedName().matches("java.util.Map%") and
72 | ma.getAnArgument() = node1.asExpr() and ma.getQualifier() = node2.asExpr()
73 | )
74 | }
75 |
76 | /** Tracks from a tainted Collection to various methods that transforms it into different data type.*/
77 | private predicate collectionTransformEdge(DataFlow::Node node1, DataFlow::Node node2) {
78 | exists(MethodAccess ma, Method m | ma.getMethod() = m and
79 | m.getDeclaringType().getASourceSupertype*().getQualifiedName().matches("java.util.Collection%") and
80 | (
81 | m.getName() = "stream" or
82 | m.getName() = "iterator" or
83 | m.getName() = "toArray" or
84 | m.getName() = "parallelStream"
85 | ) and
86 | ma = node2.asExpr() and ma.getQualifier() = node1.asExpr()
87 | ) or
88 | exists(MethodAccess ma, Method m | ma.getMethod() = m and
89 | m.getDeclaringType().getASourceSupertype*().getQualifiedName().matches("java.util.Collection%") and
90 | (
91 | m.getName() = "toArray"
92 | ) and
93 | ma.getQualifier() = node1.asExpr() and ma.getAnArgument() = node2.asExpr()
94 | )
95 | }
96 |
97 | /** Tracks from a tainted Collection to its elements or other representations of its data.*/
98 | predicate collectionsGetEdge(DataFlow::Node node1, DataFlow::Node node2) {
99 | collectionTransformEdge(node1, node2) or
100 | keyEntryEdge(node1, node2) or
101 | listEdge(node1, node2) or
102 | mapGetEdge(node1, node2) or
103 | mapEntryEdge(node1, node2)
104 | }
105 |
106 | /** Tracks from an element into a tainted Collection. Taints the whole collection and may cause significant increase in FP.*/
107 | predicate collectionsPutEdge(DataFlow::Node node1, DataFlow::Node node2) {
108 | mapPutEdge(node1, node2)
109 | }
--------------------------------------------------------------------------------
/semmle-security-java/lib/dataflow_extra/ExtraEdges.qll:
--------------------------------------------------------------------------------
1 | import java
2 | import semmle.code.java.dataflow.DataFlow
3 | import semmle.code.java.dataflow.DefUse
4 | import lib.dataflow_extra.CollectionsEdges
5 | import semmle.code.java.dataflow.TaintTracking
6 |
7 | /** General dataflow edges that are useful for hunting vulnerabilities but not included in the standard library.*/
8 |
9 | /** Holds if `node1` is a tainted value assigned to a field and `node2` is an access to the field. This essentially
10 | * says that if a field is assigned to a tainted value at some point, then any access to that field is considered tainted.
11 | * This has high risk of producing FP, but worth a try to see what you get.
12 | */
13 | predicate isTaintedFieldStep(DataFlow::Node node1, DataFlow::Node node2) {
14 | exists(Field f, RefType t | node1.asExpr() = f.getAnAssignedValue() and node2.asExpr() = f.getAnAccess() and
15 | node1.asExpr().getEnclosingCallable().getDeclaringType() = t and
16 | node2.asExpr().getEnclosingCallable().getDeclaringType() = t
17 | )
18 | }
19 |
20 | /** Tracks an object once any of its field is assigned to something tainted. Can be risky in terms of FP.*/
21 | predicate taintFieldFromQualifier(DataFlow::Node n1, DataFlow::Node n2) {
22 | exists(Field f |
23 | n1 = DataFlow::getFieldQualifier(n2.asExpr()) and
24 | n2.asExpr() = f.getAnAccess()
25 | )
26 | }
27 |
28 | /** Tracks from an object to the output of its `toString` method. */
29 | predicate toStringStep(DataFlow::Node node1, DataFlow::Node node2) {
30 | exists(MethodAccess ma | ma.getMethod().getName() = "toString" and
31 | ma = node2.asExpr() and ma.getQualifier() = node1.asExpr()
32 | )
33 | }
34 |
35 | /** Bundle up the less risky edges that are usually ok for bug hunting.*/
36 | predicate standardExtraEdges(DataFlow::Node node1, DataFlow::Node node2) {
37 | collectionsGetEdge(node1, node2) or
38 | forLoopEdge(node1, node2) or
39 | toStringStep(node1, node2) or
40 | TaintTracking::localAdditionalTaintStep(node1, node2)
41 | }
--------------------------------------------------------------------------------
/semmle-security-java/lib/dataflow_extra/ExtraSources.qll:
--------------------------------------------------------------------------------
1 | import java
2 | import semmle.code.java.dataflow.DataFlow
3 |
4 | /** Extra remote sources that comes from `ServletRequest`.*/
5 | predicate extraRequestSource(DataFlow::Node source) {
6 | exists(Method m, MethodAccess ma | m.getName().matches("get%") and
7 | not (m.getName() = "getAttribute" or m.getName() = "getContextPath") |
8 | (m.getDeclaringType().getASupertype*().hasQualifiedName("javax.servlet.http", "HttpServletRequest")
9 | or m.getDeclaringType().getASupertype*().hasQualifiedName("javax.servlet", "ServletRequest"))and
10 | source.asExpr() = ma and ma.getMethod() = m
11 | )
12 | }
--------------------------------------------------------------------------------
/semmle-security-java/lib/dataflow_extra/Sanitizers.qll:
--------------------------------------------------------------------------------
1 | import java
2 | import semmle.code.java.dataflow.DataFlow
3 |
4 | /** A `Node` that is inside commonly used `Map` methods of rarely used subclasses of `Map`.*/
5 | abstract class MapMethodSanitizer extends DataFlow::Node {
6 | }
7 |
8 | /** A `Node` that is inside the `toString` method of subclasses.*/
9 | abstract class ToStringSanitizer extends DataFlow::Node {
10 | }
11 |
12 | /** Holds if `node` is inside test code. */
13 | predicate isNodeInTestCode(DataFlow::Node node) {
14 | node.getEnclosingCallable() instanceof TestMethod
15 | or
16 | node.getEnclosingCallable().getDeclaringType() instanceof TestClass
17 | or
18 | node.asExpr().getFile().getAbsolutePath().toLowerCase().matches("%test%")
19 | }
--------------------------------------------------------------------------------
/semmle-security-java/lib/struts/DataFlow.qll:
--------------------------------------------------------------------------------
1 | import java
2 | import semmle.code.java.dataflow.DataFlow
3 | /** Contains data flow steps that are specific to apache struts2*/
4 |
5 |
6 | /** A method in `ActionProxy` that may return remote user input. */
7 | class ActionProxyGetMethod extends Method {
8 | ActionProxyGetMethod() {
9 | getDeclaringType().getASupertype*().hasQualifiedName("com.opensymphony.xwork2", "ActionProxy") and
10 | (
11 | hasName("getMethod") or
12 | hasName("getNamespace") or
13 | hasName("getActionName")
14 | )
15 | }
16 | }
17 |
18 | /** The class `ActionMapping`.*/
19 | class ActionMapping extends RefType {
20 | ActionMapping() {
21 | hasQualifiedName("org.apache.struts2.dispatcher.mapper", "ActionMapping")
22 | }
23 | }
24 |
25 | /** A method in `ActionMapper` that returns a field that may be tainted.*/
26 | class ActionMappingGetMethod extends Method {
27 | ActionMappingGetMethod() {
28 | getDeclaringType() instanceof ActionMapping and
29 | (
30 | hasName("getName") or
31 | hasName("getNamespace") or
32 | hasName("getMethod") or
33 | hasName("getParams") or
34 | hasName("getExtension")
35 | )
36 | }
37 | }
38 |
39 | /** Holds if `source` is a remote user input in struts. */
40 | predicate isRemoteUserInputSource(DataFlow::Node source) {
41 | source.asExpr().(MethodAccess).getMethod() instanceof ActionProxyGetMethod
42 | }
43 |
44 | /** Tracks through constructor and getter of `ActionMapping`.*/
45 | predicate actionMapperEdge(DataFlow::Node node1, DataFlow::Node node2) {
46 | exists(ConstructorCall c | c.getAnArgument() = node1.asExpr() and
47 | c.getConstructedType() instanceof ActionMapping and c = node2.asExpr()
48 | ) or
49 | exists(MethodAccess ma | ma.getMethod() instanceof ActionMappingGetMethod and
50 | node1.asExpr() = ma.getQualifier() and node2.asExpr() = ma
51 | )
52 | }
--------------------------------------------------------------------------------
/semmle-security-java/lib/struts/OGNL.qll:
--------------------------------------------------------------------------------
1 | import java
2 | import semmle.code.java.dataflow.DataFlow
3 | import semmle.code.java.dataflow.DataFlow3
4 | import lib.dataflow_extra.CollectionsEdges
5 | import lib.dataflow_extra.ExtraEdges
6 | import lib.struts.Sanitizers
7 | import lib.dataflow_extra.Sanitizers
8 |
9 | /** Contains classes and predicates related to the use of ognl.*/
10 |
11 | class OgnlUtil extends RefType {
12 | OgnlUtil() {
13 | hasQualifiedName("com.opensymphony.xwork2.ognl", "OgnlUtil")
14 | }
15 | }
16 |
17 | /** Holds when `sink` is an argument to a call that ended up executing it as ognl.*/
18 | predicate isOgnlSink(DataFlow::Node sink) {
19 | exists(MethodAccess ma | (ma.getMethod().hasName("compileAndExecute")) and
20 | ma.getMethod().getDeclaringType() instanceof OgnlUtil and
21 | sink.asExpr() = ma.getArgument(0)
22 | )
23 | }
24 |
25 | /** Tracks parameters of a `Method` that ended up being evaluated as ognl.*/
26 | class OgnlCallConfiguration extends DataFlow3::Configuration {
27 | OgnlCallConfiguration() {
28 | this = "OgnlCallConfiguration"
29 | }
30 |
31 | override predicate isSource(DataFlow::Node source) {
32 | exists(Method m | m.getAParameter() = source.asParameter() and
33 | source.asParameter().getType() instanceof TypeString
34 | )
35 | }
36 |
37 | override predicate isSink(DataFlow::Node sink) {
38 | isOgnlSink(sink)
39 | }
40 |
41 | override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
42 | standardExtraEdges(node1, node2) or
43 | collectionsPutEdge(node1, node2)
44 | }
45 |
46 | override predicate isBarrier(DataFlow::Node node) {
47 | ognlSanitizers(node) or
48 | node instanceof StrutsTestSanitizer or
49 | node instanceof ToStringSanitizer or
50 | node instanceof MapMethodSanitizer
51 | }
52 | }
53 |
54 | /** A `Method` whose parameter ended gets evaluated as ognl.*/
55 | class OgnlCallMethod extends Method {
56 | OgnlCallMethod() {
57 | exists(OgnlCallConfiguration cfg, DataFlow::Node source |
58 | cfg.hasFlow(source, _) and source.asParameter() = this.getAParameter()
59 | ) and
60 | not hasName("completeExpressionIfAltSyntax") and
61 | not hasName("stripExpressionIfAltSyntax") and
62 | not hasName("setLocation")
63 | }
64 | }
65 |
66 | /** An `OgnlCallMethod` that is not used by another `OgnlCallMethod`.*/
67 | class OgnlEntryPointMethod extends OgnlCallMethod {
68 | OgnlEntryPointMethod() {
69 | exists(Method m | m.polyCalls(this) and not m instanceof OgnlCallMethod)
70 | }
71 | }
--------------------------------------------------------------------------------
/semmle-security-java/lib/struts/README.md:
--------------------------------------------------------------------------------
1 | #Struts QL libraries
2 |
3 | This contains project specific libraries for Apache Struts. You can import these libraries in your custom queries and use them on snapshots of [Apache Struts].(https://lgtm.com/projects/g/apache/struts)
4 |
--------------------------------------------------------------------------------
/semmle-security-java/lib/struts/Sanitizers.qll:
--------------------------------------------------------------------------------
1 | import java
2 | import semmle.code.java.dataflow.DataFlow
3 | import lib.dataflow_extra.Sanitizers
4 | import OGNL
5 | /** Contains sanitizers that are specific to apache struts 2.*/
6 |
7 | /** A `MapMethodSanitizer` where the `Map` is the `ValueStackShadowMap`.*/
8 | class StrutsMapMethodSanitizer extends MapMethodSanitizer {
9 | StrutsMapMethodSanitizer() {
10 | exists(Method m | (m.hasName("get") or m.hasName("containsKey") or m.hasName("entrySet")) and
11 | m.getDeclaringType().getASourceSupertype*().getQualifiedName().matches("java.util.Map%") and
12 | this.getEnclosingCallable() = m
13 | )
14 | }
15 | }
16 |
17 | /** A `ToStringSanitizer` that corresponds to the various `toString` method.*/
18 | class StrutsToStringSanitizer extends ToStringSanitizer {
19 | StrutsToStringSanitizer() {
20 | exists(Method m |
21 | m.hasName("toString") and this.getEnclosingCallable() = m
22 | )
23 | }
24 | }
25 |
26 | /** A `DataFlow::Node` that is inside test code. */
27 | class StrutsTestSanitizer extends DataFlow::Node {
28 | StrutsTestSanitizer() {
29 | isNodeInTestCode(this) or
30 | this.getEnclosingCallable().getDeclaringType().getName().matches("%Mock%")
31 | }
32 | }
33 |
34 | /** Holds if a node flows into a sanitizer method that filters out ognl script.*/
35 | predicate ognlSanitizers(DataFlow::Node node) {
36 | exists(MethodAccess ma, Method m | ma.getMethod() = m and m.hasName("callMethod") and
37 | ma.getAnArgument() = node.asExpr() and m.getDeclaringType() instanceof OgnlUtil
38 | ) or
39 | exists(MethodAccess ma, Method m | m.hasName("cleanupActionName") or m.hasName("cleanupMethodName") |
40 | m = ma.getMethod() and ma.getAnArgument() = node.asExpr() and
41 | m.getDeclaringType().hasQualifiedName("org.apache.struts2.dispatcher.mapper", "DefaultActionMapper")
42 | )
43 | or
44 | exists(VarAccess v | v.getVariable().getType() instanceof NumericType and node.asExpr() = v)
45 | }
--------------------------------------------------------------------------------
/semmle-security-java/queries.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/semmle-security-java/queries/struts/README.md:
--------------------------------------------------------------------------------
1 | # Apache Struts specific queries
2 |
3 | This directory contains security queries specific for [Apache Struts](https://struts.apache.org/). You can run the queries here on Apache Struts snapshots that you get from [LGTM](https://lgtm.com/projects/g/apache/struts). Follow the steps [here](https://help.semmle.com/ql-for-eclipse/Content/WebHelp/basic-usage.html) to import the snapshot for Struts and run the queries. Many of the queries here are used for identifying a particular vulnerabilities and you may need to run them on a specific snapshot that contains the vulnerabilities to see the results. Please see the `README` files in the subdirectories that contains the query.
4 |
--------------------------------------------------------------------------------
/semmle-security-java/queries/struts/cve_2018_11776/README.md:
--------------------------------------------------------------------------------
1 | #CVE-2018-11776
2 |
3 | The queries here are used for identifying CVE-2018-11776 and should be used on the following snapshot:
4 |
5 | * [Apache Struts `7fd1622` for `CVE-2018-11776`](https://downloads.lgtm.com/snapshots/java/apache/struts/apache-struts-7fd1622-CVE-2018-11776.zip)
6 |
7 | The blog post write up for the queries `initial.ql` and `final.ql` can be found [here.](https://lgtm.com/blog/apache_struts_CVE-2018-11776)
8 |
9 | The blog post write up for the more detailed queries `ognl_injection_initial.ql` and `ognl_injection_final.ql` can be found [here.](https://lgtm.com/blog/apache_struts_CVE-2018-11776-part2)
10 |
--------------------------------------------------------------------------------
/semmle-security-java/queries/struts/cve_2018_11776/final.ql:
--------------------------------------------------------------------------------
1 | /**
2 | * @name cve-2018-11776 final
3 | * @description Final query for detecting CVE-2018-11776 in Struts.
4 | * @kind path-problem
5 | * @id cve_2018_11776_final
6 | */
7 |
8 |
9 | import java
10 | import lib.struts.DataFlow
11 | import lib.struts.OGNL
12 | import lib.struts.Sanitizers
13 | import lib.dataflow_extra.ExtraEdges
14 | import DataFlow::PathGraph
15 | import semmle.code.java.dataflow.TaintTracking
16 |
17 |
18 | class MappingCfg extends DataFlow::Configuration {
19 | MappingCfg() {
20 | this = "cve 2018-11776"
21 | }
22 |
23 | override predicate isSource(DataFlow::Node source) {
24 | isRemoteUserInputSource(source)
25 | }
26 |
27 | override predicate isSink(DataFlow::Node sink) {
28 | isOgnlSink(sink)
29 | }
30 |
31 | override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
32 | TaintTracking::localAdditionalTaintStep(node1, node2) or
33 | isTaintedFieldStep(node1, node2)
34 | }
35 |
36 | override predicate isBarrier(DataFlow::Node node) {
37 | node instanceof MapMethodSanitizer or
38 | node instanceof ToStringSanitizer
39 | }
40 | }
41 |
42 | from MappingCfg cfg, DataFlow::PathNode source, DataFlow::PathNode sink
43 | where cfg.hasFlowPath(source, sink)
44 | select source, source, sink, "This user input flows to an $@.", sink, "OGNL sink"
--------------------------------------------------------------------------------
/semmle-security-java/queries/struts/cve_2018_11776/initial.ql:
--------------------------------------------------------------------------------
1 | /**
2 | * @name cve-2018-11776 final
3 | * @description Final query for detecting CVE-2018-11776 in Struts.
4 | * @kind path-problem
5 | * @id cve_2018_11776_final
6 | */
7 |
8 |
9 | import java
10 | import lib.struts.DataFlow
11 | import lib.struts.OGNL
12 | import lib.struts.Sanitizers
13 | import lib.dataflow_extra.ExtraEdges
14 | import DataFlow::PathGraph
15 | import semmle.code.java.dataflow.TaintTracking
16 |
17 |
18 | class MappingCfg extends DataFlow::Configuration {
19 | MappingCfg() {
20 | this = "cve 2018-11776"
21 | }
22 |
23 | override predicate isSource(DataFlow::Node source) {
24 | isRemoteUserInputSource(source)
25 | }
26 |
27 | override predicate isSink(DataFlow::Node sink) {
28 | isOgnlSink(sink)
29 | }
30 |
31 | override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
32 | TaintTracking::localAdditionalTaintStep(node1, node2) or
33 | isTaintedFieldStep(node1, node2)
34 | }
35 | }
36 |
37 | from MappingCfg cfg, DataFlow::PathNode source, DataFlow::PathNode sink
38 | where cfg.hasFlowPath(source, sink)
39 | select source, source, sink, "This user input flows to an $@.", sink, "OGNL sink"
--------------------------------------------------------------------------------
/semmle-security-java/queries/struts/cve_2018_11776/ognl_Injection_final.ql:
--------------------------------------------------------------------------------
1 | /**
2 | * @name Ognl injection
3 | * @description Identifies where remote user input may get evaluated as Ognl expression.
4 | * @kind path-problem
5 | * @problem.severity error
6 | * @id OgnlInjection
7 | */
8 |
9 | import java
10 | import semmle.code.java.dataflow.FlowSources
11 | import semmle.code.java.dataflow.TaintTracking
12 | import semmle.code.java.frameworks.Servlets
13 | import semmle.code.java.dataflow.internal.DataFlowUtil
14 | import DataFlow::PathGraph
15 | import lib.struts.Sanitizers
16 | import lib.dataflow_extra.ExtraEdges
17 | import lib.dataflow_extra.CollectionsEdges
18 | import lib.dataflow_extra.ExtraSources
19 | import lib.struts.OGNL
20 |
21 | class OgnlInjectionCfg extends DataFlow::Configuration {
22 | OgnlInjectionCfg() {
23 | this = "ognl injection final"
24 | }
25 |
26 | override predicate isSource(DataFlow::Node source) {
27 | source instanceof RemoteUserInput or extraRequestSource(source)
28 | }
29 |
30 | override predicate isSink(DataFlow::Node sink) {
31 | isOgnlSink(sink)
32 | }
33 |
34 | override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
35 | standardExtraEdges(node1, node2) or
36 | collectionsPutEdge(node1, node2) or
37 | taintStringFieldFromQualifier(node1, node2) or
38 | isTaintedFieldStep(node1, node2)
39 | }
40 |
41 | override predicate isBarrier(DataFlow::Node node) {
42 | node instanceof StrutsTestSanitizer
43 | or
44 | ognlSanitizers(node)
45 | or
46 | node instanceof ToStringSanitizer
47 | or
48 | node instanceof MapMethodSanitizer
49 | or
50 | restfulMapperSanitizer(node)
51 | or
52 | tagUtilsSanitizer(node)
53 | or
54 | exists(MethodAccess ma, FieldAccess fa | ma.getMethod().hasName("get") and
55 | ma.getQualifier() = fa and fa.getField().hasName("validatorCache") and
56 | fa.getField().getDeclaringType().hasName("DefaultActionValidatorManager") and
57 | node.asExpr() = ma
58 | )
59 | or
60 | actionContextSanitizer(node)
61 | }
62 | }
63 |
64 | /** Tracks from tainted object to its field access when the field is of type string.*/
65 | predicate taintStringFieldFromQualifier(DataFlow::Node node1, DataFlow::Node node2) {
66 | taintFieldFromQualifier(node1, node2) and
67 | exists(Field f | f.getAnAccess() = node2.asExpr() and f.getType() instanceof TypeString)
68 | }
69 |
70 | /** Filters out the internals of `ActionContext`, which are unlikely to be of user control.*/
71 | predicate actionContextSanitizer(DataFlow::Node node) {
72 | exists(MethodAccess ma, Method m | ma.getMethod() = m and m.getDeclaringType().hasName("ActionContext") and
73 | m.hasName("get") and node.asExpr() = ma
74 | )
75 | }
76 |
77 | /** Filters out the cases where `RestfulActionMapper` is used.*/
78 | predicate restfulMapperSanitizer(DataFlow::Node node) {
79 | node.asExpr().getEnclosingCallable().hasName("getUriFromActionMapping") and
80 | node.asExpr().getEnclosingCallable().getDeclaringType().hasName("RestfulActionMapper")
81 | }
82 |
83 | /** Filters out cases where jsp file is exposed. Not considered as vulnerable, see https://issues.apache.org/jira/browse/WW-4945*/
84 | predicate tagUtilsSanitizer(DataFlow::Node node) {
85 | node.asExpr().getEnclosingCallable().getDeclaringType().hasName("TagUtils") and
86 | node.asExpr().getEnclosingCallable().hasName("buildNamespace")
87 | }
88 |
89 | /** Filters out results that we've already seen, use and modify this to highlight results in different files.*/
90 | predicate knowResultsSanitizer(DataFlow::Node node) {
91 | node.asExpr().getFile().getBaseName() = "ServletUrlRenderer.java"
92 | or
93 | node.asExpr().getFile().getBaseName() = "PostbackResult.java"
94 | or
95 | node.asExpr().getFile().getBaseName() = "ActionChainResult.java"
96 | or
97 | node.asExpr().getFile().getBaseName() = "ServletActionRedirectResult.java"
98 | or
99 | node.asExpr().getFile().getBaseName() = "PortletActionRedirectResult.java"
100 | }
101 |
102 | from OgnlInjectionCfg cfg, DataFlow::PathNode source, DataFlow::PathNode sink
103 | where cfg.hasFlowPath(source, sink)
104 | select source,source, sink, "$@ flows to here and is used in OGNL.", sink, "User input"
--------------------------------------------------------------------------------
/semmle-security-java/queries/struts/cve_2018_11776/ognl_Injection_initial.ql:
--------------------------------------------------------------------------------
1 | /**
2 | * @name Ognl injection
3 | * @description Identifies where remote user input may get evaluated as Ognl expression.
4 | * @kind path-problem
5 | * @problem.severity error
6 | * @id OgnlInjection
7 | */
8 |
9 | import java
10 | import semmle.code.java.dataflow.FlowSources
11 | import semmle.code.java.dataflow.TaintTracking
12 | import semmle.code.java.frameworks.Servlets
13 | import semmle.code.java.dataflow.internal.DataFlowUtil
14 | import DataFlow::PathGraph
15 | import lib.struts.Sanitizers
16 | import lib.dataflow_extra.ExtraEdges
17 | import lib.dataflow_extra.CollectionsEdges
18 | import lib.dataflow_extra.ExtraSources
19 | import lib.struts.OGNL
20 |
21 | class OgnlInjectionCfg extends DataFlow::Configuration {
22 | OgnlInjectionCfg() {
23 | this = "ognl injection initial"
24 | }
25 |
26 | override predicate isSource(DataFlow::Node source) {
27 | source instanceof RemoteUserInput or extraRequestSource(source)
28 | }
29 |
30 | override predicate isSink(DataFlow::Node sink) {
31 | isOgnlSink(sink)
32 | }
33 |
34 | override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
35 | standardExtraEdges(node1, node2) or
36 | collectionsPutEdge(node1, node2) or
37 | taintStringFieldFromQualifier(node1, node2) or
38 | isTaintedFieldStep(node1, node2)
39 | }
40 |
41 | override predicate isBarrier(DataFlow::Node node) {
42 | node instanceof StrutsTestSanitizer
43 | or
44 | ognlSanitizers(node)
45 | or
46 | node instanceof ToStringSanitizer
47 | or
48 | node instanceof MapMethodSanitizer
49 | }
50 | }
51 |
52 | /** Tracks from tainted object to its field access when the field is of type string.*/
53 | predicate taintStringFieldFromQualifier(DataFlow::Node node1, DataFlow::Node node2) {
54 | taintFieldFromQualifier(node1, node2) and
55 | exists(Field f | f.getAnAccess() = node2.asExpr() and f.getType() instanceof TypeString)
56 | }
57 |
58 | from OgnlInjectionCfg cfg, DataFlow::PathNode source, DataFlow::PathNode sink
59 | where cfg.hasFlowPath(source, sink)
60 | select source,source, sink, "$@ flows to here and is used in OGNL.", sink, "User input"
--------------------------------------------------------------------------------
/semmle-security-java/queries/struts/double_evaluation/README.md:
--------------------------------------------------------------------------------
1 | #Double evaluation
2 |
3 | The queries here are used for identifying double evaluations in Struts.
4 |
5 | The blog post write up can be found [here.](https://lgtm.com/blog/apache_struts_double_evaluations) This [snapshot](https://downloads.lgtm.com/snapshots/java/apache/struts/apache-struts-7fd1622-CVE-2018-11776.zip) is used in the blog post, but the query can be run on any Struts snapshot from lgtm.com.
6 |
--------------------------------------------------------------------------------
/semmle-security-java/queries/struts/double_evaluation/double_eval_final.ql:
--------------------------------------------------------------------------------
1 | /**
2 | * @name Double Ognl Evaluation
3 | * @description Fields that are initialized from configuration that may get evaluated twice as Ognl expression.
4 | * @kind path-problem
5 | * @problem.severity error
6 | * @id double_eval
7 | */
8 |
9 | import java
10 | import semmle.code.java.dataflow.FlowSources
11 | import semmle.code.java.dataflow.TaintTracking
12 | import semmle.code.java.frameworks.Servlets
13 | import semmle.code.java.dataflow.internal.DataFlowUtil
14 | import lib.dataflow_extra.CollectionsEdges
15 | import lib.dataflow_extra.ExtraEdges
16 | import lib.struts.Sanitizers
17 | import lib.struts.DataFlow
18 | import lib.dataflow_extra.Sanitizers
19 | import DataFlow::PathGraph
20 | import lib.struts.OGNL
21 |
22 | /** A `Field` whose value is a compile time constant.*/
23 | class ConstantField extends Field {
24 | ConstantField() {
25 | exists(CompileTimeConstantExpr e | this.getAnAssignedValue() = e and
26 | this.isFinal()
27 | )
28 | }
29 | }
30 |
31 | /** A `Class` whose fields may be initialized from a config file.*/
32 | class InputClass extends RefType {
33 | InputClass() {
34 | hasQualifiedName("org.apache.struts2.views.jsp", "StrutsBodyTagSupport") or
35 | hasQualifiedName("org.apache.struts2.components", "Component") or
36 | hasQualifiedName("com.opensymphony.xwork2", "Result") or
37 | hasQualifiedName("org.apache.struts.action", "Action") or
38 | hasQualifiedName("com.opensymphony.xwork2.interceptor", "Interceptor")
39 | }
40 | }
41 |
42 | /** A `Field` that may take value from a config file.*/
43 | class ConfigurableField extends Field {
44 | ConfigurableField() {
45 | getDeclaringType().getASupertype*() instanceof InputClass
46 | }
47 | }
48 |
49 | /** Tracks from a field that may take value from configuration file into the an ognl evaluation method.*/
50 | class InputCfg extends DataFlow::Configuration {
51 | InputCfg() {
52 | this = "input"
53 | }
54 |
55 | override predicate isSource(DataFlow::Node source) {
56 | exists(ConfigurableField f | f.getAnAccess() = source.asExpr() and
57 | not f instanceof ConstantField)
58 | or
59 | //`ActionConfig` params are also taken from configuration.
60 | exists(MethodAccess ma, Method m | ma.getMethod() = m and
61 | m.getDeclaringType().hasName("ActionConfig") and
62 | m.hasName("getParams") and source.asExpr() = ma
63 | )
64 | }
65 |
66 | override predicate isSink(DataFlow::Node sink) {
67 | exists(MethodAccess ma, OgnlEntryPointMethod entry, Method m | ma.getMethod() = m and
68 | ma.getAnArgument() = sink.asExpr() and entry.overridesOrInstantiates*(m)
69 | )
70 | }
71 |
72 | override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
73 | standardExtraEdges(node1, node2) or
74 | collectionsPutEdge(node1, node2) or
75 | actionMapperEdge(node1, node2)
76 | }
77 |
78 | override predicate isBarrier(DataFlow::Node node) {
79 | node instanceof StrutsTestSanitizer
80 | or
81 | ognlSanitizers(node)
82 | or
83 | node instanceof ToStringSanitizer
84 | or
85 | node instanceof MapMethodSanitizer
86 | }
87 | }
88 |
89 | class DoubleEvalConfig extends DataFlow::Configuration {
90 | DoubleEvalConfig() {
91 | this = "doubleEvalConfig"
92 | }
93 |
94 | override predicate isSource(DataFlow::Node source) {
95 | exists(MethodAccess ma, OgnlEntryPointMethod entry, Method m | ma.getMethod() = m and
96 | source.asExpr() = ma and entry.overridesOrInstantiates*(m)
97 | )
98 | }
99 |
100 | override predicate isSink(DataFlow::Node sink) {
101 | exists(MethodAccess ma, OgnlEntryPointMethod entry, Method m, int i | ma.getMethod() = m and
102 | sink.asExpr() = ma.getArgument(i) and entry.overridesOrInstantiates*(m) and
103 | m.getParameter(i).getType() instanceof TypeString
104 | ) or
105 | isOgnlSink(sink)
106 | }
107 |
108 |
109 | override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
110 | standardExtraEdges(node1, node2) or
111 | collectionsPutEdge(node1, node2) or
112 | actionMapperEdge(node1, node2)
113 | }
114 |
115 | override predicate isBarrier(DataFlow::Node node) {
116 | ognlSanitizers(node) or
117 | node instanceof StrutsTestSanitizer or
118 | node instanceof ToStringSanitizer or
119 | node instanceof MapMethodSanitizer or
120 | //Stops when we reach an `OgnlEntryPointMethod` to cut down on duplicate results.
121 | exists(OgnlEntryPointMethod m, DataFlow::Node n |TaintTracking::localTaint(n, node) and m.getAParameter() = n.asParameter()) or
122 | exists(ReturnStmt stmt, DataFlow::Node rtn | stmt.getResult() = rtn.asExpr() and TaintTracking::localTaint(node, rtn) and
123 | stmt.getEnclosingCallable() instanceof OgnlEntryPointMethod)
124 | }
125 | }
126 |
127 | from DoubleEvalConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink,
128 | InputCfg input, DataFlow::Node inputSrc, DataFlow::Node inputSink
129 | where cfg.hasFlowPath(source, sink) and input.hasFlow(inputSrc, inputSink) and
130 | //use call site of `InputCfg` as source of `DoubleEvalConfig`
131 | exists(MethodAccess ma | ma = source.getNode().asExpr() and ma.getAnArgument() = inputSink.asExpr()) and
132 | //Remove `circular` evaluations
133 | not exists(MethodAccess ma | source.getNode().asExpr() = ma and sink.getNode().asExpr() = ma.getAnArgument()) and
134 | //Cut down on paths that contains one another
135 | not exists(DataFlow::Node s | TaintTracking::localTaintStep+(s, inputSrc))
136 | select source, source, sink, "$@ from configuration first $@ and then evaluated $@.", inputSrc, "Input", source, "evaluated", sink, "here"
--------------------------------------------------------------------------------