CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/tools/exploit/find_badchars.rb
Views: 11766
1
#!/usr/bin/env ruby
2
3
##
4
# This module requires Metasploit: https://metasploit.com/download
5
# Current source: https://github.com/rapid7/metasploit-framework
6
##
7
8
#
9
# This script is intended to assist an exploit developer in deducing what
10
# "bad characters" exist for a given input path to a program.
11
#
12
begin
13
msfbase = __FILE__
14
while File.symlink?(msfbase)
15
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
16
end
17
18
gem 'rex-text'
19
20
$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))
21
require 'msfenv'
22
23
$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
24
require 'rex'
25
26
OutStatus = "[*] "
27
OutError = "[-] "
28
29
$args = Rex::Parser::Arguments.new(
30
"-b" => [ true, "The list of characters to avoid: '\\x00\\xff'" ],
31
"-h" => [ false, "Help banner" ],
32
"-i" => [ true, "Read memory contents from the supplied file path" ],
33
"-t" => [ true, "The format that the memory contents are in (empty to list)" ])
34
35
def usage
36
$stderr.puts("\n" + " Usage: #{File.basename($0)} <options>\n" + $args.usage)
37
exit
38
end
39
40
def show_format_list
41
$stderr.puts("Supported formats:\n")
42
$stderr.puts(" raw raw binary data\n")
43
$stderr.puts(" windbg output from windbg's \"db\" command\n")
44
$stderr.puts(" gdb output from gdb's \"x/bx\" command\n")
45
$stderr.puts(" hex hex bytes like \"\\xFF\\x41\" or \"eb fe\"\n")
46
end
47
48
def debug_buffer(name, buf)
49
str = "\n#{buf.length} bytes of "
50
str << name
51
str += ":" if buf.length > 0
52
str += "\n\n"
53
$stderr.puts str
54
if buf.length > 0
55
$stderr.puts Rex::Text.to_hex_dump(buf)
56
end
57
end
58
59
60
# Input defaults
61
badchars = ''
62
fmt = 'raw'
63
input = $stdin
64
65
# Output
66
new_badchars = ''
67
68
# Parse the argument and rock it
69
$args.parse(ARGV) { |opt, idx, val|
70
case opt
71
when "-i"
72
begin
73
input = File.new(val)
74
rescue
75
$stderr.puts(OutError + "Failed to open file #{val}: #{$!}")
76
exit
77
end
78
when "-b"
79
badchars = Rex::Text.dehex(val)
80
when "-t"
81
if (val =~ /^(raw|windbg|gdb|hex)$/)
82
fmt = val
83
else
84
if val.nil? or val.length < 1
85
show_format_list
86
else
87
$stderr.puts(OutError + "Invalid format: #{val}")
88
end
89
exit
90
end
91
when "-h"
92
usage
93
end
94
}
95
96
if input == $stdin
97
$stderr.puts(OutStatus + "Please paste the memory contents in \"" + fmt + "\" format below (end with EOF):\n")
98
end
99
100
101
102
# Working data set
103
from_msf = Rex::Text.charset_exclude(badchars)
104
from_dbg = ''
105
106
107
# Process the input
108
from_dbg = input.read
109
case fmt
110
when "raw"
111
# this should already be in the correct format :)
112
113
when "windbg"
114
translated = ''
115
from_dbg.each_line do |ln|
116
translated << ln.chomp[10,47].gsub!(/(-| )/, '')
117
end
118
from_dbg = Rex::Text.hex_to_raw(translated)
119
120
when "gdb"
121
translated = ''
122
from_dbg.each_line do |ln|
123
translated << ln.chomp.split(':')[1].gsub!(/0x/, '\x').gsub!(/ /, '')
124
end
125
from_dbg = Rex::Text.hex_to_raw(translated)
126
127
when "hex"
128
translated = ''
129
from_dbg.each_line do |ln|
130
translated << ln.chomp.gsub!(/ /,'')
131
end
132
from_dbg = Rex::Text.hex_to_raw(translated)
133
end
134
135
136
137
=begin
138
# Uncomment these to debug stuff ..
139
debug_buffer("BadChars", badchars)
140
debug_buffer("memory contents", from_dbg)
141
debug_buffer("Rex::Text.charset_exclude() output", from_msf)
142
=end
143
144
145
# Find differences between the two data sets
146
from_msf = from_msf.unpack('C*')
147
from_dbg = from_dbg.unpack('C*')
148
minlen = from_msf.length
149
minlen = from_dbg.length if from_dbg.length < minlen
150
(0..(minlen-1)).each do |idx|
151
ch1 = from_msf[idx]
152
ch2 = from_dbg[idx]
153
if ch1 != ch2
154
str = "Byte at index 0x%04x differs (0x%02x became 0x%02x)" % [idx, ch1, ch2]
155
$stderr.puts OutStatus + str
156
new_badchars << ch1
157
end
158
end
159
160
161
# show the results
162
if new_badchars.length < 1
163
$stderr.puts(OutStatus + "All characters matched, no new bad characters discovered.")
164
else
165
$stderr.puts(OutStatus + "Proposed BadChars: \"" + Rex::Text.to_hex(new_badchars) + "\"")
166
end
167
rescue SignalException => e
168
puts("Aborted! #{e}")
169
end
170
171