├── .classpath
├── .gitignore
├── .project
├── .settings
├── org.eclipse.core.resources.prefs
├── org.eclipse.jdt.core.prefs
└── org.eclipse.m2e.core.prefs
├── .travis.yml
├── LICENSE
├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── gov
│ │ └── ornl
│ │ └── stucco
│ │ ├── RelationExtractor.java
│ │ ├── graph
│ │ ├── Edge.java
│ │ └── Vertex.java
│ │ ├── model
│ │ └── CyberRelation.java
│ │ └── pattern
│ │ ├── ExactPattern.java
│ │ ├── FuzzyPattern.java
│ │ ├── MatchingPattern.java
│ │ ├── ParseTreePattern.java
│ │ ├── Pattern.java
│ │ ├── Patterns.java
│ │ ├── elements
│ │ ├── CyberEntity.java
│ │ ├── POS.java
│ │ ├── PatternElement.java
│ │ ├── Token.java
│ │ └── TreeElement.java
│ │ └── utils
│ │ └── PatternLoader.java
└── resources
│ ├── patterns
│ └── patterns_relations.json
│ └── patterns_relations_abbrev.json
└── test
└── java
└── gov
└── ornl
└── stucco
└── RelationExtractorTest.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | *.DS_Store
3 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | relation-extractor
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.m2e.core.maven2Builder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.jdt.core.javanature
21 | org.eclipse.m2e.core.maven2Nature
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | encoding//src/main/java/gov/ornl/stucco/RelationExtractor.java=UTF-8
3 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
4 | org.eclipse.jdt.core.compiler.compliance=1.7
5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
7 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
8 | org.eclipse.jdt.core.compiler.source=1.7
9 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.m2e.core.prefs:
--------------------------------------------------------------------------------
1 | activeProfiles=
2 | eclipse.preferences.version=1
3 | resolveWorkspaceProjects=true
4 | version=1
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - oraclejdk7
4 | - openjdk7
5 | - oraclejdk8
6 | before_install:
7 | - mvn scm:checkout -Dmodule.name=entity-extractor
8 | - cd entity-extractor
9 | - mvn clean install
10 | - cd ..
11 | after_success:
12 | - wget https://raw.githubusercontent.com/stucco/test/master/rerun-test.sh
13 | - chmod a+x ./rerun-test.sh
14 | - ./rerun-test.sh
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This software is freely distributable under the terms of the MIT License.
2 |
3 | Copyright (c) UT-Battelle, LLC (the "Original Author")
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS, THE U.S. GOVERNMENT, OR UT-BATTELLE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Relation Extraction
2 | Library to create vertices and edges from a document annotated with cyber-entity labels and a list of relationship patterns between these cyber entities.
3 |
4 | ## Dependency
5 | The Relation Extraction library shares object models with the Entity Extraction library. To install the dependency locally:
6 |
7 | mvn scm:checkout -Dmodule.name=entity-extractor
8 | cd entity-extractor
9 | mvn clean install
10 |
11 | ## Entity Types
12 | * Software
13 | * Vendor
14 | * Product
15 | * Version
16 | * File
17 | * Name
18 | * Function
19 | * Name
20 | * Vulnerability
21 | * Name
22 | * Description
23 | * CVE
24 | * MS
25 |
26 | ## Relationship Types
27 | * ExploitTargetRelatedObservable Edge
28 |
29 | Exploit Target (e.g. vulnerability) --> Observable (e.g. software)
30 |
31 | * Sub-Observable Edge
32 |
33 | Observable (e.g. software) --> Observable (e.g. file)
34 |
35 | * Software, File, Function, Vulnerability Vertices
36 |
37 | Software/file/function/vulnerability properties are part of the same vertex
38 |
39 | Example: "... **MS15-035**, which addresses a **remote code execution** bug ..."
40 | "MS15-035" is extracted as a vulnerability MS property, and "remote code execution" is extracted as a vulnerability description property. This type of relationship indicates that both properties are describing the same vulnerability object.
41 |
42 |
43 | ## Relationship Patterns
44 | These patterns are defined in a JSON-formatted file. There are three types of patterns we will need to find:
45 |
46 | * The exact-match pattern consists of at least two cyber-entity labels, and words or part-of-speech (pos) tags. The annotated document must match the pattern exactly with no extra words.
47 |
48 | Example Text: “Tomcat from Apache”
49 | Pattern: , "from",
50 |
51 | * The fuzzy-match pattern begins and ends with cyber-entity labels, but it allows for extra words to be present in the document that are not reflected in the pattern. The words, or pos tags, in the pattern must appear in the annotated document, but there can be extra words as well. The only restriction is the two entities are no more than 10 words apart in the document.
52 |
53 | Example Text: “Apache Tomcat’s latest update 8.0.22”
54 | Pattern: , “update”,
55 |
56 | * The parse-tree-path pattern defines a path through a sentence’s parse tree, where the first and last elements of the path are labeled cyber entities.
57 |
58 | Example Parse Tree: (NP (NP (NNP Apache) (NNP Tomcat) (POS 's)) (JJS latest))
59 | Pattern: -- NNP -- NP -- NNP --
60 |
61 | The majority of the knowledge graph's ontology is defined within this file, so the file can be modified while the extractor's mechanics remain the same. The file format is as follows:
62 |
63 | {"Patterns": [
64 | {"edgeType": "ExploitTargetRelatedObservable", "patternType": "ExactPattern", "patternSequence": [{"class": "CyberEntity", "value": "sw.product", "vType": "inV"}, {"class": "Token", "value": "update"}, {"class": "Token", "value": "-LRB-"}, {"class": "CyberEntity", "value": "vuln.name", "vType": "outV"}]},
65 | {"vertexType": "software", "patternType": "ExactPattern", "patternSequence": [{"class": "Token", "value": "versions"}, {"class": "Token", "value": "of"}, {"class": "CyberEntity", "value": "sw.product"}, {"class": "Token", "value": "are"}, {"class": "CyberEntity", "value": "sw.version"}, {"class": "POS", "value": "IN"}, {"class": "CyberEntity", "value": "sw.version"}]},
66 | {"vertexType": "software", "patternType": "ParseTreePattern", "patternSequence": [{"class": "CyberEntity", "value": "sw.product"}, {"class": "TreeElement", "value": "NNP"}, ...]},
67 | ...
68 | ] }
69 |
70 |
71 | ## Input
72 | * Output from the [Entity-Extractor](https://github.com/stucco/entity-extractor) as an Annotation object, which represents the sentences, list of words from the text, along with each word's part of speech tag and cyber domain label.
73 | * The String name of the document's source
74 | * A JSON file containing the set of patterns to find in the annotated document
75 |
76 |
77 | ## Current Process
78 | * For each pattern:
79 | * Search the document for candidate instances and for each instance:
80 | * If the pattern type is ExactPattern, then all tokens listed in the pattern sequence must match
81 | * If the pattern type is FuzzyPattern, then all the cyber entities must match those in the pattern sequence with no more than 10 words between them, but there can be other tokens in the document that are not represented in the pattern sequence
82 | * If the pattern type is ParseTreePattern, then the pattern sequence represents a path, between cyber entities, in the parse tree and all elements must match exactly
83 |
84 |
85 | ## Output
86 | * A JSON-formatted subgraph of the vertices and edges is created, which loosely resembles the STIX data model
87 |
88 | ```
89 | { "vertices" :
90 | {
91 | id1 : { "vertexType": "software", "vendor": "Apache", "product": "Tomcat"},
92 | id2 : { "vertexType": "vulnerability", "description": "buffer overflow"},
93 | ...
94 | },
95 | "edges" :
96 | [
97 | {"id": "vuln_Tomcat_1234", "inV": "id1", "outV": "id2", "label": "ExploitTargetRelatedObservable"},
98 | ...
99 | ]
100 | }
101 | ```
102 |
103 | ## Usage
104 | EntityLabeler labeler = new EntityLabeler();
105 | Annotation doc = labeler.getAnnotatedDoc("My Doc", exampleText);
106 | RelationExtractor rx = new RelationExtractor();
107 | String graph = rx.createSubgraph(doc, "My source");
108 |
109 | ## Test
110 | 1) Install the dependency as described [above](https://github.com/stucco/relation-extractor#dependency)
111 |
112 | 2) Run the commands:
113 |
114 | mvn clean package
115 | mvn test
116 |
117 | ## License
118 | This software is freely distributable under the terms of the MIT License.
119 |
120 | Copyright (c) UT-Battelle, LLC (the "Original Author")
121 |
122 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
123 |
124 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
125 |
126 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS, THE U.S. GOVERNMENT, OR UT-BATTELLE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
127 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 | gov.ornl.stucco
4 | relation-extractor
5 | 1.0.0
6 |
7 | UTF-8
8 | true
9 | gov.ornl.stucco.RelationExtractor
10 |
11 |
12 |
13 | gov.ornl.stucco
14 | entity-extractor
15 | 1.0.0
16 |
17 |
18 | edu.stanford.nlp
19 | stanford-corenlp
20 | 3.4.1
21 |
22 |
23 | edu.stanford.nlp
24 | stanford-corenlp
25 | 3.4.1
26 | models
27 |
28 |
29 | com.fasterxml.jackson.core
30 | jackson-databind
31 | 2.7.0
32 |
33 |
34 | junit
35 | junit
36 | 4.8.1
37 | test
38 |
39 |
40 |
41 |
42 |
43 | org.apache.maven.plugins
44 | maven-scm-plugin
45 | 1.9
46 |
47 | scm:git:https://github.com/stucco/${module.name}.git
48 | ${module.name}
49 |
50 |
51 |
52 | org.apache.maven.plugins
53 | maven-compiler-plugin
54 | 3.1
55 |
56 | 1.7
57 | 1.7
58 | true
59 | true
60 | true
61 |
62 |
63 |
64 | compile
65 |
66 | compile
67 |
68 |
69 |
70 |
71 |
72 | org.codehaus.mojo
73 | exec-maven-plugin
74 | 1.2.1
75 |
76 |
77 |
78 | exec
79 |
80 |
81 |
82 |
83 | java
84 | true
85 | false
86 | compile
87 | ${main.class}
88 |
89 |
90 |
91 |
92 |
93 | src/main/resources
94 |
95 | patterns/patterns_relations.json
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/src/main/java/gov/ornl/stucco/RelationExtractor.java:
--------------------------------------------------------------------------------
1 | package gov.ornl.stucco;
2 |
3 | import edu.stanford.nlp.ling.CoreAnnotations.SentencesAnnotation;
4 | import edu.stanford.nlp.ling.CoreAnnotations.TextAnnotation;
5 | import edu.stanford.nlp.ling.CoreAnnotations.TokensAnnotation;
6 | import edu.stanford.nlp.ling.CoreLabel;
7 | import edu.stanford.nlp.pipeline.Annotation;
8 | import edu.stanford.nlp.util.CoreMap;
9 | import gov.ornl.stucco.entity.CyberEntityAnnotator.CyberAnnotation;
10 | import gov.ornl.stucco.entity.EntityLabeler;
11 | import gov.ornl.stucco.graph.Edge;
12 | import gov.ornl.stucco.graph.Vertex;
13 | import gov.ornl.stucco.model.CyberRelation;
14 | import gov.ornl.stucco.pattern.MatchingPattern;
15 | import gov.ornl.stucco.pattern.Pattern;
16 | import gov.ornl.stucco.pattern.Patterns;
17 | import gov.ornl.stucco.pattern.utils.PatternLoader;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | /**
23 | * Main class responsible for creating the vertices from labeled entities,
24 | * and edges from interpreted relationships between the entities.
25 | *
26 | */
27 | public class RelationExtractor {
28 |
29 | public static final String SOURCE_PROPERTY = "source";
30 | private static final String DEFAULT_PATTERNS = "patterns/patterns_relations.json";
31 |
32 | private Patterns patterns;
33 | private List relationships;
34 |
35 | public RelationExtractor() {
36 | this(DEFAULT_PATTERNS);
37 | }
38 |
39 | public RelationExtractor(String patternFile) {
40 | this.patterns = PatternLoader.loadPatterns(patternFile);
41 | this.relationships = new ArrayList();
42 | }
43 |
44 | private void findPatterns(Annotation doc, String source) {
45 | for (Pattern pattern : patterns.getPatterns()) {
46 | MatchingPattern patternClass = pattern.getPattern();
47 | relationships.addAll(patternClass.findPattern(doc));
48 | }
49 | }
50 |
51 | /**
52 | * @param doc annotated version of the unstructured text
53 | * @param source name of the data source
54 | * @return graph in GraphSON format
55 | */
56 | public String createSubgraph(Annotation doc, String source) {
57 | this.findPatterns(doc, source);
58 |
59 | List vertices = new ArrayList();
60 | List edges = new ArrayList();
61 | StringBuilder graphBuilder = new StringBuilder();
62 | for (CyberRelation relation : relationships) {
63 | List relationVertices = relation.getVertexList(source);
64 | List relationEdges = relation.getEdgeList(relationVertices, source);
65 | vertices.addAll(relationVertices);
66 | edges.addAll(relationEdges);
67 | }
68 |
69 | graphBuilder.append("{\"vertices\": {");
70 | for (int i=0; i sentences = doc.get(SentencesAnnotation.class);
107 | for ( CoreMap sentence : sentences) {
108 | // Label cyber entities appropriately
109 | for ( CoreLabel token : sentence.get(TokensAnnotation.class)) {
110 | System.out.println(token.get(TextAnnotation.class) + "\t\t" + token.get(CyberAnnotation.class));
111 | }
112 | System.out.println();
113 | }
114 |
115 | RelationExtractor rx = new RelationExtractor("src/main/resources/patterns_relations_abbrev.json");
116 | System.out.println(rx.createSubgraph(doc, "CNN"));
117 |
118 | }
119 |
120 | }
121 |
--------------------------------------------------------------------------------
/src/main/java/gov/ornl/stucco/graph/Edge.java:
--------------------------------------------------------------------------------
1 | package gov.ornl.stucco.graph;
2 |
3 |
4 | /**
5 | * Represents the relationship between two entities, where the entities are vertices
6 | * and the relationship is an edge in the knowledge graph.
7 | */
8 | public class Edge {
9 | private static final String _type = "edge";
10 |
11 | private String _id;
12 | private String relation;
13 | private String inVertID;
14 | private String outVertID;
15 | private String inVType;
16 | private String outVType;
17 | private String source;
18 |
19 |
20 | public Edge(String id, String label, String inV, String inVType, String outV, String outVType, String source) {
21 | this._id = id;
22 | this.relation = label;
23 | this.inVertID = inV;
24 | this.inVType = inVType;
25 | this.outVertID = outV;
26 | this.outVType = outVType;
27 | this.source = source;
28 | }
29 |
30 | public String get_id() {
31 | return _id;
32 | }
33 |
34 | public void set_id(String _id) {
35 | this._id = _id;
36 | }
37 |
38 | public String get_label() {
39 | return relation;
40 | }
41 |
42 | public void set_label(String _label) {
43 | this.relation = _label;
44 | }
45 |
46 | public String get_inV() {
47 | return inVertID;
48 | }
49 |
50 | public void set_inV(String _inV) {
51 | this.inVertID = _inV;
52 | }
53 |
54 | public String get_outV() {
55 | return outVertID;
56 | }
57 |
58 | public void set_outV(String _outV) {
59 | this.outVertID = _outV;
60 | }
61 |
62 | public String getInVType() {
63 | return inVType;
64 | }
65 |
66 | public void setInVType(String inVType) {
67 | this.inVType = inVType;
68 | }
69 |
70 | public String getOutVType() {
71 | return outVType;
72 | }
73 |
74 | public void setOutVType(String outVType) {
75 | this.outVType = outVType;
76 | }
77 |
78 | public String getSource() {
79 | return source;
80 | }
81 |
82 | public void setSource(String source) {
83 | this.source = source;
84 | }
85 |
86 | public static String getType() {
87 | return _type;
88 | }
89 |
90 | @Override
91 | public int hashCode() {
92 | final int prime = 31;
93 | int result = 1;
94 | result = prime * result + ((_id == null) ? 0 : _id.hashCode());
95 | result = prime * result + ((inVertID == null) ? 0 : inVertID.hashCode());
96 | result = prime * result + ((relation == null) ? 0 : relation.hashCode());
97 | result = prime * result + ((outVertID == null) ? 0 : outVertID.hashCode());
98 | result = prime * result + ((inVType == null) ? 0 : inVType.hashCode());
99 | result = prime * result
100 | + ((outVType == null) ? 0 : outVType.hashCode());
101 | result = prime * result + ((source == null) ? 0 : source.hashCode());
102 | return result;
103 | }
104 |
105 | @Override
106 | public boolean equals(Object obj) {
107 | if (this == obj)
108 | return true;
109 | if (obj == null)
110 | return false;
111 | if (getClass() != obj.getClass())
112 | return false;
113 | Edge other = (Edge) obj;
114 | if (_id == null) {
115 | if (other._id != null)
116 | return false;
117 | } else if (!_id.equals(other._id))
118 | return false;
119 | if (inVertID == null) {
120 | if (other.inVertID != null)
121 | return false;
122 | } else if (!inVertID.equals(other.inVertID))
123 | return false;
124 | if (relation == null) {
125 | if (other.relation != null)
126 | return false;
127 | } else if (!relation.equals(other.relation))
128 | return false;
129 | if (outVertID == null) {
130 | if (other.outVertID != null)
131 | return false;
132 | } else if (!outVertID.equals(other.outVertID))
133 | return false;
134 | if (inVType == null) {
135 | if (other.inVType != null)
136 | return false;
137 | } else if (!inVType.equals(other.inVType))
138 | return false;
139 | if (outVType == null) {
140 | if (other.outVType != null)
141 | return false;
142 | } else if (!outVType.equals(other.outVType))
143 | return false;
144 | if (source == null) {
145 | if (other.source != null)
146 | return false;
147 | } else if (!source.equals(other.source))
148 | return false;
149 | return true;
150 | }
151 |
152 | @Override
153 | public String toString() {
154 | return "[_id=" + _id + ", relation=" + relation + ", inVertID=" + inVertID
155 | + ", outVertID=" + outVertID + ", inVType=" + inVType + ", outVType="
156 | + outVType + ", source=" + source + "]";
157 | }
158 |
159 | public String toGraphSON() {
160 | StringBuilder graph = new StringBuilder();
161 |
162 | graph.append("{");
163 |
164 | graph.append("\"inVertID\":\"");
165 | graph.append(inVertID);
166 | graph.append("\",");
167 |
168 | graph.append("\"outVertID\":\"");
169 | graph.append(outVertID);
170 | graph.append("\",");
171 |
172 | graph.append("\"relation\":\"");
173 | graph.append(relation);
174 |
175 | graph.append("\"}");
176 |
177 | return graph.toString();
178 | }
179 |
180 | }
181 |
--------------------------------------------------------------------------------
/src/main/java/gov/ornl/stucco/graph/Vertex.java:
--------------------------------------------------------------------------------
1 | package gov.ornl.stucco.graph;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | /**
7 | * Represents an entity in the knowledge graph.
8 | *
9 | */
10 | public class Vertex {
11 | private static long uid = 1234;
12 |
13 | private String _id;
14 | private String name;
15 | private String vertexType;
16 | private Map properties;
17 |
18 | public Vertex(String id, String type) {
19 | this._id = id;
20 | this.name = id;
21 | this.vertexType = type;
22 | this.properties = new HashMap();
23 | }
24 |
25 | public Vertex(String type) {
26 | this(String.valueOf(getNextUID()), type);
27 | }
28 |
29 | public String get_id() {
30 | return _id;
31 | }
32 |
33 | public void set_id(String _id) {
34 | this._id = _id;
35 | }
36 |
37 | public String getName() {
38 | return name;
39 | }
40 |
41 | public void setName(String name) {
42 | this.name = name;
43 | }
44 |
45 | public String getVertexType() {
46 | return vertexType;
47 | }
48 |
49 | public void setVertexType(String vertexType) {
50 | this.vertexType = vertexType;
51 | }
52 |
53 | public Map getProperties() {
54 | return properties;
55 | }
56 |
57 | public void setProperties(Map properties) {
58 | this.properties = properties;
59 | }
60 |
61 | public void addProperty(String propertyName, String propertyValue) {
62 | properties.put(propertyName, propertyValue);
63 | }
64 |
65 | public String getProperty(String propertyName) {
66 | String value = null;
67 | if (properties.containsKey(propertyName)) {
68 | value = (String) properties.get(propertyName);
69 | }
70 | return value;
71 | }
72 |
73 | @Override
74 | public int hashCode() {
75 | final int prime = 31;
76 | int result = 1;
77 | result = prime * result + ((_id == null) ? 0 : _id.hashCode());
78 | result = prime * result + ((name == null) ? 0 : name.hashCode());
79 | result = prime * result
80 | + ((properties == null) ? 0 : properties.hashCode());
81 | result = prime * result
82 | + ((vertexType == null) ? 0 : vertexType.hashCode());
83 | return result;
84 | }
85 |
86 | @Override
87 | public boolean equals(Object obj) {
88 | if (this == obj)
89 | return true;
90 | if (obj == null)
91 | return false;
92 | if (getClass() != obj.getClass())
93 | return false;
94 | Vertex other = (Vertex) obj;
95 | if (_id == null) {
96 | if (other._id != null)
97 | return false;
98 | } else if (!_id.equals(other._id))
99 | return false;
100 | if (name == null) {
101 | if (other.name != null)
102 | return false;
103 | } else if (!name.equals(other.name))
104 | return false;
105 | if (properties == null) {
106 | if (other.properties != null)
107 | return false;
108 | } else if (!properties.equals(other.properties))
109 | return false;
110 | if (vertexType == null) {
111 | if (other.vertexType != null)
112 | return false;
113 | } else if (!vertexType.equals(other.vertexType))
114 | return false;
115 | return true;
116 | }
117 |
118 | @Override
119 | public String toString() {
120 | return "[_id=" + _id + ", name=" + name + ", vertexType="
121 | + vertexType + ", properties=" + properties + "]";
122 | }
123 |
124 | public String toJSON() {
125 | StringBuilder graph = new StringBuilder();
126 | graph.append("\"");
127 | graph.append(_id);
128 | graph.append("\": {");
129 |
130 | graph.append("\"name\":\"");
131 | graph.append(name);
132 | graph.append("\",");
133 |
134 | graph.append("\"vertexType\":\"");
135 | if (vertexType.equalsIgnoreCase("sw")) {
136 | graph.append("software");
137 | }
138 | else if (vertexType.equalsIgnoreCase("vuln")) {
139 | graph.append("vulnerability");
140 | }
141 | else {
142 | graph.append(vertexType);
143 | }
144 | graph.append("\",");
145 |
146 | for(String prop : properties.keySet()) {
147 | graph.append("\"");
148 | graph.append(prop);
149 | graph.append("\":\"");
150 | graph.append(properties.get(prop));
151 | graph.append("\",");
152 | }
153 | graph.deleteCharAt(graph.length()-1);
154 |
155 | graph.append("}");
156 |
157 | return graph.toString();
158 | }
159 |
160 | private static long getNextUID() {
161 | uid = uid + 1;
162 | return uid;
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/src/main/java/gov/ornl/stucco/model/CyberRelation.java:
--------------------------------------------------------------------------------
1 | package gov.ornl.stucco.model;
2 |
3 | import gov.ornl.stucco.RelationExtractor;
4 | import gov.ornl.stucco.entity.models.CyberEntityMention;
5 | import gov.ornl.stucco.graph.Edge;
6 | import gov.ornl.stucco.graph.Vertex;
7 |
8 | import java.util.ArrayList;
9 | import java.util.HashSet;
10 | import java.util.List;
11 | import java.util.Set;
12 |
13 | public class CyberRelation {
14 |
15 | private List cyberEntities;
16 | private String relationshipName;
17 | private boolean isEdge;
18 | private Set inVTypes;
19 | private Set outVTypes;
20 |
21 | public CyberRelation(List entities, String relationship, boolean isEdge, Set inVTypes, Set outVTypes) {
22 | this.cyberEntities = entities;
23 | this.relationshipName = relationship;
24 | this.isEdge = isEdge;
25 | this.inVTypes = inVTypes;
26 | this.outVTypes = outVTypes;
27 | }
28 |
29 | public CyberRelation(List entities, String relationship, boolean isEdge) {
30 | this(entities, relationship, isEdge, new HashSet(), new HashSet());
31 | }
32 |
33 | public CyberRelation(String relationship, boolean isEdge) {
34 | this(new ArrayList(), relationship, isEdge);
35 | }
36 |
37 | public List getCyberEntities() {
38 | return cyberEntities;
39 | }
40 |
41 | public void setCyberEntities(List cyberEntities) {
42 | this.cyberEntities = cyberEntities;
43 | }
44 |
45 | public void addCyberEntity(CyberEntityMention cyberEntity) {
46 | this.cyberEntities.add(cyberEntity);
47 | }
48 |
49 | public String getRelationshipName() {
50 | return relationshipName;
51 | }
52 |
53 | public void setRelationshipName(String relationshipName) {
54 | this.relationshipName = relationshipName;
55 | }
56 |
57 | public boolean isEdge() {
58 | return isEdge;
59 | }
60 |
61 | public void setIsEdge(boolean isEdge) {
62 | this.isEdge = isEdge;
63 | }
64 |
65 | public void addInVType(String inVType) {
66 | this.inVTypes.add(inVType);
67 | }
68 |
69 | public void addOutVType(String outVType) {
70 | this.outVTypes.add(outVType);
71 | }
72 |
73 | public void setInVType(Set inVTypeSet) {
74 | this.inVTypes = inVTypeSet;
75 | }
76 |
77 | public void setOutVType(Set outVTypeSet) {
78 | this.outVTypes = outVTypeSet;
79 | }
80 |
81 | public List getVertexList(String source) {
82 | List vertices = new ArrayList();
83 | if (this.isEdge) {
84 | vertices = createVertexList(source);
85 | }
86 | else {
87 | Vertex v = createVertex(source);
88 | if (v != null) {
89 | vertices.add(v);
90 | }
91 | }
92 | return vertices;
93 | }
94 |
95 | private List createVertexList(String source) {
96 | List newVertices = new ArrayList();
97 | if ((this.cyberEntities != null) && (!this.cyberEntities.isEmpty())) {
98 |
99 | for (CyberEntityMention mention : this.cyberEntities) {
100 | Vertex v = null;
101 | v = new Vertex(mention.getType());
102 |
103 | boolean exists = false;
104 | for (int i=newVertices.size()-1; i>=0; i--) {
105 | Vertex existingV = newVertices.get(i);
106 | if ((existingV.getVertexType().equalsIgnoreCase(v.getVertexType())) && (existingV.getProperty(mention.getSubType()) == null)) {
107 | v = existingV;
108 | exists = true;
109 | break;
110 | }
111 | }
112 | v.addProperty(mention.getSubType(), mention.getValue());
113 | v.addProperty(RelationExtractor.SOURCE_PROPERTY, source);
114 | if (!exists) {
115 | newVertices.add(v);
116 | }
117 | }
118 |
119 | }
120 |
121 | return newVertices;
122 | }
123 |
124 | private Vertex createVertex(String source) {
125 | Vertex v = null;
126 |
127 | if ((this.cyberEntities != null) && (!this.cyberEntities.isEmpty())) {
128 | v = new Vertex(this.relationshipName);
129 |
130 | for (CyberEntityMention mention : this.cyberEntities) {
131 | v.addProperty(mention.getSubType(), mention.getValue());
132 | }
133 | v.addProperty(RelationExtractor.SOURCE_PROPERTY, source);
134 |
135 | }
136 |
137 | return v;
138 | }
139 |
140 | public List getEdgeList(List vertices, String source) {
141 | List edges = new ArrayList();
142 |
143 | if (this.isEdge) {
144 | if ((vertices == null) || (vertices.isEmpty())) {
145 | vertices = getVertexList(source);
146 | }
147 |
148 | for (int i=0; i seq, String edgeType, String vertexType) {
26 | super(seq, edgeType, vertexType);
27 | }
28 |
29 | public List findPattern(Annotation doc) {
30 | List relationships = new ArrayList();
31 |
32 | //get the cyber entity elements from the pattern to find in the sentence
33 | //Note: patterns have at least 2 cyber entities to make a vertex or edge
34 | int patternEntityIndex1 = this.getCyberEntityIndex(0);
35 | if (patternEntityIndex1 == -1) {
36 | return relationships;
37 | }
38 | CyberEntity patternEntity1 = (CyberEntity) sequence.get(patternEntityIndex1);
39 | int patternEntityIndex2 = this.getCyberEntityIndex(patternEntityIndex1+1);
40 | if (patternEntityIndex2 == -1) {
41 | return relationships;
42 | }
43 | CyberEntity patternEntity2 = (CyberEntity) sequence.get(patternEntityIndex2);
44 | int patternDistance = patternEntityIndex2 - patternEntityIndex1;
45 |
46 | //collect all document's cyber entity mentions
47 | //Note: patterns can span sentences
48 | //TODO: make CyberEntityMention a doc level annotation??
49 | List entities = new ArrayList();
50 | List sentences = doc.get(SentencesAnnotation.class);
51 | for (CoreMap sentence : sentences) {
52 | List sentenceEntities = sentence.get(CyberEntityMentionsAnnotation.class);
53 | if ((sentenceEntities != null) && (!sentenceEntities.isEmpty())) {
54 | entities.addAll(sentenceEntities);
55 | }
56 | }
57 |
58 | //there can be multiple instances of the same pattern in a given document
59 | for (int j=0; j (mention1.getSentence().get(TokensAnnotation.class)).size()) {
70 | startIndex = (mention1.getSentence().get(TokensAnnotation.class)).size() - startIndex;
71 | startIndex = startIndex * -1;
72 | }
73 |
74 | if ((mention2.getType().equalsIgnoreCase(patternEntity2.getType()) && mention2.getSubType().equalsIgnoreCase(patternEntity2.getSubType())) && (startIndex + patternDistance >= endIndex)) {
75 | if (startIndex + patternDistance == endIndex) {
76 | CyberRelation newRelationship = this.subDocumentMatch(doc, patternEntityIndex1, mention1, mention2, entities, i+1);
77 | if (newRelationship != null) {
78 | relationships.add(newRelationship);
79 | break;
80 | }
81 | else {
82 | //there will not be another possible mention2 within the right token distance
83 | break;
84 | }
85 | }
86 | }
87 | // there cannot be another mention2 that matches token distance
88 | else if (startIndex + patternDistance < endIndex) {
89 | break;
90 | }
91 | }
92 |
93 | }
94 | }
95 |
96 | return relationships;
97 |
98 | }
99 |
100 |
101 | private CyberRelation subDocumentMatch(Annotation doc, int patternIndex, CyberEntityMention mention1, CyberEntityMention mention2, List entities, int mentionIndex) {
102 | //collect the matching cyber entities to be used in the relationship
103 | List relationEntities = new ArrayList();
104 |
105 | //gather the vertex type names that are the inVertex types and those that are the outVertex types
106 | // Set inVTypes = new HashSet();
107 | // Set outVTypes = new HashSet();
108 |
109 | CoreMap testSentence = mention1.getSentence();
110 | int docIndex = mention1.getHeadTokenStart() - patternIndex;
111 | //if the sub document starts in the previous sentence from the first cyber entity, start there
112 | if (docIndex < 0) {
113 | testSentence = doc.get(SentencesAnnotation.class).get(mention1.getSentence().get(SentenceIndexAnnotation.class) - 1);
114 | docIndex = testSentence.get(TokensAnnotation.class).size() + (mention1.getHeadTokenStart() - patternIndex);
115 | }
116 | List tokens = testSentence.get(TokensAnnotation.class);
117 | CoreLabel candidateToken = tokens.get(docIndex);
118 |
119 | //match each pattern element to a consecutive element in the document
120 | for (int i=0; i= tokens.size()) {
126 | tokens = doc.get(SentencesAnnotation.class).get(testSentence.get(SentenceIndexAnnotation.class) + 1).get(TokensAnnotation.class);
127 | candidateToken = tokens.get(0);
128 | }
129 | else {
130 | candidateToken = tokens.get(mention1.getHeadTokenEnd());
131 | }
132 | relationEntities.add(mention1);
133 | // if (this.edgeType != null) {
134 | // if (patternElement.getvType() == PatternElement.edgeVType.inV) {
135 | // inVTypes.add(mention1.getType());
136 | // }
137 | // else if (patternElement.getvType() == PatternElement.edgeVType.outV) {
138 | // outVTypes.add(mention1.getType());
139 | // }
140 | // else {
141 | // System.err.println("Warning: The ExactPattern with '" + this.sequence + "' has an invalid vType definition.");
142 | // }
143 | // }
144 | }
145 | else if (patternElement instanceof CyberEntity) {
146 | if ((mention2.getType().equalsIgnoreCase(((CyberEntity) patternElement).getType())) && (mention2.getSubType().equalsIgnoreCase(((CyberEntity) patternElement).getSubType()))) {
147 | //if the consecutive elements in the document overlap a sentence, go to the next sentence, and continue
148 | if ((mention2.getHeadTokenEnd()) >= tokens.size()) {
149 | tokens = doc.get(SentencesAnnotation.class).get(testSentence.get(SentenceIndexAnnotation.class) + 1).get(TokensAnnotation.class);
150 | candidateToken = tokens.get(0);
151 | }
152 | else {
153 | candidateToken = tokens.get(mention2.getHeadTokenEnd());
154 | }
155 | relationEntities.add(mention2);
156 | // if (this.edgeType != null) {
157 | // if (patternElement.getvType() == PatternElement.edgeVType.inV) {
158 | // inVTypes.add(mention2.getType());
159 | // }
160 | // else if (patternElement.getvType() == PatternElement.edgeVType.outV) {
161 | // outVTypes.add(mention2.getType());
162 | // }
163 | // else {
164 | // System.err.println("Warning: The ExactPattern with '" + this.sequence + "' has an invalid vType definition.");
165 | // }
166 | // }
167 | }
168 | else if (!(candidateToken.get(CyberAnnotation.class).toString()).equalsIgnoreCase(patternElement.getValue())) {
169 | return null;
170 | }
171 | else {
172 | CyberEntityMention newMention = entities.get(mentionIndex);
173 | if(newMention.getHeadTokenStart() + 1 == candidateToken.index()) {
174 | if ((newMention.getType().equalsIgnoreCase(((CyberEntity) patternElement).getType())) && (newMention.getSubType().equalsIgnoreCase(((CyberEntity) patternElement).getSubType()))) {
175 | //if the consecutive elements in the document overlap a sentence, go to the next sentence, and continue
176 | if ((newMention.getHeadTokenEnd()) >= tokens.size()) {
177 | tokens = doc.get(SentencesAnnotation.class).get(testSentence.get(SentenceIndexAnnotation.class) + 1).get(TokensAnnotation.class);
178 | candidateToken = tokens.get(0);
179 | }
180 | else {
181 | candidateToken = tokens.get(newMention.getHeadTokenEnd());
182 | }
183 | mentionIndex = mentionIndex + 1;
184 | relationEntities.add(newMention);
185 | // if (this.edgeType != null) {
186 | // if (patternElement.getvType() == PatternElement.edgeVType.inV) {
187 | // inVTypes.add(newMention.getType());
188 | // }
189 | // else if (patternElement.getvType() == PatternElement.edgeVType.outV) {
190 | // outVTypes.add(newMention.getType());
191 | // }
192 | // else {
193 | // System.err.println("Warning: The ExactPattern with '" + this.sequence + "' has an invalid vType definition.");
194 | // }
195 | // }
196 | }
197 | }
198 | }
199 | }
200 | else if (patternElement instanceof Token) {
201 | if (!candidateToken.get(TextAnnotation.class).equalsIgnoreCase(patternElement.getValue())) {
202 | return null;
203 | }
204 | //if the consecutive elements in the document overlap a sentence, go to the next sentence, and continue
205 | if ((candidateToken.index()) >= tokens.size()) {
206 | tokens = doc.get(SentencesAnnotation.class).get(testSentence.get(SentenceIndexAnnotation.class) + 1).get(TokensAnnotation.class);
207 | candidateToken = tokens.get(0);
208 | }
209 | else {
210 | candidateToken = tokens.get(candidateToken.index());
211 | }
212 | }
213 | else if (patternElement instanceof POS) {
214 | if (!candidateToken.getString(PartOfSpeechAnnotation.class).equalsIgnoreCase(patternElement.getValue())) {
215 | return null;
216 | }
217 | //if the consecutive elements in the document overlap a sentence, go to the next sentence, and continue
218 | if ((candidateToken.index()) >= tokens.size()) {
219 | tokens = doc.get(SentencesAnnotation.class).get(testSentence.get(SentenceIndexAnnotation.class) + 1).get(TokensAnnotation.class);
220 | candidateToken = tokens.get(0);
221 | }
222 | else {
223 | candidateToken = tokens.get(candidateToken.index());
224 | }
225 | }
226 | }
227 |
228 | //build the new cyber-domain vertex or multiple vertices and connecting edge
229 | CyberRelation newRelation = null;
230 | if (this.edgeType != null) {
231 | newRelation = new CyberRelation(relationEntities, this.edgeType, true, this.inVTypes, this.outVTypes);
232 | }
233 | else if (this.vertexType != null) {
234 | newRelation = new CyberRelation(relationEntities, this.vertexType, false);
235 | }
236 |
237 | return newRelation;
238 | }
239 |
240 | private int getCyberEntityIndex(int fromIndex) {
241 | if (fromIndex >= 0) {
242 | for (int i=fromIndex; i seq, String edgeType, String vertexType) {
29 | super(seq, edgeType, vertexType);
30 | }
31 |
32 | public List findPattern(Annotation doc) {
33 | List relationships = new ArrayList();
34 |
35 | // Collect all document's cyber entity mentions
36 | // Note: patterns can span sentences
37 | //TODO: make CyberEntityMention a doc level annotation??
38 | List entities = new ArrayList();
39 | List sentences = doc.get(SentencesAnnotation.class);
40 | for (CoreMap sentence : sentences) {
41 | List sentenceEntities = sentence.get(CyberEntityMentionsAnnotation.class);
42 | if ((sentenceEntities != null) && (!sentenceEntities.isEmpty())) {
43 | entities.addAll(sentenceEntities);
44 | }
45 | }
46 |
47 | //gather the vertex type names that are the inVertex types and those that are the outVertex types
48 | // Set inVTypes = new HashSet();
49 | // Set outVTypes = new HashSet();
50 |
51 | // First and last elements of the sequence should be labeled cyber entities
52 | CyberEntity seqEntity1 = null;
53 | CyberEntity seqEntity2 = null;
54 | PatternElement seqElement = this.sequence.get(0);
55 | if (seqElement instanceof CyberEntity) {
56 | seqEntity1 = (CyberEntity)seqElement;
57 | }
58 | seqElement = this.sequence.get(this.sequence.size()-1);
59 | if (seqElement instanceof CyberEntity) {
60 | seqEntity2 = (CyberEntity)seqElement;
61 | }
62 |
63 | for (int i=0; i entityMentionList = new ArrayList();
81 | entityMentionList.add(docEntity1);
82 | entityMentionList.add(docEntity2);
83 | if (this.edgeType != null) {
84 | CyberRelation newRelation = new CyberRelation(entityMentionList, this.edgeType, true, this.inVTypes, this.outVTypes);
85 | relationships.add(newRelation);
86 | }
87 | else if (this.vertexType != null) {
88 | CyberRelation newRelation = new CyberRelation(entityMentionList, this.vertexType, false);
89 | relationships.add(newRelation);
90 | }
91 | }
92 | }
93 | }
94 | else if (docSentence1.get(SentenceIndexAnnotation.class) + 1 == docSentence2.get(SentenceIndexAnnotation.class)) {
95 | int distance = (docSentence1.get(TokensAnnotation.class).size() - docEntity1.getHeadTokenEnd()) + docEntity2.getHeadTokenStart();
96 | if (distance <= FUZZY_MATCH_DISTANCE) {
97 | if (isBetweenMatch(docSentence1, docSentence2, docEntity1, docEntity2)) {
98 | List entityMentionList = new ArrayList();
99 | entityMentionList.add(docEntity1);
100 | entityMentionList.add(docEntity2);
101 | if (this.edgeType != null) {
102 | CyberRelation newRelation = new CyberRelation(entityMentionList, this.edgeType, true, this.inVTypes, this.outVTypes);
103 | relationships.add(newRelation);
104 | }
105 | else if (this.vertexType != null) {
106 | CyberRelation newRelation = new CyberRelation(entityMentionList, this.vertexType, false);
107 | relationships.add(newRelation);
108 | }
109 | }
110 | }
111 | }
112 |
113 | }
114 |
115 | }
116 | else {
117 | break;
118 | }
119 | }
120 | }
121 |
122 | return relationships;
123 | }
124 |
125 |
126 | private boolean isBetweenMatch(CoreMap docSentence1, CoreMap docSentence2, CyberEntityMention docEntity1, CyberEntityMention docEntity2) {
127 | List tokens = docSentence1.get(TokensAnnotation.class);
128 | int startTokenIndex = docEntity1.getHeadTokenEnd();
129 | int endTokenIndex = docEntity2.getHeadTokenStart();
130 |
131 | //Working with two consecutive sentence, or a single sentence
132 | if (docSentence2 != null) {
133 | endTokenIndex = tokens.size() + docEntity2.getHeadTokenStart() - 1;
134 | tokens.addAll(docSentence2.get(TokensAnnotation.class));
135 | }
136 |
137 | // Loop through all tokens and see that each PatternElement appears
138 | int tokenIndex = startTokenIndex;
139 | int i;
140 | for (i=1; i endTokenIndex) {
159 | return false;
160 | }
161 | }
162 | // If we have matched all PatternElements, this subDocument is a match
163 | if (i == sequence.size()-1) {
164 | return true;
165 | }
166 |
167 | return false;
168 | }
169 |
170 | }
171 |
--------------------------------------------------------------------------------
/src/main/java/gov/ornl/stucco/pattern/MatchingPattern.java:
--------------------------------------------------------------------------------
1 | package gov.ornl.stucco.pattern;
2 |
3 | import edu.stanford.nlp.pipeline.Annotation;
4 | import gov.ornl.stucco.model.CyberRelation;
5 | import gov.ornl.stucco.pattern.elements.CyberEntity;
6 | import gov.ornl.stucco.pattern.elements.PatternElement;
7 |
8 | import java.util.ArrayList;
9 | import java.util.HashSet;
10 | import java.util.List;
11 | import java.util.Set;
12 |
13 | public class MatchingPattern {
14 |
15 | protected List sequence;
16 | protected String edgeType;
17 | protected String vertexType;
18 | protected Set inVTypes;
19 | protected Set outVTypes;
20 |
21 | public MatchingPattern(List seq, String edgeType, String vertexType) {
22 | this.sequence = seq;
23 | this.edgeType = edgeType;
24 | this.vertexType = vertexType;
25 | inVTypes = new HashSet();
26 | outVTypes = new HashSet();
27 | collectVTypes();
28 | }
29 |
30 | public List getSequence() {
31 | return sequence;
32 | }
33 |
34 | public void setSequence(List sequence) {
35 | this.sequence = sequence;
36 | }
37 |
38 | public String getEdgeType() {
39 | return edgeType;
40 | }
41 |
42 | public void setEdgeType(String edgeType) {
43 | this.edgeType = edgeType;
44 | }
45 |
46 | public String getVertexType() {
47 | return vertexType;
48 | }
49 |
50 | public void setVertexType(String vertexType) {
51 | this.vertexType = vertexType;
52 | }
53 |
54 | public Set getInVTypes() {
55 | return inVTypes;
56 | }
57 |
58 | public void setInVTypes(Set inVTypes) {
59 | this.inVTypes = inVTypes;
60 | }
61 |
62 | public void addInVType(String inVType) {
63 | this.inVTypes.add(inVType);
64 | }
65 |
66 | public Set getOutVTypes() {
67 | return outVTypes;
68 | }
69 |
70 | public void setOutVTypes(Set outVTypes) {
71 | this.outVTypes = outVTypes;
72 | }
73 |
74 | public void addOutVType(String outVType) {
75 | this.outVTypes.add(outVType);
76 | }
77 |
78 | public List findPattern(Annotation doc) {
79 | List relationships = new ArrayList();
80 | return relationships;
81 | }
82 |
83 | private void collectVTypes() {
84 | if (this.edgeType != null) {
85 | for (int i=0; i seq, String edgeType, String vertexType) {
23 | super(seq, edgeType, vertexType);
24 | }
25 |
26 | // For each cyber entity mention in the sentence
27 | // 1) Find the head node of the subtree containing all words of the cyber entity mention
28 | // 2) Attempt to find this pattern's sequence of parse-tree elements between each pair of cyber entities
29 | // in this sentence.
30 | public List findPattern(Annotation doc) {
31 | List relationships = new ArrayList();
32 |
33 | List sentences = doc.get(SentencesAnnotation.class);
34 | // Parse trees are only constructed per sentence, so there is no paths
35 | // that cross the sentence boundary.
36 | for (CoreMap sentence : sentences) {
37 | Tree rootTree = sentence.get(TreeAnnotation.class);
38 | List cyberMentions = sentence.get(CyberEntityMentionsAnnotation.class);
39 | if ((cyberMentions == null) || (cyberMentions.isEmpty())) {
40 | continue;
41 | }
42 | Map entitySubtreeMap = new HashMap();
43 |
44 | // Gather subtrees of cyber entity mentions
45 | for (CyberEntityMention cyberMention : cyberMentions) {
46 | Tree sharedHead = getSharedHeadNode(cyberMention, rootTree);
47 | if (sharedHead != null) {
48 | entitySubtreeMap.put(cyberMention, sharedHead);
49 | }
50 | }
51 |
52 | // Attempt to find the pattern's sequence between every two cyber entity mentions
53 | Iterator cyberMentionIter = entitySubtreeMap.keySet().iterator();
54 | while (cyberMentionIter.hasNext()) {
55 | CyberEntityMention cyberMention = cyberMentionIter.next();
56 | Tree subTree = entitySubtreeMap.get(cyberMention);
57 |
58 | // Initial checks include the first cyber mention and its subtree root matches the first two element in the sequence,
59 | // and the second cyber mention, along with its subtree root matches the last two sequence element. Otherwise,
60 | // don't bother comparing the path between.
61 | if ((this.sequence.get(0) instanceof CyberEntity) && (this.sequence.get(this.sequence.size()-1) instanceof CyberEntity)) {
62 | CyberEntity seqFirst = (CyberEntity) this.sequence.get(0);
63 | CyberEntity seqLast = ((CyberEntity) this.sequence.get(this.sequence.size()-1));
64 |
65 | if ((cyberMention.getType().equalsIgnoreCase(seqFirst.getType())) && (cyberMention.getSubType().equalsIgnoreCase(seqFirst.getSubType())) && ((subTree.label().toString()).equalsIgnoreCase(this.sequence.get(1).getValue()))) {
66 | for (CyberEntityMention cyberMention2 : entitySubtreeMap.keySet()) {
67 | Tree subTree2 = entitySubtreeMap.get(cyberMention2);
68 | if ((!cyberMention2.equals(cyberMention, true)) && (cyberMention2.getType().equalsIgnoreCase(seqLast.getType())) && (cyberMention2.getSubType().equalsIgnoreCase(seqLast.getSubType())) && ((subTree2.label().toString()).equalsIgnoreCase(this.sequence.get(this.sequence.size()-2).getValue()))) {
69 |
70 | // Compare the path between elements to the parse-tree portion of the sequence
71 | List pathBetween = rootTree.pathNodeToNode(subTree, subTree2);
72 | if (pathBetween != null) {
73 | int i;
74 | for (i=1; i relationEntityList = new ArrayList();
84 | relationEntityList.add(cyberMention);
85 | relationEntityList.add(cyberMention2);
86 | if (this.edgeType != null) {
87 | CyberRelation newRelation = new CyberRelation(relationEntityList, this.edgeType, true, this.inVTypes, this.outVTypes);
88 | relationships.add(newRelation);
89 | }
90 | else if (this.vertexType != null) {
91 | CyberRelation newRelation = new CyberRelation(relationEntityList, this.vertexType, false);
92 | relationships.add(newRelation);
93 | }
94 | }
95 | }
96 |
97 | }
98 | }
99 | }
100 | }
101 | }
102 | }
103 |
104 | return relationships;
105 | }
106 |
107 | private Tree getSharedHeadNode(CyberEntityMention cyberMention, Tree rootTree) {
108 | Tree currentHead = null;
109 |
110 | // Match the cyber entity word(s) to the parse-tree leaf/leaves
111 | List leaves = rootTree.getLeaves();
112 | int mentionStart = cyberMention.getHeadTokenStart();
113 | int mentionEnd = cyberMention.getHeadTokenEnd() - 1;
114 |
115 | // Find the most dominate node in all paths from the first word in the cyber entity mention
116 | // to each of the other words. If this is a one-word cyber entity, then the POS of the word
117 | // will be the shared head node.
118 | Tree t1 = leaves.get(mentionStart);
119 | currentHead = t1.parent(rootTree);
120 | for (int i=mentionStart+1; i<=mentionEnd; i++) {
121 | Tree t2 = leaves.get(i);
122 | List path = rootTree.pathNodeToNode(t1.parent(rootTree), t2.parent(rootTree));
123 | if (path != null) {
124 | for (Tree pathTree : path) {
125 | if (pathTree.dominates(currentHead)) {
126 | currentHead = pathTree;
127 | }
128 | }
129 | }
130 | }
131 |
132 | return currentHead;
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/gov/ornl/stucco/pattern/Pattern.java:
--------------------------------------------------------------------------------
1 | package gov.ornl.stucco.pattern;
2 |
3 | import gov.ornl.stucco.pattern.elements.PatternElement;
4 |
5 | import java.io.Serializable;
6 | import java.lang.reflect.Constructor;
7 | import java.lang.reflect.InvocationTargetException;
8 | import java.util.List;
9 |
10 | import com.fasterxml.jackson.annotation.JsonGetter;
11 | import com.fasterxml.jackson.annotation.JsonIgnore;
12 | import com.fasterxml.jackson.annotation.JsonProperty;
13 | import com.fasterxml.jackson.annotation.JsonSetter;
14 |
15 | public class Pattern implements Serializable {
16 | private static final long serialVersionUID = 1L;
17 |
18 | @JsonProperty("edgeType")
19 | private String edgeType;
20 |
21 | @JsonProperty("vertexType")
22 | private String vertexType;
23 |
24 | @JsonProperty("patternType")
25 | private String patternType;
26 |
27 | @JsonProperty("patternSequence")
28 | private List patternSequence;
29 |
30 | @JsonIgnore
31 | private MatchingPattern pattern;
32 |
33 | @JsonGetter("edgeType")
34 | public String getEdgeType() {
35 | return edgeType;
36 | }
37 |
38 | @JsonSetter("edgeType")
39 | public void setEdgeType(String edgeType) {
40 | this.edgeType = edgeType;
41 | }
42 |
43 | @JsonGetter("vertexType")
44 | public String getVertexType() {
45 | return vertexType;
46 | }
47 |
48 | @JsonSetter("vertexType")
49 | public void setVertexType(String vertexType) {
50 | this.vertexType = vertexType;
51 | }
52 |
53 | @JsonGetter("patternType")
54 | public String getPatternType() {
55 | return patternType;
56 | }
57 |
58 | @JsonSetter("patternType")
59 | public void setPatternType(String patternType) {
60 | this.patternType = patternType;
61 | }
62 |
63 | @JsonSetter("patternSequence")
64 | public void setPatternSequence(List patternSequence) {
65 | this.patternSequence = patternSequence;
66 | }
67 |
68 | @JsonGetter("patternSequence")
69 | public List getPatternSequence() {
70 | return patternSequence;
71 | }
72 |
73 | public MatchingPattern getPattern() {
74 | this.createPattern();
75 | return pattern;
76 | }
77 |
78 | public void createPattern() {
79 | String patternClassName = Pattern.class.getPackage().getName() + "." + this.patternType;
80 | try {
81 | Class> clas = Pattern.class.getClassLoader().loadClass(patternClassName);
82 | Constructor> constructor = clas.getConstructor(List.class, String.class, String.class);
83 | this.pattern = (MatchingPattern) constructor.newInstance(this.patternSequence, this.edgeType, this.vertexType);
84 | } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) {
85 | e.printStackTrace();
86 | }
87 | }
88 |
89 | @Override
90 | public String toString() {
91 | return "Pattern [edgeType=" + edgeType + ", vertexType=" + vertexType
92 | + ", patternType=" + patternType + ", patternSequence="
93 | + patternSequence + "]";
94 | }
95 |
96 | @Override
97 | public int hashCode() {
98 | final int prime = 31;
99 | int result = 1;
100 | result = prime * result
101 | + ((edgeType == null) ? 0 : edgeType.hashCode());
102 | result = prime * result
103 | + ((patternSequence == null) ? 0 : patternSequence.hashCode());
104 | result = prime * result
105 | + ((patternType == null) ? 0 : patternType.hashCode());
106 | result = prime * result
107 | + ((vertexType == null) ? 0 : vertexType.hashCode());
108 | return result;
109 | }
110 |
111 | @Override
112 | public boolean equals(Object obj) {
113 | if (this == obj)
114 | return true;
115 | if (obj == null)
116 | return false;
117 | if (getClass() != obj.getClass())
118 | return false;
119 | Pattern other = (Pattern) obj;
120 | if (edgeType == null) {
121 | if (other.edgeType != null)
122 | return false;
123 | } else if (!edgeType.equals(other.edgeType))
124 | return false;
125 | if (patternSequence == null) {
126 | if (other.patternSequence != null)
127 | return false;
128 | } else if (!patternSequence.equals(other.patternSequence))
129 | return false;
130 | if (patternType == null) {
131 | if (other.patternType != null)
132 | return false;
133 | } else if (!patternType.equals(other.patternType))
134 | return false;
135 | if (vertexType == null) {
136 | if (other.vertexType != null)
137 | return false;
138 | } else if (!vertexType.equals(other.vertexType))
139 | return false;
140 | return true;
141 | }
142 |
143 | }
144 |
--------------------------------------------------------------------------------
/src/main/java/gov/ornl/stucco/pattern/Patterns.java:
--------------------------------------------------------------------------------
1 | package gov.ornl.stucco.pattern;
2 |
3 | import java.io.Serializable;
4 | import java.util.List;
5 |
6 | import com.fasterxml.jackson.annotation.JsonGetter;
7 | import com.fasterxml.jackson.annotation.JsonProperty;
8 | import com.fasterxml.jackson.annotation.JsonSetter;
9 |
10 | public class Patterns implements Serializable {
11 | private static final long serialVersionUID = 1L;
12 |
13 | @JsonProperty("Patterns")
14 | private List patterns;
15 |
16 | @JsonGetter("Patterns")
17 | public List getPatterns() {
18 | return patterns;
19 | }
20 |
21 | @JsonSetter("Patterns")
22 | public void setPatterns(List patterns) {
23 | this.patterns = patterns;
24 | }
25 |
26 | public void addPattern(Pattern newPattern) {
27 | this.patterns.add(newPattern);
28 | }
29 |
30 | @Override
31 | public String toString() {
32 | return "Patterns [patterns=" + patterns + "]";
33 | }
34 |
35 | @Override
36 | public int hashCode() {
37 | final int prime = 31;
38 | int result = 1;
39 | result = prime * result
40 | + ((patterns == null) ? 0 : patterns.hashCode());
41 | return result;
42 | }
43 |
44 | @Override
45 | public boolean equals(Object obj) {
46 | if (this == obj)
47 | return true;
48 | if (obj == null)
49 | return false;
50 | if (getClass() != obj.getClass())
51 | return false;
52 | Patterns other = (Patterns) obj;
53 | if (patterns == null) {
54 | if (other.patterns != null)
55 | return false;
56 | } else if (!patterns.equals(other.patterns))
57 | return false;
58 | return true;
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/gov/ornl/stucco/pattern/elements/CyberEntity.java:
--------------------------------------------------------------------------------
1 | package gov.ornl.stucco.pattern.elements;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 | import com.fasterxml.jackson.annotation.JsonSetter;
5 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
6 | import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
7 |
8 | @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.PROPERTY, property="class")
9 | public class CyberEntity extends PatternElement {
10 |
11 | @JsonIgnore
12 | private String type;
13 |
14 | @JsonIgnore
15 | private String subType;
16 |
17 | @Override
18 | @JsonSetter("value")
19 | public void setValue(String value) {
20 | this.value = value;
21 |
22 | //separate label
23 | if (super.getValue().contains(".")) {
24 | int index = super.getValue().indexOf(".");
25 | this.type = super.getValue().substring(0, index);
26 | this.subType = super.getValue().substring(index + 1);
27 | }
28 | else {
29 | this.type = super.getValue();
30 | this.subType = "";
31 | }
32 | }
33 |
34 | @JsonIgnore
35 | public String getType() {
36 | return type;
37 | }
38 |
39 | @JsonIgnore
40 | public String getSubType() {
41 | return subType;
42 | }
43 |
44 | @Override
45 | public String toString() {
46 | return "CyberEntity=" + value;
47 | }
48 |
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/gov/ornl/stucco/pattern/elements/POS.java:
--------------------------------------------------------------------------------
1 | package gov.ornl.stucco.pattern.elements;
2 |
3 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
4 | import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
5 |
6 | @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.PROPERTY, property="class")
7 | public class POS extends PatternElement {
8 |
9 | @Override
10 | public String toString() {
11 | return "POS=" + value;
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/gov/ornl/stucco/pattern/elements/PatternElement.java:
--------------------------------------------------------------------------------
1 | package gov.ornl.stucco.pattern.elements;
2 |
3 | import com.fasterxml.jackson.annotation.JsonGetter;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.fasterxml.jackson.annotation.JsonSetter;
6 | import com.fasterxml.jackson.annotation.JsonSubTypes;
7 | import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
8 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
9 | import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
10 |
11 | @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.PROPERTY, property="class")
12 | @JsonSubTypes({
13 | @Type(value = CyberEntity.class),
14 | @Type(value = POS.class),
15 | @Type(value = Token.class),
16 | @Type(value = TreeElement.class)
17 | })
18 | public abstract class PatternElement {
19 |
20 | public static enum edgeVType {
21 | outV,
22 | inV
23 | }
24 |
25 | @JsonProperty("value")
26 | protected String value;
27 | @JsonProperty("vType")
28 | protected edgeVType vType;
29 |
30 | @JsonGetter("value")
31 | public String getValue() {
32 | return value;
33 | }
34 |
35 | @JsonSetter("value")
36 | public void setValue(String value) {
37 | this.value = value;
38 | }
39 |
40 | @JsonGetter("vType")
41 | public edgeVType getvType() {
42 | return vType;
43 | }
44 |
45 | @JsonSetter("vType")
46 | public void setvType(edgeVType vType) {
47 | this.vType = vType;
48 | }
49 |
50 | @Override
51 | public String toString() {
52 | return "PatternElement [value=" + value + "]";
53 | }
54 |
55 | @Override
56 | public int hashCode() {
57 | final int prime = 31;
58 | int result = 1;
59 | result = prime * result + ((value == null) ? 0 : value.hashCode());
60 | return result;
61 | }
62 |
63 | @Override
64 | public boolean equals(Object obj) {
65 | if (this == obj)
66 | return true;
67 | if (obj == null)
68 | return false;
69 | if (getClass() != obj.getClass())
70 | return false;
71 | PatternElement other = (PatternElement) obj;
72 | if (value == null) {
73 | if (other.value != null)
74 | return false;
75 | } else if (!value.equals(other.value))
76 | return false;
77 | return true;
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/gov/ornl/stucco/pattern/elements/Token.java:
--------------------------------------------------------------------------------
1 | package gov.ornl.stucco.pattern.elements;
2 |
3 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
4 | import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
5 |
6 | @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.PROPERTY, property="class")
7 | public class Token extends PatternElement {
8 |
9 | @Override
10 | public String toString() {
11 | return "Token=" + value;
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/gov/ornl/stucco/pattern/elements/TreeElement.java:
--------------------------------------------------------------------------------
1 | package gov.ornl.stucco.pattern.elements;
2 |
3 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
4 | import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
5 |
6 | @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.PROPERTY, property="class")
7 | public class TreeElement extends PatternElement {
8 |
9 | @Override
10 | public String toString() {
11 | return "TreeElement=" + value;
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/gov/ornl/stucco/pattern/utils/PatternLoader.java:
--------------------------------------------------------------------------------
1 | package gov.ornl.stucco.pattern.utils;
2 |
3 | import gov.ornl.stucco.pattern.Patterns;
4 |
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.InputStream;
8 |
9 | import com.fasterxml.jackson.databind.DeserializationFeature;
10 | import com.fasterxml.jackson.databind.ObjectMapper;
11 |
12 | public class PatternLoader {
13 | private static ObjectMapper mapper = new ObjectMapper();
14 |
15 | public static Patterns loadPatterns(String patternFile) {
16 | mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
17 |
18 | System.err.println("Loading relationship patterns from '" + patternFile + "'...");
19 | Patterns patterns = null;
20 | try {
21 | InputStream inputStream = PatternLoader.class.getClassLoader().getResourceAsStream(patternFile);
22 | patterns = mapper.readValue(inputStream, Patterns.class);
23 | } catch (Exception e) {
24 | try {
25 | InputStream inputStream = new FileInputStream(new File(patternFile));
26 | patterns = mapper.readValue(inputStream, Patterns.class);
27 | } catch (Exception ex) {
28 | ex.printStackTrace();
29 | }
30 | }
31 |
32 | return patterns;
33 | }
34 |
35 | public static void main(String[] args) {
36 | Patterns patterns = PatternLoader.loadPatterns("patterns_relations.json");
37 | System.out.println(patterns.toString());
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/resources/patterns/patterns_relations.json:
--------------------------------------------------------------------------------
1 | {
2 | "Patterns": [
3 | {
4 | "edgeType": "ExploitTargetRelatedObservable",
5 | "patternSequence": [
6 | {
7 | "class": "CyberEntity",
8 | "vType": "inV",
9 | "value": "sw.product"
10 | },
11 | {
12 | "class": "Token",
13 | "value": "update"
14 | },
15 | {
16 | "class": "Token",
17 | "value": "-LRB-"
18 | },
19 | {
20 | "class": "CyberEntity",
21 | "vType": "outV",
22 | "value": "vuln.name"
23 | }
24 | ],
25 | "patternType": "ExactPattern"
26 | },
27 | {
28 | "patternSequence": [
29 | {
30 | "class": "CyberEntity",
31 | "value": "vuln.description"
32 | },
33 | {
34 | "class": "Token",
35 | "value": "-LRB-"
36 | },
37 | {
38 | "class": "CyberEntity",
39 | "value": "vuln.name"
40 | }
41 | ],
42 | "patternType": "ExactPattern",
43 | "vertexType": "vulnerability"
44 | },
45 | {
46 | "edgeType": "ExploitTargetRelatedObservable",
47 | "patternSequence": [
48 | {
49 | "class": "CyberEntity",
50 | "vType": "outV",
51 | "value": "vuln.ms"
52 | },
53 | {
54 | "class": "Token",
55 | "value": ","
56 | },
57 | {
58 | "class": "Token",
59 | "value": "a"
60 | },
61 | {
62 | "class": "Token",
63 | "value": "flaw"
64 | },
65 | {
66 | "class": "Token",
67 | "value": "in"
68 | },
69 | {
70 | "class": "Token",
71 | "value": "the"
72 | },
73 | {
74 | "class": "CyberEntity",
75 | "vType": "inV",
76 | "value": "sw.product"
77 | }
78 | ],
79 | "patternType": "ExactPattern"
80 | },
81 | {
82 | "edgeType": "ExploitTargetRelatedObservable",
83 | "patternSequence": [
84 | {
85 | "class": "CyberEntity",
86 | "vType": "outV",
87 | "value": "vuln.ms"
88 | },
89 | {
90 | "class": "Token",
91 | "value": "deals"
92 | },
93 | {
94 | "class": "Token",
95 | "value": "with"
96 | },
97 | {
98 | "class": "CyberEntity",
99 | "vType": "inV",
100 | "value": "sw.product"
101 | }
102 | ],
103 | "patternType": "ExactPattern"
104 | },
105 | {
106 | "edgeType": "ExploitTargetRelatedObservable",
107 | "patternSequence": [
108 | {
109 | "class": "CyberEntity",
110 | "vType": "inV",
111 | "value": "sw.product"
112 | },
113 | {
114 | "class": "Token",
115 | "value": "update"
116 | },
117 | {
118 | "class": "CyberEntity",
119 | "vType": "outV",
120 | "value": "vuln.ms"
121 | }
122 | ],
123 | "patternType": "ExactPattern"
124 | },
125 | {
126 | "edgeType": "ExploitTargetRelatedObservable",
127 | "patternSequence": [
128 | {
129 | "class": "CyberEntity",
130 | "vType": "outV",
131 | "value": "vuln.ms"
132 | },
133 | {
134 | "class": "Token",
135 | "value": ","
136 | },
137 | {
138 | "class": "Token",
139 | "value": "which"
140 | },
141 | {
142 | "class": "Token",
143 | "value": "updates"
144 | },
145 | {
146 | "class": "CyberEntity",
147 | "vType": "inV",
148 | "value": "sw.vendor"
149 | },
150 | {
151 | "class": "Token",
152 | "value": "'s"
153 | },
154 | {
155 | "class": "CyberEntity",
156 | "vType": "inV",
157 | "value": "sw.product"
158 | }
159 | ],
160 | "patternType": "ExactPattern"
161 | },
162 | {
163 | "edgeType": "ExploitTargetRelatedObservable",
164 | "patternSequence": [
165 | {
166 | "class": "CyberEntity",
167 | "vType": "inV",
168 | "value": "sw.product"
169 | },
170 | {
171 | "class": "Token",
172 | "value": "-LRB-"
173 | },
174 | {
175 | "class": "CyberEntity",
176 | "vType": "outV",
177 | "value": "vuln.ms"
178 | }
179 | ],
180 | "patternType": "ExactPattern"
181 | },
182 | {
183 | "edgeType": "ExploitTargetRelatedObservable",
184 | "patternSequence": [
185 | {
186 | "class": "CyberEntity",
187 | "vType": "outV",
188 | "value": "vuln.ms"
189 | },
190 | {
191 | "class": "Token",
192 | "value": "flaw"
193 | },
194 | {
195 | "class": "Token",
196 | "value": "in"
197 | },
198 | {
199 | "class": "CyberEntity",
200 | "vType": "inV",
201 | "value": "sw.product"
202 | }
203 | ],
204 | "patternType": "FuzzyPattern"
205 | },
206 | {
207 | "patternSequence": [
208 | {
209 | "class": "CyberEntity",
210 | "value": "vuln.ms"
211 | },
212 | {
213 | "class": "Token",
214 | "value": "is"
215 | },
216 | {
217 | "class": "Token",
218 | "value": "also"
219 | },
220 | {
221 | "class": "Token",
222 | "value": "related"
223 | },
224 | {
225 | "class": "Token",
226 | "value": "to"
227 | },
228 | {
229 | "class": "CyberEntity",
230 | "value": "vuln.description"
231 | }
232 | ],
233 | "patternType": "ExactPattern",
234 | "vertexType": "vulnerability"
235 | },
236 | {
237 | "patternSequence": [
238 | {
239 | "class": "CyberEntity",
240 | "value": "vuln.ms"
241 | },
242 | {
243 | "class": "Token",
244 | "value": "which"
245 | },
246 | {
247 | "class": "Token",
248 | "value": "addresses"
249 | },
250 | {
251 | "class": "CyberEntity",
252 | "value": "vuln.description"
253 | }
254 | ],
255 | "patternType": "FuzzyPattern",
256 | "vertexType": "vulnerability"
257 | },
258 | {
259 | "patternSequence": [
260 | {
261 | "class": "CyberEntity",
262 | "value": "vuln.ms"
263 | },
264 | {
265 | "class": "Token",
266 | "value": "which"
267 | },
268 | {
269 | "class": "Token",
270 | "value": "addresses"
271 | },
272 | {
273 | "class": "Token",
274 | "value": "another"
275 | },
276 | {
277 | "class": "CyberEntity",
278 | "value": "vuln.description"
279 | }
280 | ],
281 | "patternType": "ExactPattern",
282 | "vertexType": "vulnerability"
283 | },
284 | {
285 | "patternSequence": [
286 | {
287 | "class": "CyberEntity",
288 | "value": "vuln.ms"
289 | },
290 | {
291 | "class": "Token",
292 | "value": "is"
293 | },
294 | {
295 | "class": "Token",
296 | "value": "also"
297 | },
298 | {
299 | "class": "Token",
300 | "value": "a"
301 | },
302 | {
303 | "class": "CyberEntity",
304 | "value": "vuln.description"
305 | }
306 | ],
307 | "patternType": "ExactPattern",
308 | "vertexType": "vulnerability"
309 | },
310 | {
311 | "patternSequence": [
312 | {
313 | "class": "CyberEntity",
314 | "value": "vuln.ms"
315 | },
316 | {
317 | "class": "Token",
318 | "value": ","
319 | },
320 | {
321 | "class": "Token",
322 | "value": "deals"
323 | },
324 | {
325 | "class": "Token",
326 | "value": "with"
327 | },
328 | {
329 | "class": "Token",
330 | "value": "a"
331 | },
332 | {
333 | "class": "CyberEntity",
334 | "value": "vuln.description"
335 | }
336 | ],
337 | "patternType": "ExactPattern",
338 | "vertexType": "vulnerability"
339 | },
340 | {
341 | "patternSequence": [
342 | {
343 | "class": "CyberEntity",
344 | "value": "vuln.ms"
345 | },
346 | {
347 | "class": "Token",
348 | "value": "relates"
349 | },
350 | {
351 | "class": "Token",
352 | "value": "to"
353 | },
354 | {
355 | "class": "Token",
356 | "value": "a"
357 | },
358 | {
359 | "class": "CyberEntity",
360 | "value": "vuln.description"
361 | }
362 | ],
363 | "patternType": "ExactPattern",
364 | "vertexType": "vulnerability"
365 | },
366 | {
367 | "patternSequence": [
368 | {
369 | "class": "CyberEntity",
370 | "value": "vuln.ms"
371 | },
372 | {
373 | "class": "Token",
374 | "value": "and"
375 | },
376 | {
377 | "class": "Token",
378 | "value": "it"
379 | },
380 | {
381 | "class": "Token",
382 | "value": "is"
383 | },
384 | {
385 | "class": "Token",
386 | "value": "yet"
387 | },
388 | {
389 | "class": "Token",
390 | "value": "another"
391 | },
392 | {
393 | "class": "CyberEntity",
394 | "value": "vuln.description"
395 | }
396 | ],
397 | "patternType": "ExactPattern",
398 | "vertexType": "vulnerability"
399 | },
400 | {
401 | "patternSequence": [
402 | {
403 | "class": "CyberEntity",
404 | "value": "sw.product"
405 | },
406 | {
407 | "class": "CyberEntity",
408 | "value": "sw.version"
409 | }
410 | ],
411 | "patternType": "ExactPattern",
412 | "vertexType": "software"
413 | },
414 | {
415 | "patternSequence": [
416 | {
417 | "class": "Token",
418 | "value": "versions"
419 | },
420 | {
421 | "class": "Token",
422 | "value": "of"
423 | },
424 | {
425 | "class": "CyberEntity",
426 | "value": "sw.product"
427 | },
428 | {
429 | "class": "Token",
430 | "value": "is"
431 | },
432 | {
433 | "class": "CyberEntity",
434 | "value": "sw.version"
435 | }
436 | ],
437 | "patternType": "ExactPattern",
438 | "vertexType": "software"
439 | },
440 | {
441 | "patternSequence": [
442 | {
443 | "class": "Token",
444 | "value": "versions"
445 | },
446 | {
447 | "class": "Token",
448 | "value": "of"
449 | },
450 | {
451 | "class": "CyberEntity",
452 | "value": "sw.product"
453 | },
454 | {
455 | "class": "Token",
456 | "value": "are"
457 | },
458 | {
459 | "class": "CyberEntity",
460 | "value": "sw.version"
461 | },
462 | {
463 | "class": "POS",
464 | "value": "IN"
465 | },
466 | {
467 | "class": "CyberEntity",
468 | "value": "sw.version"
469 | }
470 | ],
471 | "patternType": "ExactPattern",
472 | "vertexType": "software"
473 | },
474 | {
475 | "patternSequence": [
476 | {
477 | "class": "CyberEntity",
478 | "value": "sw.product"
479 | },
480 | {
481 | "class": "Token",
482 | "value": "to"
483 | },
484 | {
485 | "class": "CyberEntity",
486 | "value": "sw.version"
487 | }
488 | ],
489 | "patternType": "ExactPattern",
490 | "vertexType": "software"
491 | },
492 | {
493 | "patternSequence": [
494 | {
495 | "class": "CyberEntity",
496 | "value": "sw.product"
497 | },
498 | {
499 | "class": "Token",
500 | "value": "affects"
501 | },
502 | {
503 | "class": "CyberEntity",
504 | "value": "sw.version"
505 | }
506 | ],
507 | "patternType": "ExactPattern",
508 | "vertexType": "software"
509 | },
510 | {
511 | "patternSequence": [
512 | {
513 | "class": "CyberEntity",
514 | "value": "sw.version"
515 | },
516 | {
517 | "class": "Token",
518 | "value": "of"
519 | },
520 | {
521 | "class": "CyberEntity",
522 | "value": "sw.product"
523 | }
524 | ],
525 | "patternType": "ExactPattern",
526 | "vertexType": "software"
527 | },
528 | {
529 | "patternSequence": [
530 | {
531 | "class": "CyberEntity",
532 | "value": "sw.vendor"
533 | },
534 | {
535 | "class": "Token",
536 | "value": "products"
537 | },
538 | {
539 | "class": "Token",
540 | "value": ","
541 | },
542 | {
543 | "class": "Token",
544 | "value": "including"
545 | },
546 | {
547 | "class": "CyberEntity",
548 | "value": "sw.product"
549 | },
550 | {
551 | "class": "Token",
552 | "value": ","
553 | },
554 | {
555 | "class": "CyberEntity",
556 | "value": "sw.product"
557 | },
558 | {
559 | "class": "Token",
560 | "value": ","
561 | },
562 | {
563 | "class": "Token",
564 | "value": "and"
565 | },
566 | {
567 | "class": "CyberEntity",
568 | "value": "sw.product"
569 | }
570 | ],
571 | "patternType": "ExactPattern",
572 | "vertexType": "software"
573 | },
574 | {
575 | "patternSequence": [
576 | {
577 | "class": "CyberEntity",
578 | "value": "sw.vendor"
579 | },
580 | {
581 | "class": "Token",
582 | "value": "products"
583 | },
584 | {
585 | "class": "Token",
586 | "value": ","
587 | },
588 | {
589 | "class": "Token",
590 | "value": "including"
591 | },
592 | {
593 | "class": "CyberEntity",
594 | "value": "sw.product"
595 | },
596 | {
597 | "class": "Token",
598 | "value": ","
599 | },
600 | {
601 | "class": "CyberEntity",
602 | "value": "sw.product"
603 | }
604 | ],
605 | "patternType": "ExactPattern",
606 | "vertexType": "software"
607 | },
608 | {
609 | "patternSequence": [
610 | {
611 | "class": "CyberEntity",
612 | "value": "sw.vendor"
613 | },
614 | {
615 | "class": "Token",
616 | "value": "products"
617 | },
618 | {
619 | "class": "Token",
620 | "value": ","
621 | },
622 | {
623 | "class": "Token",
624 | "value": "including"
625 | },
626 | {
627 | "class": "CyberEntity",
628 | "value": "sw.product"
629 | }
630 | ],
631 | "patternType": "ExactPattern",
632 | "vertexType": "software"
633 | },
634 | {
635 | "patternSequence": [
636 | {
637 | "class": "CyberEntity",
638 | "value": "sw.vendor"
639 | },
640 | {
641 | "class": "Token",
642 | "value": "has"
643 | },
644 | {
645 | "class": "Token",
646 | "value": "issued"
647 | },
648 | {
649 | "class": "Token",
650 | "value": "updates"
651 | },
652 | {
653 | "class": "Token",
654 | "value": "for"
655 | },
656 | {
657 | "class": "Token",
658 | "value": "its"
659 | },
660 | {
661 | "class": "CyberEntity",
662 | "value": "sw.version"
663 | },
664 | {
665 | "class": "Token",
666 | "value": "versions"
667 | },
668 | {
669 | "class": "Token",
670 | "value": "of"
671 | },
672 | {
673 | "class": "CyberEntity",
674 | "value": "sw.product"
675 | },
676 | {
677 | "class": "Token",
678 | "value": "and"
679 | },
680 | {
681 | "class": "CyberEntity",
682 | "value": "sw.product"
683 | }
684 | ],
685 | "patternType": "ExactPattern",
686 | "vertexType": "software"
687 | },
688 | {
689 | "patternSequence": [
690 | {
691 | "class": "CyberEntity",
692 | "value": "sw.vendor"
693 | },
694 | {
695 | "class": "Token",
696 | "value": "has"
697 | },
698 | {
699 | "class": "Token",
700 | "value": "issued"
701 | },
702 | {
703 | "class": "Token",
704 | "value": "updates"
705 | },
706 | {
707 | "class": "Token",
708 | "value": "for"
709 | },
710 | {
711 | "class": "Token",
712 | "value": "its"
713 | },
714 | {
715 | "class": "CyberEntity",
716 | "value": "sw.version"
717 | },
718 | {
719 | "class": "Token",
720 | "value": "versions"
721 | },
722 | {
723 | "class": "Token",
724 | "value": "of"
725 | },
726 | {
727 | "class": "CyberEntity",
728 | "value": "sw.product"
729 | }
730 | ],
731 | "patternType": "ExactPattern",
732 | "vertexType": "software"
733 | },
734 | {
735 | "patternSequence": [
736 | {
737 | "class": "CyberEntity",
738 | "value": "sw.product"
739 | },
740 | {
741 | "class": "Token",
742 | "value": "from"
743 | },
744 | {
745 | "class": "CyberEntity",
746 | "value": "sw.vendor"
747 | }
748 | ],
749 | "patternType": "ExactPattern",
750 | "vertexType": "software"
751 | },
752 | {
753 | "patternSequence": [
754 | {
755 | "class": "CyberEntity",
756 | "value": "sw.vendor"
757 | },
758 | {
759 | "class": "Token",
760 | "value": "'s"
761 | },
762 | {
763 | "class": "CyberEntity",
764 | "value": "sw.product"
765 | }
766 | ],
767 | "patternType": "ExactPattern",
768 | "vertexType": "software"
769 | },
770 | {
771 | "patternSequence": [
772 | {
773 | "class": "CyberEntity",
774 | "value": "sw.product"
775 | },
776 | {
777 | "class": "Token",
778 | "value": "are"
779 | },
780 | {
781 | "class": "Token",
782 | "value": "available"
783 | },
784 | {
785 | "class": "Token",
786 | "value": "from"
787 | },
788 | {
789 | "class": "Token",
790 | "value": "the"
791 | },
792 | {
793 | "class": "CyberEntity",
794 | "value": "sw.vendor"
795 | }
796 | ],
797 | "patternType": "ExactPattern",
798 | "vertexType": "software"
799 | },
800 | {
801 | "patternSequence": [
802 | {
803 | "class": "CyberEntity",
804 | "value": "sw.product"
805 | },
806 | {
807 | "class": "Token",
808 | "value": "issued"
809 | },
810 | {
811 | "class": "Token",
812 | "value": "a"
813 | },
814 | {
815 | "class": "Token",
816 | "value": "fix"
817 | },
818 | {
819 | "class": "Token",
820 | "value": "for"
821 | },
822 | {
823 | "class": "Token",
824 | "value": "its"
825 | },
826 | {
827 | "class": "CyberEntity",
828 | "value": "sw.vendor"
829 | }
830 | ],
831 | "patternType": "ExactPattern",
832 | "vertexType": "software"
833 | },
834 | {
835 | "patternSequence": [
836 | {
837 | "class": "CyberEntity",
838 | "value": "sw.vendor"
839 | },
840 | {
841 | "class": "CyberEntity",
842 | "value": "sw.product"
843 | }
844 | ],
845 | "patternType": "ExactPattern",
846 | "vertexType": "software"
847 | },
848 | {
849 | "patternSequence": [
850 | {
851 | "class": "CyberEntity",
852 | "value": "sw.vendor"
853 | },
854 | {
855 | "class": "Token",
856 | "value": "also"
857 | },
858 | {
859 | "class": "Token",
860 | "value": "released"
861 | },
862 | {
863 | "class": "Token",
864 | "value": "a"
865 | },
866 | {
867 | "class": "Token",
868 | "value": "new"
869 | },
870 | {
871 | "class": "Token",
872 | "value": "version"
873 | },
874 | {
875 | "class": "Token",
876 | "value": "of"
877 | },
878 | {
879 | "class": "Token",
880 | "value": "its"
881 | },
882 | {
883 | "class": "CyberEntity",
884 | "value": "sw.product"
885 | }
886 | ],
887 | "patternType": "ExactPattern",
888 | "vertexType": "software"
889 | },
890 | {
891 | "patternSequence": [
892 | {
893 | "class": "CyberEntity",
894 | "value": "sw.vendor"
895 | },
896 | {
897 | "class": "CyberEntity",
898 | "value": "sw.product"
899 | },
900 | {
901 | "class": "Token",
902 | "value": "and"
903 | },
904 | {
905 | "class": "CyberEntity",
906 | "value": "sw.product"
907 | }
908 | ],
909 | "patternType": "ExactPattern",
910 | "vertexType": "software"
911 | },
912 | {
913 | "patternSequence": [
914 | {
915 | "class": "CyberEntity",
916 | "value": "sw.vendor"
917 | },
918 | {
919 | "class": "Token",
920 | "value": "version"
921 | },
922 | {
923 | "class": "Token",
924 | "value": "of"
925 | },
926 | {
927 | "class": "CyberEntity",
928 | "value": "sw.product"
929 | }
930 | ],
931 | "patternType": "FuzzyPattern",
932 | "vertexType": "software"
933 | },
934 | {
935 | "patternSequence": [
936 | {
937 | "class": "CyberEntity",
938 | "value": "sw.product"
939 | },
940 | {
941 | "class": "Token",
942 | "value": "fix"
943 | },
944 | {
945 | "class": "Token",
946 | "value": "available"
947 | },
948 | {
949 | "class": "Token",
950 | "value": "from"
951 | },
952 | {
953 | "class": "CyberEntity",
954 | "value": "sw.vendor"
955 | }
956 | ],
957 | "patternType": "FuzzyPattern",
958 | "vertexType": "software"
959 | },
960 | {
961 | "edgeType": "ExploitTargetRelatedObservable",
962 | "patternSequence": [
963 | {
964 | "class": "CyberEntity",
965 | "vType": "outV",
966 | "value": "vuln.description"
967 | },
968 | {
969 | "class": "Token",
970 | "value": "issue"
971 | },
972 | {
973 | "class": "Token",
974 | "value": "affects"
975 | },
976 | {
977 | "class": "Token",
978 | "value": "the"
979 | },
980 | {
981 | "class": "CyberEntity",
982 | "vType": "inV",
983 | "value": "sw.product"
984 | }
985 | ],
986 | "patternType": "ExactPattern"
987 | },
988 | {
989 | "edgeType": "ExploitTargetRelatedObservable",
990 | "patternSequence": [
991 | {
992 | "class": "CyberEntity",
993 | "vType": "outV",
994 | "value": "vuln.description"
995 | },
996 | {
997 | "class": "Token",
998 | "value": "that"
999 | },
1000 | {
1001 | "class": "Token",
1002 | "value": "is"
1003 | },
1004 | {
1005 | "class": "Token",
1006 | "value": "hittable"
1007 | },
1008 | {
1009 | "class": "Token",
1010 | "value": "through"
1011 | },
1012 | {
1013 | "class": "CyberEntity",
1014 | "vType": "inV",
1015 | "value": "sw.product"
1016 | }
1017 | ],
1018 | "patternType": "ExactPattern"
1019 | },
1020 | {
1021 | "edgeType": "ExploitTargetRelatedObservable",
1022 | "patternSequence": [
1023 | {
1024 | "class": "CyberEntity",
1025 | "vType": "inV",
1026 | "value": "sw.product"
1027 | },
1028 | {
1029 | "class": "Token",
1030 | "value": "vulnerabilities"
1031 | },
1032 | {
1033 | "class": "Token",
1034 | "value": "that"
1035 | },
1036 | {
1037 | "class": "Token",
1038 | "value": "could"
1039 | },
1040 | {
1041 | "class": "Token",
1042 | "value": "lead"
1043 | },
1044 | {
1045 | "class": "Token",
1046 | "value": "to"
1047 | },
1048 | {
1049 | "class": "CyberEntity",
1050 | "vType": "outV",
1051 | "value": "vuln.description"
1052 | }
1053 | ],
1054 | "patternType": "ExactPattern"
1055 | },
1056 | {
1057 | "edgeType": "ExploitTargetRelatedObservable",
1058 | "patternSequence": [
1059 | {
1060 | "class": "CyberEntity",
1061 | "vType": "inV",
1062 | "value": "sw.product"
1063 | },
1064 | {
1065 | "class": "CyberEntity",
1066 | "vType": "outV",
1067 | "value": "vuln.description"
1068 | }
1069 | ],
1070 | "patternType": "ExactPattern"
1071 | },
1072 | {
1073 | "edgeType": "ExploitTargetRelatedObservable",
1074 | "patternSequence": [
1075 | {
1076 | "class": "CyberEntity",
1077 | "vType": "inV",
1078 | "value": "sw.product"
1079 | },
1080 | {
1081 | "class": "Token",
1082 | "value": "is"
1083 | },
1084 | {
1085 | "class": "Token",
1086 | "value": "suffering"
1087 | },
1088 | {
1089 | "class": "Token",
1090 | "value": "from"
1091 | },
1092 | {
1093 | "class": "Token",
1094 | "value": "these"
1095 | },
1096 | {
1097 | "class": "Token",
1098 | "value": "types"
1099 | },
1100 | {
1101 | "class": "Token",
1102 | "value": "of"
1103 | },
1104 | {
1105 | "class": "CyberEntity",
1106 | "vType": "outV",
1107 | "value": "vuln.description"
1108 | }
1109 | ],
1110 | "patternType": "ExactPattern"
1111 | },
1112 | {
1113 | "edgeType": "ExploitTargetRelatedObservable",
1114 | "patternSequence": [
1115 | {
1116 | "class": "CyberEntity",
1117 | "vType": "inV",
1118 | "value": "sw.product"
1119 | },
1120 | {
1121 | "class": "Token",
1122 | "value": "could"
1123 | },
1124 | {
1125 | "class": "Token",
1126 | "value": "allow"
1127 | },
1128 | {
1129 | "class": "CyberEntity",
1130 | "vType": "outV",
1131 | "value": "vuln.description"
1132 | }
1133 | ],
1134 | "patternType": "ExactPattern"
1135 | },
1136 | {
1137 | "edgeType": "ExploitTargetRelatedObservable",
1138 | "patternSequence": [
1139 | {
1140 | "class": "CyberEntity",
1141 | "vType": "inV",
1142 | "value": "sw.product"
1143 | },
1144 | {
1145 | "class": "Token",
1146 | "value": "."
1147 | },
1148 | {
1149 | "class": "Token",
1150 | "value": "The"
1151 | },
1152 | {
1153 | "class": "Token",
1154 | "value": "vulnerabilities"
1155 | },
1156 | {
1157 | "class": "Token",
1158 | "value": "could"
1159 | },
1160 | {
1161 | "class": "Token",
1162 | "value": "allow"
1163 | },
1164 | {
1165 | "class": "CyberEntity",
1166 | "vType": "outV",
1167 | "value": "vuln.description"
1168 | }
1169 | ],
1170 | "patternType": "ExactPattern"
1171 | },
1172 | {
1173 | "edgeType": "ExploitTargetRelatedObservable",
1174 | "patternSequence": [
1175 | {
1176 | "class": "CyberEntity",
1177 | "vType": "inV",
1178 | "value": "sw.product"
1179 | },
1180 | {
1181 | "class": "Token",
1182 | "value": "."
1183 | },
1184 | {
1185 | "class": "Token",
1186 | "value": "The"
1187 | },
1188 | {
1189 | "class": "Token",
1190 | "value": "vulnerability"
1191 | },
1192 | {
1193 | "class": "Token",
1194 | "value": "could"
1195 | },
1196 | {
1197 | "class": "Token",
1198 | "value": "allow"
1199 | },
1200 | {
1201 | "class": "CyberEntity",
1202 | "vType": "outV",
1203 | "value": "vuln.description"
1204 | }
1205 | ],
1206 | "patternType": "ExactPattern"
1207 | },
1208 | {
1209 | "edgeType": "ExploitTargetRelatedObservable",
1210 | "patternSequence": [
1211 | {
1212 | "class": "CyberEntity",
1213 | "vType": "inV",
1214 | "value": "sw.product"
1215 | },
1216 | {
1217 | "class": "Token",
1218 | "value": "."
1219 | },
1220 | {
1221 | "class": "Token",
1222 | "value": "The"
1223 | },
1224 | {
1225 | "class": "Token",
1226 | "value": "most"
1227 | },
1228 | {
1229 | "class": "Token",
1230 | "value": "severe"
1231 | },
1232 | {
1233 | "class": "Token",
1234 | "value": "vulnerabilities"
1235 | },
1236 | {
1237 | "class": "Token",
1238 | "value": "could"
1239 | },
1240 | {
1241 | "class": "Token",
1242 | "value": "allow"
1243 | },
1244 | {
1245 | "class": "CyberEntity",
1246 | "vType": "outV",
1247 | "value": "vuln.description"
1248 | }
1249 | ],
1250 | "patternType": "ExactPattern"
1251 | },
1252 | {
1253 | "edgeType": "ExploitTargetRelatedObservable",
1254 | "patternSequence": [
1255 | {
1256 | "class": "CyberEntity",
1257 | "vType": "outV",
1258 | "value": "vuln.description"
1259 | },
1260 | {
1261 | "class": "Token",
1262 | "value": "vulnerability"
1263 | },
1264 | {
1265 | "class": "Token",
1266 | "value": "in"
1267 | },
1268 | {
1269 | "class": "CyberEntity",
1270 | "vType": "inV",
1271 | "value": "sw.product"
1272 | }
1273 | ],
1274 | "patternType": "ExactPattern"
1275 | },
1276 | {
1277 | "edgeType": "ExploitTargetRelatedObservable",
1278 | "patternSequence": [
1279 | {
1280 | "class": "CyberEntity",
1281 | "vType": "outV",
1282 | "value": "vuln.description"
1283 | },
1284 | {
1285 | "class": "Token",
1286 | "value": "vulnerability"
1287 | },
1288 | {
1289 | "class": "Token",
1290 | "value": "in"
1291 | },
1292 | {
1293 | "class": "CyberEntity",
1294 | "vType": "inV",
1295 | "value": "sw.product"
1296 | },
1297 | {
1298 | "class": "Token",
1299 | "value": "and"
1300 | },
1301 | {
1302 | "class": "CyberEntity",
1303 | "vType": "inV",
1304 | "value": "sw.product"
1305 | }
1306 | ],
1307 | "patternType": "ExactPattern"
1308 | },
1309 | {
1310 | "edgeType": "ExploitTargetRelatedObservable",
1311 | "patternSequence": [
1312 | {
1313 | "class": "CyberEntity",
1314 | "vType": "inV",
1315 | "value": "sw.product"
1316 | },
1317 | {
1318 | "class": "Token",
1319 | "value": "that"
1320 | },
1321 | {
1322 | "class": "Token",
1323 | "value": "may"
1324 | },
1325 | {
1326 | "class": "Token",
1327 | "value": "lead"
1328 | },
1329 | {
1330 | "class": "Token",
1331 | "value": "to"
1332 | },
1333 | {
1334 | "class": "CyberEntity",
1335 | "vType": "outV",
1336 | "value": "vuln.description"
1337 | }
1338 | ],
1339 | "patternType": "ExactPattern"
1340 | },
1341 | {
1342 | "edgeType": "ExploitTargetRelatedObservable",
1343 | "patternSequence": [
1344 | {
1345 | "class": "CyberEntity",
1346 | "vType": "inV",
1347 | "value": "sw.product"
1348 | },
1349 | {
1350 | "class": "Token",
1351 | "value": "is"
1352 | },
1353 | {
1354 | "class": "Token",
1355 | "value": "vulnerable"
1356 | },
1357 | {
1358 | "class": "Token",
1359 | "value": "to"
1360 | },
1361 | {
1362 | "class": "CyberEntity",
1363 | "vType": "outV",
1364 | "value": "vuln.description"
1365 | }
1366 | ],
1367 | "patternType": "FuzzyPattern"
1368 | },
1369 | {
1370 | "edgeType": "ExploitTargetRelatedObservable",
1371 | "patternSequence": [
1372 | {
1373 | "class": "CyberEntity",
1374 | "vType": "outV",
1375 | "value": "vuln.description"
1376 | },
1377 | {
1378 | "class": "Token",
1379 | "value": "flaw"
1380 | },
1381 | {
1382 | "class": "Token",
1383 | "value": "in"
1384 | },
1385 | {
1386 | "class": "CyberEntity",
1387 | "vType": "inV",
1388 | "value": "sw.product"
1389 | }
1390 | ],
1391 | "patternType": "ExactPattern"
1392 | },
1393 | {
1394 | "edgeType": "Sub-Observable",
1395 | "patternSequence": [
1396 | {
1397 | "class": "CyberEntity",
1398 | "vType": "outV",
1399 | "value": "sw.product"
1400 | },
1401 | {
1402 | "class": "Token",
1403 | "value": "system"
1404 | },
1405 | {
1406 | "class": "Token",
1407 | "value": "file"
1408 | },
1409 | {
1410 | "class": "Token",
1411 | "value": ":"
1412 | },
1413 | {
1414 | "class": "CyberEntity",
1415 | "vType": "inV",
1416 | "value": "file.name"
1417 | }
1418 | ],
1419 | "patternType": "ExactPattern"
1420 | },
1421 | {
1422 | "edgeType": "Sub-Observable",
1423 | "patternSequence": [
1424 | {
1425 | "class": "CyberEntity",
1426 | "vType": "outV",
1427 | "value": "sw.product"
1428 | },
1429 | {
1430 | "class": "POS",
1431 | "value": "NN"
1432 | },
1433 | {
1434 | "class": "Token",
1435 | "value": "-LRB-"
1436 | },
1437 | {
1438 | "class": "CyberEntity",
1439 | "vType": "inV",
1440 | "value": "file.name"
1441 | }
1442 | ],
1443 | "patternType": "ExactPattern"
1444 | }
1445 | ]
1446 | }
1447 |
--------------------------------------------------------------------------------
/src/main/resources/patterns_relations_abbrev.json:
--------------------------------------------------------------------------------
1 | {
2 | "Patterns": [
3 | {
4 | "patternSequence": [
5 | {
6 | "class": "CyberEntity",
7 | "value": "sw.vendor"
8 | },
9 | {
10 | "class": "CyberEntity",
11 | "value": "sw.product"
12 | },
13 | {
14 | "class": "CyberEntity",
15 | "value": "sw.version"
16 | }
17 | ],
18 | "patternType": "ExactPattern",
19 | "vertexType": "software"
20 | },
21 | {
22 | "edgeType": "ExploitTargetRelatedObservable",
23 | "patternSequence": [
24 | {
25 | "class": "CyberEntity",
26 | "vType": "inV",
27 | "value": "file.name"
28 | },
29 | {
30 | "class": "Token",
31 | "value": "refer"
32 | },
33 | {
34 | "class": "Token",
35 | "value": "to"
36 | },
37 | {
38 | "class": "CyberEntity",
39 | "vType": "outV",
40 | "value": "vuln.cve"
41 | }
42 | ],
43 | "patternType": "FuzzyPattern"
44 | },
45 | {
46 | "vertexType": "software",
47 | "patternSequence": [
48 | {
49 | "class": "CyberEntity",
50 | "value": "sw.vendor"
51 | },
52 | {
53 | "class": "TreeElement",
54 | "value": "NNP"
55 | },
56 | {
57 | "class": "TreeElement",
58 | "value": "NP"
59 | },
60 | {
61 | "class": "CyberEntity",
62 | "value": "sw.product"
63 | }
64 | ],
65 | "patternType": "ParseTreePattern"
66 | },
67 | {
68 | "vertexType": "software",
69 | "patternSequence": [
70 | {
71 | "class": "CyberEntity",
72 | "value": "sw.product"
73 | },
74 | {
75 | "class": "TreeElement",
76 | "value": "NP"
77 | },
78 | {
79 | "class": "TreeElement",
80 | "value": "NP"
81 | },
82 | {
83 | "class": "TreeElement",
84 | "value": "PP"
85 | },
86 | {
87 | "class": "CyberEntity",
88 | "value": "sw.version"
89 | }
90 | ],
91 | "patternType": "ParseTreePattern"
92 | },
93 | {
94 | "edgeType": "ExploitTargetRelatedObservable",
95 | "patternSequence": [
96 | {
97 | "class": "CyberEntity",
98 | "vType": "inV",
99 | "value": "sw.product"
100 | },
101 | {
102 | "class": "TreeElement",
103 | "value": "NP"
104 | },
105 | {
106 | "class": "TreeElement",
107 | "value": "NP"
108 | },
109 | {
110 | "class": "TreeElement",
111 | "value": "S"
112 | },
113 | {
114 | "class": "TreeElement",
115 | "value": "VP"
116 | },
117 | {
118 | "class": "TreeElement",
119 | "value": "NP"
120 | },
121 | {
122 | "class": "TreeElement",
123 | "value": "NP"
124 | },
125 | {
126 | "class": "CyberEntity",
127 | "vType": "outV",
128 | "value": "vuln.description"
129 | }
130 | ],
131 | "patternType": "ParseTreePattern"
132 | },
133 | {
134 | "edgeType": "ExploitTargetRelatedObservable",
135 | "patternSequence": [
136 | {
137 | "class": "CyberEntity",
138 | "vType": "inV",
139 | "value": "sw.product"
140 | },
141 | {
142 | "class": "TreeElement",
143 | "value": "NP"
144 | },
145 | {
146 | "class": "TreeElement",
147 | "value": "NP"
148 | },
149 | {
150 | "class": "TreeElement",
151 | "value": "S"
152 | },
153 | {
154 | "class": "TreeElement",
155 | "value": "VP"
156 | },
157 | {
158 | "class": "TreeElement",
159 | "value": "NP"
160 | },
161 | {
162 | "class": "TreeElement",
163 | "value": "PP"
164 | },
165 | {
166 | "class": "TreeElement",
167 | "value": "NP"
168 | },
169 | {
170 | "class": "TreeElement",
171 | "value": "PRN"
172 | },
173 | {
174 | "class": "TreeElement",
175 | "value": "S"
176 | },
177 | {
178 | "class": "TreeElement",
179 | "value": "VP"
180 | },
181 | {
182 | "class": "TreeElement",
183 | "value": "PP"
184 | },
185 | {
186 | "class": "TreeElement",
187 | "value": "NP"
188 | },
189 | {
190 | "class": "TreeElement",
191 | "value": "NN"
192 | },
193 | {
194 | "class": "CyberEntity",
195 | "vType": "outV",
196 | "value": "vuln.cve"
197 | }
198 | ],
199 | "patternType": "ParseTreePattern"
200 | },
201 | {
202 | "edgeType": "Sub-Observable",
203 | "patternSequence": [
204 | {
205 | "class": "CyberEntity",
206 | "vType": "outV",
207 | "value": "sw.product"
208 | },
209 | {
210 | "class": "TreeElement",
211 | "value": "NP"
212 | },
213 | {
214 | "class": "TreeElement",
215 | "value": "NP"
216 | },
217 | {
218 | "class": "TreeElement",
219 | "value": "S"
220 | },
221 | {
222 | "class": "TreeElement",
223 | "value": "VP"
224 | },
225 | {
226 | "class": "TreeElement",
227 | "value": "NP"
228 | },
229 | {
230 | "class": "TreeElement",
231 | "value": "PP"
232 | },
233 | {
234 | "class": "TreeElement",
235 | "value": "NP"
236 | },
237 | {
238 | "class": "TreeElement",
239 | "value": "NP"
240 | },
241 | {
242 | "class": "TreeElement",
243 | "value": "NN"
244 | },
245 | {
246 | "class": "CyberEntity",
247 | "vType": "inV",
248 | "value": "file.name"
249 | }
250 | ],
251 | "patternType": "ParseTreePattern"
252 | }
253 | ]
254 | }
255 |
--------------------------------------------------------------------------------
/src/test/java/gov/ornl/stucco/RelationExtractorTest.java:
--------------------------------------------------------------------------------
1 | package gov.ornl.stucco;
2 |
3 | import edu.stanford.nlp.pipeline.Annotation;
4 | import gov.ornl.stucco.entity.EntityLabeler;
5 |
6 | import org.junit.Test;
7 |
8 | public class RelationExtractorTest {
9 | private static String expectedGraph = "{" +
10 | "\"vertices\": {" +
11 | "\"1235\": {" +
12 | "\"name\": \"1235\"," +
13 | "\"vertexType\": \"software\"," +
14 | "\"product\": \"Windows XP\"," +
15 | "\"source\": \"CNN\"," +
16 | "\"vendor\": \"Microsoft\"," +
17 | "\"version\": \"before 2.8\"" +
18 | "}," +
19 | "\"1236\": {" +
20 | "\"name\": \"file.php\"," +
21 | "\"vertexType\": \"file\"," +
22 | "\"source\": \"CNN\"" +
23 | "}," +
24 | "\"1237\": {" +
25 | "\"name\": \"1237\"," +
26 | "\"vertexType\": \"vulnerability\"," +
27 | "\"source\": \"CNN\"," +
28 | "\"cve\": \"CVE-2014-1234\"" +
29 | "}," +
30 | "\"1238\": {" +
31 | "\"name\": \"1238\"," +
32 | "\"vertexType\": \"software\"," +
33 | "\"product\": \"Windows XP\"," +
34 | "\"source\": \"CNN\"," +
35 | "\"vendor\": \"Microsoft\"" +
36 | "}," +
37 | "\"1239\": {" +
38 | "\"name\": \"1239\"," +
39 | "\"vertexType\": \"software\"," +
40 | "\"product\": \"Windows XP\"," +
41 | "\"source\": \"CNN\"," +
42 | "\"version\": \"before 2.8\"" +
43 | "}," +
44 | "\"1240\": {" +
45 | "\"name\": \"1240\"," +
46 | "\"vertexType\": \"software\"," +
47 | "\"product\": \"Windows XP\"," +
48 | "\"source\": \"CNN\"" +
49 | "}," +
50 | "\"1241\": {" +
51 | "\"name\": \"1241\"," +
52 | "\"vertexType\": \"vulnerability\"," +
53 | "\"source\": \"CNN\"," +
54 | "\"description\": \"cross-site scripting\"" +
55 | "}," +
56 | "\"1242\": {" +
57 | "\"name\": \"1242\"," +
58 | "\"vertexType\": \"software\"," +
59 | "\"product\": \"Windows XP\"," +
60 | "\"source\": \"CNN\"" +
61 | "}," +
62 | "\"1243\": {" +
63 | "\"name\": \"1243\"," +
64 | "\"vertexType\": \"vulnerability\"," +
65 | "\"source\": \"CNN\"," +
66 | "\"cve\": \"CVE-2014-1234\"" +
67 | "}," +
68 | "\"1244\": {" +
69 | "\"name\": \"1244\"," +
70 | "\"vertexType\": \"software\"," +
71 | "\"product\": \"Windows XP\"," +
72 | "\"source\": \"CNN\"" +
73 | "}," +
74 | "\"1245\": {" +
75 | "\"name\": \"file.php\"," +
76 | "\"vertexType\": \"file\"," +
77 | "\"source\": \"CNN\"" +
78 | "}" +
79 | "}," +
80 | "\"edges\": [" +
81 | "{" +
82 | "\"inVertID\": \"1236\"," +
83 | "\"outVertID\": \"1237\"," +
84 | "\"relation\": \"ExploitTargetRelatedObservable\"" +
85 | "}," +
86 | "{" +
87 | "\"inVertID\": \"1240\"," +
88 | "\"outVertID\": \"1241\"," +
89 | "\"relation\": \"ExploitTargetRelatedObservable\"" +
90 | "}," +
91 | "{" +
92 | "\"inVertID\": \"1242\"," +
93 | "\"outVertID\": \"1243\"," +
94 | "\"relation\": \"ExploitTargetRelatedObservable\"" +
95 | "}," +
96 | "{" +
97 | "\"inVertID\": \"1245\"," +
98 | "\"outVertID\": \"1244\"," +
99 | "\"relation\": \"Sub-Observable\"" +
100 | "}" +
101 | "]" +
102 | "}";
103 |
104 | @Test
105 | public void testGetGraph() {
106 | String testSentence = "Microsoft Windows XP before 2.8 has cross-site scripting vulnerability in file.php (refer to CVE-2014-1234).";
107 | EntityLabeler labeler = new EntityLabeler();
108 | Annotation doc = labeler.getAnnotatedDoc("My Doc", testSentence);
109 | RelationExtractor rx = new RelationExtractor("src/main/resources/patterns_relations_abbrev.json");
110 | String graph = rx.createSubgraph(doc, "a source");
111 | assert(graph.equals(expectedGraph));
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------