ileitch-hijack 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,26 +1,128 @@
1
1
  = Hijack: Provides an irb session to an existing ruby process.
2
2
 
3
+ == Intro
4
+
5
+ Hijack allows you to connect to any ruby process and execute code as if it were a normal irb session. Hijack does not require your target process to require any hijacking code, hijack is able to connect to any ruby process. It achieves this by using gdb to inject a payload into the process which starts up a DRb server, hijack then detaches gdb and reconnects via DRb. Please note that gdb will halt your target process while it is attached, though the injection process is very quick and your process should only be halted for a few milliseconds.
6
+
7
+ Hijack uses DRb over a unix socket file, so you need to be on the same machine as the process you want to hijack. This is by design for security reasons. You also need to run the hijack client as the same user as the remote process.
8
+
3
9
  == WARNING
4
10
 
5
11
  Hijack is new code, I'd think twice about trying it out on your critical production systems. I'd love to get some feedback though so if you have any staging systems to try it out on then please do... ;)
6
12
 
7
- == Intro
13
+ == Using Hijack
8
14
 
9
- Hijack allows you to connect to any ruby process and execute code as if it were a normal Irb session. Hijack does not require your target process to require any hijack code, Hijack is able to connect to any ruby process. It achieves this by using gdb to inject a payload into the process which starts up a DRb server, Hijack then detaches gdb and reconnects via DRb. Please note that gdb will halt your target process while it is attached, though the injection process is very quick and your process should only be halted for a few milliseconds.
15
+ $ hijack 16451
16
+ => Hijacked 16451 (my_script.rb) (ruby 1.8.7 [i686-darwin9])
17
+ >>
10
18
 
11
- Hijack uses DRb over a unix socket file, so you need to be on the same machine as the process you want to hijack. This is by design for security reasons. You also need to run the hijack client as the same user as the remote process.
19
+ == Using ruby-debug
12
20
 
13
- == Using Hijack
21
+ Hijack can be used a means to start ruby-debug in your target process, for example:
22
+
23
+ $ hijack 61378
24
+ => Hijacked 61378 (/opt/local/bin/thin) (ruby 1.8.7 [i686-darwin9])
25
+ >> hijack_debug_mode
26
+ => true
27
+
28
+ We've enabled debug mode, but we still need to insert a breakpoint:
29
+
30
+ >> ActionController::Dispatcher.class_eval do
31
+ >> class << self
32
+ >> def dispatch_with_debugger(cgi, session_options, output)
33
+ >> debugger
34
+ >> dispatch_without_debugger(cgi, session_options, output)
35
+ >> end
36
+ >> alias_method :dispatch_without_debugger, :dispatch
37
+ >> alias_method :dispatch, :dispatch_with_debugger
38
+ >> end
39
+ >> end
40
+
41
+ Now tell hijack that we can start debugging:
42
+
43
+ >> hijack_debug_start
44
+ Connected.
45
+
46
+ Point your browser at http://0.0.0.0:3000 to trigger the breakpoint and ruby-debug's console will appear:
47
+
48
+ >> hijack_debug_start
49
+ Connected.
50
+ (eval):5
51
+ (rdb:4) step
52
+ /Users/ian/Projects/zioko/vendor/rails/actionpack/lib/action_controller/dispatcher.rb:28 new(output).dispatch_cgi(cgi, session_options)
53
+ (rdb:4) backtrace
54
+ --> #0 /Users/ian/Projects/zioko/vendor/rails/actionpack/lib/action_controller/dispatcher.rb:28 in 'dispatch_without_debugger'
55
+ #1 (eval):5 in 'dispatch'
56
+ #2 /opt/local/lib/ruby/gems/1.8/gems/thin-1.2.2/lib/rack/adapter/rails.rb:81 in 'call'
57
+ #3 /opt/local/lib/ruby/gems/1.8/gems/thin-1.2.2/lib/rack/adapter/rails.rb:69 in 'call'
58
+ #4 /opt/local/lib/ruby/gems/1.8/gems/thin-1.2.2/lib/thin/connection.rb:76 in 'pre_process'
59
+ #5 /opt/local/lib/ruby/gems/1.8/gems/thin-1.2.2/lib/thin/connection.rb:74 in 'pre_process'
60
+ #6 /opt/local/lib/ruby/gems/1.8/gems/thin-1.2.2/lib/thin/connection.rb:57 in 'process'
61
+ #7 /opt/local/lib/ruby/gems/1.8/gems/thin-1.2.2/lib/thin/connection.rb:42 in 'receive_data'
62
+ (rdb:4)
63
+
64
+ One caveat is that ruby-debug's 'irb' command will not work because the debug connection is remote, you also can't use hijack's irb console whilst debugging. A future version of hijack will hopefully allow you to switch between the two.
65
+
66
+ == Monkey Patching
67
+
68
+ Just as in a normal irb session, you can redefine the code running in your target process.
69
+
70
+ This example redefines ActionController's dispatcher to print basic request activity (the example can be found in examples/rails_dispatcher.rb).
71
+
72
+ Start up a Thin web server:
73
+
74
+ $ thin start
75
+ >> Using rails adapter
76
+ >> Thin web server (v1.2.2 codename I Find Your Lack of Sauce Disturbing)
77
+ >> Maximum connections set to 1024
78
+ >> Listening on 0.0.0.0:3000, CTRL+C to stop
79
+
80
+ In another console hijack the Thin process:
81
+
82
+ $ ps | grep thin
83
+ 61160 ttys001 0:01.43 /opt/local/bin/ruby /opt/local/bin/thin start
84
+
85
+ $ hijack 61160
86
+ => Hijacked 61160 (/opt/local/bin/thin) (ruby 1.8.7 [i686-darwin9])
87
+ >> ActionController::Dispatcher.class_eval do
88
+ ?> class << self
89
+ >> def dispatch_with_spying(cgi, session_options, output)
90
+ >> env = cgi.__send__(:env_table)
91
+ >> puts "#{Time.now.strftime('%Y/%m/%d %H:%M:%S')} - #{env['REMOTE_ADDR']} - #{env['REQUEST_URI']}"
92
+ >> dispatch_without_spying(cgi, session_options, output)
93
+ >> end
94
+ >> alias_method :dispatch_without_spying, :dispatch
95
+ >> alias_method :dispatch, :dispatch_with_spying
96
+ >> end
97
+ >> end
98
+
99
+ Point your browser to http://0.0.0.0:3000.
100
+
101
+ Back in hijack you'll see your browsing activity:
102
+
103
+ 2009/08/22 14:24:48 - 127.0.0.1 - /
104
+ 2009/08/22 14:24:53 - 127.0.0.1 - /login
105
+ 2009/08/22 14:24:54 - 127.0.0.1 - /signup
106
+
107
+ Instead of pasting your code into hijack, you can pass hijack the -e option at startup to execute from a file:
108
+
109
+ $ hijack -e examples/rails_dispatcher.rb 61565
110
+ => Hijacked 61565 (/opt/local/bin/thin) (ruby 1.8.7 [i686-darwin9])
111
+ => Executing examples/rails_dispatcher.rb... done!
112
+ >> 2009/08/22 14:46:36 - 127.0.0.1 - /
113
+
114
+ == Process Output
115
+
116
+ By default hijack will forward your process output to the hijack client. This can get a little messy if your trying to type and command at the same time as the target process writes to STDOUT/STDERR. You can mute and unmute the process with:
14
117
 
15
- $ ruby hijack 16451
16
- => Hijacking...
17
- => Mirroring: 100%
18
- => Hijacked 16451 (my_script.rb) (ruby 1.8.7 [i686-darwin9])
19
- >>
118
+ >> hijack_mute
119
+ >> true
120
+ >> hijack_unmute
121
+ >> true
20
122
 
21
123
  == Process Mirroring
22
124
 
23
- DRb cannot dump objects to the Hijack client for types that are not loaded in the client process. E.g if the remote process had required ActiveRecord and you tried to dump ActiveRecord::Base back to the client, DRb would instead return a DRb::Unknown object as ActiveRecord
24
- isn't loaded in the Hijack client.
125
+ DRb cannot dump objects to the hijack client for types that are not loaded in the client process. E.g if the remote process had required ActiveRecord and you tried to dump ActiveRecord::Base back to the client, DRb would instead return a DRb::Unknown object as ActiveRecord
126
+ isn't loaded in the hijack client.
25
127
 
26
- To work around this, when Hijack connects to a remote process it will inspect all the files required by the process and also attempt to require them itself. This may not work for all object types however so you may still get a warning when an object cannot be dumped.
128
+ To work around this, when hijack connects to a remote process it will inspect all the files required by the process and also attempt to require them itself. This may not work for all object types however so you may still get a warning when an object cannot be dumped.
@@ -5,8 +5,7 @@ ActionController::Dispatcher.class_eval do
5
5
  puts "#{Time.now.strftime('%Y/%m/%d %H:%M:%S')} - #{env['REMOTE_ADDR']} - #{env['REQUEST_URI']}"
6
6
  dispatch_without_spying(cgi, session_options, output)
7
7
  end
8
-
9
8
  alias_method :dispatch_without_spying, :dispatch
10
9
  alias_method :dispatch, :dispatch_with_spying
11
10
  end
12
- end
11
+ end
@@ -33,7 +33,7 @@ module Hijack
33
33
  end
34
34
 
35
35
  def signal_drb_start
36
- Process.kill('USR1', @pid.to_i)
36
+ Process.kill('USR2', @pid.to_i)
37
37
  loop do
38
38
  break if File.exists?(Hijack.socket_path_for(@pid))
39
39
  sleep 0.1
data/lib/hijack/helper.rb CHANGED
@@ -2,7 +2,7 @@ module Hijack
2
2
  module Helper
3
3
  class << self
4
4
  def helpers
5
- ['hijack_mute', 'hijack_unmute']
5
+ methods.find_all {|meth| meth =~ /^hijack_/}
6
6
  end
7
7
 
8
8
  def find_helper(statements)
@@ -23,6 +23,23 @@ module Hijack
23
23
  Hijack::Console::OutputReceiver.unmute
24
24
  true
25
25
  end
26
+
27
+ def hijack_debug_mode(remote)
28
+ hijack_mute(remote)
29
+ require 'rubygems'
30
+ require 'ruby-debug'
31
+ remote.evaluate(<<-RB)
32
+ require 'rubygems'
33
+ require 'ruby-debug'
34
+ Debugger.start_remote
35
+ RB
36
+ true
37
+ end
38
+
39
+ def hijack_debug_start(remote)
40
+ Debugger.start_client
41
+ true
42
+ end
26
43
  end
27
44
  end
28
45
  end
@@ -71,7 +71,7 @@ module Hijack
71
71
  end
72
72
  end
73
73
  __hijack_context = self
74
- Signal.trap('USR1') { Hijack.start(__hijack_context) }
74
+ Signal.trap('USR2') { Hijack.start(__hijack_context) }
75
75
  EOS
76
76
  end
77
77
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ileitch-hijack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ian Leitch
@@ -21,7 +21,6 @@ extensions: []
21
21
 
22
22
  extra_rdoc_files:
23
23
  - README.rdoc
24
- - TODO
25
24
  files:
26
25
  - README.rdoc
27
26
  - Rakefile