Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 05/23/20 in all areas

  1. OBLIGATORY INTRO Howdy! This is the first post in a multi-part series detailing steps taken, and exploits written, as part of my OSCE exam preparation. I intend to use these practice sessions to refine my exploit development process while sharing any knowledge gained. I originally wanted to take this course a few years ago, but could never quite lock it in. Recently, I was fortunate enough to have work fund the course. Since then, I’ve been spending my free time listening to Muts’ dulcet tones and working through the modules. I wrapped up the official course material yesterday and plan to work through some additional work recommended by some OSCE graduates. What makes the timing awesome for me is that I just finished up CSC 748 - Software Exploitation for my graduate course work. The course dealt with Windows x86 exploitation, fuzzing, and shellcoding. Sound familiar? It dove into some topics that OSCE doesn’t cover such as using ROP to bypass DEP. I’m incredibly happy to have been able to do both of them one right after the other. I’ll be including some of the shellcoding tricks I learned from the course in this series at some point. EXPLOIT DEVELOPMENT ENVIRONMENT This post will cover setting up a lab environment. While this may not be the most interesting topic, we’ll cover some setup tips that may be helpful. Don’t worry, we won’t go step by step through setting up all these things unless it’s warranted. OPERATING SYSTEM For these practice sessions, we’ll attempt to stick reasonably close to an OSCE environment by using a 32bit Windows 7 VM. Unfortunately, Microsoft has taken down the IE/Edge Virtual Machine images from their site. You can only get the Windows 10 images nowadays. Fear not! If you find yourself in need of an older version, they’re archived and can still be downloaded at the link below. Windows VM Images SCRIPTING LANGUAGE We’ll be writing all proof of concepts using Python 3. Python 2 still gets a lot of use in PoCs for exploits and exploit-centric tooling, however, I strongly prefer 3 as a language overall and will stick to it throughout these posts. The latest version of Python (3.8.2 at the time of this writing) can be found here. HEX EDITOR There are times we’ll need a hex editor. I prefer 010 when working on windows. NASMSHELL Part of creating shellcode is janking™ around with the instructions to find what works in the smallest amount of space without known bad characters. nasmshell makes it incredibly easy to check which opcodes are generated by which instructions. Of note, nasmshell requires python2. FUZZER For network fuzzing, we’ll be using boofuzz. It’s a fork of and the successor to the venerable Sulley fuzzing framework. Sulley has been the preeminent open source fuzzer for some time, but has fallen out of maintenance. Installation consists of a simple pip command. pip install boofuzz --user AUTOMATIC CRASH DETECTION & PROCESS RESTART This part is totally optional. Boofuzz offers a utility called process_monitor.py that detects crashes and restarts the target binary automatically. It requires a few additional libraries to run and must run on the target machine itself. As we’ll be doing all coding and fuzzing from the same windows environment, this is fine. The install steps are located here. I won’t copy and paste them here, however I will note something that I was forced to do during installation. All of the libraries for process_monitor.py are installed into my Python2.7 environment. Whereas boofuzz is installed into my Python3.8 environment. This is because pydasm requires Python2.7. The end result is that we’ll be scripting fuzzers in Python3, and executing process_monitor.py with Python2. Also, there is a note on the install page: I didn’t need to do anything to satisfy this requirement, as my flare-vm install script pulled it down for me. DEBUGGER The topic of which debugger to use seems to be pretty contentious in the OSCE forums/chats. We’ll be using WinDbg. The reason is that I spent 4 months using it for college and have come to like it. FLARE-VM To install WinDbg (and some other tools), I used the Flare-VM install script. Flare-VM will take a Windows 7-10 machine and install a plethora of RE tools. I modified the flare’s profile.json for a relatively light-weight installer. Flare-VM install instructions Customizing Installed Packages And if you’re feeling lazy, here’s my profile.json. { "env": { "TOOL_LIST_DIR": "%ProgramData%\\Microsoft\\Windows\\Start Menu\\Programs\\FLARE", "TOOL_LIST_SHORTCUT": "%UserProfile%\\Desktop\\FLARE.lnk", "RAW_TOOLS_DIR": "%SystemDrive%\\Tools", "TEMPLATE_DIR": "flarevm.installer.flare" }, "packages": [ {"name": "dotnetfx"}, {"name": "powershell"}, {"name": "vcbuildtools.fireeye"}, {"name": "vcpython27"}, { "name": "python2.x86.nopath.flare", "x64Only": true, "args": "--package-parameters \'/InstallDir:C:\\Python27.x86\'" }, {"name": "libraries.python2.fireeye"}, {"name": "libraries.python3.fireeye"}, {"name": "windbg.flare"}, {"name": "windbg.kenstheme.flare"}, {"name": "windbg.ollydumpex.flare"}, {"name": "windbg.pykd.flare"}, {"name": "ghidra.fireeye"}, {"name": "vbdecompiler.flare"}, {"name": "010editor.flare"}, {"name": "resourcehacker.flare"}, {"name": "processdump.fireeye"}, {"name": "7zip.flare"}, {"name": "putty"}, {"name": "wget"}, {"name": "processhacker.flare"}, {"name": "sysinternals.flare"}, {"name": "ncat.flare"}, {"name": "shellcode_launcher.flare"}, {"name": "xorsearch.flare"}, {"name": "xorstrings.flare"}, {"name": "lordpe.flare"}, {"name": "googlechrome.flare"}, {"name": "nasm.fireeye"} ] } MONA.PY Even after using Flare-VM’s installer, we’re still missing a key tool, mona.py. Mona.py is an incredible tool; it’s bonkers how many facets of exploit dev on windows are made easier with mona. To get mona up and running with WinDbg, we’ll just need to follow these steps. We can confirm everything works by opening up WinDbg, attaching to some benign process, and running the following commands: .load pykd.pyd ══════════════ Processing initial command '.load pykd.pyd' !py mona ════════ [+] Command used: !py C:\Program Files\Windows Kits\10\Debuggers\x86\mona.py 'mona' - Exploit Development Swiss Army Knife - WinDBG (32bit) Plugin version : 2.0 r605 Python version : 2.7.18 (v2.7.18:8d21aa21f2, Apr 20 2020, 13:19:08) [MSC v.1500 32 bit (Intel)] PyKD version 0.3.2.2 Written by Corelan - https://www.corelan.be Project page : https://github.com/corelan/mona |------------------------------------------------------------------| | _ __ ___ ___ _ __ __ _ _ __ _ _ | | | '_ ` _ \ / _ \ | '_ \ / _` | | '_ \ | | | | | | | | | | | || (_) || | | || (_| | _ | |_) || |_| | | | |_| |_| |_| \___/ |_| |_| \__,_|(_)| .__/ \__, | | | |_| |___/ | | | |------------------------------------------------------------------| SQLITE BROWSER We’ll need a way to look at boofuzz’s results. They’re stored in a database, and the provided web interface leaves something to be desired. As we’ll be working on windows, we’ll need to grab a sqlite database browser. One can be found here. WINDBG - QUALITY OF LIFE TWEAKS We’re going to be spending a ton of time in the debugger, so it should be a debugger that sparks joy! Typing .load pykd.pyd isn’t terribly hard, but doing it every time you restart your debugger can be irksome. We can automatically load the file with a pretty simple trick. right-click on the windbg icon in the toolbar (assuming flare-vm put it there for you) right-click on the windbg (x86) menu item select properties Once we’re in the properties menu, perform the following click on the Shortcut tab add the following command-line option to the Target field: -c ".load pykd.pyd" SANE LOGGING LOCATION Without any configuration, mona.py stores command results beside the debugger’s exe. The exe is stored six levels deep under Program Files and isn’t exactly accessible. The command below will get the logging location squared away for us. !py mona config -set workingfolder c:\monalogs\%p_%i The %p will get populated with the debuggee’s name and the %i will be replaced by the debuggee’s pid. Ex. C:\monalogs\TFTPServerSP_1300 PERSONALIZED WORKSPACE W/ SCRATCHPAD You can personalize WinDbg quite a bit. There are a few themes shipped with WinDbg, and some others can be found with google, though it’s not obvious how to work with them. WinDbg will read Workspace settings from the registry or a .wew file. If you’re loading a .reg file, you can simply double-click the file and it will load. However, we’ll be creating our own .wew file. CREATE THE LAYOUT We’ll take a look at my setup, which is pretty much default, with a slight modification. I like having WinDbg’s scratchpad open. It’s a convenient place for simple notes (usually addresses/offsets). It’s not open in the default configuration, so let’s fix that. Open WinDbg Press alt+8 to open the scratchpad Position it wherever you like My setup looks like this, with the scratchpad positioned to the right of the assembly window. ASSOCIATE THE SCRATCHPAD If the scratchpad isn’t associated to a file on disk, the information disappears when the debugger exits. Fortunately, making the scratchpad persistent is easy. First, right-click the scratchpad’s top bar and select Associate with file.... After that, simply pick a location (I store mine in C:\monalogs) SAVE THE WORKSPACE With a new layout created, we need to save it to disk. There are four different options to save a workspace… We want to use the Save Workspace to File... option. Store it wherever you like. AUTOLOAD THE WORKSPACE With the scratchpad setup and the workspace file saved somewhere, we need to configure windbg to load the workspace on startup. The premise is the same as what we used to autoload pykd. We just need to add the following command-line option to the Target field in WinDbg’s properties. -WF "C:\Users\vagrant\Desktop\with_scratchpad.WEW" FURTHER CONFIGURATION In case you want to go further, you could use some of the themes listed below as a starting point and tweak until you’re content. https://github.com/lololosys/windbg-theme https://github.com/Stolas/WinDBG-DarkTheme C:\ProgramData\chocolatey\lib\windbg.kenstheme.flare\tools\ken.reg https://www.zachburlingame.com/2011/12/customizing-your-windbg-workspace-and-color-scheme/ OBLIGATORY OUTRO The next post in this series will cover exploiting VulnServer’s TRUN command. Check it out here. Source epi052.gitlab.io
    1 point
  2. Simple userland rootkit – a case study Posted December 7, 2016 by Malwarebytes Labs Rootkits are tools and techniques used to hide (potentially malicious) modules from being noticed by system monitoring. Many people, hearing the word “rootkit” directly think of techniques applied in a kernel mode, like IDT (Interrupt Descriptor Table) hooking, SSDT (System Service Dispatch Table) hooking, DKOM (Direct Kernel Object Manipulation), and etc. But rootkits appear also in a simpler, user-mode flavor. They are not as stealthy as kernel-mode, but due to their simplicity of implementation they are much more spread. That’s why it is good to know how they works. In this article, we will have a case study of a simple userland rootkit, that uses a technique of API redirection in order to hide own presence from the popular monitoring tools. Analyzed sample 01fb4a4280cc3e6af4f2f0f31fa41ef9 //special thanks to @MalwareHunterTeam The rootkit code This malware is written in .NET and not obfuscated – it means we can decompile it easily by a decompiler like dnSpy. As we can see in the code, it hooks 3 popular monitoring applications: Process Explorer (procexp), ProcessHacker and Windows Task Manager (taskmgr): Let’s try to run this malware under dnSpy and observe it’s behavior under Process Explorer. The sample has been named malware.exe. At the beginning it is visible, like any other process: …but after executing the hooking routine, it just disappears from the list: Attaching a debugger to the Process Explorer we can see that some of the API functions, i.e., NtOpenProcess starts in atypical way – from a jump to some different memory page: The redirection leads to the injected code: It is placed in added memory page with full access rights: We can dump this page and open it in IDA, getting a view of 3 functions: The code of the first function begins at offset 0x60: The space before is filled with some other data, that will be discussed in a second part of the article. Rootkit implementation Let’s have a look at the implementation details now. As we saw before, hooking is executed in a function HookApplication. Looking at the beginning of this function we can confirm, that the rootkit’s role is to install in-line hooks on particular API functions: NtReadVirtualMemory, NtOpenProcess, NtQuerySystemInformation. Those functions are imported from ntdll.dll. Let’s have a look at what is required in order to implement such a simple rootkit. The original decompiled class is available here: ROOT1.cs. Preparing the data First, the malware needs to know the base address, where ntdll.dll is loaded in the space of the attacked process. The base is fetched by a function GetModuleBase address, that employs enumerating through the modules loaded within the examined process (using: Module32First – Module32Next). Having the module base, the malware needs to know the addresses of the functions, that are going to be overwritten. The GetRemoteProcAddressManual searches those address in the export table of the found module. Fetched addresses are saved in an array: //fetch addresses of imported functions: func_to_be_hooked[0] = (uint)((int)ROOT1.RemoteGetProcAddressManual(intPtr, (uint)((int)ROOT1.GetModuleBaseAddress(ProcessName, "ntdll.dll")), "NtReadVirtualMemory") ); func_to_be_hooked[1] = (uint)((int)ROOT1.RemoteGetProcAddressManual(intPtr, (uint)((int)ROOT1.GetModuleBaseAddress(ProcessName, "ntdll.dll")), "NtOpenProcess") ); func_to_be_hooked[2] = (uint)((int)ROOT1.RemoteGetProcAddressManual(intPtr, (uint)((int)ROOT1.GetModuleBaseAddress(ProcessName, "ntdll.dll")), "NtQuerySystemInformation") ); Code from the beginning of those functions is being read and stored in buffers: //copy original functions' code (24 bytes): original_func_code[0] = ROOT1.ReadMemoryByte(intPtr, (IntPtr)((long)((ulong)func_to_be_hooked[0])), 24u); original_func_code[1] = ROOT1.ReadMemoryByte(intPtr, (IntPtr)((long)((ulong)func_to_be_hooked[1])), 24u); original_func_code[2] = ROOT1.ReadMemoryByte(intPtr, (IntPtr)((long)((ulong)func_to_be_hooked[2])), 24u); The small 5-byte long array will be used to prepare a jump. The first byte, 233 is 0xE9 hex, and it represents the opcode of the JMP instruction. Other 4 bytes will be filled with the address of the detour function: Another array contains prepared detours functions in form of shellcodes: Shellcodes are stored as arrays of decimal numbers: In order to analyze the details, we can dump each shellcode to a binary form and load it in IDA. For example, the resulting pseudocode of the detour function of NtOpenProcess is: int __stdcall NtOpenProcess_filter(int ProcessHandle, int DesiredAccess, int ObjectAttributes, _DWORD *ClientId) { int res; //result of the operation if ( ClientId && *ClientId == *(_DWORD *)((char *)&malwareId + 3) ) res = 0xC0000022; //STATUS_ACCESS_DENIED else res = ((int (__stdcall *)(int, int, int, _DWORD *))((char *)&NOpentProcess_original))( ProcessHandle, DesiredAccess, ObjectAttributes, ClientId); return res; } view rawshellcode2.cpp hosted with ❤ by GitHub So, what does this detour function do? Very simple filtering: “if someone ask about the malware, tell them that it’s not there. But if someone ask about something else, tell the truth”. Other filters, applied on NtReadVirtualMemory and NtQuerySystemInformation (for SYSTEM_INFORMATION_CLASS types: 5 = SystemProcessInformation, 16 = SystemHandleInformation) – manipulates, appropriately: reading memory of the hooked process and reading information about all the processes. Of course, the fiters must know, how to identify the malicious process that wants to remain hidden. In this rootkit it is identified by the process ID – so, it needs to be fetched and saved in the data that is injected along with the shellcode. The detour function of NtReadVirtualMemory will also call from inside functions: GetProcessId and GetCurrentProcessId in order to apply filtering – so, their handles need to be fetched and saved as well: getProcId_ptr = (uint)((int)ROOT1.RemoteGetProcAddressManual(intPtr, (uint)((int)ROOT1.GetModuleBaseAddress(ProcessName, "kernel32.dll")), "GetProcessId") ); getCuttentProcId_ptr = (uint)((int)ROOT1.RemoteGetProcAddressManual(intPtr, (uint)((int)ROOT1.GetModuleBaseAddress(ProcessName, "kernel32.dll")), "GetCurrentProcessId") ); Putting it all together All the required elements must be put together in a proper way. First, the malware allocates a new memory area, and copies all the elements in order: BitConverter.GetBytes(getProcId_ptr).CopyTo(array, 0); BitConverter.GetBytes(getCuttentProcId_ptr).CopyTo(array, 4); //... // copy the current process ID BitConverter.GetBytes(Process.GetCurrentProcess().Id).CopyTo(array, 8); //... // copy the original functions' addresses: BitConverter.GetBytes(func_to_be_hooked[0]).CopyTo(array, 12); BitConverter.GetBytes(func_to_be_hooked[1]).CopyTo(array, 16); BitConverter.GetBytes(func_to_be_hooked[2]).CopyTo(array, 20); //... //copy the code of original functions: original_func_code[0].CopyTo(array, 24); original_func_code[1].CopyTo(array, 48); original_func_code[2].CopyTo(array, 72); After this prolog, the three shellcodes are being copied into the same memory page – and the page is injected into the attacked process. Finally, the beginning of each attacked function is being patched with a jump, redirecting to the appropriate detour function within the injected page. Bugs and Limitations The basic functionality of a rootkit has been achieved here, however, this code contains also some bugs and limitations. For example, it causes an application to crash if the functions have been already hooked (for example in the case if the malware has been deployed for the second time). It is caused by the fact that the hook needs also a copy of the original function in order to work. The hooking function assumes, that the code in the memory of ntdll.dll is always the original one and it copies it to the required buffer (rather than copying it from the raw image of ntdll.dll). Of course this assumption is valid only in optimistic case, and fails if the function was hooked before. There are also many limitations – i.e. the hooking function is deployed only at the beginning of the execution, but when we deploy a monitoring program while the malware is running, we can still see it set of hooked applications is small – we can still attach to the malware via debugger or view it by any tool that is not considered by the authors the implemented code works only for 32 bit applications Conclusion The demonstrated rootkit is very simple, probably created by a novice. However, it allows us to illustrate very well the basic idea behind API hooking and how it can be used in order to hide the process. This was a guest post written by Hasherezade, an independent researcher and programmer with a strong interest in InfoSec. She loves going in details about malware and sharing threat information with the community. Check her out on Twitter @hasherezade and her personal blog: https://hshrzd.wordpress.com. Sursa: https://blog.malwarebytes.com/threat-analysis/2016/12/simple-userland-rootkit-a-case-study/
    1 point
×
×
  • Create New...