Skip to content

Commit 9f69dbb

Browse files
update unless statements, targeturi, and resolve var
1 parent 0de23a7 commit 9f69dbb

File tree

1 file changed

+54
-35
lines changed

1 file changed

+54
-35
lines changed

modules/auxiliary/scanner/http/wordpress_pingback_access.rb

Lines changed: 54 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,22 @@ def initialize(info = {})
2424
[
2525
'Thomas McCarthy "smilingraccoon" <smilingraccoon[at]gmail.com>',
2626
'Brandon McCann "zeknox" <bmccann[at]accuvant.com>' ,
27-
'FireFart', # Original PoC
27+
'FireFart' # Original PoC
2828
],
2929
'License' => MSF_LICENSE,
3030
'References' =>
3131
[
3232
[ 'URL', 'http://www.securityfocus.com/archive/1/525045/30/30/threaded'],
3333
[ 'URL', 'http://www.ethicalhack3r.co.uk/security/introduction-to-the-wordpress-xml-rpc-api/'],
34-
[ 'URL', 'https://github.com/FireFart/WordpressPingbackPortScanner'],
35-
],
34+
[ 'URL', 'https://github.com/FireFart/WordpressPingbackPortScanner']
35+
]
3636
))
3737

38+
register_options(
39+
[
40+
OptString.new('TARGETURI', [ true, 'The path to wordpress installation (e.g. /wordpress/)', '/'])
41+
], self.class)
42+
3843
register_advanced_options(
3944
[
4045
OptInt.new('NUM_REDIRECTS', [ true, "Number of HTTP redirects to follow", 10])
@@ -55,16 +60,21 @@ def get_xml_rpc_url(ip)
5560
vprint_status("Enumerating XML-RPC URI for #{ip}...")
5661

5762
begin
63+
64+
uri = target_uri.path
65+
uri << '/' if uri[-1,1] != '/'
66+
5867
res = send_request_cgi(
5968
{
6069
'method' => 'HEAD',
70+
'uri' => "#{uri}"
6171
})
6272
# Check if X-Pingback exists and return value
63-
unless res.nil?
64-
unless res['X-Pingback'].nil?
73+
if res
74+
if res['X-Pingback']
6575
return res['X-Pingback']
6676
else
67-
print_error("X-Pingback header not found, quiting")
77+
vprint_status("X-Pingback header not found at #{ip}")
6878
return nil
6979
end
7080
else
@@ -92,29 +102,29 @@ def generate_pingback_xml (target, valid_blog_post)
92102

93103
def get_blog_posts(xml_rpc, ip)
94104
# find all blog posts within IP and determine if pingback is enabled
95-
vprint_status("Enumerating Blog posts...")
96-
blog_posts = {}
105+
vprint_status("Enumerating Blog posts on #{ip}...")
106+
blog_posts = ""
107+
108+
uri = target_uri.path
109+
uri << '/' if uri[-1,1] != '/'
97110

98111
# make http request to feed url
99112
begin
113+
vprint_status("Resolving #{ip}#{uri}?feed=rss2 to locate wordpress feed...")
100114
res = send_request_cgi({
101-
'uri' => '/?feed=rss2',
102-
'method' => 'GET',
115+
'uri' => "#{uri}?feed=rss2",
116+
'method' => 'GET'
103117
})
104118

105-
resolve = true
106119
count = datastore['NUM_REDIRECTS']
107-
while (res.code == 301 || res.code == 302) and count != 0
108-
if resolve
109-
print_status("Resolving #{ip}/?feed=rss2 to locate wordpress feed...")
110-
resolve = false
111-
else
112-
vprint_status("Web server returned a #{res.code}...following to #{res.headers['location']}")
113-
end
114-
uri = res.headers['location'].sub(/.*?#{ip}/, "")
120+
121+
# Follow redirects
122+
while (res.code == 301 || res.code == 302) and res.headers['Location'] and count != 0
123+
vprint_status("Web server returned a #{res.code}...following to #{res.headers['Location']}")
124+
uri = res.headers['Location'].sub(/.*?#{ip}/, "")
115125
res = send_request_cgi({
116126
'uri' => "#{uri}",
117-
'method' => 'GET',
127+
'method' => 'GET'
118128
})
119129

120130
if res.code == 200
@@ -129,31 +139,37 @@ def get_blog_posts(xml_rpc, ip)
129139
end
130140

131141
# parse out links and place in array
142+
if res.nil? or res.code != 200
143+
return blog_posts
144+
end
145+
132146
links = res.to_s.scan(/<link>([^<]+)<\/link>/i)
133147

134-
if res.code != 200 or links.nil? or links.empty?
148+
if links.nil? or links.empty?
135149
return blog_posts
136150
end
137151

152+
138153
links.each do |link|
139154
blog_post = link[0]
140-
pingback_request = get_pingback_request(xml_rpc, 'http://127.0.0.1', blog_post)
141-
142-
pingback_disabled_match = pingback_request.body.match(/<value><int>33<\/int><\/value>/i)
143-
if pingback_request.code == 200 and pingback_disabled_match.nil?
144-
print_good("Pingback enabled: #{link.join}")
145-
blog_posts = link.join
146-
return blog_posts
147-
else
148-
vprint_status("Pingback disabled: #{link.join}")
155+
pingback_response = get_pingback_request(xml_rpc, 'http://127.0.0.1', blog_post)
156+
if pingback_response
157+
pingback_disabled_match = pingback_response.body.match(/<value><int>33<\/int><\/value>/i)
158+
if pingback_response.code == 200 and pingback_disabled_match.nil?
159+
print_good("Pingback enabled: #{link.join}")
160+
blog_posts = link.join
161+
return blog_posts
162+
else
163+
vprint_status("Pingback disabled: #{link.join}")
164+
end
149165
end
150166
end
151167
return blog_posts
152168
end
153169

154170
# method to send xml-rpc requests
155171
def get_pingback_request(xml_rpc, target, blog_post)
156-
uri = xml_rpc.sub(/.*?#{ip}/,"")
172+
uri = xml_rpc.sub(/.*?#{target}/,"")
157173
# create xml pingback request
158174
pingback_xml = generate_pingback_xml(target, blog_post)
159175

@@ -162,7 +178,7 @@ def get_pingback_request(xml_rpc, target, blog_post)
162178
res = send_request_cgi({
163179
'uri' => "#{uri}",
164180
'method' => 'POST',
165-
'data' => "#{pingback_xml}",
181+
'data' => "#{pingback_xml}"
166182
})
167183
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
168184
print_error("Unable to connect to #{uri}")
@@ -177,9 +193,12 @@ def get_pingback_request(xml_rpc, target, blog_post)
177193
# Save data to vuln table
178194
def store_vuln(ip, blog)
179195
report_vuln(
180-
:host => ip,
181-
:name => self.name,
182-
:info => "Module #{self.fullname} found pingback at #{blog}"
196+
:host => ip,
197+
:proto => 'tcp',
198+
:port => datastore['RPORT'],
199+
:name => self.name,
200+
:info => "Module #{self.fullname} found pingback at #{blog}",
201+
:sname => datastore['SSL'] ? "https" : "http"
183202
)
184203
end
185204

0 commit comments

Comments
 (0)