threatstack-agent-ruby 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,240 @@
1
+
2
+ #ifndef LIBINJECTION_PATH_TRAVERSAL_DATA_H
3
+ #define LIBINJECTION_PATH_TRAVERSAL_DATA_H
4
+
5
+ const char *const path_traversal_payloads[] = {
6
+ "\\access_log",
7
+ "%2faccess_log",
8
+ "%5caccess_log",
9
+ "/access_log",
10
+ "\\access.log",
11
+ "%2faccess.log",
12
+ "%5caccess.log",
13
+ "/access.log",
14
+ "\\error_log",
15
+ "%2ferror_log",
16
+ "%5cerror_log",
17
+ "/error_log",
18
+ "\\error.log",
19
+ "%2ferror.log",
20
+ "%5cerror.log",
21
+ "/error.log",
22
+ "\\license.log",
23
+ "%2flicense.log",
24
+ "%5clicense.log",
25
+ "/license.log",
26
+ "\\license_log",
27
+ "%2flicense_log",
28
+ "%5clicense_log",
29
+ "/license_log",
30
+ "\\login.log",
31
+ "%2flogin.log",
32
+ "%5clogin.log",
33
+ "/login.log",
34
+ "\\login_log",
35
+ "%2flogin_log",
36
+ "%5clogin_log",
37
+ "/login_log",
38
+ "\\system.log",
39
+ "%2fsystem.log",
40
+ "%5csystem.log",
41
+ "/system.log",
42
+ "\\system_log",
43
+ "%2fsystem_log",
44
+ "%5csystem_log",
45
+ "/system_log",
46
+ "\\stats.log",
47
+ "%2fstats.log",
48
+ "%5cstats.log",
49
+ "/stats.log",
50
+ "\\stats_log",
51
+ "%2fstats_log",
52
+ "%5cstats_log",
53
+ "/stats_log",
54
+ "\\.bash_history",
55
+ "%2f.bash_history",
56
+ "%5c.bash_history",
57
+ "/.bash_history",
58
+ "\\.sh_history",
59
+ "%2f.sh_history",
60
+ "%5c.sh_history",
61
+ "/.sh_history",
62
+ "\\php.ini",
63
+ "%2fphp.ini",
64
+ "%5cphp.ini",
65
+ "/php.ini",
66
+ "\\my.cnf",
67
+ "%2fmy.cnf",
68
+ "%5cmy.cnf",
69
+ "/my.cnf",
70
+ "\\my.ini",
71
+ "%2fmy.ini",
72
+ "%5cmy.ini",
73
+ "/my.ini",
74
+ "\\boot.ini",
75
+ "%2fboot.ini",
76
+ "%5cboot.ini",
77
+ "/boot.ini",
78
+ "\\win.ini",
79
+ "%2fwin.ini",
80
+ "%5cwin.ini",
81
+ "/win.ini",
82
+ "\\httpd.conf",
83
+ "%2fhttpd.conf",
84
+ "%5chttpd.conf",
85
+ "/httpd.conf",
86
+ "\\vhosts.conf",
87
+ "%2fvhosts.conf",
88
+ "%5cvhosts.conf",
89
+ "/vhosts.conf",
90
+ "\\nginx.conf",
91
+ "%2fnginx.conf",
92
+ "%5cnginx.conf",
93
+ "/nginx.conf",
94
+ "\\apache2.conf",
95
+ "%2fapache2.conf",
96
+ "%5capache2.conf",
97
+ "/apache2.conf",
98
+ "\\pureftpd",
99
+ "%2fpureftpd",
100
+ "%5cpureftpd",
101
+ "/pureftpd",
102
+ "\\pure-ftpd",
103
+ "%2fpure-ftpd",
104
+ "%5cpure-ftpd",
105
+ "/pure-ftpd",
106
+ "etc/hosts",
107
+ "etc\\hosts",
108
+ "etc%2fhosts",
109
+ "etc%5chosts",
110
+ "etc%c0%afhosts",
111
+ "etc/passwd",
112
+ "etc\\passwd",
113
+ "etc%2fpasswd",
114
+ "etc%5cpasswd",
115
+ "etc%c0%afpasswd",
116
+ "etc/shadow",
117
+ "etc\\shadow",
118
+ "etc%2fshadow",
119
+ "etc%5cshadow",
120
+ "etc%c0%afshadow",
121
+ "\\system32\\drivers\\hosts",
122
+ "/system32/drivers/hosts",
123
+ "\\data\\hostname.err",
124
+ "\\data\\mysql-bin.log",
125
+ "\\data\\mysql.err",
126
+ "\\data\\mysql.log",
127
+ "\\php4\\sessions\\",
128
+ "\\php5\\sessions\\",
129
+ "\\php\\sessions\\",
130
+ "\\windows\\repair\\sam",
131
+ "\\windows\\temp\\",
132
+ ".htaccess",
133
+ "/etc/apache2/sites-available/default",
134
+ "/etc/apache2/sites-enabled/000-default",
135
+ "/etc/chrootusers",
136
+ "/etc/crontab",
137
+ "/etc/fstab",
138
+ "/etc/ftpchroot",
139
+ "/etc/ftphosts",
140
+ "/etc/group",
141
+ "/etc/inittab",
142
+ "/etc/issue",
143
+ "/etc/issue",
144
+ "/etc/logrotate.d/ftp",
145
+ "/etc/logrotate.d/proftpd",
146
+ "/etc/logrotate.d/vsftpd.log",
147
+ "/etc/master.passwd",
148
+ "/etc/motd",
149
+ "/etc/nginx/sites-available/default",
150
+ "/etc/nginx/sites-enabled/default",
151
+ "/etc/pam.d/proftpd",
152
+ "/etc/phpmyadmin/config.inc.php",
153
+ "/etc/proftp.conf",
154
+ "/etc/proftpd/modules.conf",
155
+ "/etc/protpd/proftpd.conf",
156
+ "/etc/redhat-release",
157
+ "/etc/release",
158
+ "/etc/security/environ",
159
+ "/etc/security/group",
160
+ "/etc/security/limits",
161
+ "/etc/security/passwd",
162
+ "/etc/security/user",
163
+ "/etc/ssh/sshd_config",
164
+ "/etc/sysconfig/network-scripts/ifcfg-eth0",
165
+ "/etc/vhcs2/proftpd/proftpd.conf",
166
+ "/etc/vsftpd.chroot_list",
167
+ "/etc/vsftpd.conf",
168
+ "/etc/vsftpd/vsftpd.conf",
169
+ "/etc/wu-ftpd/ftpaccess",
170
+ "/etc/wu-ftpd/ftphosts",
171
+ "/etc/wu-ftpd/ftpusers",
172
+ "php://input",
173
+ "/proc/cmdline",
174
+ "/proc/self/",
175
+ "/proc/version",
176
+ "/root/.bash_history",
177
+ "/tmp/sess_",
178
+ "/usr/lib/security/mkuser.default",
179
+ "/usr/local/cpanel/logs",
180
+ "/usr/sbin/pure-config.pl",
181
+ "/var/adm/lastlog",
182
+ "/var/adm/log/xferlog",
183
+ "/var/adm/messages",
184
+ "/var/adm/utmpx",
185
+ "/var/adm/wtmpx",
186
+ "/var/cpanel/cpanel.config",
187
+ "/var/db/shadow/hash",
188
+ "/session/sess_",
189
+ "/var/log/authlog",
190
+ "/var/log/auth.log",
191
+ "/var/log/exim_mainlog",
192
+ "/var/log/exim/mainlog",
193
+ "/var/log/exim_paniclog",
194
+ "/var/log/exim/paniclog",
195
+ "/var/log/exim_rejectlog",
196
+ "/var/log/exim/rejectlog",
197
+ "/var/log/ftplog",
198
+ "/var/log/ftp-proxy",
199
+ "/var/log/kernel.log",
200
+ "/var/log/lastlog",
201
+ "/var/log/maillog",
202
+ "/var/log/mail.log",
203
+ "/var/log/messages",
204
+ "/var/log/mysqlderror.log",
205
+ "/var/log/mysql.log",
206
+ "/var/log/mysql/mysql-bin.log",
207
+ "/var/log/mysql/mysql.log",
208
+ "/var/log/mysql/mysql-slow.log",
209
+ "/var/log/proftpd",
210
+ "/var/log/secure.log",
211
+ "/var/log/syslog",
212
+ "/var/log/vsftpd.log",
213
+ "/var/log/wtmp",
214
+ "/var/log/xferlog",
215
+ "/var/mail/apache",
216
+ "/var/mail/nobody",
217
+ "/var/mail/www",
218
+ "/var/mail/www-data",
219
+ "/var/mysql.log",
220
+ "/var/run/utmp",
221
+ "/var/www/config.php",
222
+ "\\xampp\\filezillaftp\\filezilla server.xml",
223
+ "\\xampp\\filezillaftp\\server.xml",
224
+ "\\xampp\\filezillaftp\\logs",
225
+ "\\xampp\\mercurymail\\logs",
226
+ "\\xampp\\mercurymail\\mercury.ini",
227
+ "\\xampp\\mysql\\data\\mysql.err",
228
+ "\\xampp\\phpmyadmin\\config.inc",
229
+ "\\xampp\\phpmyadmin\\phpinfo.php",
230
+ "\\xampp\\sendmail\\sendmail.ini",
231
+ "\\xampp\\sendmail\\sendmail.log",
232
+ "\\xampp\\tomcat\\conf\\tomcat-users.xml",
233
+ "\\xampp\\tomcat\\conf\\web.xml",
234
+ "\\xampp\\webalizer\\webalizer.conf",
235
+ "\\xampp\\webdav\\webdav.txt",
236
+ };
237
+
238
+ #define path_traversal_payloads_size (sizeof (path_traversal_payloads) / sizeof (const char *))
239
+
240
+ #endif
@@ -2119,6 +2119,41 @@ fail:
2119
2119
  }
2120
2120
 
2121
2121
 
2122
+ SWIGINTERN VALUE
2123
+ _wrap_libinjection_pathtraversal(int argc, VALUE *argv, VALUE self) {
2124
+ char *arg1 = (char *) 0 ;
2125
+ size_t arg2 ;
2126
+ int res1 ;
2127
+ char *buf1 = 0 ;
2128
+ int alloc1 = 0 ;
2129
+ size_t val2 ;
2130
+ int ecode2 = 0 ;
2131
+ int result;
2132
+ VALUE vresult = Qnil;
2133
+
2134
+ if ((argc < 2) || (argc > 2)) {
2135
+ rb_raise(rb_eArgError, "wrong # of arguments(%d for 2)",argc); SWIG_fail;
2136
+ }
2137
+ res1 = SWIG_AsCharPtrAndSize(argv[0], &buf1, NULL, &alloc1);
2138
+ if (!SWIG_IsOK(res1)) {
2139
+ SWIG_exception_fail(SWIG_ArgError(res1), Ruby_Format_TypeError( "", "char const *","libinjection_pathtraversal", 1, argv[0] ));
2140
+ }
2141
+ arg1 = (char *)(buf1);
2142
+ ecode2 = SWIG_AsVal_size_t(argv[1], &val2);
2143
+ if (!SWIG_IsOK(ecode2)) {
2144
+ SWIG_exception_fail(SWIG_ArgError(ecode2), Ruby_Format_TypeError( "", "size_t","libinjection_pathtraversal", 2, argv[1] ));
2145
+ }
2146
+ arg2 = (size_t)(val2);
2147
+ result = (int)libinjection_pathtraversal((char const *)arg1,arg2);
2148
+ vresult = SWIG_From_int((int)(result));
2149
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
2150
+ return vresult;
2151
+ fail:
2152
+ if (alloc1 == SWIG_NEWOBJ) free((char*)buf1);
2153
+ return Qnil;
2154
+ }
2155
+
2156
+
2122
2157
 
2123
2158
  /* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
2124
2159
 
@@ -2389,5 +2424,6 @@ SWIGEXPORT void Init_libinjection(void) {
2389
2424
  rb_define_module_function(mLibinjection, "libinjection_version", _wrap_libinjection_version, -1);
2390
2425
  rb_define_module_function(mLibinjection, "libinjection_sqli", _wrap_libinjection_sqli, -1);
2391
2426
  rb_define_module_function(mLibinjection, "libinjection_xss", _wrap_libinjection_xss, -1);
2427
+ rb_define_module_function(mLibinjection, "libinjection_pathtraversal", _wrap_libinjection_pathtraversal, -1);
2392
2428
  }
2393
2429
 
data/lib/constants.rb CHANGED
@@ -20,6 +20,16 @@ module Threatstack
20
20
  TRUTHY.include?(val.to_s.downcase)
21
21
  end
22
22
 
23
+ def self.app_root_dir
24
+ return Bundler.root if defined?(Bundler)
25
+
26
+ return ENV['RAILS_ROOT'] if defined?(ENV['RAILS_ROOT']) && ENV['RAILS_ROOT'].to_s.strip.length != 0
27
+
28
+ return Rails.root if defined?(Rails) && Rails.root.to_s.strip.length != 0
29
+
30
+ Dir.pwd
31
+ end
32
+
23
33
  TRUTHY = ['true', '1', 'yes'].freeze
24
34
 
25
35
  # AGENT
@@ -29,14 +39,18 @@ module Threatstack
29
39
  AGENT_ID = self.env('AGENT_ID', '')
30
40
  ## autogenerated Id for this agent instance
31
41
  AGENT_INSTANCE_ID = SecureRandom.uuid
32
- ## whether or not the agent is disabled
42
+ ## whether or not the agent is disabled, defaults to false
33
43
  DISABLED = self.is_truthy('DISABLED')
34
- ## whether or not initialization is done manually by calling
44
+ ## whether or not initialization is done manually, defaults to false
35
45
  MANUAL_INIT = self.is_truthy('MANUAL_INIT')
36
- ## whether or not requests containing XSS payloads should be blocked
46
+ ## whether or not requests containing XSS payloads should be blocked, defaults to false
37
47
  BLOCK_XSS = self.is_truthy('BLOCK_XSS')
38
- ## whether or not requests containing SQLI payloads should be blocked
48
+ ## whether or not requests containing SQLI payloads should be blocked, defaults to false
39
49
  BLOCK_SQLI = self.is_truthy('BLOCK_SQLI')
50
+ ## whether or not requests containing Path Traversal payloads should be blocked, defaults to false
51
+ BLOCK_PATH_TRAVERSAL = self.is_truthy('BLOCK_PATH_TRAVERSAL')
52
+ ## whether or not requests should be checked for Path Traversal payloads, defaults to true
53
+ DETECT_PATH_TRAVERSAL = self.is_truthy('DETECT_PATH_TRAVERSAL', true)
40
54
  ## specifies which user fields should be omitted from event payloads
41
55
  DROP_FIELDS = self.env('DROP_FIELDS', false) ? self.env('DROP_FIELDS').split(',').each_with_object({}) do |val, h|
42
56
  h[val] = true
@@ -49,6 +63,8 @@ module Threatstack
49
63
  JOB_INTERVAL = Integer(self.env('SUBMISSION_INTERVAL', 10))
50
64
  ## max number of events per request
51
65
  EVENTS_PER_REQ = Integer(self.env('EVENTS_PER_REQ', 1000))
66
+ ## max number of events to keep in memory
67
+ MAX_QUEUED_EVENTS = Integer(self.env('MAX_QUEUED_EVENTS', 1000))
52
68
  ## base url
53
69
  APPSEC_BASE_URL = self.env('API_COLLECTOR_URL', 'https://appsec-sensors.threatstack.com')
54
70
  ## event collector path
@@ -76,12 +92,16 @@ module Threatstack
76
92
  # Strings
77
93
  XSS = 'xss'
78
94
  SQLI = 'sqli'
95
+ PATH_TRAVERSAL = 'path_traversal'
79
96
  REQUEST_BLOCKED = 'Request blocked'
80
97
  DETECTED_NOT_BLOCKED = 'Detected not blocked'
81
98
  CGI_VARIABLES = Set.new(%w[ AUTH_TYPE CONTENT_LENGTH CONTENT_TYPE GATEWAY_INTERFACE HTTPS PATH_INFO
82
99
  PATH_TRANSLATED REMOTE_ADDR REMOTE_HOST REMOTE_IDENT REMOTE_USER
83
100
  REQUEST_METHOD SCRIPT_NAME SERVER_NAMESERVER_PORT SERVER_PROTOCOL
84
101
  SERVER_SOFTWARE]).freeze
102
+
103
+ # Utils
104
+ ROOT_DIR = self.app_root_dir
85
105
  end
86
106
  end
87
107
 
@@ -99,12 +119,16 @@ module Threatstack
99
119
  APPSEC SENSOR URL: #{APPSEC_BASE_URL}
100
120
  BLOCK SQLI: #{BLOCK_SQLI}
101
121
  BLOCK XSS: #{BLOCK_XSS}
122
+ BLOCK PATH TRAVERSAL: #{BLOCK_PATH_TRAVERSAL}
123
+ DETECT PATH TRAVERSAL: #{DETECT_PATH_TRAVERSAL}
102
124
  DROP FIELDS: #{DROP_FIELDS}
103
125
  SUBMIT INTERVAL: #{JOB_INTERVAL}
104
126
  EVENTS PER REQ: #{EVENTS_PER_REQ}
127
+ MAX QUEUED EVENTS: #{MAX_QUEUED_EVENTS}
105
128
  LOG LEVEL: #{LOG_LEVEL}
106
129
  LOG COLORS: #{LOG_COLORS}
107
130
  MANUAL INIT: #{MANUAL_INIT}
108
- REDACTED TEXT: #{REDACTED}"""
131
+ REDACTED TEXT: #{REDACTED}
132
+ ROOT DIR: #{ROOT_DIR}"""
109
133
  end
110
134
  end
data/lib/control.rb CHANGED
@@ -4,8 +4,9 @@ require 'thread'
4
4
 
5
5
  require_relative './events/models/environment_event'
6
6
  require_relative './events/models/dependency_event'
7
- require_relative './instrumentation/rails'
8
- require_relative './instrumentation/kernel'
7
+ require_relative './instrumentation/frameworks/rails'
8
+ require_relative './instrumentation/frameworks/kernel'
9
+ require_relative './instrumentation/frameworks/random'
9
10
  require_relative './jobs/event_submitter'
10
11
  require_relative './jobs/delayed_job'
11
12
  require_relative './utils/logger'
@@ -26,21 +27,29 @@ module Threatstack
26
27
  logger = Threatstack::Utils::TSLogger.create 'MainAgent'
27
28
  logger.info 'Initializing Threatstack Ruby agent'
28
29
 
29
- # patch Rails ActionController
30
+ ############################## Instrumentation ##############################
31
+ ## patch Rails ActionController
30
32
  logger.info 'Instrumenting Rails...'
31
- Threatstack::Instrumentation::TSRails.patch_action_controller
33
+ Threatstack::Instrumentation::Frameworks::TSRails.patch_action_controller
32
34
  logger.info 'Done instrumenting Rails'
33
35
 
34
- # patch Kernel methods
36
+ ## patch Kernel methods
35
37
  logger.info 'Instrumenting Kernel methods...'
36
- Threatstack::Instrumentation::TSKernel.wrap_methods
38
+ Threatstack::Instrumentation::Frameworks::TSKernel.wrap_methods
37
39
  logger.info 'Done instrumenting Kernel methods'
38
40
 
41
+ ## patch Kernel methods
42
+ logger.info 'Instrumenting Random methods...'
43
+ Threatstack::Instrumentation::Frameworks::TSRandom.wrap_methods
44
+ logger.info 'Done instrumenting Random methods'
45
+
46
+ ############################## Event Submitter ##############################
39
47
  # Start EventSubmitter asynchronously
40
48
  logger.info 'Starting Event Submitter...'
41
49
  Threatstack::Jobs::EventSubmitter.instance.start
42
50
  logger.info 'Started Event Submitter'
43
51
 
52
+ ############################## Delayed Tasks ##############################
44
53
  # Gather environment and dependency info asynchronously
45
54
  Threatstack::Jobs::DelayedJob.new(logger, 5) do
46
55
  dep_event = Threatstack::Events::DependencyEvent.new
@@ -49,6 +58,10 @@ module Threatstack
49
58
  # submit environment event
50
59
  Threatstack::Jobs::EventSubmitter.instance.queue_event Threatstack::Events::EnvironmentEvent.new
51
60
  end
61
+ # Report Rails config once it's loaded
62
+ Threatstack::Jobs::DelayedJob.new('DelayedConfig', 20) do
63
+ Threatstack::Instrumentation::Frameworks::TSRails.report_application_config
64
+ end
52
65
 
53
66
  logger.info 'Initialization done for agent'
54
67
  end
@@ -2,7 +2,9 @@
2
2
 
3
3
  require 'singleton'
4
4
 
5
+ require_relative '../constants'
5
6
  require_relative '../utils/logger'
7
+ require_relative '../utils/capped_queue'
6
8
 
7
9
  module Threatstack
8
10
  module Events
@@ -10,21 +12,28 @@ module Threatstack
10
12
  class EventAccumulator
11
13
  include Singleton
12
14
 
13
- attr_reader :events
14
-
15
15
  def initialize
16
- @events = []
16
+ @events = Threatstack::Utils::CappedQueue.new Threatstack::Constants::MAX_QUEUED_EVENTS
17
17
  @logger = Threatstack::Utils::TSLogger.create 'EventAccumulator'
18
18
  end
19
19
 
20
+ def total_events
21
+ @events.length
22
+ end
23
+
20
24
  def add_event(event)
21
- @logger.debug "Adding event - New Total: #{@events.length + 1}"
22
25
  @events.push(event)
26
+ @logger.debug "Added event - New Total: #{@events.length}"
27
+ end
28
+
29
+ def remove_event
30
+ @events.shift
23
31
  end
24
32
 
25
- def remove_events(num = 1)
26
- @logger.debug "Removing #{num} event(s) - New Total: #{@events.length - num}"
27
- @events.shift(num)
33
+ def remove_events(num)
34
+ ev = @events.shift(num)
35
+ @logger.debug "Removed #{ev.length} event(s) - New Total: #{@events.length}"
36
+ ev
28
37
  end
29
38
 
30
39
  def clear_events