@@ -16,33 +16,76 @@ def initialize(info = {})
16
16
to send messages to users on the target system.
17
17
} ,
18
18
'License' => MSF_LICENSE ,
19
- 'Author' => [ 'Jon Hart <jon_hart[at]rapid7.com>' ] ,
19
+ 'Author' => [
20
+ 'Jon Hart <jon_hart[at]rapid7.com>' # original metasploit module
21
+ ] ,
20
22
# TODO: is there a way to do this on Windows?
21
23
'Platform' => %w( linux osx unix ) ,
22
24
'SessionTypes' => %w( shell meterpreter )
23
25
)
24
26
)
25
27
register_options (
26
28
[
27
- OptString . new ( 'MESSAGE' , [ true , 'The message to send' ] ) ,
29
+ OptString . new ( 'MESSAGE' , [ false , 'The message to send' , ' '] ) ,
28
30
OptString . new ( 'USERS' , [ false , 'List of users to write(1) to, separated by commas. ' \
29
- ' wall(1)s to all users by default' ] )
31
+ ' wall(1)s to all users by default' ] ) ,
32
+ OptBool . new ( 'COWSAY' , [ true , 'Display MESSAGE in a ~cowsay way' , false ] )
30
33
] , self . class )
31
34
end
32
35
36
+ def cowsay ( text )
37
+ # cowsay(1) chunks a message up into 39-byte chunks and wraps it in '| ' and ' |'
38
+ # Rex::Text.wordwrap(text, 0, 39, ' |', '| ') almost does this, but won't
39
+ # split a word that has > 39 characters in it which results in oddly formed
40
+ # text in the cowsay banner, so just do it by hand
41
+ text_lines = text . scan ( /.{1,34}/ )
42
+ max_length = text_lines . map ( &:size ) . sort . last
43
+ cloud_parts = [ ]
44
+ cloud_parts << " #{ '_' * ( max_length + 2 ) } "
45
+ if text_lines . size == 1
46
+ cloud_parts << "< #{ text } >"
47
+ else
48
+ cloud_parts << "/ #{ text_lines . first . ljust ( max_length , ' ' ) } \\ "
49
+ if text_lines . size > 2
50
+ text_lines [ 1 , text_lines . length - 2 ] . each do |line |
51
+ cloud_parts << "| #{ line . ljust ( max_length , ' ' ) } |"
52
+ end
53
+ end
54
+ cloud_parts << "\\ #{ text_lines . last . ljust ( max_length , ' ' ) } /"
55
+ end
56
+ cloud_parts << " #{ '-' * ( max_length + 2 ) } "
57
+ cloud_parts << <<EOS
58
+ \\ ,__,
59
+ \\ (oo)____
60
+ (__) )\\
61
+ ||--|| *
62
+ EOS
63
+ cloud_parts . join ( "\n " )
64
+ end
65
+
33
66
def users
34
67
datastore [ 'USERS' ] ? datastore [ 'USERS' ] . split ( /\s *,\s */ ) : nil
35
68
end
36
69
37
70
def message
38
- datastore [ 'MESSAGE' ] ? datastore [ 'MESSAGE' ] : "Hello metasploit session #{ session . id } , the time is #{ Time . now } "
71
+ if datastore [ 'MESSAGE' ] . blank?
72
+ text = "Hello from a metasploit session at #{ Time . now } "
73
+ else
74
+ text = datastore [ 'MESSAGE' ]
75
+ end
76
+
77
+ datastore [ 'COWSAY' ] ? cowsay ( text ) : text
39
78
end
40
79
41
80
def run
42
81
if users
82
+ # this requires that the target user has write turned on
43
83
users . map { |user | cmd_exec ( "echo '#{ message } ' | write #{ user } " ) }
44
84
else
45
- cmd_exec ( "echo '#{ message } ' | wall" )
85
+ # this will send the messages to all users, regardless of whether or
86
+ # not they have write turned on. If the session is root, the -n will disable
87
+ # the annoying banner
88
+ cmd_exec ( "echo '#{ message } ' | wall -n" )
46
89
end
47
90
end
48
91
end
0 commit comments