This is Second Breakfast, Implicit and Mutation-Based Serialization Vulnerabilities in .NET. I'm Jonathan Birch. I hack Office for Microsoft. And if you want to talk to me about this presentation... I'm Jonathan Birch. I hack Office for Microsoft. If you want to talk to me about this presentation or anything else security-related, please contact me on Mastodon. In this talk, I'm going to explain remote code execution vulnerabilities I found in several .NET NoSQL engines. I'll talk about what I'm calling a mutation-based serialization vulnerability. I'll explain how you can bypass serialization binders and how you can defend against all of that. Also some bonus stuff just for DEF CON at the end. So a lot of my day job is doing security design reviews. I have a bunch of meetings every week where I'm looking at data flow diagrams, telling people, look this way instead, that kind of thing. And something I do in those meetings anymore to sort of add value is I'll just open up their repo that I've never seen before and spend like a half hour while I'm talking to them figuring out what are the actual vulnerabilities here so I can talk to them about that too. And so the research that led to this talk happened because last fall I saw an article on a certain orange-colored website about LightDB. And it's a .NET open source library for a NoSQL engine. I thought, okay, you know, I'll just go do a security review of their repo. And so when I did that, I saw this code. And what jumps out to me in this code specifically is this line, this call to type get type that's being passed a string. And to me at least, that's a really bad sign. But why is that a bad sign? So type get type in .NET is used to convert a string that's like the name of a .NET type into an actual type object. And what that means is that someone's going to be giving you the name of a type generally for an object you're going to create. So they're telling you what kinds of objects you're creating, which means they're telling you essentially what code you're going to run. And that means that if someone malicious comes along, they give you a malicious type name, and you're running malicious code. And so how does that show up in LightDB? Well, LightDB is a NoSQL engine, and generally when an application is using it, it's just saying to LightDB, store this object I've got. And maybe at this index with these properties, that kind of thing. And what LightDB is doing is it's going to put that in a file, so it serializes it with a serializer called BSON mapper into a BSON stream, and stores that BSON stream in a file. And when the application wants the object back, it deserializes that BSON back into an object again. So BSON is just a binary encoding of JSON, so you can take that file LightDB makes, decode it back into JSON, and if you do that, it looks about like this. And if you look at this JSON here, it's got this underscore type key in it, and after that, it's got the name of an actual .NET type. So what LightDB is doing with type get type, is it's taking that type name, it's passing it to type get type to actually create the object during that deserialization. So the data in that BSON is telling LightDB what types it's going to make. And that means that this is just a polymorphic serializer behind the scenes, and that means it's got all of the classic vulnerabilities that polymorphic serializers have. But let's explain a little bit what I'm talking about there. So .NET serialization vulnerabilities. .NET serialization vulnerabilities generally happen because you have a polymorphic serializer. A serializer where the data is telling you what type it wants to be. So in this case, we've got a box, it's some self-describing data, it says it's a cat, it's labeled cat. When your serializer sees that label, it says, well I guess I'm making a cat object, and it just makes a cat object, and then sets some properties from the contents of that box. And the problem with this is, someone malicious can come along, and give you a box labeled pain, your serializer says, well I guess I'm making some pain then, and you're having a bad time. So, if you want a little more information in general on how .NET serialization works, as far as for those sorts of serialization exploits, I suggest looking at the Friday the 13th JSON talks from Black Hat 17. But, I'll also give you a few examples of what this pain is here. So, in general when I'm talking about pain here, what I'm talking about is types that were, if you tell an application to create them, they're going to have side effects that can further exploit goals, either when you call their constructor, set their properties, maybe the destructor, will do something that you want to have happen. Here's a couple of classic ones, assembly installer has a path property, when you set the path property, it just calls load library on whatever path you give it. So, if you've been able to drop a malicious DLL on a server somewhere, you're going to be able to do DLL injection. It turns out that if you give it an HTTP URL, it will actually go and request the file from that URL, it won't load it, but this is still really useful for getting ping backs, if you're attacking a server somewhere. Object data provider is sort of the more classic RCE gadget for .NET serialization. It's got properties where if you set the properties on it, you can call any static method on any type in .NET with whatever string and integer parameters you want. So, people usually call process.start just to pivot the shell injection. Okay, so that's how .NET serialization vulnerabilities work. Now, I'll go back to LightDB and explain what I'm calling implicit serialization vulnerabilities. So, here's a remote code execution exploit for LightDB. If you look at this JSON blob here, this is going to be the JSON we're going to put into LightDB. It's got that underscore type key where it's telling you what type it wants to be. It's going to be an object data provider. That's that gadget that lets you call any static method you want. We're going to call process.start and launch calc. And all we're going to do with this JSON is convert it to BSON and then pass it into BSON mapper to deserialize it. It's worth noting that when you call the BSON mapper's deserialized method, you tell it what type you expect, and it does not matter. So, LightDB will actually respect the type the data says it wants to be. It'll go make it. It'll set its properties. Your serialization exploit gadget will run. It will then try to do a cast that will fail and probably throw an exception, but it doesn't matter. Your code is already run. So, going back to how LightDB works. If you remember, LightDB uses BSON mapper to read its own storage. So, the problem here is that anything that can put malicious data in the database file will not achieve RCE. It's also worth noting that when a client's using LightDB, they don't know they're using a serializer, probably. They're almost never going to call BSON mapper directly. So, this is an implicit serialization vulnerability. The client is vulnerable to the serialization that's in LightDB, even though they're not using the serializer. LightDB is. And this makes that client vulnerable in a lot of ways. First of all, LightDB, when it stores a database file, it just stores a local file. So, a lot of applications use LightDB just to write document formats, or save files for games. So, if you provide someone a document or a file that they're reading with LightDB, you can put an RCE payload in there, and it will run code when they open it. LightDB is a NoSQL engine. It also has queries, which means you can achieve query injection, and then you can put a malicious record in the database, and when someone reads that record, you've got RCE. And there's one extra special exploit technique I figured out for this that I'll come back to. So, what do you do when you find a remote code execution vulnerability in a major open source library? Well, you look at all the other libraries that are like it and find the same vulnerability there. So, here's essentially the same vulnerability in MongoDB. So, here's a JSON payload. It's got this underscore T key. That's the type specifier Mongo uses. That's the way the data says what type it wants to be. We're again making an object data provider. We're going to again call process.start and launch calc. And again, all we're going to do with this is convert it into BSIN and then deserialize it with the BSIN serializer that MongoDB uses. Now, it's worth noting that you also tell the BSIN serializer what type you expect, and that does matter. So, in MongoDB, it will actually check that the type the data says it wants to be is assignable to the type it's expecting to get before it creates it. So, if you want to exploit MongoDB, you have to find something in the data structure the application's expecting that's open-ended so you can fit a serialization gadget into it. That said, it's almost always there. When I've looked at applications that use BSIN databases, there's almost always either an interface member on something or just a member of type object that's like a catch-all. And so you just put your serialization gadget in that slot, and you still have RCE. Because MongoDB again uses this BSIN serializer to read its own database, it means that anything that puts malicious data in the database gets your remote code execution. MongoDB uses a client-server kind of architecture most of the time. So you can have one malicious client that talks to the database, puts a bad record in there, some other client reads that you're running code on that other client. You can also do, again, query injection. I will say that I was only able to exploit the .NET driver for MongoDB, not Java or Python. I won't say you can't, just that I couldn't figure out how to do it. And then we're going to move on to yet another remote code execution vulnerability for yet another NoSQL engine. This one is RavenDB. So, once again, we've got a JSON payload. This one, the type it says it wants to be is a Windows identity Windows identity is a JSON.NET RCE serialization gadget. I suggest looking at YSOSerial for details of how it works. But essentially, it lets you pivot to a binary formatter payload, which you then use to get RCE. And in this case, what we're going to do with this payload is we're just going to actually make a connection to the database server and then do a put request to stick the JSON in the database. So RavenDB lets you interact with the database in two ways. You can read or write JSON to it, or you can read or write objects from it. And so what you can do is if you put malicious JSON in the database and it's read as an object, that gets you RCE. Now, it's worth noting here, again, that the type that's being expected matters. There's an assignability check like there was in MongoDB, and so you have to actually have some way to fit your payload into the expected types. This, again, is an implicit serialization vulnerability because RavenDB is just using JSON.NET with unsafe settings to read its own storage. So anything that puts bad data in the database gets you RCE. And that special attack pattern that I mentioned for LightDB works here also. And I looked at some things that were NoSQL but not strictly databases. So here is a remote code execution vulnerability for servicedac.redis. Servicedac.redis is sort of a NoSQL wrapper for a Redis cache. So here we've got some JSON. It says what type it wants to be. In this case it's saying it's going to be an assembly installer. That's that one that lets you call load library on an arbitrary path. We're just going to say I dropped a malicious DLL somewhere for it to read. And then what we're going to do with this JSON is we're going to stick it in the Redis cache and then read it back. So when we stick the JSON in the Redis cache as JSON, it's just JSON, but when you read it back as an object using servicedac.redis, it's going to turn into whatever object we say it wants to be and it can run code. Now, again, the type matters. So when you're using servicedac.redis, you tell it what type you're expecting and the payload you're using has to fit into the object graph you're going to have there. This is, again, an implicit serialization vulnerability. So because servicedac.redis is using unsafe serializer to read the Redis cache, anything that lets you put bad data in the Redis cache also gets you RCE. And that extra pattern I keep talking about works here also. And now I'm going to tell you a little bit about how I discovered it. And that's because I was looking at one other NoSQL engine in .NET, and that's MartinDB. So MartinDB, like RavenDB, uses JSON.NET with unsafe settings to read its own storage. But unlike RavenDB, it doesn't just let you write JSON. You can only read and write objects from the database. And when I tried to write an object to MartinDB that was just like a serialization exploit gadget, it would choke on it every time I tried. So I played with that a lot, and I found a completely different way to attack it. And that's what I'm calling a serialization mutation attack. So here's a remote code execution payload for MartinDB. This one's a little bit different. So what I'm going to do here is I'm going to make in .NET a dictionary of string string. This could be a hash table too, but you need something that's got key value pairs mapping a string to a string. And what I'm going to put in that dictionary is first a dollar type key paired with the name of a .NET type. In this case, workflow designer, which is another JSON.NET serialization gadget. It lets you do an arbitrary XAML read. Again, look at YSO serial for details about how it works. One other thing where I'm going to set another key value pair where this is the name of a property on workflow designer, which is the one you set the XAML with to get an arbitrary XAML parse out of it. And what I'm going to do with that is I'm just going to write it to the database. So if you write this object to the database and then read it back, that will run code. It will launch calc. And that's kind of weird. We're writing a dictionary to the database, but when you read it back, it runs calc. Why does that work? So this is using JSON.NET as its serializer. So let's look at how this works in JSON.NET. So in JSON.NET, if you serialize one of these dictionary string strings, like, say you have a dictionary where you've got a key named fruit and the value pair, it uses the key names exactly as you provide them. So your key as fruit is just going to go into the serialized JSON as the key named fruit. Now if you compare that to what an RCE payload looks like for JSON.NET, here's an example of one. You've got that type specifier key, that dollar type, and then you've got that type name as a value for it, and so on. And the key trick with this is there's nothing special about that dollar type key. There's nothing special about the type specifier used really in any of the serializers I've talked about. So you can make a key for a string string dictionary named dollar type, and it turns out that if you serialize one of those string string dictionaries in JSON.NET or most of the other serializers I've talked about, it just uses the key directly. It doesn't filter it out even though it matches its type specifier. So what happens there is that you're essentially colliding with the syntax of what that RCE payload looked like. You're making it just output data where it's going to be the type specifier, so when this object gets serialized and then deserialized, it mutates into a different type entirely. And you can choose whatever type you want. And this doesn't just work for dictionary, it works for hash table, J object, expando object, and like 50 others. Just go look around at .NET for things that have key value structures. And because of this mutation attack, you can do a lot of attacks on serialization that usually weren't considered possible. So say you have a website that takes some key value data, and this is a screenshot from a certain website you might recognize that did not have this vulnerability, but does let you enter key value data where you can choose both the keys and the values. And you send that to a web front end with a form post, and on the web front end they're going to make like a dictionary or a hash table with the data you sent them. And later on, say that dictionary or hash table gets serialized to like a database or a cache, and then later on after that, it gets read back from that database or cache using an unsafe serializer. Well in that case, you can provide key value data where you're using that type specifier as the key name, and when it gets read from that cache on some backend server, you can make it so it mutates into whatever object you want, it's now your serialization exploit gadget, it's now that pain, and you've got remote code execution whenever that happens. So I was saying that was that extra attack pattern against all of these NoSQL engines, here's how that works against LiteDB. So LiteDB, you can make a dictionary string string, you put your payload in there, so you've got that underscore type key specified with a type name, in this case assembly installer, so we're going to do again an arbitrary call to load library, we're saying we're loading a malicious DLL, and all you do is you write it to the database and read it back. Now, this hack is kind of magic, it doesn't matter where this is in the data structure, if you can control two key value pairs in some part of some object graph, if it gets saved and read back, that gets you RCE, and this actually makes a lot of attacks really ridiculous and easy, like there's some application that's just asking you for a couple of string pairs and later you get RCE when it gets read from the database. And this kind of attack works with a lot of serializers, here's a list of all the ones I know, these are all the .NET serializers I know where this sort of mutation attack works, you'll notice these are all JSON and BSIN serializers, this doesn't work for binary formatter because it doesn't use anything like this kind of syntax. And it's also worth noting that this doesn't work against MongoDB serializer. You'll note that there's different requirements for this to work in certain cases, some of them you have to control the first key value pair, some of them there's that assignability check, some of them there's other like specific unsafe properties you've got to set, so there's a lot of variability in how exploitable mutation can be. For example, JSON.NET, like most popular open source library in the world as far as I'm aware, you can get mutation attacks against it, but it's a little bit tricky. You have to control the first key value pair because that's the only one it'll read the type specifier from, it has to be deserialized using unsafe settings, it has to be serialized in such a way that it doesn't double up the type specifier, and in general, I would suggest experimenting with this, there's a lot of weird special cases and nuances, but sometimes you can make this work, and you can use this to exploit things where the serialization is just not something you can touch. Serialization happens on the backend, you can't see the deserialized data, maybe it even gets an HMAX stuck on it, it doesn't matter. On the other hand, there's serializers where this just works all the time, so if you've got JavaScript serializer with a type resolver, it will go out of its way to make the exploit work. It doesn't matter if you've got other entries in your key value storage, it doesn't matter if your type specifier is the last thing in the list, it doesn't matter if the assignability doesn't make sense, it'll just run the code and it'll just work. You can also do kind of a blind scanning technique to find these vulnerabilities. If you've got websites out there that you think are running on .net and might have some backend cache or database, you can just stick key value data in there, you can use that assembly installer pingback trick I talked about, and you can wait to see if you later get a request back to your own server. So you can stick data and services blind, use maybe unique URLs for your pingback so you can see which ones talk back to you, and then maybe later on when it gets read from the cache you'll get a request and you know there's an RCE happening there. You can defend against these attacks in a bunch of ways. If you're writing an application, the best thing to do is don't use a polymorphic serializer. And I'm going to say that a lot in this talk. Don't use a serializer where the data gets to tell you what type it wants to be. If you have to, for some reason, you can try using a serialization binder, but I'm about to tell you how to bypass serialization binders, so kind of a grain of salt there. So here's how to bypass serialization binders. In general, if you're talking about using a serialization binder for security purposes, it's acting like a filter. What's happening is during deserialization, your binder's going to get asked about every type that's directly referenced in the serialized data, and it'll say, okay, this is the type I expect, go ahead, or if you're doing it right, you throw an exception when some type you don't expect shows up. And that means if someone throws pain at you, you say, I don't know what pain is, you throw an exception, and nothing bad happens. So if you're doing it right, your serialization binder looks sort of like this. What this is, is just an allow list of all the expected types, it's a string allow list for both the assembly name and the type from the assembly name, and if you see one that you don't expect, you throw an exception. The problem is, a lot of times, people don't do this. Usually what you see for a serialization binder is something more like this, where you have some assembly you've written yourself. You say, well, I trust all my types, there's no crazy serialization gadgets in there, so if the type says it's coming from my assembly, I'll just allow it and I'll use type get type to actually get the type out of there. And the problem with this approach is, say your assembly contains a type like this. This is an initialized list type we're going to invent that just derives, inherits from the just generic list type in .net, and we're adding another property to it. That seems pretty harmless, but if you've got a type like this in that assembly that you're trusting, you can export it like this. So, here's a JSON payload to bypass that serialization binder I just showed you. The type it's saying it wants to be is initialized list, the type I just mentioned, but the type in the template for that is assembly installer, that one that lets you do an arbitrary load library. The trick with this is, initialized list is the type you're getting asked about, that comes from your assembly, so that binder is okay with it. And you'll notice that assembly installer is only ever referenced inside the template here. But, when this value part of the JSON blob gets deserialized, it'll still make an assembly installer object, it'll still set its path property, and you're still doing load library, so your RCE is still working. There's a trick here that when you serialize this with JSON.net, it'll put another dollar type entry in there for the assembly installer, but you don't need it. It can figure out what it's supposed to be if it's not there, so you can just take it back out again and then bypass the binder. There's another trick you can use to bypass serialization binders that I'm calling contagion. So, for JSON.net and a lot of other Beeson and JSON serializers, you've got that dollar type entry that's saying what type it's supposed to be, but that object you're creating has members, properties, constructor arguments that have their own types. And you don't have to specify the types of those in the JSON. If you serialize it, it will, but if you don't, the serializer will just figure it out. So if there's some serialization gadget you want to use, and it's a member of something that's a member of something that's a member of something that you can get past the binder, you can use that one object that has it in its tree somewhere to get it past the binder. Here's one example. So Windows Identity that I mentioned before is a JSON.net RCE gadget. It lets you pivot to binary formatter. And you could have a serialization binder that specifically block lists that. And if you do that, you can still get it by. The way you do that is you use a Windows authentication event args object. So if you serialize Windows authentication event args, it has a constructor argument called identity whose type is Windows identity. So when you serialize that, the only type going by the binder is this dollar type, because the only things that the binder gets asked about are the types explicitly listed in the JSON. But when the identity part of it gets deserialized here, it'll still make a Windows identity object, it'll still set its properties, you still get RCE. So that's a lot of problems. What if this has been fixed? So I am with Microsoft. I practice responsible disclosure. I told all of these people about these issues in January or earlier. Everybody except MartinDB made some sort of fix. MartinDB, as far as I've checked last, still hasn't. MongoDB's fix is pretty solid. I don't know how to bypass it. They added a pretty strict allow list on the types that can get created during deserialization. It seems good. Everybody else here added a block list. LightDB also added an assignability check, so that puts them about on par for MongoDB before they made a fix. I just showed you how to bypass block lists. I can bypass all of the fixes for LightDB, RavenDB, and ServiceDoc.redis. Like I said, MartinDB didn't get fixed. I told all of these people, look, I can still bypass these fixes. They said we're not making additional fixes. So there's remote code execution vulnerabilities that are live right now for all of those libraries. Worth looking at. The mutation attack I mentioned against JSON.net is not being fixed. I talked to James Newton King, the maintainer for JSON.net about this. He said essentially it's supposed to do that. So that behavior is not going to be changed. If you've got some application that's using JSON.net, it might be vulnerable to mutation. Similarly, JavaScript serializer, the .net serializer I mentioned that works really well for mutation attacks, will not be fixed. I talked to the .net team about this. They said we tell people don't use JavaScript serializer, we tell people don't use type resolver, so we're not going to fix them. Just don't use them. So, best practices to avoid these issues. First thing I keep saying, don't use a polymorphic serializer. Don't roll your own. It's a really bad idea. Don't have that data let you tell you what type it wants to be. It leads to all kinds of problems. Don't call type get type because if you're doing that you're probably writing a polymorphic serializer even if you don't realize you're doing it. Similarly in Java, don't call class for name. Also remember that you can't use an unsafe serializer anywhere because mutation attacks. If it's on your back end, if you've got an HVAC, it doesn't matter for mutation. You can attack like deep copy tricks. A lot of people use serializers to just deep copy objects. You can get RCE out of that because of mutation, which is kind of silly. So, don't use unsafe serializers anywhere. This one kind of hurts, but maybe don't read untrusted data from NoSQL. Mongo might be okay, but it kind of looks like every other NoSQL engine I've looked at. You can get RCE if someone can write back bad data and you can read it back. Now, I only really looked at .NET NoSQL engines, but there's kind of a pattern here with NoSQL where they say just take this object and then later on you can tell the NoSQL engine I want the object back and I don't care what it is. Any time you have that pattern, there's a polymorphic serializer in there somewhere and you can probably get RCE out of it if you want a research project or want to go find libraries that are vulnerable. Maybe look at Java or Python NoSQL engines. Don't try to use serialization binders. It's possible to write a good one, but nobody ever does it. Everybody screws this up. I see bypasses for these all the time. In general, you're better off architecting your application so you don't need a serialization binder in the first place. And now I'm going to get into the bonus stuff that's just for DEF CON. So, I've been talking about .NET framework exploits, but what about .NET 6 plus? Everyone seems to think that's different. It's not going to have these serialization vulnerabilities. So, since 2016, .NET has had a couple of different flavors. There's .NET framework and then there's .NET. That's what they want me to call it, but .NET 6 through 8, those are the ones people use right now. All these exploits have been .NET framework exploits, so the ones that are in YSO serial, but what about .NET 6 plus? Can you do this sort of stuff there? There is this myth that .NET 6 plus is immune to serialization attacks. So, here's the CVE Mongo open for the vulnerability I found and it's kind of an eye chart there, but it's I'll underline the important part here and what they said was it must be running Windows host using full .NET framework, not .NET core. That's not true. Similarly, if you look at YSO serial, they have a bug there, which is, is there any gadget for .NET core? And no one has found one there. So, admittedly exploiting .NET 6 plus is harder. A lot of the exploitable types, the gadgets that people use in .NET framework just aren't there in the framework at all. There's also this whole issue where .NET, .NET 6 plus, whatever we're calling it, actually divides the framework into three parts. There's .NET core, there's ASP.NET, and there's the Windows desktop part. And depending on how you build your application, you only get some of the DLLs that are even visible at all. So you can only use gadgets from the ones that are appropriate to how you built your application. So, the ASP.NET core app types and the Windows desktop app types won't be found by type-get-type. You can't deserialize them unless you've built with an ASP.NET app or a Windows desktop app. But you can still do deserialization exploits. So, object data provider is still there in .NET 6. It's still there in .NET 8. You have to have Windows desktop loaded for it to work, but if it's loaded, the payloads I've been showing you for object data provider, they just work fine. There are also some serialization gadgets that do exist in .NET core app. And now I'm going to go to the parts that aren't on my slides because I think I've got some time left. So, I told you earlier how you can get a ping back with assembly installer. There's a similar trick you can do in .NET 6 and .NET 8 and so on. And there's a few types you can use to do that. One of them is assembly dependency resolver. Another one is system.io.fileinfo. The trick with both of those is they will call create file with whatever string you give them. So, assembly dependency resolver has a constructor argument which is just a path and it will just call create file on that path. The file info type, you can set the read only flag on a file with it and you can do that, however, so you can also use that as a payload to do DOS because you can make files on the server read only. But when you do that, it will also call create file on that path. Now, there's a thing with create file in Windows where if you give it an internet SMB URL or a WebDAV URL, it will go talk to that. It's happy to do it. So, if you've got an SMB server on the internet or a WebDAV server somewhere, you can use those gadgets to get a ping back to that server. Now, a lot of times if they're doing their OPSEC correctly, SMB outbound will be blocked on the server you're trying to attack and sometimes the WebDAV redirector won't exist in the Windows install. So, it's a little bit iffy, but in my experience usually one or the other of those works. So, you can still get a ping back essentially by using assembly dependency resolver or file info setting the read only flag and then giving either an internet SMB URL or a WebDAV URL. And that's actually all I had. So, are there any questions? Thanks. I saw one over here. Sorry. Can you tell me that one more time? Sorry. Okay, the question was do I have any examples of the vulnerable games? I don't remember which ones they are, but what you can do is go on GitHub or like if you go on to NuGet. Okay, so two approaches. Go to NuGet, look at projects that are dependent on LightDB and then look at where those get used or just search on GitHub for uses of LightDB for things that look like games. That's how I found a bunch of examples of that before. Yeah, so, for example. Over here. Sorry. You said that after you're reading the object it will actually initialize the object injection, right? So, how did you find that in the first time? Because it's not something that you typically think about when you're doing this research. Okay, to clarify, was the question how did I realize that the vulnerability was there in the code that I was looking at to begin with? Yeah, because you said I can control the key, I can control the value, and then when I read it, it will initialize the object injection. Right? Oh, okay. So, as far as that goes, if you're looking for polymorphic serializers where people are rolling their own, which is a really bad idea in general, what I look for when I'm doing these sorts of code reviews is calls to type-get-type that are just being passed a string, especially if the string somehow comes from user data. Type-get-type being called on a user-provided string almost always is either unsafe serialization or someone doing really sketchy with reflection invokes. And both of those are probably RCE. Does that explain it? Yes, it is. Thank you. Okay, in the middle here? Okay, the question was I did at least, okay, the question was did I look at DynamoDB NoSQL? I glanced at it. I did not do an in-depth test. It did not have as easy of an exploit as the other ones I looked at. I won't say it's safe. And then there was one over here. . Okay, the question here was the assembly installer exploit that I'm loading malicious DLL with, and how can I make sure the malicious DLL is there present on the system? In that case, the assumption is you've got some other exploit that lets you do a file drop, something I should explain is the cases where I was using assembly installer exploits, that's because the string is shorter than the object data provider ones. Object data provider works for all of these two. So do lots of other .NET gadgets. Assembly installer I feel like honestly is more useful for doing a ping back to an HTTP URL because that lets you do that blind scanning I mentioned. And one way in the back. You might have to come forward for me to hear you. . So the question was whether automapper and fastmapper that also use that sort of reflection under the covers are also vulnerable. I'll admit I haven't looked at those. I'm honestly not quite sure what you're referring to. So maybe we can talk a little bit more about it after this. And... Well, if there's no other questions, I'll finish there. Thank you.