Project

General

Profile

SnortSignature.java

Luke Murphey, 10/25/2010 12:45 AM

Download (7.51 KB)

 
1
package net.lukeMurphey.nsia.scanRules;
2

    
3
import java.util.regex.*;
4
import java.util.*;
5

    
6
/**
7
 * This class provides the ability to parse Snort rules and evaluate content to determine if the Snort rules match. 
8
 * @author luke
9
 *
10
 */
11
public class SnortSignature implements ContentSignature{
12
        
13
        private String snortSignatureName;
14
        private int sid;
15
        private int revision;
16
        private String classtype;
17
        
18
        private Vector<Option> options = new Vector<Option>();
19
        private Vector<Reference> references = new Vector<Reference>();
20
        
21
        private static final Pattern SNORT_RULE_REGEX = Pattern.compile("([a-zA-Z]+) ([a-zA-Z]+) ([0-9a-zA-Z$_]+) ([0-9a-zA-Z$_]+) (\\->|<>|<\\-) ([0-9a-zA-Z$_]+) ([0-9a-zA-Z$_]+) (\\()([ /()a-zA-Z%0-9=!?._;:,\\-$\\\"\\']*)(\\))");
22
        private static final Pattern SNORT_OPTIONS_REGEX = Pattern.compile("([ ]*([()a-zA-Z0-9._,\\-$']+)(:[ ]*(([ /()a-zA-Z%0-9=!?._,\\-$']+)|\"([ /()a-zA-Z%0-9!?=._,\\-$']+)\"))?)+");
23
        
24
        /**
25
         * This class represents a snort rule option.
26
         * @author luke
27
         *
28
         */
29
        public class Option{
30
                
31
                private String name;
32
                private String value = null;
33
                
34
                public Option( String name ){
35
                        this.name = name;
36
                }
37
                
38
                public Option( String name, String value ){
39
                        this.name = name;
40
                        this.value = value;
41
                }
42
                
43
                public String getName(){
44
                        return name;
45
                }
46
                
47
                public String getValue(){
48
                        return value;
49
                }
50
                
51
                public boolean hasValue(){
52
                        if( value == null )
53
                                return false;
54
                        else
55
                                return true;
56
                }
57
        }
58
        
59
        /**
60
         * This class represents a Snort signature reference (URL, CVE entry, etc.).
61
         * @author luke
62
         *
63
         */
64
        public static class Reference{
65
                
66
                public final static Type BUGTRAQ = new Type(1, "http://www.securityfocus.com/bid/");
67
                public final static Type CVE = new Type(2, "http://cve.mitre.org/cgi-bin/cvename.cgi?name=");
68
                public final static Type NESSUS = new Type(3, "http://cgi.nessus.org/plugins/dump.php3?id=");
69
                public final static Type ARACHNIDS = new Type(4, "http://www.whitehats.com/info/IDS");
70
                public final static Type MCAFEE = new Type(5, "http://vil.nai.com/vil/dispVirus.asp?virus_k=");
71
                public final static Type URL = new Type(6, "http://");
72
                
73
                /**
74
                 * This class represents the possible Snort reference types.
75
                 * See http://www.snort.org/docs/snort_htmanuals/htmanual_2.4/node18.html#SECTION00442000000000000000
76
                 * @author luke
77
                 *
78
                 */
79
                public static class Type{
80
                        
81
                        private int id;
82
                        private String urlPrefix;
83
                        
84
                        protected Type( int id, String urlPrefix ){
85
                                this.id = id;
86
                                this.urlPrefix = urlPrefix;
87
                        }
88
                        
89
                        public String getUrlPrefix(){
90
                                return urlPrefix; 
91
                        }
92
                        
93
                        public boolean equals(Type type){
94
                                
95
                                // 0 -- Precondition check
96
                                if( type == null ){
97
                                        throw new IllegalArgumentException("Type cannot be null");
98
                                }
99
                                
100
                                // 1 -- Compare the types
101
                                return type.id == id;
102
                        }
103
                }
104
                
105
                private Type type;
106
                private String value;
107
                
108
                public Reference(Type type, String value){
109
                        this.type = type;
110
                        this.value = value;
111
                }
112
                
113
                public static Reference parse(String value) throws SignatureParseException{
114
                        int firstComma = value.indexOf(',');
115
                        
116
                        String type = value.substring(0, firstComma).trim();
117
                        String argument = value.substring(firstComma+1).trim();
118
                        
119
                        if( type.equalsIgnoreCase("bugtraq") ){
120
                                return new Reference(Reference.BUGTRAQ, argument);
121
                        }
122
                        else if( type.equalsIgnoreCase("cve") ){
123
                                return new Reference(Reference.CVE, argument);
124
                        }
125
                        else if( type.equalsIgnoreCase("nessus") ){
126
                                return new Reference(Reference.NESSUS, argument);
127
                        }
128
                        else if( type.equalsIgnoreCase("arachnids") ){
129
                                return new Reference(Reference.ARACHNIDS, argument);
130
                        }
131
                        else if( type.equalsIgnoreCase("mcafee") ){
132
                                return new Reference(Reference.MCAFEE, argument);
133
                        }
134
                        else if( type.equalsIgnoreCase("url") ){
135
                                return new Reference(Reference.URL, argument);
136
                        }
137
                        else{
138
                                throw new SignatureParseException("Reference name (\"" + type + "\" is invalid");
139
                        }
140
                }
141
                
142
                public String toString(){
143
                        return type.getUrlPrefix() + value;
144
                }
145
        }
146
        
147
        /**
148
         * Takes a Snort rule string and creates an SnortSignature object that is capable of evaluting content for exploits. 
149
         * @param snortRule
150
         * @return
151
         * @throws SignatureParseException 
152
         */
153
        public static SnortSignature parse(String snortRule) throws SignatureParseException{
154
                
155
                // 0 -- Precondition check
156
                
157
                //         0.1 --Rule must not be null
158
                if( snortRule == null ){
159
                        throw new IllegalArgumentException("Snort rule must not be null");
160
                }
161
                
162
                //         0.2 --Rule must not be empty
163
                if( snortRule.isEmpty() ){
164
                        throw new IllegalArgumentException("Snort rule must not be empty");
165
                }
166
                
167
                
168
                // 1 -- Identify the section with the options
169
                String options;
170
                Matcher ruleMatcher = SNORT_RULE_REGEX.matcher(snortRule);
171
                
172
                if( !ruleMatcher.matches() || ruleMatcher.groupCount() < 10 ){
173
                        throw new SignatureParseException("The snort rule given does not match a known rule format");
174
                }
175
                else{
176
                        options = ruleMatcher.group(9);
177
                }
178
                
179
                // 2 -- Parse out the rule options
180
                SnortSignature snortSig = new SnortSignature();
181
                
182
                Matcher optionsMatcher = SNORT_OPTIONS_REGEX.matcher(options);
183
                
184
                while (optionsMatcher.find()){
185
                        
186
                        //         2.1 --Get the option name
187
                        String optionName = optionsMatcher.group(2).trim();
188
                        
189
                        //         2.2 -- Get the option value (if exists)
190
                        String optionValue = null;
191
                        
192
                        if( optionsMatcher.group(6) != null ){
193
                                optionValue = optionsMatcher.group(6);
194
                        }
195
                        else{
196
                                optionValue = optionsMatcher.group(5);
197
                        }
198
                        
199
                        //         2.3 -- Save the option to the list
200
                        if(optionValue == null){
201
                                snortSig.options.add( snortSig.new Option( optionName ) );
202
                        }
203
                        else{
204
                                snortSig.options.add( snortSig.new Option( optionName, optionValue) );
205
                        }
206
                        
207
                        
208
                }
209
                
210
                
211
                // 3 -- Populate the signature from the options
212
                for( int c = 0; c < snortSig.options.size(); c++){
213
                        Option option = snortSig.options.get(c);
214
                        
215
                        if( option.getName().equalsIgnoreCase("msg") ){
216
                                snortSig.snortSignatureName = option.getValue();
217
                        }
218
                        
219
                        if( option.getName().equalsIgnoreCase("sid") ){
220
                                snortSig.sid = Integer.parseInt( option.getValue() );
221
                        }
222
                        
223
                        if( option.getName().equalsIgnoreCase("rev") ){
224
                                snortSig.revision = Integer.parseInt( option.getValue() );
225
                        }
226
                        
227
                        if( option.getName().equalsIgnoreCase("classtype") ){
228
                                snortSig.classtype = option.getValue();
229
                        }
230
                        
231
                        if( option.getName().equalsIgnoreCase("reference") ){
232
                                snortSig.references.add( Reference.parse( option.getValue() ) );
233
                        }
234
                }
235
                
236
                return snortSig;
237
        }
238

    
239
        
240
        
241
        public String getName() {
242
                String description = "This signature detects attacks originating from monitored resource. Details are below:\n\nSignature: " + snortSignatureName;
243
                
244
                if( references != null && references.size() > 0 ){
245
                        return description + "\nReferences:\n" + getNotes();
246
                }
247
                else
248
                        return description;
249
        }
250

    
251
        public String getNotes() {
252
                StringBuffer notes = new StringBuffer("");
253
                if( references != null ){
254
                        for( int c = 0; c < references.size(); c++){
255
                                if( c > 0 ){
256
                                        notes.append("\n" + references.get(c).toString());
257
                                }
258
                                else{
259
                                        notes.append(references.get(c).toString());
260
                                }
261
                        }
262
                }
263
                
264
                return notes.toString();
265
        }
266

    
267
        public String getCategoryName(){
268
                return "Exploit Signature";
269
        }
270

    
271
        public String getClassType() {
272
                return classtype;
273
        }
274
        
275
        public Reference[] getReferences() {
276
                return (Reference[])references.toArray();
277
        }
278

    
279
        public String getSubCategoryName() {
280
                return snortSignatureName;
281
        }
282
        
283
        public int getID() {
284
                return sid;
285
        } 
286
        
287
        public int getRevision() {
288
                return revision;
289
        }
290
        
291
        public Option[] getOptions(){
292
                Option[] optionsArray = new Option[options.size()];
293
                options.toArray(optionsArray);
294
                
295
                return optionsArray;
296
        }
297

    
298
}