threatstack-agent-ruby 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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