Repository: Invoke-IR/ACE Branch: master Commit: f5abdfdef562 Files: 159 Total size: 1.2 MB Directory structure: gitextract_n0h_95a4/ ├── ACE-Docker/ │ ├── README.md │ ├── ace-ca/ │ │ └── dockerfile │ ├── ace-nginx/ │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── entrypoint.sh │ │ └── nginx.conf │ ├── ace-rabbitmq/ │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── ace-cache.py │ │ ├── ace-entrypoint.sh │ │ └── ace-lookup.py │ ├── ace-sql/ │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── ace.sql │ │ └── import-data.sh │ ├── ace.env │ ├── docker-compose.yml │ ├── settings.sh │ └── start.sh ├── ACE-Management/ │ └── PS-ACE/ │ ├── Cmdlets/ │ │ ├── Download-AceFile.ps1 │ │ ├── Get-AceComputer.ps1 │ │ ├── Get-AceCredential.ps1 │ │ ├── Get-AceSchedule.ps1 │ │ ├── Get-AceScript.ps1 │ │ ├── Get-AceSweep.ps1 │ │ ├── Get-AceSweepResult.ps1 │ │ ├── Get-AceUser.ps1 │ │ ├── Invoke-AceWebRequest.ps1 │ │ ├── New-AceCredential.ps1 │ │ ├── New-AceScheduledScan.ps1 │ │ ├── New-AceScript.ps1 │ │ ├── New-AceUser.ps1 │ │ ├── Remove-AceCredential.ps1 │ │ ├── Remove-AceScript.ps1 │ │ ├── Remove-AceUser.ps1 │ │ ├── Send-AceResult.ps1 │ │ ├── Start-AceDiscovery.ps1 │ │ ├── Start-AceSweep.ps1 │ │ ├── Update-AceCredential.ps1 │ │ └── Update-AceUser.ps1 │ ├── PS-ACE.psm1 │ ├── README.md │ ├── Scripts/ │ │ ├── ACE-Master.ps1 │ │ ├── ACE_Get-AccessToken.ps1 │ │ ├── ACE_Get-ArpCache.ps1 │ │ ├── ACE_Get-Atom.ps1 │ │ ├── ACE_Get-InjectedThread.ps1 │ │ ├── ACE_Get-KerberosTicketCache.ps1 │ │ ├── ACE_Get-LogonSession.ps1 │ │ ├── ACE_Get-MasterBootRecord.ps1 │ │ ├── ACE_Get-NetworkConnection.ps1 │ │ ├── ACE_Get-PSAutorun.ps1 │ │ ├── ACE_Get-PSIProcess.ps1 │ │ ├── ACE_Get-PSIScheduledTask.ps1 │ │ ├── ACE_Get-PSIService.ps1 │ │ ├── ACE_Get-PSIWindowsSecurityEvent.ps1 │ │ ├── ACE_Get-ScheduledJob.ps1 │ │ ├── ACE_Get-SecurityPackage.ps1 │ │ ├── ACE_Get-SimpleNamedPipe.ps1 │ │ └── Invoke-MonsterWinRM.ps1 │ └── Working/ │ └── ACE_Get-PSIPrefetch.ps1 ├── ACE-WebService/ │ ├── .gitignore │ ├── ACEWebService.sln │ ├── Configure-AceWebService.ps1 │ ├── NuGet.config │ ├── dockerfile │ └── src/ │ └── ACEWebService/ │ ├── ACEWebService.csproj │ ├── App.config │ ├── AppSettings.cs │ ├── Controllers/ │ │ ├── ComputerController.cs │ │ ├── CredentialController.cs │ │ ├── DiscoverController.cs │ │ ├── DownloadController.cs │ │ ├── ResultController.cs │ │ ├── ScanController.cs │ │ ├── ScriptController.cs │ │ ├── SweepController.cs │ │ └── UserController.cs │ ├── DbModelBuilder.cs │ ├── Entities/ │ │ ├── ACEWebServiceDbContext.cs │ │ ├── Computer.cs │ │ ├── ComputerGroup.cs │ │ ├── Credential.cs │ │ ├── Download.cs │ │ ├── Scan.cs │ │ ├── Schedule.cs │ │ ├── Script.cs │ │ ├── Sweep.cs │ │ └── User.cs │ ├── Migrations/ │ │ ├── 20170322221439_MyFirstMigration.Designer.cs │ │ ├── 20170322221439_MyFirstMigration.cs │ │ ├── 20170322222622_MySecondMigration.Designer.cs │ │ ├── 20170322222622_MySecondMigration.cs │ │ ├── 20170417201050_MyThirdMigration.Designer.cs │ │ ├── 20170417201050_MyThirdMigration.cs │ │ ├── 20170420231736_MyFourthMigration.Designer.cs │ │ ├── 20170420231736_MyFourthMigration.cs │ │ ├── 20170421030619_MyFifthMigration.Designer.cs │ │ ├── 20170421030619_MyFifthMigration.cs │ │ ├── 20170429215921_MySixthMigration.Designer.cs │ │ ├── 20170429215921_MySixthMigration.cs │ │ ├── 20170430141205_MySeventhMigration.Designer.cs │ │ ├── 20170430141205_MySeventhMigration.cs │ │ ├── 20170707032113_MyEigthMigration.Designer.cs │ │ ├── 20170707032113_MyEigthMigration.cs │ │ ├── 20170707040959_MyNinthMigration.Designer.cs │ │ ├── 20170707040959_MyNinthMigration.cs │ │ ├── 20170707042221_MyTenthMigration.Designer.cs │ │ ├── 20170707042221_MyTenthMigration.cs │ │ ├── 20170713053904_MyEleventhMigration.Designer.cs │ │ ├── 20170713053904_MyEleventhMigration.cs │ │ ├── 20171116210534_MyTwelfthMigration.Designer.cs │ │ ├── 20171116210534_MyTwelfthMigration.cs │ │ ├── 20171116211023_MyThirteenthMigration.Designer.cs │ │ ├── 20171116211023_MyThirteenthMigration.cs │ │ ├── 20171116233431_MyFourteenthMigration.Designer.cs │ │ ├── 20171116233431_MyFourteenthMigration.cs │ │ └── ACEWebServiceDbContextModelSnapshot.cs │ ├── Program.cs │ ├── Project_Readme.html │ ├── Properties/ │ │ ├── PublishProfiles/ │ │ │ ├── ACEWebService-publish.ps1 │ │ │ ├── ACEWebService.pubxml │ │ │ ├── FileSystem-publish.ps1 │ │ │ ├── FileSystem.pubxml │ │ │ └── publish-module.psm1 │ │ └── launchSettings.json │ ├── Security/ │ │ ├── ApiKeyPolicy.cs │ │ └── IsAdminPolicy.cs │ ├── Services/ │ │ ├── IAceConfiguration.cs │ │ ├── ICryptographyService.cs │ │ ├── IDiscoveryService.cs │ │ ├── IDownloadService.cs │ │ ├── ISweepExecutionService.cs │ │ └── ISweepResultProcessorService.cs │ ├── Startup.cs │ ├── ViewModels/ │ │ ├── ArbitrarySweepViewModel.cs │ │ ├── CredentialViewModel.cs │ │ ├── DiscoveryActiveDirectoryViewModel.cs │ │ ├── DiscoveryComputerListViewModel.cs │ │ ├── DownloadReceiveViewModel.cs │ │ ├── DownloadRequestViewModel.cs │ │ ├── ErrorViewModel.cs │ │ ├── FileViewModel.cs │ │ ├── ScheduleIntervalViewModel.cs │ │ ├── ScheduleTimeViewModel.cs │ │ ├── SweepExecutionViewModel.cs │ │ ├── SweepResultViewModel.cs │ │ └── UserViewModel.cs │ ├── appsettings.Production.json │ ├── appsettings.json │ ├── nuget.config │ ├── scripts/ │ │ ├── Download-AceFile.ps1 │ │ └── Start-AceScript.ps1 │ └── web.config ├── LICENSE-Quartz.NET ├── LICENSE-RabbitMQ ├── LICENSE-SSH.NET ├── LICENSE-osxcollector └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: ACE-Docker/README.md ================================================ # ACE-Docker This project focuses on simplifying ACE's deployment process as much as possible. ## Goals ## Components ### [specterops/ace-mssql-linux](https://hub.docker.com/r/specterops/ace-mssql-linux/) MSSQL Server. This database provides a backend to keep track of all of the data ACE needs to do its job. This includes User, Credential, Computer, Script, and Schedules. ### [specterops/ace-rabbitmq](https://hub.docker.com/r/specterops/ace-rabbitmq/) RabbitMQ Messaging System. ACE's enrichment pipeline is built on a robust messaging system that guides each scan result through data enrichments, like Virus Total hash lookups, all the way to ingestion into a SIEM. ### [specterops/ace-nginx](https://hub.docker.com/r/specterops/ace-nginx/) NGINX HTTP(S) Reverse Proxy. Proxy's access to the ACE Web Application and provides SSL Certificates for those connections. ## Getting Started Our goal is to make provisioning ACE as simple as possible, so we wrote a small batch script to get things set up. Follow the steps, on a Linux or OSX machine, below and you should be in business: * Install Docker * If on Linux, Install Docker Compose * Adjust Docker preferences to allow containers to use 4GBs of RAM (Docker -> Preferences -> Advanced -> Memory) * Download this repository * Execute start.sh start.sh is a simple shell script that accomplishes the remaining set up steps. Below is a list of tasks accomplished by start.sh: * Create SSL certificate * Add SSL Thumbprint to the ACE Web Application's appsettings.json file * Build ACE Docker images with Docker Compose * Start ACE Docker containers ================================================ FILE: ACE-Docker/ace-ca/dockerfile ================================================ FROM cfssl/cfssl:latest RUN cfssl print-defaults config > ca-config.json && cfssl print-defaults csr > ca-csr.json \ && cfssl genkey -initca ca-csr.json | cfssljson -bare ca EXPOSE 8888 ENTRYPOINT ["cfssl"] CMD ["serve","-ca=ca.pem","-ca-key=ca-key.pem","-address=0.0.0.0"] ================================================ FILE: ACE-Docker/ace-nginx/Dockerfile ================================================ FROM nginx MAINTAINER Jared Atkinson RUN apt-get update; apt-get install -y openssl COPY ./nginx.conf /etc/nginx/nginx.conf COPY ./entrypoint.sh /opt/entrypoint.sh RUN chmod +x /opt/entrypoint.sh CMD /bin/bash /opt/entrypoint.sh && nginx -c /etc/nginx/nginx.conf -g "daemon off;" ================================================ FILE: ACE-Docker/ace-nginx/README.md ================================================ Built on [nginx](https://hub.docker.com/_/nginx/), this image provides an SSL proxy for the [ACE Web Application](https://github.com/Invoke-IR/ACE/tree/master/ACE-WebService). ACE relies on SSL for two important features: * Encryption - Data sent to and from the ACE Web Application is encrypted * Authentication - Certificate pinning is used to provide server side authentication to avoid Man-in-the-Middle attacks. ## Using this Image The ACE Nginx can be run in a couple different ways. ### Standalone If you are running ACE in a test/development/standalone deployment, then you can simply run the container as shown below. ``` docker run --name ace-nginx -p 80:80 -p 443:443 -d specterops/ace-nginx ``` ### Clustered/Redundant If you plan on running ACE in a Kubernetes cluster with replication, you want to maintain the same SSL certificates in all instances of the specterops/ace-nginx image. This can be achieved through the use of Volumes. Simply create a docker volume (it can be named "certs" or whatever you choose). ``` docker volume create --name certs ``` Then run your container(s) with the -v flag, linking your newly created volume to "/etc/nginx/certs". The volume will ensure a consistent SSL certificate across all ace-nginx instances. ``` docker run --name ace-nginx -v certs:/etc/nginx/certs -p 80:80 -p 443:443 -d specterops/ace-nginx ``` ### Get SSL Certificate Thumbprint The .NET WebClient does not trust self-signed SSL Certificates by default. The ACE PowerShell module bypasses this limitation by using certificate pinning, where the PowerShell script compares the user supplied SSL Thumbprint to that returned by the target server. If the Thumbprints match, then the server is authenticated and the request is allowed. The SSL Thumbprint is output at container runtime and can be found with the following command: ``` docker logs ace-nginx ################################################################ # ACE SSL Thumbprint: 3179CC1A0A0E20477260BFB8D559F35240297E6B # ################################################################ ``` ================================================ FILE: ACE-Docker/ace-nginx/entrypoint.sh ================================================ #!/bin/sh # Add Environment Variable to nginx.conf sed -i -e 's/\[WEBSERVICE_IP\]/'"$WEBSERVICE_IP"'/g' /etc/nginx/nginx.conf # Check if /etc/nginx/certs directory exits if [ ! -d /etc/nginx/certs ]; then mkdir /etc/nginx/certs fi # Check if SSL Cert exists, if it doesn't then make it if [ ! -f /etc/nginx/certs/server.crt ]; then openssl req -x509 -nodes -days 365 -newkey rsa:2048 -subj "/C=US/ST=Washington/L=Seattle/O=web.ace/CN=local.specterops.ace" -keyout "/etc/nginx/certs/server.key" -out "/etc/nginx/certs/server.crt" 2> /dev/null fi # Get and output SSL Thumbprint fingerprint=$(openssl x509 -in /etc/nginx/certs/server.crt -noout -fingerprint | sed 's/SHA1 Fingerprint=//g' | sed 's/://g') echo "\"Thumbprint\": \"$fingerprint\"," ================================================ FILE: ACE-Docker/ace-nginx/nginx.conf ================================================ worker_processes 4; events { worker_connections 1024; } http { # Allow files of <= 2MB to be uploaded client_max_body_size 2M; # Act as Load Balancer for 4 nodes upstream web.ace.local { server [WEBSERVICE_IP]:80; # server dockernginxkestrel_core-app_2:80; # server dockernginxkestrel_core-app_3:80; # server dockernginxkestrel_core-app_4:80; } # Redirect all HTTP traffic to HTTPS server { listen 80; return 301 https://$host$request_uri; } # HTTPS Server server { # Listen on port 443 listen 443; # Server name. You need a DNS record (or add this hostname to your hosts file) server_name web.ace.local; # Digital certificates generated with makecert.sh / makecert.bat ssl_certificate /etc/nginx/certs/server.crt; ssl_certificate_key /etc/nginx/certs/server.key; # SSL configuration ssl on; ssl_session_cache builtin:1000 shared:SSL:10m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4; ssl_prefer_server_ciphers on; # Location configuration to use the core-app.local upstream defined before location / { proxy_pass http://web.ace.local; proxy_read_timeout 90; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_redirect http://localhost https://web.ace.local; } } } ================================================ FILE: ACE-Docker/ace-rabbitmq/Dockerfile ================================================ FROM rabbitmq:3-management MAINTAINER Jared Atkinson ADD ace-entrypoint.sh /root/ace-entrypoint.sh ADD ace-cache.py /root/ace-cache.py ADD ace-lookup.py /root/ace-lookup.py RUN \ chmod +x /root/ace-entrypoint.sh \ && chmod +x /root/ace-cache.py \ && chmod +x /root/ace-lookup.py \ && apt-get update -y \ && apt-get upgrade -y \ && apt-get dist-upgrade -y \ && apt-get install -y python2.7 python-pip \ && pip install pika requests CMD \ /usr/local/bin/docker-entrypoint.sh rabbitmq-server > /dev/null & \ sleep 30 \ && /root/ace-entrypoint.sh ================================================ FILE: ACE-Docker/ace-rabbitmq/README.md ================================================ Built on [RabbitMQ](https://hub.docker.com/_/rabbitmq/), this images provides the backend database used by the [ACE RabbitMQ Server](https://github.com/Invoke-IR/ACE/tree/master/ACE-RabbitMQ). ## Requirements * This image requires Docker Engine 1.8+ in any of their supported platforms. * Requires the following environment flags * RABBITMQ_DEFAULT_USER= * RABBITMQ_DEFAULT_PASS= * APIKEY= ## Using this Image ### Run ``` docker run --name ace-rabbitmq -e 'RABBITMQ_DEFAULT_USER=yourUsername' -e 'RABBITMQ_DEFAULT_PASS=yourPassword' -e 'APIKEY=yourVirusTotalPublicAPIKey' -p 5672:5672 -p 15672:15672 -d specterops/ace-rabbitmq ``` # For Persistence If you desire your RabbitMQ data and setting to persist between containers, you need to create a docker volume `docker volume create rabbitmq` then add `-v rabbitmq:/var/lib/rabbitmq` to the docker run command ### Environment Variables * **RABBITMQ_DEFAULT_USER** Username for RabbitMQ server. Will be used to connect to server and log into management interface. * **RABBITMQ_DEFAULT_PASS** Password for RabbitMQ server. Will be used to connect to server and log into management interface. * **APIKEY** Public VirusTotal API key. Allows for lookups of hashes on VirusTotal ================================================ FILE: ACE-Docker/ace-rabbitmq/ace-cache.py ================================================ #!/usr/bin/env python import json import sys import pika import requests from argparse import ArgumentParser from json import dumps # Our local cache of hashes. Each of the consumers checks this dictionary first # before doing a lookup against VirusTotal to save time and API queries cachedEntries = {} class CachedConsumer(object): """A consumer that receives hashes and queries the VirusTotal api to find if VirusTotal has any matching hashes, and how many positive (malicious) results for that hash. """ EXCHANGE = 'ace_exchange' EXCHANGE_TYPE = 'topic' def __init__(self, connection): """Create a new instance of LookupConsumer, passing in the API key to use. :param connection connection: A pika connection object. """ self._connection = connection self._channel = None def consume_message(self, channel, method, properties, body): """Consume a message from channel. This function is passed as a callback to basic_consume. After checking the body of the message, the consumer checks the cache and either publish the cached entry, or perform a lookup and add the result to the cache. """ self._channel = channel message = json.loads(body) # parse the JSON results from the message newRoutingKey = "" if 'SHA256Hash' in message and message['SHA256Hash'] is not None: sha256hash = message['SHA256Hash'] # assign the value temporarily instead of doing a lookup each time if sha256hash in cachedEntries: #hash is cached print "Hash is cached" message[u"VTRecordExists"] = cachedEntries[sha256hash][u"VTRecordExists"] if u"VTPositives" in cachedEntries[sha256hash]: message[u"VTPositives"] = cachedEntries[sha256hash][u"VTPositives"] enrichment,newRoutingKey = method.routing_key.split(".",1) self.publish_message(method, message, newRoutingKey) elif u'VTRecordExists' in message: #needs to be cached print "Adding hash to cache" cachedEntries[sha256hash] = {} cachedEntries[sha256hash][u"VTRecordExists"] = message[u"VTRecordExists"] if u'VTPositives' in message: cachedEntries[sha256hash][u'VTPositives'] = message[u'VTPositives'] enrichment,newRoutingKey = method.routing_key.split(".",1) self.publish_message(method, message, newRoutingKey) else: #send for lookup print "sending to VT" newRoutingKey = "lookup." + method.routing_key self.publish_message(method, message, newRoutingKey) self._connection.sleep(1) elif message['SHA256Hash'] is None: print "Hash is null" enrichment,newRoutingKey = method.routing_key.split(".",1) self.publish_message(method, message, newRoutingKey) def publish_message(self, method, message, routingKey): """Publish a message to the channel with the new routing key after enrichment. """ body = json.dumps(message) channel = self._channel channel.basic_ack(delivery_tag = method.delivery_tag) channel.basic_publish(exchange=self.EXCHANGE, routing_key=routingKey,body=body, properties=pika.BasicProperties(delivery_mode = 2,)) def main(): parser = ArgumentParser() parser.add_argument( '-s', '--Server', dest='rabbitmq_server', default='', help='[MANDATORY] RabbitMQ server hostname or IP address') parser.add_argument( '-u', '--User', dest='rabbitmq_user', default='', help='[OPTIONAL] RabbitMQ username') parser.add_argument( '-p', '--Password', dest='rabbitmq_password', default='', help='[OPTIONAL] RabbitMQ password') args = parser.parse_args() try: if (args.rabbitmq_password != '' and args.rabbitmq_user != ''): creds = pika.PlainCredentials(args.rabbitmq_user, args.rabbitmq_password) connection = pika.BlockingConnection(pika.ConnectionParameters(host=args.rabbitmq_server, credentials=creds)) elif (args.rabbitmq_server != ''): connection = pika.BlockingConnection(pika.ConnectionParameters(host=args.rabbitmq_server)) else: print("Must provide command line parameters, run 'python ACE_RabbitMQ.py -h' for help") return channel = connection.channel() except: print("Issue connecting to RabbitMQ,") channel.exchange_declare(exchange='ace_exchange',exchange_type='topic', durable=True) channel.queue_declare(queue='siem', durable=True) channel.queue_declare(queue='cached_hash', durable=True) channel.queue_declare(queue='lookup', durable=True) channel.queue_declare(queue='status', durable=True) channel.queue_bind(exchange='ace_exchange', queue='siem', routing_key='siem') channel.queue_bind(exchange='ace_exchange', queue='cached_hash', routing_key='hash.#') channel.queue_bind(exchange='ace_exchange', queue='lookup', routing_key='lookup.hash.#') channel.queue_bind(exchange='ace_exchange', queue='status', routing_key='status') channel.basic_qos(prefetch_count=1) print("Waiting for messages") cacheConsume = CachedConsumer(connection) channel.basic_consume(cacheConsume.consume_message, queue='cached_hash') channel.start_consuming() connection.close() if __name__ == '__main__': main() ================================================ FILE: ACE-Docker/ace-rabbitmq/ace-entrypoint.sh ================================================ #!/bin/bash python /root/ace-lookup.py -s 127.0.0.1 -u $RABBITMQ_DEFAULT_USER -p $RABBITMQ_DEFAULT_PASS -k $APIKEY & python /root/ace-cache.py -s 127.0.0.1 -u $RABBITMQ_DEFAULT_USER -p $RABBITMQ_DEFAULT_PASS & echo "\"RabbitMQUserName\": \"$RABBITMQ_DEFAULT_USER\"," echo "\"RabbitMQPassword\": \"$RABBITMQ_DEFAULT_PASS\"," while true; do :; sleep 600; done ================================================ FILE: ACE-Docker/ace-rabbitmq/ace-lookup.py ================================================ #!/usr/bin/env python import json import sys import pika import requests from argparse import ArgumentParser from json import dumps class VTConsumer(object): """A consumer that receives hashes and queries the VirusTotal api to find if VirusTotal has any matching hashes, and how many positive (malicious) results for that hash. """ EXCHANGE = 'ace_exchange' EXCHANGE_TYPE = 'topic' def __init__(self, api_key, connection): """Create a new instance of VTConsumer, passing in the API key to use. :param str api_key: The VirusTotal API key to use. :param connection connection: A pika connection object. """ self._apikey = api_key self._connection = connection self._channel = None def consume_message(self, channel, method, properties, body): """Consume a message from channel. This function is passed as a callback to basic_consume. After checking the body of the message, the consumer checks the cache and either publish the cached entry, or perform a lookup and add the result to the cache. """ self._channel = channel message = json.loads(body) # parse the JSON results from the message entry = {} sha256hash = message['SHA256Hash'] entry = self.lookup_hash(sha256hash) print entry if u'VTRecordExists' in entry: message[u"VTRecordExists"] = entry[u"VTRecordExists"] if u'VTPositives' in entry: message[u'VTPositives'] = entry[u'VTPositives'] self.publish_message(method, message) def lookup_hash(self, sha256hash): """Perform a lookup against VirusTotal for a given hash. :param str vt_hash: A SHA256Hash to check against the VirusTotal API. """ params = { 'apikey': self._apikey, 'resource': sha256hash } headers = {"Accept-Encoding": "gzip, deflate", "User-Agent" : "gzip, VirusTotal ACE Enrichment Consumer v0.1"} response = requests.get('https://www.virustotal.com/vtapi/v2/file/report', params=params, headers=headers) if response.status_code == 204: self._connection.sleep(60) response = requests.get('https://www.virustotal.com/vtapi/v2/file/report', params=params, headers=headers) json_response = response.json() if json_response['response_code'] == 1: new_record = {} new_record[u"VTRecordExists"] = u"True" new_record[u"VTPositives"] = json_response['positives'] elif json_response['response_code'] == 0: new_record = {} new_record[u"VTRecordExists"] = u"False" elif json_response['response_code'] == -2: new_record = {} new_record[u"VTRecordExists"] = u"False" return new_record def publish_message(self, method, message): """Publish a message to the channel with the new routing key after enrichment. """ enrichment,newRoutingKey = method.routing_key.split(".",1) body = json.dumps(message) channel = self._channel channel.basic_ack(delivery_tag = method.delivery_tag) channel.basic_publish(exchange=self.EXCHANGE, routing_key=newRoutingKey,body=body, properties=pika.BasicProperties(delivery_mode = 2,)) def main(): parser = ArgumentParser() parser.add_argument( '-s', '--Server', dest='rabbitmq_server', default='', help='[MANDATORY] RabbitMQ server hostname or IP address') parser.add_argument( '-u', '--User', dest='rabbitmq_user', default='', help='[OPTIONAL] RabbitMQ username') parser.add_argument( '-p', '--Password', dest='rabbitmq_password', default='', help='[OPTIONAL] RabbitMQ password') parser.add_argument( '-k', '--APIKey', dest='VTAPIKey', default='', help='[MANDATORY] VirusTotal API Key') args = parser.parse_args() try: if (args.VTAPIKey == ''): print("Must provide command line parameters, run 'python ACE_RabbitMQ.py -h' for help") return if (args.rabbitmq_password != '' and args.rabbitmq_user != ''): creds = pika.PlainCredentials(args.rabbitmq_user, args.rabbitmq_password) connection = pika.BlockingConnection(pika.ConnectionParameters(host=args.rabbitmq_server, credentials=creds)) elif (args.rabbitmq_server != ''): connection = pika.BlockingConnection(pika.ConnectionParameters(host=args.rabbitmq_server)) else: print("Must provide command line parameters, run 'python ACE_RabbitMQ.py -h' for help") return channel = connection.channel() except: print("Issue connecting to RabbitMQ,") channel.exchange_declare(exchange='ace_exchange',exchange_type='topic', durable=True) channel.queue_declare(queue='siem', durable=True) channel.queue_declare(queue='cached_hash', durable=True) channel.queue_declare(queue='lookup', durable=True) channel.queue_declare(queue='status', durable=True) channel.queue_bind(exchange='ace_exchange', queue='siem', routing_key='siem') channel.queue_bind(exchange='ace_exchange', queue='cached_hash', routing_key='hash.#') channel.queue_bind(exchange='ace_exchange', queue='lookup', routing_key='lookup.hash.#') channel.queue_bind(exchange='ace_exchange', queue='status', routing_key='status') channel.basic_qos(prefetch_count=1) print("Waiting for messages") consumer = VTConsumer(args.VTAPIKey, connection) channel.basic_consume(consumer.consume_message, queue='lookup') channel.start_consuming() connection.close() if __name__ == '__main__': main() ================================================ FILE: ACE-Docker/ace-sql/Dockerfile ================================================ FROM microsoft/mssql-server-linux MAINTAINER Jared Atkinson ENV ACCEPT_EULA Y # Create app directory RUN mkdir -p /usr/src/ace WORKDIR /usr/src/ace # Copy files to container COPY import-data.sh /usr/src/ace COPY ace.sql /usr/src/ace # Grant permissions for the import-data script to be executable RUN chmod +x /usr/src/ace/import-data.sh CMD /bin/bash /usr/src/ace/import-data.sh ================================================ FILE: ACE-Docker/ace-sql/README.md ================================================ Built on [microsoft/mssql-server-linux](https://hub.docker.com/r/microsoft/mssql-server-linux/), this images provides the backend database used by the [ACE Web Application](https://github.com/Invoke-IR/ACE/tree/master/ACE-WebService). ## Requirements * This image requires Docker Engine 1.8+ in any of their supported platforms. * At least 3.25 GB of RAM. Make sure to assign enough memory to the Docker VM if you're running on Docker for Mac or Windows. * Requires the following environment flags * SA_PASSWORD= * A strong system administrator (SA) password: At least 8 characters including uppercase, lowercase letters, base-10 digits and/or non-alphanumeric symbols. ## Using this Image ### Run ``` docker run --name ace-sql -e 'SA_PASSWORD=yourStrong(!)Password' -e 'MSSQL_PID=Standard' -p 1433:1433 -d specterops/ace-sql ``` ### For Persistence If you desire your RabbitMQ data and setting to persist between containers, you need to create a docker volume `docker volume create sql-data` then add `-v sql-data:/var/opt/mssql` to the docker run command ### Environment Variables * **SA_PASSWORD** is the database system administrator (userid = 'sa') password used to connect to SQL Server once the container is running. Important note: This password needs to include at least 8 characters of at least three of these four categories: uppercase letters, lowercase letters, numbers and non-alphanumeric symbols. ================================================ FILE: ACE-Docker/ace-sql/ace.sql ================================================ CREATE TABLE [dbo].[Credentials] ( [Id] UNIQUEIDENTIFIER NOT NULL, [Password] NVARCHAR (MAX) NOT NULL, [UserName] NVARCHAR (MAX) NOT NULL, CONSTRAINT [PK_Credentials] PRIMARY KEY CLUSTERED ([Id] ASC) ); CREATE TABLE [dbo].[Computers] ( [Id] UNIQUEIDENTIFIER NOT NULL, [ComputerName] NVARCHAR (MAX) NULL, [CredentialId] UNIQUEIDENTIFIER NOT NULL, [OperatingSystem] NVARCHAR (MAX) NULL, [RPC] BIT NOT NULL, [SMB] BIT NOT NULL, [SSH] BIT NOT NULL, [Scanned] BIT NOT NULL, [WinRM] BIT NOT NULL, CONSTRAINT [PK_Computers] PRIMARY KEY CLUSTERED ([Id] ASC), CONSTRAINT [FK_Computers_Credentials_CredentialId] FOREIGN KEY ([CredentialId]) REFERENCES [dbo].[Credentials] ([Id]) ON DELETE CASCADE ); GO CREATE NONCLUSTERED INDEX [IX_Computers_CredentialId] ON [dbo].[Computers]([CredentialId] ASC); CREATE TABLE [dbo].[Scans] ( [Id] UNIQUEIDENTIFIER NOT NULL, [ComputerId] UNIQUEIDENTIFIER NOT NULL, [StartTime] DATETIME2 (7) NOT NULL, [Status] NVARCHAR (MAX) NULL, [StopTime] DATETIME2 (7) NOT NULL, [SweepIdentifier] UNIQUEIDENTIFIER DEFAULT ('00000000-0000-0000-0000-000000000000') NOT NULL, CONSTRAINT [PK_Scans] PRIMARY KEY CLUSTERED ([Id] ASC), CONSTRAINT [FK_Scans_Computers_ComputerId] FOREIGN KEY ([ComputerId]) REFERENCES [dbo].[Computers] ([Id]) ON DELETE CASCADE ); CREATE TABLE [dbo].[Scripts] ( [Id] UNIQUEIDENTIFIER NOT NULL, [CreationTime] DATETIME2 (7) NOT NULL, [Language] NVARCHAR (MAX) NOT NULL, [LastUpdateTime] DATETIME2 (7) NOT NULL, [Name] NVARCHAR (MAX) NOT NULL, [Uri] NVARCHAR (MAX) NOT NULL, [RoutingKey] NVARCHAR (MAX) NOT NULL, CONSTRAINT [PK_Scripts] PRIMARY KEY CLUSTERED ([Id] ASC) ); CREATE TABLE [dbo].[Downloads] ( [Id] UNIQUEIDENTIFIER NOT NULL, [ComputerName] NVARCHAR (MAX) NOT NULL, [Content] VARBINARY (MAX) NOT NULL, [DownloadTime] DATETIME2 (7) NOT NULL, [FullPath] NVARCHAR (MAX) NOT NULL, [Name] NVARCHAR (MAX) NOT NULL, CONSTRAINT [PK_Downloads] PRIMARY KEY CLUSTERED ([Id] ASC) ); CREATE TABLE [dbo].[Schedules] ( [Id] UNIQUEIDENTIFIER NOT NULL, [ExecutionCount] INT NOT NULL, [StartTime] DATETIME2 (7) NOT NULL, [JobName] NVARCHAR (MAX) NULL, [TriggerName] NVARCHAR (MAX) NULL, [ScriptId] NVARCHAR (MAX) NULL, [RepeatCount] INT DEFAULT ((0)) NOT NULL, CONSTRAINT [PK_Schedules] PRIMARY KEY CLUSTERED ([Id] ASC) ); CREATE TABLE [dbo].[Sweeps] ( [Id] UNIQUEIDENTIFIER NOT NULL, [CompleteCount] INT NOT NULL, [EndTime] DATETIME2 (7) NOT NULL, [ScanCount] INT NOT NULL, [StartTime] DATETIME2 (7) NOT NULL, [Status] NVARCHAR (MAX) NULL, [ErrorCount] INT DEFAULT ((0)) NOT NULL, CONSTRAINT [PK_Sweeps] PRIMARY KEY CLUSTERED ([Id] ASC) ); CREATE TABLE [dbo].[Users] ( [Id] UNIQUEIDENTIFIER NOT NULL, [ApiKey] NVARCHAR (MAX) NOT NULL, [FirstName] NVARCHAR (MAX) NULL, [IsAdmin] BIT NOT NULL, [LastName] NVARCHAR (MAX) NULL, [UserName] NVARCHAR (MAX) NOT NULL, CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ([Id] ASC) ); INSERT INTO [dbo].[Users] ([Id], [ApiKey], [FirstName], [IsAdmin], [LastName], [UserName]) VALUES (N'334d89c9-da7a-43e8-a648-5dc8b22019ed', N'[APIKEY]', N'Admin', 1, N'Admin', N'admin') ================================================ FILE: ACE-Docker/ace-sql/import-data.sh ================================================ /opt/mssql/bin/sqlservr > /dev/null & #wait for the SQL Server to come up sleep 45s # Check if the database already exists /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -d ACEWebService -Q "SELECT * FROM dbo.Scripts" >> /dev/null 2>&1 ERROR=$? if [ $ERROR -ne 0 ]; then # Create Unique API Key apikey=$(cat /proc/sys/kernel/random/uuid) sed -i -e 's/\[APIKEY\]/'"$apikey"'/g' /usr/src/ace/ace.sql #run the setup script to create the DB and the schema in the DB /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -Q "CREATE DATABASE ACEWebService" > /dev/null /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -d ACEWebService -i /usr/src/ace/ace.sql > /dev/null else # We need to return the ApiKey apikey="$(/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -d ACEWebService -Q "SELECT ApiKey FROM dbo.Users WHERE Id='334D89C9-DA7A-43E8-A648-5DC8B22019ED'" | grep -E '[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}')" fi echo "\"ApiKey\": \"$apikey\"," echo "\"SQLPassword\": \"$SA_PASSWORD\"" #echo "\"DefaultConnection\": \"Server=sql.ace.local;Database=ACEWebService;User Id=sa;Password=$SA_PASSWORD;MultipleActiveResultSets=true\"" while true; do sleep 300 done ================================================ FILE: ACE-Docker/ace.env ================================================ SA_PASSWORD=P@ssw0rd! MSSQL_PID=Standard RABBITMQ_DEFAULT_USER=ace RABBITMQ_DEFAULT_PASS=P@ssw0rd! APIKEY=YOURAPIKEYHERE WEBSERVICE_IP=192.168.1.10 ================================================ FILE: ACE-Docker/docker-compose.yml ================================================ version: '2.1' networks: ace: driver: bridge ipam: config: - subnet: 172.18.0.0/16 services: ace-rabbitmq: image: specterops/ace-rabbitmq container_name: ace-rabbitmq env_file: ./ace.env hostname: ace-rabbitmq networks: ace: ipv4_address: 172.18.0.2 aliases: - rabbitmq.ace.local ports: - 5672:5672 - 15672:15672 ace-sql: image: specterops/ace-sql container_name: ace-sql env_file: ./ace.env hostname: ace-sql networks: ace: aliases: - sql.ace.local ipv4_address: 172.18.0.3 ports: - 1433:1433 ace-nginx: image: specterops/ace-nginx container_name: ace-nginx env_file: ./ace.env hostname: ace-nginx networks: ace: aliases: - nginx.ace.local ipv4_address: 172.18.0.4 ports: - "80:80" - "443:443" ================================================ FILE: ACE-Docker/settings.sh ================================================ clear get_host_ip(){ # *********** Getting Host IP *************** # https://github.com/Invoke-IR/ACE/blob/master/ACE-Docker/start.sh echo "[ACE-INSTALLATION-INFO] Obtaining current host IP.." unameOut="$(uname -s)" case "${unameOut}" in Linux*) host_ip=$(ip route get 1 | awk '{print $NF;exit}');; Darwin*) host_ip=$(ifconfig en0 | grep inet | grep -v inet6 | cut -d ' ' -f2);; *) host_ip="UNKNOWN:${unameOut}" esac } # Write appsettings.Production.json to screen get_appsettings_data(){ echo "" echo "" echo "==========================================================" echo "" echo " \"RabbitMQServer\": \"${host_ip}\"" echo " $(docker logs ace-rabbitmq | grep UserName)" echo " $(docker logs ace-rabbitmq | grep Password)" echo " $(docker logs ace-nginx | grep Thumbprint)" echo " \"SQLServer\": \"${host_ip}\"" echo " $(docker logs ace-sql | grep SQLPassword)" echo "" echo "==========================================================" echo "" echo "" } get_ps_settings(){ # Provide configuration details for PowerShell Module echo "" echo "" echo "===============================================================" echo "| Thank you for provisioning ACE with Docker!! |" echo "| Please use the following information to interact with ACE |" echo "===============================================================" echo "" echo " \$settings = @{" echo " Uri = 'https://${host_ip}'" IFS='"' read -r -a array <<< "$(docker logs ace-sql | grep Api)" echo " ApiKey = '${array[3]}'" IFS='"' read -r -a array <<< "$(docker logs ace-nginx | grep Thumbprint)" echo " Thumbprint = '${array[3]}'" echo " }" echo "" echo "==============================================================" echo "" echo "" } get_host_ip get_appsettings_data get_ps_settings ================================================ FILE: ACE-Docker/start.sh ================================================ # Get directory of script and change to it DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $DIR # *********** Check if user is root *************** if [[ $EUID -ne 0 ]]; then echo "[ACE-INSTALLATION-INFO] YOU MUST BE ROOT TO RUN THIS SCRIPT!!!" exit 1 fi LOGFILE="/var/log/ace-install.log" echoerror() { printf "${RC} * ERROR${EC}: $@\n" 1>&2; } # *********** Check System Kernel Name *************** systemKernel="$(uname -s)" install_docker(){ if [ "${systemKernel}" == "Linux" ]; then # Reference: https://get.docker.com/ echo "[ACE-DOCKER-INSTALLATION-INFO] ACE identified Linux as the system kernel" echo "[ACE-DOCKER-INSTALLATION-INFO] Checking distribution list and version" # *********** Check distribution list *************** lsb_dist="$(. /etc/os-release && echo "$ID")" lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')" # *********** Check distribution version *************** case "$lsb_dist" in ubuntu) if [ -x "$(command -v lsb_release)" ]; then dist_version="$(lsb_release --codename | cut -f2)" fi if [ -z "$dist_version" ] && [ -r /etc/lsb-release ]; then dist_version="$(. /etc/lsb-release && echo "$DISTRIB_CODENAME")" fi ;; debian|raspbian) dist_version="$(sed 's/\/.*//' /etc/debian_version | sed 's/\..*//')" case "$dist_version" in 9) dist_version="stretch" ;; 8) dist_version="jessie" ;; 7) dist_version="wheezy" ;; esac ;; centos) if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then dist_version="$(. /etc/os-release && echo "$VERSION_ID")" fi ;; rhel|ol|sles) ee_notice "$lsb_dist" #exit 1 ;; *) if [ -x "$(command -v lsb_release)"]; then dist_version="$(lsb_release --release | cut -f2)" fi if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then dist_version="$(. /etc/os-release && echo "$VERSION_ID")" fi ;; esac echo "[ACE-DOCKER-INSTALLATION-INFO] You're using $lsb_dist version $dist_version" ERROR=$? if [ $ERROR -ne 0 ]; then echoerror "Could not verify distribution or version of the OS (Error Code: $ERROR)." fi # *********** Check if docker is installed *************** if [ -x "$(command -v docker)" ]; then echo "[ACE-DOCKER-INSTALLATION-INFO] Docker already installed" echo "[ACE-DOCKER-INSTALLATION-INFO] Dockerizing ACE.." else echo "[ACE-DOCKER-INSTALLATION-INFO] Docker is not installed" echo "[ACE-DOCKER-INSTALLATION-INFO] Checking if curl is installed first" if [ -x "$(command -v curl)" ]; then echo "[ACE-DOCKER-INSTALLATION-INFO] curl is already installed" echo "[ACE-DOCKER-INSTALLATION-INFO] Ready to install Docker.." else echo "[ACE-DOCKER-INSTALLATION-INFO] curl is not installed" echo "[ACE-DOCKER-INSTALLATION-INFO] Installing curl before installing docker.." apt-get install -y curl >> $LOGFILE 2>&1 ERROR=$? if [ $ERROR -ne 0 ]; then echoerror "Could not install curl (Error Code: $ERROR)." #exit 1 fi fi # ****** Installing via convenience script *********** echo "[ACE-DOCKER-INSTALLATION-INFO] Installing docker via convenience script.." curl -fsSL get.docker.com -o /tmp/get-docker.sh >> $LOGFILE 2>&1 chmod +x /tmp/get-docker.sh >> $LOGFILE 2>&1 /tmp/get-docker.sh >> $LOGFILE 2>&1 ERROR=$? if [ $ERROR -ne 0 ]; then echoerror "Could not install docker via convenience script (Error Code: $ERROR)." #exit 1 fi # ****** Installing docker-compose *********** echo "[ACE-DOCKER-INSTALLATION-INFO] Installing docker-compose .." curl -L https://github.com/docker/compose/releases/download/1.19.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose >> $LOGFILE 2>&1 chmod +x /usr/local/bin/docker-compose >> $LOGFILE 2>&1 ERROR=$? if [ $ERROR -ne 0 ]; then echoerror "Could not install docker-compose (Error Code: $ERROR)." exit 1 fi fi else # *********** Check if docker is installed *************** if [ -x "$(command -v docker)" ]; then echo "[ACE-DOCKER-INSTALLATION-INFO] Docker already installed" echo "[ACE-DOCKER-INSTALLATION-INFO] Dockerizing ACE.." else echo "[ACE-DOCKER-INSTALLATION-INFO] Install docker for $systemKernel" #exit 1 fi fi } get_host_ip(){ # *********** Getting Host IP *************** # https://github.com/Invoke-IR/ACE/blob/master/ACE-Docker/start.sh echo "[ACE-INSTALLATION-INFO] Obtaining current host IP.." unameOut="$(uname -s)" case "${unameOut}" in Linux*) host_ip=$(ip route get 1 | awk '{print $NF;exit}');; Darwin*) host_ip=$(ifconfig en0 | grep inet | grep -v inet6 | cut -d ' ' -f2);; *) host_ip="UNKNOWN:${unameOut}" esac # *********** Accepting Defaults or Allowing user to set ACE IP *************** local ip_choice local read_input read -t 30 -p "[ACE-INSTALLATION-INFO] Set ACE IP. Default value is your current IP: " -e -i ${host_ip} ip_choice read_input=$? ip_choice="${ip_choice:-$host_ip}" if [ $ip_choice != $host_ip ]; then host_ip=$ip_choice fi if [ $read_input = 142 ]; then echo -e "\n[ACE-INSTALLATION-INFO] ACE IP set to ${host_ip}" else echo "[ACE-INSTALLATION-INFO] ACE IP set to ${host_ip}" fi } # Write appsettings.Production.json to screen get_appsettings_data(){ echo "" echo "" echo "==========================================================" echo "" echo " \"RabbitMQServer\": \"${host_ip}\"" echo " $(docker logs ace-rabbitmq | grep UserName)" echo " $(docker logs ace-rabbitmq | grep Password)" echo " $(docker logs ace-nginx | grep Thumbprint)" echo " \"SQLServer\": \"${host_ip}\"" echo " $(docker logs ace-sql | grep SQLPassword)" echo "" echo "==========================================================" echo "" echo "" } get_ps_settings(){ # Provide configuration details for PowerShell Module echo "" echo "" echo "===============================================================" echo "| Thank you for provisioning ACE with Docker!! |" echo "| Please use the following information to interact with ACE |" echo "===============================================================" echo "" echo " \$settings = @{" echo " Uri = 'https://${host_ip}'" IFS='"' read -r -a array <<< "$(docker logs ace-sql | grep Api)" echo " ApiKey = '${array[3]}'" IFS='"' read -r -a array <<< "$(docker logs ace-nginx | grep Thumbprint)" echo " Thumbprint = '${array[3]}'" echo " }" echo "" echo "==============================================================" echo "" echo "" } # Test if Docker and Docker-Compose are installed install_docker # Get the IP Address for later get_host_ip # Build Docker Images and Start Containers echo "[ACE-INSTALLATION-INFO] Building ACE Docker Containers" docker-compose build >> $LOGFILE 2>&1 echo "[ACE-INSTALLATION-INFO] Starting ACE Docker Images" docker-compose up -d >> $LOGFILE 2>&1 echo "[ACE-INSTALLATION-INFO] Waiting for Docker Images to Start" sleep 60 get_appsettings_data get_ps_settings ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Download-AceFile.ps1 ================================================ function Download-AceFile { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter(Mandatory)] [Guid] $ComputerId, [Parameter(Mandatory)] [string] $FilePath ) $body = @{ Uri = $Uri ComputerId = $ComputerId FilePath = $FilePath } try { $result = Invoke-AceWebRequest -Method Post -Uri "$($Uri)/ace/download" -Body (ConvertTo-Json $body -Compress) -ContentType application/json -ApiKey $ApiKey -Thumbprint $Thumbprint Write-Output ($result | ConvertFrom-Json) } catch { Write-Warning "test" } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Get-AceComputer.ps1 ================================================ function Get-AceComputer { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter()] [Guid] $Id ) if ($PSBoundParameters.ContainsKey('Id')) { $Url = "$($Uri)/ace/computer/$($Id)" } else { $Url = "$($Uri)/ace/computer" } try { $result = Invoke-AceWebRequest -Method Get -Uri $Url -ApiKey $ApiKey -Thumbprint $Thumbprint -ErrorAction Stop Write-Output ($result | ConvertFrom-Json) } catch { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Get-AceCredential.ps1 ================================================ function Get-AceCredential { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter()] [Guid] $Id ) try { if($PSBoundParameters.ContainsKey('Id')) { $result = Invoke-AceWebRequest -Method Get -Uri "$($Uri)/ace/credential/pscredential/$($Id)" -ApiKey $ApiKey -Thumbprint $Thumbprint -ErrorAction Stop $result = $result | ConvertFrom-Json $secpassword = ConvertTo-SecureString -String $result.password -AsPlainText -Force $cred = New-Object -TypeName System.Management.Automation.PSCredential($result.userName, $secpassword) Write-Output $cred } else { $result = Invoke-AceWebRequest -Method Get -Uri "$($Uri)/ace/credential" -ApiKey $ApiKey -Thumbprint $Thumbprint -ErrorAction Stop Write-Output ($result | ConvertFrom-Json) } } catch { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Get-AceSchedule.ps1 ================================================ function Get-AceSchedule { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint ) try { $result = Invoke-AceWebRequest -Method Get -Uri "$($Uri)/ace/schedule" -ApiKey $ApiKey -Thumbprint $Thumbprint -ErrorAction Stop Write-Output ($result | ConvertFrom-Json) } catch { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Get-AceScript.ps1 ================================================ function Get-AceScript { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint ) try { $result = Invoke-AceWebRequest -Method Get -Uri "$($Uri)/ace/script" -ApiKey $ApiKey -Thumbprint $Thumbprint -ErrorAction Stop Write-Output ($result | ConvertFrom-Json) } catch { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Get-AceSweep.ps1 ================================================ function Get-AceSweep { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter()] [Guid] $Id ) if ($PSBoundParameters.ContainsKey('Id')) { $Url = "$($Uri)/ace/sweep/$($Id)" } else { $Url = "$($Uri)/ace/sweep" } try { $result = Invoke-AceWebRequest -Method Get -Uri $Url -ApiKey $ApiKey -Thumbprint $Thumbprint -ErrorAction Stop Write-Output ($result | ConvertFrom-Json) } catch { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Get-AceSweepResult.ps1 ================================================ function Get-AceSweepResult { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter()] [Guid] $Id ) try { $result = Invoke-AceWebRequest -Method Get -Uri "$($Uri)/ace/scan/$($Id)" -ApiKey $ApiKey -Thumbprint $Thumbprint -ErrorAction Stop Write-Output ($result | ConvertFrom-Json) } catch { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Get-AceUser.ps1 ================================================ function Get-AceUser { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint ) try { $result = Invoke-AceWebRequest -Method Get -Uri "$($Uri)/ace/user" -ApiKey $ApiKey -Thumbprint $Thumbprint -ErrorAction Stop Write-Output ($result | ConvertFrom-Json) } catch { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Invoke-AceWebRequest.ps1 ================================================ function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter()] [ValidateSet('Delete','Get','Post','Put')] [string] $Method = 'Get', [Parameter()] [string] $ContentType = 'application/json', [Parameter()] [string] $Body ) try { # Create web request $WebRequest = [System.Net.WebRequest]::Create($Uri) $WebRequest.Headers.Add('X-API-Version:1.0') $webrequest.Headers.Add("X-ApiKey:$($ApiKey)") $WebRequest.Method = $Method $WebRequest.ContentType = $ContentType # Set the callback to check for null certificate and thumbprint matching. $WebRequest.ServerCertificateValidationCallback = { $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteWarningLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteWarningLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") $Host.UI.WriteWarningLine(" Expected thumbprint: $($Thumbprint)") $Host.UI.WriteWarningLine(" Received thumbprint: $($certificate.Thumbprint)") } return $false } if($PSBoundParameters.ContainsKey('Body')) { $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() } # Get response stream $ResponseStream = $webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() $StreamReader.Close() $ResponseStream.Close() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/New-AceCredential.ps1 ================================================ function New-AceCredential { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter(Mandatory)] [Management.Automation.PSCredential] [Management.Automation.CredentialAttribute()] $Credential ) $body = @{ UserName = $Credential.UserName Password = $Credential.GetNetworkCredential().Password } try { $result = Invoke-AceWebRequest -Method Post -Uri "$($Uri)/ace/credential" -Body (ConvertTo-Json $body -Compress) -ContentType application/json -ApiKey $ApiKey -Thumbprint $Thumbprint Write-Output ($result | ConvertFrom-Json) } catch { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/New-AceScheduledScan.ps1 ================================================ function New-AceScheduledScan { [CmdletBinding()] param ( [Parameter(Mandatory)] [string[]] $ComputerId, [Parameter(Mandatory)] [string] $ScriptId, [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter(Mandatory)] [Int32] $Hour, [Parameter(Mandatory)] [Int32] $Minute, [Parameter(Mandatory)] [Int32] $IntervalInMinutes, [Parameter()] [Int32] $RepeatCount = 0 ) $body = @{ ComputerId = $ComputerId ScriptId = $ScriptId Uri = $Uri Hour = $Hour Minute = 0 Interval = $IntervalInMinutes RepeatCount = $RepeatCount } $result = Invoke-AceWebRequest -Method Post -Uri "$($Uri)/ace/schedule" -Body (ConvertTo-Json $body -Compress) -ContentType application/json -ApiKey $ApiKey -Thumbprint $Thumbprint Write-Output ($result | ConvertFrom-Json) } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/New-AceScript.ps1 ================================================ function New-AceScript { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter(Mandatory)] [string] $Path, [Parameter(Mandatory)] [string] $Name, [Parameter(Mandatory)] [string] $Language, [Parameter()] [string] $RoutingKey ) $body = @{ Name = $Name Language = $Language RoutingKey = $RoutingKey Content = [System.IO.File]::ReadAllBytes($Path) } try { $result = Invoke-AceWebRequest -Method Post -Uri "$($Uri)/ace/script" -Body (ConvertTo-Json $body -Compress) -ContentType application/json -ApiKey $ApiKey -Thumbprint $Thumbprint Write-Output ($result | ConvertFrom-Json) } catch { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/New-AceUser.ps1 ================================================ function New-AceUser { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter(Mandatory)] [string] $UserName, [Parameter()] [string] $FirstName = $null, [Parameter()] [string] $LastName = $null, [Parameter()] [bool] $IsAdmin = $false ) $body = @{ UserName = $UserName FirstName = $FirstName LastName = $LastName IsAdmin = $IsAdmin } try { $result = Invoke-AceWebRequest -Method Post -Uri "$($Uri)/ace/user" -Body (ConvertTo-Json $body -Compress) -ContentType application/json -ApiKey $ApiKey -Thumbprint $Thumbprint Write-Output ($result | ConvertFrom-Json) } catch { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Remove-AceCredential.ps1 ================================================ function Remove-AceCredential { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter(Mandatory)] [Guid] $Id ) try { $result = Invoke-AceWebRequest -Method Get -Uri "$($Uri)/ace/credential/delete/$($Id)" -ApiKey $ApiKey -Thumbprint $Thumbprint Write-Output ($result | ConvertFrom-Json) } catch { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Remove-AceScript.ps1 ================================================ function Remove-AceScript { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter(Mandatory)] [Guid] $Id ) try { $result = Invoke-AceWebRequest -Method Get -Uri "$($Uri)/ace/script/delete/$($Id)" -ApiKey $ApiKey -Thumbprint $Thumbprint Write-Output ($result | ConvertFrom-Json) } catch { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Remove-AceUser.ps1 ================================================ function Remove-AceUser { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter(Mandatory)] [Guid] $Id ) try { $result = Invoke-AceWebRequest -Method Get -Uri "$($Uri)/ace/user/delete/$($Id)" -ApiKey $ApiKey -Thumbprint $Thumbprint Write-Output ($result | ConvertFrom-Json) } catch { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Send-AceResult.ps1 ================================================ function Send-AceResult { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [psobject[]] $InputObject, [Parameter(Mandatory)] [string] $Uri ) begin { $header = @{ 'X-API-Version' = '1.0' } } process { foreach($o in $InputObject) { $result = Invoke-WebRequest -Method Post -Uri "$($Uri)/ace/result/e989000d-2b98-44bd-94fc-403c41f42bf5" -Body (ConvertTo-Json $o) -Headers $header -ContentType application/json Write-Output ($result.Content | ConvertFrom-Json) } } end { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Start-AceDiscovery.ps1 ================================================ function Start-AceDiscovery { [CmdletBinding(DefaultParameterSetName = "Domain")] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter(Mandatory)] [Guid] $CredentialId, [Parameter(Mandatory, ParameterSetName = "Domain")] [string] $Domain, [Parameter(Mandatory, ParameterSetName = "ComputerList")] [string[]] $ComputerName ) switch($PSCmdlet.ParameterSetName) { ComputerList { $body = @{ ComputerName = $ComputerName CredentialId = $CredentialId } $result = Invoke-AceWebRequest -Method Post -Uri "$($Uri)/ace/discover/computerlist" -Body (ConvertTo-Json $body -Compress) -ContentType application/json -ApiKey $ApiKey -Thumbprint $Thumbprint } Domain { $body = @{ Domain = $Domain CredentialId = $CredentialId } $result = Invoke-AceWebRequest -Method Post -Uri "$($Uri)/ace/discover/domain" -Body (ConvertTo-Json $body -Compress) -ContentType application/json -ApiKey $ApiKey -CheckCert } } Write-Output ($result | ConvertFrom-Json) } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Start-AceSweep.ps1 ================================================ function Start-AceSweep { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter()] [string] $ExternalUri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter(Mandatory)] [Guid[]] $ComputerId, [Parameter(Mandatory)] [Guid] $ScriptId ) if(-not $PSBoundParameters.ContainsKey('ExternalUri')) { $ExternalUri = $Uri } $body = @{ ComputerId = $ComputerId ScriptId = $ScriptId Uri = $Uri ExternalUri = $ExternalUri } try { $result = Invoke-AceWebRequest -Method Post -Uri "$($Uri)/ace/sweep" -Body (ConvertTo-Json $body -Compress) -ContentType application/json -ApiKey $ApiKey -Thumbprint $Thumbprint Write-Output ($result | ConvertFrom-Json) } catch { } } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Update-AceCredential.ps1 ================================================ function Update-AceCredential { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter(Mandatory)] [Guid] $CredentialId, [Parameter(Mandatory)] [Management.Automation.PSCredential] [Management.Automation.CredentialAttribute()] $Credential ) $body = @{ UserName = $Credential.UserName Password = $Credential.GetNetworkCredential().Password } $result = Invoke-AceWebRequest -Method Put -Uri "$($Uri)/ace/credential/$($CredentialId)" -Body (ConvertTo-Json $body) -ContentType application/json -ApiKey $ApiKey -Thumbprint $Thumbprint Write-Output ($result.Content | ConvertFrom-Json) } ================================================ FILE: ACE-Management/PS-ACE/Cmdlets/Update-AceUser.ps1 ================================================ function Update-AceUser { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $Uri, [Parameter(Mandatory)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter(Mandatory)] [string] $UserId, [Parameter(Mandatory)] [string] $UserName, [Parameter()] [string] $FirstName = $null, [Parameter()] [string] $LastName = $null, [Parameter()] [bool] $IsAdmin = $false ) $body = @{ UserName = $UserName FirstName = $FirstName LastName = $LastName IsAdmin = $IsAdmin } $result = Invoke-AceWebRequest -Method Put -Uri "$($Uri)/ace/user/$($UserId)" -Body (ConvertTo-Json $body -Compress) -ContentType application/json -ApiKey $ApiKey -Thumbprint $Thumbprint Write-Output ($result | ConvertFrom-Json) } ================================================ FILE: ACE-Management/PS-ACE/PS-ACE.psm1 ================================================ Get-ChildItem "$($PSScriptRoot)\Cmdlets\*" -Include '*.ps1' | ForEach-Object {. $_.FullName} ================================================ FILE: ACE-Management/PS-ACE/README.md ================================================ # PS-ACE The ACE Web Application provides a RESTful API for managment and sweep tasking. PS-ACE is a PowerShell module that interacts with this API. The supported mechanism for provisioning ACE is to use the start.sh script in the ACE-Docker directory. Upon completion, start.sh provides the user with all of the information required to interact with ACE's RESTful API. The three pieces of information necessary to interact with the ACE Web Application are: * Web Server URI * Builtin Administrator's API Key * Web Server's SSL Certificate Thumbprint Below is an example of the output from start.sh: ``` ========================================================== | Thank you for provisioning ACE with Docker!! | ========================================================== Please use the following information to interact with ACE: Uri: https://10.57.106.141 ApiKey: 9C8DC642-268D-41EA-9521-43F718119FB7 Thumbprint: FA4608B93B017DF46D1BC6155DC4C5AF7D83EA1D ========================================================== ``` The best way to pass this information to the PS-ACE cmdlets is through a technique called [splatting](https://docs.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Core/about_Splatting?view=powershell-5.0). Splatting allows for a Hash Table to be passed as a set of parameter names (Keys) and values (Values) by using the '@' instead of the '$'. Below is an example of creating a hash table called **props** with keys Uri, ApiKey, and Thumbprint (these are derived from the output of start.sh above) and using this hash table to splat **Get-AceUser**: ```powershell # Create a hash table with ACE's common parameters PS> $props = @{ Uri = 'https://192.168.50.187' ApiKey = 'd0bf91fa-9934-40ca-8cb9-5a1168546abc' Thumbprint = '39F459D8CBE1D92396A435F6D5B375AED42CE518' } # Pass parameters through Splatting the props variable PS> Get-AceUser @props id : 334d89c9-da7a-43e8-a648-5dc8b22019ed userName : admin firstName : Admin lastName : Admin isAdmin : True apiKey : 9C8DC642-268D-41EA-9521-43F718119FB7 ``` ## Cmdlets ### Get-AceComputer ### Get-AceCredential ### Get-AceSchedule ### Get-AceScript ### Get-AceSweep ### Get-AceSweepResult ### Get-AceUser ### Invoke-AceWebRequest ### New-AceCredential ### New-AceScheduledScan ### New-AceScript ### New-AceUser ### Remove-AceCredential ### Remove-AceScript ### Remove-AceUser ### Send-AceResult ### Start-AceDiscovery ### Start-AceSweep ### Update-AceCredential ### Update-AceUser ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE-Master.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter()] [ValidateSet('All','AccessToken','ArpCache','AtomTable','FullProcess','FullService','InjectedThread','KerberosTicket','LogonSession','MasterBootRecord','NetworkConnection','RegistryAutoRun','ScheduledTask','SecurityPackage','SimpleNamedPipe','WmiEventSubscription')] [string[]] $ScanType = 'All' ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $scans = New-Object -TypeName System.Collections.Generic.List['Hashtable'] if($ScanType -contains 'All' -or $ScanType -contains 'AccessToken') { $scans.Add(@{Function = 'Get-AccessToken'; RoutingKey = 'siem'; ScanType = 'AccessToken'}) } if($ScanType -contains 'All' -or $ScanType -contains 'ArpCache') { $scans.Add(@{Function = 'Get-ArpCache -ReturnHashtables'; RoutingKey = 'siem'; ScanType = 'ArpCache'}) } if($ScanType -contains 'All' -or $ScanType -contains 'AtomTable') { $scans.Add(@{Function = 'Get-AtomTable -ReturnHashtables'; RoutingKey = 'siem'; ScanType = 'AtomTable'}) } if($ScanType -contains 'All' -or $ScanType -contains 'FullProcess') { $scans.Add(@{Function = 'Get-PSIProcess -ReturnHashtables'; RoutingKey = 'hash.siem'; ScanType = 'FullProcess'}) } if($ScanType -contains 'All' -or $ScanType -contains 'FullService') { $scans.Add(@{Function = 'Get-PSIService -ReturnHashtables'; RoutingKey = 'siem'; ScanType = 'FullService'}) } if($ScanType -contains 'All' -or $ScanType -contains 'InjectedThread') { $scans.Add(@{Function = 'Get-InjectedThread'; RoutingKey = 'siem'; ScanType = 'InjectedThread'}) } if($ScanType -contains 'All' -or $ScanType -contains 'KerberosTicket') { $scans.Add(@{Function = 'Get-KerberosTicketCache'; RoutingKey = 'siem'; ScanType = 'KerberosTicket'}) } if($ScanType -contains 'All' -or $ScanType -contains 'LogonSession') { $scans.Add(@{Function = 'Get-LogonSession -ReturnHashtables'; RoutingKey = 'siem'; ScanType = 'LogonSession'}) } if($ScanType -contains 'All' -or $ScanType -contains 'MasterBootRecord') { $scans.Add(@{Function = 'Get-MasterBootRecord -ReturnHashtables'; RoutingKey = 'siem'; ScanType = 'MasterBootRecord'}) } if($ScanType -contains 'All' -or $ScanType -contains 'NetworkConnection') { $scans.Add(@{Function = 'Get-NetworkConnection -ReturnHashtables'; RoutingKey = 'siem'; ScanType = 'NetworkConnection'}) } if($ScanType -contains 'All' -or $ScanType -contains 'RegistryAutoRun') { $scans.Add(@{Function = 'Get-RegistryAutoRun'; RoutingKey = 'siem'; ScanType = 'RegistryAutoRun'}) } if($ScanType -contains 'All' -or $ScanType -contains 'ScheduledTask') { $scans.Add(@{Function = 'Get-PSIScheduledTask -ReturnHashtables'; RoutingKey = 'siem'; ScanType = 'ScheduledTask'}) } if($ScanType -contains 'All' -or $ScanType -contains 'SecurityPackage') { $scans.Add(@{Function = 'Get-SecurityPackage -ReturnHashtables'; RoutingKey = 'siem'; ScanType = 'SecurityPackage'}) } if($ScanType -contains 'All' -or $ScanType -contains 'SimpleNamedPipe') { $scans.Add(@{Function = 'Get-SimpleNamedPipe -ReturnHashtables'; RoutingKey = 'siem'; ScanType = 'SimpleNamedPipe'}) } if($ScanType -contains 'All' -or $ScanType -contains 'WmiEventSubscription') { $scans.Add(@{Function = 'Get-WmiEventSubscription -ReturnHashtables'; RoutingKey = 'siem'; ScanType = 'WmiEventSubscription'}) } foreach($scan in $scans) { $dataList = New-Object -TypeName System.Collections.Generic.List['string'] Write-Host -NoNewline -ForegroundColor Yellow -Object '[!] ' Write-Host "[$($HostFQDN)] $($scan.ScanType)" foreach($o in (Invoke-Expression $scan.Function)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', $scan.ScanType) $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = $scan.ScanType RoutingKey = $scan.RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) #Write-Output $body Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { #Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } #region Collection Functions function Get-AccessToken { param ( [Parameter()] [System.Diagnostics.Process[]] $Process ) begin { <# try { Get-System } catch { Write-Error "Unable to Impersonate NT AUTHORITY\SYSTEM token" } #> if(-not ($PSBoundParameters.ContainsKey('Process'))) { $Process = Get-Process } } process { foreach($proc in $Process) { if($proc.Id -ne 0 -and $proc.Id -ne 4 -and $proc.Id -ne $PID) { $ProcessGuid = [Guid]::NewGuid() try { $hProcess = OpenProcess -ProcessId $proc.Id -DesiredAccess PROCESS_QUERY_LIMITED_INFORMATION } catch { if($_.Exception.Message -ne "OpenProcess Error: The parameter is incorrect") { Write-Warning "Process Handle: $($proc.Id)" Write-Warning $_.Exception.Message } } try { $hToken = OpenProcessToken -ProcessHandle $hProcess -DesiredAccess TOKEN_QUERY } catch { #Write-Warning "Process Token Handle: $($proc.Id)" #Write-Warning $_.Exception.Message } try { $TokenUser = GetTokenInformation -TokenInformationClass TokenUser -TokenHandle $hToken $TokenGroup = GetTokenInformation -TokenInformationClass TokenGroups -TokenHandle $hToken $TokenOwner = GetTokenInformation -TokenInformationClass TokenOwner -TokenHandle $hToken $TokenIntegrityLevel = GetTokenInformation -TokenInformationClass TokenIntegrityLevel -TokenHandle $hToken $TokenType = GetTokenInformation -TokenInformationClass TokenType -TokenHandle $hToken $TokenSessionId = GetTokenInformation -TokenInformationClass TokenSessionId -TokenHandle $hToken $TokenOrigin = GetTokenInformation -TokenInformationClass TokenOrigin -TokenHandle $hToken $TokenPrivileges = (GetTokenInformation -TokenInformationClass TokenPrivileges -TokenHandle $hToken | Where-Object {$_.Attributes -like "*ENABLED*"} | select -ExpandProperty Privilege) -join ";" $TokenElevation = GetTokenInformation -TokenInformationClass TokenElevation -TokenHandle $hToken $TokenElevationType = GetTokenInformation -TokenInformationClass TokenElevationType -TokenHandle $hToken $props = @{ ProcessGuid = $ProcessGuid ProcessName = $proc.Name ProcessId = $proc.Id ThreadId = 0 UserSid = $TokenUser.Sid.ToString() UserName = $TokenUser.Name.Value OwnerSid = $TokenOwner.Sid.ToString() OwnerName = $TokenOwner.Name.Value #Groups = $TokenGroup IntegrityLevel = $TokenIntegrityLevel.ToString() Type = $TokenType.ToString() ImpersonationLevel = 'None' SessionId = $TokenSessionId -as ([Int32]) Origin = $TokenOrigin -as ([Int32]) Privileges = $TokenPrivileges IsElevated = $TokenElevation -as ([bool]) ElevationType = $TokenElevationType.ToString() } Write-Output $props CloseHandle -Handle $hProcess CloseHandle -Handle $hToken } catch { #Write-Warning "Process Token Query: $($proc.Id)" #Write-Warning $_.Exception.Message } foreach($thread in $proc.Threads) { try { $hThread = OpenThread -ThreadId $thread.Id -DesiredAccess THREAD_QUERY_LIMITED_INFORMATION try { $hToken = OpenThreadToken -ThreadHandle $hThread -DesiredAccess TOKEN_QUERY $TokenUser = GetTokenInformation -TokenInformationClass TokenUser -TokenHandle $hToken $TokenGroup = GetTokenInformation -TokenInformationClass TokenGroups -TokenHandle $hToken $TokenOwner = GetTokenInformation -TokenInformationClass TokenOwner -TokenHandle $hToken $TokenIntegrityLevel = GetTokenInformation -TokenInformationClass TokenIntegrityLevel -TokenHandle $hToken $TokenType = GetTokenInformation -TokenInformationClass TokenType -TokenHandle $hToken if($TokenType -eq 'TokenImpersonation') { $TokenImpersonationLevel = GetTokenInformation -TokenInformationClass TokenImpersonationLevel -TokenHandle $hToken } else { $TokenImpersonationLevel = 'None' } $TokenSessionId = GetTokenInformation -TokenInformationClass TokenSessionId -TokenHandle $hToken $TokenOrigin = GetTokenInformation -TokenInformationClass TokenOrigin -TokenHandle $hToken $TokenPrivileges = (GetTokenInformation -TokenInformationClass TokenPrivileges -TokenHandle $hToken | Where-Object {$_.Attributes -like "*ENABLED*"} | select -ExpandProperty Privilege) -join ";" $TokenElevation = GetTokenInformation -TokenInformationClass TokenElevation -TokenHandle $hToken $TokenElevationType = GetTokenInformation -TokenInformationClass TokenElevationType -TokenHandle $hToken $props = @{ ProcessGuid = $ProcessGuid ProcessName = $proc.Name ProcessId = $proc.Id ThreadId = $thread.Id UserSid = $TokenUser.Sid.ToString() UserName = $TokenUser.Name.Value OwnerSid = $TokenOwner.Sid.ToString() OwnerName = $TokenOwner.Name.Value #Groups = $TokenGroup IntegrityLevel = $TokenIntegrityLevel.ToString() Type = $TokenType.ToString() ImpersonationLevel = $TokenImpersonationLevel.ToString() SessionId = $TokenSessionId -as ([Int32]) Origin = $TokenOrigin -as ([Int32]) Privileges = $TokenPrivileges IsElevated = $TokenElevation -as ([bool]) ElevationType = $TokenElevationType.ToString() } Write-Output $props CloseHandle -Handle $hThread CloseHandle -Handle $hToken } catch { if($_.Exception.Message -ne 'OpenThreadToken Error: An attempt was made to reference a token that does not exist') { #Write-Warning "Thread Token Handle" #Write-Warning $_.Exception.Message } } } catch { #Write-Warning "Thread Handle: [Proc] $($proc.Id) [THREAD] $($thread.Id)" #Write-Warning $_.Exception.Message } } } } } end { RevertToSelf } } function Get-ArpCache { <# .SYNOPSIS Gets the contents of the ARP Cache. .DESCRIPTION The Get-ArpCache function retreives the contents of the system's ARP Cache. The ARP Cache contains cached mappings from IPv4 Addresses to their Physical Address (MAC Address). .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .EXAMPLE Get-ArpCache AdapterIndex : 1 PhysicalAddress : 00-00-00-00-00-00 IpAddress : 224.0.0.22 Type : STATIC AdapterServiceName : e1iexpress AdapterMacAddress : 00:0C:29:3A:DF:39 AdapterType : Ethernet 802.3 AdapterName : Intel(R) 82574L Gigabit Network Connection AdapterSpeed : 1000000000 AdapterIndex : 1 PhysicalAddress : 00-00-00-00-00-00 IpAddress : 224.0.0.252 Type : STATIC AdapterServiceName : e1iexpress AdapterMacAddress : 00:0C:29:3A:DF:39 AdapterType : Ethernet 802.3 AdapterName : Intel(R) 82574L Gigabit Network Connection AdapterSpeed : 1000000000 AdapterIndex : 1 PhysicalAddress : 00-00-00-00-00-00 IpAddress : 239.255.255.250 Type : STATIC AdapterServiceName : e1iexpress AdapterMacAddress : 00:0C:29:3A:DF:39 AdapterType : Ethernet 802.3 AdapterName : Intel(R) 82574L Gigabit Network Connection AdapterSpeed : 1000000000 #> param ( [Parameter()] [switch] $ReturnHashtables ) $Entries = GetIpNetTable foreach($Entry in $Entries) { $Adapter = Get-WmiObject -Class win32_networkadapter -Filter "DeviceID = $($Entry.AdapterIndex)" $Entry.Add('AdapterServiceName', $Adapter.ServiceName) $Entry.Add('AdapterMacAddress', $Adapter.MACAddress) $Entry.Add('AdapterType', $Adapter.AdapterType) $Entry.Add('AdapterName', $Adapter.Name) $Entry.Add('AdapterSpeed', $Adapter.Speed) if($ReturnHashtables) { Write-Output $Entry } else { New-Object -TypeName psobject -Property $Entry } } } function Get-AtomTable { [CmdletBinding()] param ( [Parameter()] [UInt16] $AtomIndex, [Parameter()] [switch] $ReturnHashtables ) if($PSBoundParameters.ContainsKey('AtomIndex')) { GlobalGetAtomName -AtomIndex $AtomIndex } else { $atomList = New-Object -TypeName System.Collections.Generic.List['string'] for($i = 0xC000; $i -lt [UInt16]::MaxValue; $i++) { try { $atomname = GlobalGetAtomName -AtomIndex $i -ErrorAction Stop $props = @{ Index = $i Name = $atomname.ToString() } if($ReturnHashtables) { Write-Output $props } else { New-Object -TypeName psobject -Property $props } } catch { } } } } function Get-InjectedThread { <# .SYNOPSIS Looks for threads that were created as a result of code injection. .DESCRIPTION Memory resident malware (fileless malware) often uses a form of memory injection to get code execution. Get-InjectedThread looks at each running thread to determine if it is the result of memory injection. Common memory injection techniques that *can* be caught using this method include: - Classic Injection (OpenProcess, VirtualAllocEx, WriteProcessMemory, CreateRemoteThread) - Reflective DLL Injection - Process Hollowing NOTE: Nothing in security is a silver bullet. An attacker could modify their tactics to avoid detection using this methodology. .NOTES Author - Jared Atkinson (@jaredcatkinson) .EXAMPLE PS > Get-InjectedThread ProcessName : ThreadStart.exe ProcessId : 7784 Path : C:\Users\tester\Desktop\ThreadStart.exe KernelPath : C:\Users\tester\Desktop\ThreadStart.exe CommandLine : "C:\Users\tester\Desktop\ThreadStart.exe" PathMismatch : False ThreadId : 14512 AllocatedMemoryProtection : PAGE_EXECUTE_READWRITE MemoryProtection : PAGE_EXECUTE_READWRITE MemoryState : MEM_COMMIT MemoryType : MEM_PRIVATE BasePriority : 8 IsUniqueThreadToken : False Integrity : MEDIUM_MANDATORY_LEVEL Privilege : SeChangeNotifyPrivilege LogonId : 999 SecurityIdentifier : S-1-5-21-386661145-2656271985-3844047388-1001 UserName : DESKTOP-HMTGQ0R\SYSTEM LogonSessionStartTime : 3/15/2017 5:45:38 PM LogonType : System AuthenticationPackage : NTLM BaseAddress : 4390912 Size : 4096 Bytes : {144, 195, 0, 0...} #> [CmdletBinding()] param ( ) $hSnapshot = CreateToolhelp32Snapshot -ProcessId 0 -Flags 4 $Thread = Thread32First -SnapshotHandle $hSnapshot do { $proc = Get-Process -Id $Thread.th32OwnerProcessId -ErrorAction SilentlyContinue if($Thread.th32OwnerProcessId -ne 0 -and $Thread.th32OwnerProcessId -ne 4) { try { $hThread = OpenThread -ThreadId $Thread.th32ThreadID -DesiredAccess THREAD_QUERY_INFORMATION if($hThread -ne 0) { $BaseAddress = NtQueryInformationThread -ThreadHandle $hThread -ThreadInformationClass ThreadQuerySetWin32StartAddress $hProcess = OpenProcess -ProcessId $Thread.th32OwnerProcessID -DesiredAccess PROCESS_QUERY_LIMITED_INFORMATION -InheritHandle $false if($hProcess -ne 0) { $memory_basic_info = VirtualQueryEx -ProcessHandle $hProcess -BaseAddress $BaseAddress $AllocatedMemoryProtection = $memory_basic_info.AllocationProtect -as $MEMORY_PROTECTION $MemoryProtection = $memory_basic_info.Protect -as $MEMORY_PROTECTION $MemoryState = $memory_basic_info.State -as $MEMORY_STATE $MemoryType = $memory_basic_info.Type -as $MEMORY_TYPE if($MemoryState -eq $MEMORY_STATE::MEM_COMMIT -and $MemoryType -ne $MEMORY_TYPE::MEM_IMAGE) { $buf = ReadProcessMemory -ProcessHandle $hProcess -BaseAddress $BaseAddress -Size 100 $proc = Get-WmiObject Win32_Process -Filter "ProcessId = '$($Thread.th32OwnerProcessID)'" $KernelPath = QueryFullProcessImageName -ProcessHandle $hProcess $PathMismatch = $proc.Path.ToLower() -ne $KernelPath.ToLower() # check if thread has unique token try { $hThreadToken = OpenThreadToken -ThreadHandle $hThread -DesiredAccess TOKEN_QUERY $TokenUser = GetTokenInformation -TokenInformationClass TokenUser -TokenHandle $hThreadToken $TokenOwner = GetTokenInformation -TokenInformationClass TokenOwner -TokenHandle $hThreadToken $TokenIntegrityLevel = GetTokenInformation -TokenInformationClass TokenIntegrityLevel -TokenHandle $hThreadToken $TokenType = GetTokenInformation -TokenInformationClass TokenType -TokenHandle $hThreadToken if($TokenType -eq 'TokenImpersonation') { $TokenImpersonationLevel = GetTokenInformation -TokenInformationClass TokenImpersonationLevel -TokenHandle $hThreadToken } else { $TokenImpersonationLevel = 'None' } $TokenSessionId = GetTokenInformation -TokenInformationClass TokenSessionId -TokenHandle $hThreadToken $TokenOrigin = GetTokenInformation -TokenInformationClass TokenOrigin -TokenHandle $hThreadToken $TokenPrivileges = (GetTokenInformation -TokenInformationClass TokenPrivileges -TokenHandle $hThreadToken | Where-Object {$_.Attributes -like "*ENABLED*"} | select -ExpandProperty Privilege) -join ";" $TokenElevation = GetTokenInformation -TokenInformationClass TokenElevation -TokenHandle $hThreadToken $TokenElevationType = GetTokenInformation -TokenInformationClass TokenElevationType -TokenHandle $hThreadToken } catch { $hProcessToken = OpenProcessToken -ProcessHandle $hProcess -DesiredAccess TOKEN_QUERY $TokenUser = GetTokenInformation -TokenInformationClass TokenUser -TokenHandle $hProcessToken $TokenOwner = GetTokenInformation -TokenInformationClass TokenOwner -TokenHandle $hProcessToken $TokenIntegrityLevel = GetTokenInformation -TokenInformationClass TokenIntegrityLevel -TokenHandle $hProcessToken $TokenType = GetTokenInformation -TokenInformationClass TokenType -TokenHandle $hProcessToken $TokenImpersonationLevel = 'None' $TokenSessionId = GetTokenInformation -TokenInformationClass TokenSessionId -TokenHandle $hProcessToken $TokenOrigin = GetTokenInformation -TokenInformationClass TokenOrigin -TokenHandle $hProcessToken $TokenPrivileges = (GetTokenInformation -TokenInformationClass TokenPrivileges -TokenHandle $hProcessToken | Where-Object {$_.Attributes -like "*ENABLED*"} | select -ExpandProperty Privilege) -join ";" $TokenElevation = GetTokenInformation -TokenInformationClass TokenElevation -TokenHandle $hProcessToken $TokenElevationType = GetTokenInformation -TokenInformationClass TokenElevationType -TokenHandle $hProcessToken } $props = @{ ProcessName = [string]$proc.Name ProcessId = $proc.ProcessId Path = [string]$proc.Path KernelPath = [string]$KernelPath CommandLine = [string]$proc.CommandLine PathMismatch = [string]$PathMismatch ThreadId = $Thread.th32ThreadId AllocatedMemoryProtection = [string]$AllocatedMemoryProtection MemoryProtection = [string]$MemoryProtection MemoryState = [string]$MemoryState MemoryType = [string]$MemoryType BasePriority = $Thread.tpBasePri BaseAddress = [string]$BaseAddress Size = $memory_basic_info.RegionSize TokenUserSid = $TokenUser.Sid.ToString() TokenUserName = $TokenUser.Name.Value TokenOwnerSid = $TokenOwner.Sid.ToString() TokenOwnerName = $TokenOwner.Name.Value TokenIntegrity = $TokenIntegrityLevel.ToString() TokenType = $TokenType.ToString() TokenImpersonationLevel = $TokenImpersonationLevel.ToString() TokenSessionId = $TokenSessionId -as ([Int32]) TokenOrigin = $TokenOrigin -as ([Int32]) TokenPrivilege = $TokenPrivileges TokenElevation = $TokenElevation -as ([bool]) TokenElevationType = $TokenElevationType.ToString() } Write-Output $props } CloseHandle($hProcess) } } CloseHandle($hThread) } catch { } } } while($Kernel32::Thread32Next($hSnapshot, [ref]$Thread)) CloseHandle($hSnapshot) } function Get-KerberosTicketCache { <# .SYNOPSIS .DESCRIPTION .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .EXAMPLE #> [CmdletBinding()] param ( ) try { # We need a Handle to LSA to list Kerberos tickets # If we want to look at tickets from a session other than our own # Then we need to use LsaRegisterLogonProcess instead of LsaConnectUntrusted $hLsa = LsaRegisterLogonProcess } catch { # If the original call fails then it is likely we don't have SeTcbPrivilege # To get SeTcbPrivilege we can Impersonate a NT AUTHORITY\SYSTEM Token Get-System # We should now have the proper privileges to get a Handle to LSA $hLsa = LsaRegisterLogonProcess # We don't need our NT AUTHORITY\SYSTEM Token anymore # So we can revert to our original token RevertToSelf } # Enumerate all Logon Sessions # We need the sessions' LogonIds to enumerate it $Sessions = Get-LogonSession foreach($Session in $Sessions) { try { # Get the tickets from the LSA provider $ticket = LsaCallAuthenticationPackage -LsaHandle $hLsa -AuthenticationPackageName MICROSOFT_KERBEROS_NAME_A -LogonId $Session.LogonId if($ticket -ne $null) { # Add properties from the Logon Session to the ticket foreach($t in $ticket) { $t.Add('SessionLogonId', $Session.LogonId) $t.Add('SessionUserName', $Session.UserName) $t.Add('SessionLogonDomain', $Session.LogonDomain) $t.Add('SessionAuthenticationPackage', $Session.AuthenticationPackage) $t.Add('SessionSid', $Session.Sid.ToString()) $t.Add('SessionLogonType', $Session.LogonType) $t.Add('SessionUserPrincipalName', $Session.Upn) } # Output the ticket Write-Output $ticket } } catch { } } # Cleanup our LSA Handle LsaDeregisterLogonProcess -LsaHandle $hLsa } function Get-LogonSession { <# .SYNOPSIS .DESCRIPTION .NOTES Author: Jared Atkinson (@jaredcatkinson) License: Required Dependencies: PSReflect, LsaEnumerateLogonSessions (Function), LsaFreeReturnBuffer (Function), LsaGetLogonSessionData (Function) LsaNtStatusToWinError (Function), SECURITY_LOGON_SESSION_DATA (Structure), LUID (Structure), LSA_UNICODE_STRING (Structure), LSA_LAST_INTER_LOGON_INFO (Structure), SecurityEntity (Enumeration), SECURITY_LOGON_TYPE (Enumeration) Optional Dependencies: None .LINK .EXAMPLE Get-LogonSession FailedAttemptCountSinceLastSuccessfulLogon : 0 DnsDomainName : HUNT.LOCAL KickOffTime : 1/1/1601 1:00:00 AM PasswordCanChange : 5/20/2017 9:51:20 PM Upn : Administrator@HUNT.LOCAL UserName : Administrator Session : 1 LogoffTime : 1/1/1601 1:00:00 AM LastFailedLogon : 1/1/1601 1:00:00 AM LogonServer : DC Sid : S-1-5-21-3250051078-751264820-3215766868-500 LogonScript : UserFlags : 49444 ProfilePath : PasswordMustChange : 6/30/2017 9:51:20 PM LogonId : 325349 LogonTime : 5/20/2017 9:47:34 AM PasswordLastSet : 5/19/2017 9:51:20 PM LogonDomain : HomeDirectory : LogonType : Interactive AuthenticationPackage : Kerberos LastSuccessfulLogon : 1/1/1601 1:00:00 AM HomeDirectoryDrive : #> [CmdletBinding()] param ( [Parameter()] [switch] $ReturnHashtables ) $LogonSessions = LsaEnumerateLogonSessions try { $Sessions = LsaGetLogonSessionData -LuidPtr $LogonSessions.SessionListPointer -SessionCount $LogonSessions.SessionCount } catch { } if($ReturnHashtables) { Write-Output $Sessions } else { foreach($session in $Sessions) { New-Object -TypeName psobject -Property $session } } } function Get-MasterBootRecord { <# .SYNOPSIS Returns detailed information about the master boot record Author: Jared Atkinson License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None #> [CmdletBinding()] Param ( [Parameter()] [String[]] $Path, [switch] $ReturnHashtables ) begin { function Get-FileHandle { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $Path ) #region Constants $GENERIC_READWRITE = 0x80000000 $FILE_SHARE_READWRITE = 0x02 -bor 0x01 $OPEN_EXISTING = 0x03 #endregion #region Reflection $DynAssembly = New-Object System.Reflection.AssemblyName('Win32') $AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run) $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('Win32', $False) $TypeBuilder = $ModuleBuilder.DefineType('Win32.Kernel32', 'Public, Class') $DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String])) $SetLastError = [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError') $SetLastErrorCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($DllImportConstructor, @('kernel32.dll'), [Reflection.FieldInfo[]]@($SetLastError), @($True)) # Define [Win32.Kernel32]::CreateFile $PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('CreateFile', 'kernel32.dll', ([Reflection.MethodAttributes]::Public -bor [Reflection.MethodAttributes]::Static), [Reflection.CallingConventions]::Standard, [Microsoft.Win32.SafeHandles.SafeFileHandle], [Type[]]@([String], [Int32], [UInt32], [IntPtr], [UInt32], [UInt32], [IntPtr]), [Runtime.InteropServices.CallingConvention]::Winapi, [Runtime.InteropServices.CharSet]::Ansi) $PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute) $Kernel32 = $TypeBuilder.CreateType() #endregion # Get handle to $FileToServe $DriveHandle = $Kernel32::CreateFile($Path, $GENERIC_READWRITE, $FILE_SHARE_READWRITE, 0, $OPEN_EXISTING, 0, 0) # Check that handle is valid if ($DriveHandle.IsInvalid) { Write-Error "Invalid handle to $($Path) returned from CreateFile" -ErrorAction Stop } else { $DriveHandle } } function Read-MbrBytes { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [Microsoft.Win32.SafeHandles.SafeFileHandle] $Handle ) try { # Create a FileStream to read from the handle $streamToRead = New-Object -TypeName System.IO.FileStream($Handle, [System.IO.FileAccess]::Read) # Set our position in the stream to $Offset $streamToRead.Position = 0x0 # Create a buffer $Length bytes long $buffer = New-Object -TypeName Byte[](0x200) # Read $Length bytes $return = $streamToRead.Read($buffer, 0x0, 0x200) # Check return value if($return -ne 0x200) { $return } $buffer } catch { Write-Error "Unable to read bytes from Drive" -ErrorAction Stop } finally { $streamToRead.Dispose() } } function Get-MD5Hash { param ( [Parameter(Mandatory = $true)] [byte[]] $Bytes ) begin { $sha1 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider $hashbytes = $sha1.ComputeHash($Bytes) $sb = New-Object -TypeName System.Text.StringBuilder } process { foreach($b in $hashbytes) { $null = $sb.Append("{0:x}" -f $b) } $sb.ToString() } end { if($sha1.Dispose) { $sha1.Dispose() } } } function Get-Partition { param ( [Parameter(Mandatory = $true)] [byte[]] $Bytes, [Parameter(Mandatory = $true)] [int] $Offset, [switch] $ReturnHashtables ) # Status (0x00 - Non-Bootable & 0x80 - Bootable) if($Bytes[0x00 + $Offset] -eq 0x80) { $Bootable = $true } else { $Bootable = $false } $props = @{ Bootable = $Bootable PartitionType = $Bytes[0x04 + $Offset] RelativeStartSector = [System.BitConverter]::ToUInt32($Bytes, 0x08 + $Offset) TotalSectors = [System.BitConverter]::ToUInt32($Bytes, 0x0C + $Offset) } if($ReturnHashtables) { $props } else { New-Object -TypeName psobject -Property $props } } } process { if(-not($PSBoundParameters.ContainsKey('Path'))) { $Disks = Get-WmiObject -Query "SELECT * FROM Win32_DiskDrive" } else { } $OS = (Get-WmiObject win32_Operatingsystem).Caption foreach($disk in $Disks) { $hDrive = Get-FileHandle -Path $disk.DeviceId if($hDrive) { $bytes = Read-MbrBytes -Handle $hDrive $CodeSection = $bytes[0x3E..0x1B7] $listPartitions = New-Object -TypeName System.Collections.Generic.List[HashTable] for($i = 0; $i -lt 4; $i++) { if($ReturnHashtables) { $partition = Get-Partition -Bytes $bytes -Offset (0x1BE + (0x10 * $i)) -ReturnHashtables } else { $partition = Get-Partition -Bytes $bytes -Offset (0x1BE + (0x10 * $i)) } if($partition.TotalSectors -ne 0) { $listPartitions.Add($partition) } } $Props = @{ OperatingSystem = $OS DeviceId = $disk.DeviceId Model = $disk.Model Signature = Get-MD5Hash -Bytes $CodeSection CodeSection = $CodeSection DiskSignature = [System.BitConverter]::ToString($bytes[0x1B8..0x1BB]).Replace("-", "") PartitionTable = $listPartitions.ToArray() } if($ReturnHashtables) { $Props } else { New-Object -TypeName psobject -Property $Props } } } } } function Get-NetworkConnection { <# .SYNOPSIS Returns current TCP and UDP connections. .NOTES Author: Lee Christensen (@tifkin_) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None #> [CmdletBinding()] param ( [switch] $ResolveHostnames, [switch] $ReturnHashtables ) $Tcp4Connections = Get-Tcp4Connections @PSBoundParameters $Tcp6Connections = Get-Tcp6Connections @PSBoundParameters $Udp4Connections = Get-Udp4Connections @PSBoundParameters $Udp6Connections = Get-Udp6Connections @PSBoundParameters $Tcp4Connections $Tcp6Connections $Udp4Connections $Udp6Connections } function Get-PSIProcess { <# .SYNOPSIS Returns detailed information about the current running processes. Author: Lee Christensen (@tifkin_) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None #> [CmdletBinding()] Param ( [switch] $ReturnHashtables ) # TODO: Optimize this cmdlet... begin { # Thanks to https://p0w3rsh3ll.wordpress.com/2015/02/05/backporting-the-get-filehash-function/ function Get-DIGSFileHash { [CmdletBinding(DefaultParameterSetName = "Path")] param ( [Parameter(Mandatory=$true, ParameterSetName="Path", Position = 0)] [System.String[]] $Path, [Parameter(Mandatory=$true, ParameterSetName="LiteralPath", ValueFromPipelineByPropertyName = $true)] [Alias("PSPath")] [System.String[]] $LiteralPath, [Parameter(Mandatory=$true, ParameterSetName="Stream")] [System.IO.Stream] $InputStream, [ValidateSet("SHA1", "SHA256", "SHA384", "SHA512", "MACTripleDES", "MD5", "RIPEMD160")] [System.String] $Algorithm="SHA256" ) begin { # Construct the strongly-typed crypto object $hasher = [System.Security.Cryptography.HashAlgorithm]::Create($Algorithm) } process { if($PSCmdlet.ParameterSetName -eq "Stream") { Get-DIGSStreamHash -InputStream $InputStream -RelatedPath $null -Hasher $hasher } else { $pathsToProcess = @() if($PSCmdlet.ParameterSetName -eq "LiteralPath") { $pathsToProcess += Resolve-Path -LiteralPath $LiteralPath | Foreach-Object { $_.ProviderPath } } if($PSCmdlet.ParameterSetName -eq "Path") { $pathsToProcess += Resolve-Path $Path | Foreach-Object { $_.ProviderPath } } foreach($filePath in $pathsToProcess) { if(Test-Path -LiteralPath $filePath -PathType Container) { continue } try { # Read the file specified in $FilePath as a Byte array [system.io.stream]$stream = [system.io.file]::OpenRead($filePath) Get-DIGSStreamHash -InputStream $stream -RelatedPath $filePath -Hasher $hasher } catch [Exception] { $errorMessage = 'FileReadError {0}:{1}' -f $FilePath, $_ Write-Error -Message $errorMessage -Category ReadError -ErrorId "FileReadError" -TargetObject $FilePath return } finally { if($stream) { $stream.Close() } } } } } } function Get-DIGSStreamHash { param ( [System.IO.Stream] $InputStream, [System.String] $RelatedPath, [System.Security.Cryptography.HashAlgorithm] $Hasher ) # Compute file-hash using the crypto object [Byte[]] $computedHash = $Hasher.ComputeHash($InputStream) [string] $hash = [BitConverter]::ToString($computedHash) -replace '-','' if ($RelatedPath -eq $null) { $retVal = [PSCustomObject] @{ Algorithm = $Algorithm.ToUpperInvariant() Hash = $hash } $retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash") $retVal } else { $retVal = [PSCustomObject] @{ Algorithm = $Algorithm.ToUpperInvariant() Hash = $hash Path = $RelatedPath } $retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash") $retVal } } $FileHashCache = @{} $Processes = Get-WmiObject -Class Win32_Process function Get-DIGSCachedFileHash { param ( [string] $File ) if($FileHashCache[$File]) { $FileHashCache[$File] } else { if($File -and (Test-Path $File)) { $ModuleMD5 = (Get-DIGSFileHash -Path $File -Algorithm MD5).Hash $ModuleSHA256 = (Get-DIGSFileHash -Path $File -Algorithm SHA256).Hash $FileHashCache[$File] = New-Object PSObject -Property @{ MD5 = $ModuleMD5 SHA256 = $ModuleSHA256 } $FileHashCache[$File] } } } } process { foreach($Process in $Processes) { $Proc = Get-Process -Id $Process.ProcessId -ErrorAction SilentlyContinue $Path = $Proc.Path $LoadedModules = $null $Owner = $null $OwnerStr = $null if($Proc) { #$PE = Get-PE -ModuleBaseAddress $Proc.MainModule.BaseAddress -ProcessID $Process.ProcessId $Proc.Modules | ForEach-Object { if($_) { $ModuleHash = Get-DIGSCachedFileHash -File $_.FileName $_ | Add-Member NoteProperty -Name "MD5Hash" -Value $ModuleHash.MD5 $_ | Add-Member NoteProperty -Name "SHA256Hash" -Value $ModuleHash.SHA256 } } $LoadedModules = $Proc.Modules } # Get file information $FileHash = $null if($Path -ne $null -and (Test-Path $Path)) { # TODO: Add error handling here in case we can't read the file (wonky exe permissions) $FileHash = Get-DIGSCachedFileHash -File $Path $File = (Get-ChildItem $Path) $FileSize = $File.Length $FileCreationTime = $File.CreationTimeUtc $FileLastAccessTime = $File.LastAccessTimeUtc $FileLastWriteTime = $File.LastWriteTimeUtc $FileExtension = $File.Extension $ProcessId = $Process.ProcessId } else { if($Proc.Id -ne 0 -and $Proc.Id -ne 4) { #Write-Warning "Could not find executable path. PSProcessName: $($Proc.Name) PSPid: $($Proc.Id) WMIProcName: $($Process.Name) WMIPid: $($Process.ProcessId)" } $Path = '' } # Get the process owner $NTVersion = [System.Environment]::OSVersion.Version try { if($NTVersion.Major -ge 6) { $Owner = $Process.GetOwner() if($Owner -and ($Owner.Domain -or $Owner.User)) { $OwnerStr = "$($Owner.Domain)\$($Owner.User)" } $OwnerObj = $Process.GetOwnerSid() if($OwnerObj) { $OwnerSid = $OwnerObj.Sid } } } catch {} $LoadedModuleList = $LoadedModules | sort ModuleName | select -ExpandProperty ModuleName $ParentProcess = Get-Process -Id $Process.ProcessId -ErrorAction SilentlyContinue $ErrorActionPreference = 'Stop' $Output = @{ Name = $Process.Name Path = [string]$Process.Path CommandLine = $Process.CommandLine MD5Hash = $FileHash.MD5 SHA256Hash = $FileHash.SHA256 FileSize = $FileSize FileCreationTime = $FileCreationTime FileLastAccessTime = $FileLastAccessTime FileLastWriteTime = $FileLastWriteTime FileExtension = $FileExtension Owner = $OwnerStr OwnerSid = $OwnerSid ParentProcessId = $Process.ParentProcessID ParentProcessName = $ParentProcess.Name ProcessId = $ProcessId ## PE = $PE #LoadedModules = $LoadedModules | select * LoadedModulesList = ($LoadedModuleList -join ";").ToLower() } try { $null = ConvertTo-JsonV2 $Output } catch { Write-Error $_ } if($ReturnHashtables) { $Output } else { New-Object PSObject -Property $Output } } } end { } } function Get-PSIScheduledTask { <# .SYNOPSIS Returns detailed information about scheduled tasks. Author: Lee Christensen (@tifkin_), Jared Atkinson License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None #> [CmdletBinding()] Param ( [switch] $ReturnHashtables ) begin { # Based on Get-ScheduledTask in the Windows 7 Resource Kit PowerShell Pack function Get-DIGSScheduledTaskData { <# .Synopsis Gets tasks scheduled on the computer .Description Gets scheduled tasks that are registered on a computer .Example Get-ScheduleTask -Recurse #> param( # The name or name pattern of the scheduled task [Parameter()] $Name = "*", # The folder the scheduled task is in [Parameter()] [String[]] $Folder = "", # If this is set, hidden tasks will also be shown. # By default, only tasks that are not marked by Task Scheduler as hidden are shown. [Switch] $Hidden, # The name of the computer to connect to. $ComputerName, # The credential used to connect [Management.Automation.PSCredential] $Credential, # If set, will get tasks recursively beneath the specified folder [switch] $Recurse ) process { $scheduler = New-Object -ComObject Schedule.Service if ($Credential) { $NetworkCredential = $Credential.GetNetworkCredential() $scheduler.Connect($ComputerName, $NetworkCredential.UserName, $NetworkCredential.Domain, $NetworkCredential.Password) } else { $scheduler.Connect($ComputerName) } $taskFolder = $scheduler.GetFolder($folder) $taskFolder.GetTasks($Hidden -as [bool]) | Where-Object { $_.Name -like $name } if ($Recurse) { $taskFolder.GetFolders(0) | ForEach-Object { $psBoundParameters.Folder = $_.Path Get-DIGSScheduledTaskData @psBoundParameters } } } } # Thanks to https://p0w3rsh3ll.wordpress.com/2015/02/05/backporting-the-get-filehash-function/ function Get-DIGSFileHash { [CmdletBinding(DefaultParameterSetName = "Path")] param( [Parameter(Mandatory=$true, ParameterSetName="Path", Position = 0)] [System.String[]] $Path, [Parameter(Mandatory=$true, ParameterSetName="LiteralPath", ValueFromPipelineByPropertyName = $true)] [Alias("PSPath")] [System.String[]] $LiteralPath, [Parameter(Mandatory=$true, ParameterSetName="Stream")] [System.IO.Stream] $InputStream, [ValidateSet("SHA1", "SHA256", "SHA384", "SHA512", "MACTripleDES", "MD5", "RIPEMD160")] [System.String] $Algorithm="SHA256" ) begin { # Construct the strongly-typed crypto object $hasher = [System.Security.Cryptography.HashAlgorithm]::Create($Algorithm) } process { if($PSCmdlet.ParameterSetName -eq "Stream") { Get-DIGSStreamHash -InputStream $InputStream -RelatedPath $null -Hasher $hasher } else { $pathsToProcess = @() if($PSCmdlet.ParameterSetName -eq "LiteralPath") { $pathsToProcess += Resolve-Path -LiteralPath $LiteralPath | Foreach-Object { $_.ProviderPath } } if($PSCmdlet.ParameterSetName -eq "Path") { $pathsToProcess += Resolve-Path $Path | Foreach-Object { $_.ProviderPath } } foreach($filePath in $pathsToProcess) { if(Test-Path -LiteralPath $filePath -PathType Container) { continue } try { # Read the file specified in $FilePath as a Byte array [system.io.stream]$stream = [system.io.file]::OpenRead($filePath) Get-DIGSStreamHash -InputStream $stream -RelatedPath $filePath -Hasher $hasher } catch [Exception] { $errorMessage = 'FileReadError {0}:{1}' -f $FilePath, $_ Write-Error -Message $errorMessage -Category ReadError -ErrorId "FileReadError" -TargetObject $FilePath return } finally { if($stream) { $stream.Close() } } } } } } function Get-DIGSStreamHash { param( [System.IO.Stream] $InputStream, [System.String] $RelatedPath, [System.Security.Cryptography.HashAlgorithm] $Hasher) # Compute file-hash using the crypto object [Byte[]] $computedHash = $Hasher.ComputeHash($InputStream) [string] $hash = [BitConverter]::ToString($computedHash) -replace '-','' if ($RelatedPath -eq $null) { $retVal = [PSCustomObject] @{ Algorithm = $Algorithm.ToUpperInvariant() Hash = $hash } $retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash") $retVal } else { $retVal = [PSCustomObject] @{ Algorithm = $Algorithm.ToUpperInvariant() Hash = $hash Path = $RelatedPath } $retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash") $retVal } } function Get-ClassID { param($ClassId) $Value = Get-ItemProperty "HKLM:\Software\Classes\CLSID\$($ClassId)\InprocServer32" -Name "(Default)" -ErrorAction SilentlyContinue if($Value) { $Value.'(Default)' } else { '' } } } process { $Tasks = Get-DIGSScheduledTaskData -Recurse foreach($Task in $Tasks) { $ActionComClassId = $null $ActionComDll = $null $ActionComDllMD5 = $null $ActionComDllSHA256 = $null $ActionComData = $null $ActionExecCommand = $null $ActionExecCommandMD5 = $null $ActionExecCommandSHA256 = $null $ActionExecArguments = $null $ActionExecWorkingDirectory = $null $Xml = [Xml]$Task.Xml $ActionCom = $Xml.Task.Actions.ComHandler $ActionComDll = if($ActionCom.ClassId) { Get-ClassID ($ActionCom.ClassId)} else { $null } if($ActionComDll) { $ActionComDllMD5 = (Get-DIGSFileHash -Path $ActionComDll -Algorithm MD5).Hash $ActionComDllSHA256 = (Get-DIGSFileHash -Path $ActionComDll -Algorithm SHA256).Hash } $ActionComData = if($ActionCom.Data) { $ActionCom.Data.InnerXml} else {$null} $ActionExec = $Xml.Task.Actions.Exec if($ActionExec.Command) { $ActionExecPath = [System.Environment]::ExpandEnvironmentVariables($ActionExec.Command) $CleanedPath = $ActionExecPath.Replace("`"", "") if(Test-Path $CleanedPath -ErrorAction SilentlyContinue) { $ActionExecCommandMD5 = (Get-DIGSFileHash -Path $CleanedPath -Algorithm MD5).Hash $ActionExecCommandSHA256 = (Get-DIGSFileHash -Path $CleanedPath -Algorithm SHA256).Hash } } $Output = @{ Name = $Task.Name Path = $Task.Path Enabled = $Task.Enabled LastRunTime = $Task.LastRunTime LastTaskResult = $Task.LastTaskResult NumberOfMissedRuns = $Task.NumberOfMissedRuns NextRunTime = $Task.NextRunTime Xml = $Task.Xml ActionComClassId = $ActionCom.ClassId ActionComDll = $ActionComDll ActionComDllMD5 = $ActionComDllMd5 ActionComDllSHA256 = $ActionComDllSHA256 ActionComData = $ActionComData ActionExecCommand = $ActionExec.Command ActionExecCommandMD5 = $ActionExecCommandMD5 ActionExecCommandSHA256 = $ActionExecCommandSHA256 ActionExecArguments = $ActionExec.Arguments ActionExecWorkingDirectory = $ActionExec.WorkingDirectory } if($ReturnHashtables) { $Output } else { New-Object PSObject -Property $Output } } } end { } } function Get-PSIService { <# .SYNOPSIS Returns detailed service information. Author: Jared Atkinson License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None #> [CmdletBinding()] Param ( [switch] $ReturnHashtables ) Begin { function Get-PathFromCommandLine { Param ( [Parameter(Mandatory = $true)] [string] $CommandLine ) if(Test-Path -Path $CommandLine -ErrorAction SilentlyContinue) { $CommandLine } else { switch -Regex ($CommandLine) { '"\s'{ $CommandLine.Split('"')[1]; break} '\s-'{ $CommandLine.Split(' ')[0]; break} '\s/'{ $CommandLine.Split(' ')[0]; break} '"'{ $CommandLine.Split('"')[1]; break} default{ $CommandLine} } } } # Thanks to https://p0w3rsh3ll.wordpress.com/2015/02/05/backporting-the-get-filehash-function/ function Get-DIGSFileHash { [CmdletBinding(DefaultParameterSetName = "Path")] param( [Parameter(Mandatory=$true, ParameterSetName="Path", Position = 0)] [System.String[]] $Path, [Parameter(Mandatory=$true, ParameterSetName="LiteralPath", ValueFromPipelineByPropertyName = $true)] [Alias("PSPath")] [System.String[]] $LiteralPath, [Parameter(Mandatory=$true, ParameterSetName="Stream")] [System.IO.Stream] $InputStream, [ValidateSet("SHA1", "SHA256", "SHA384", "SHA512", "MACTripleDES", "MD5", "RIPEMD160")] [System.String] $Algorithm="SHA256" ) begin { # Construct the strongly-typed crypto object $hasher = [System.Security.Cryptography.HashAlgorithm]::Create($Algorithm) } process { if($PSCmdlet.ParameterSetName -eq "Stream") { Get-DIGSStreamHash -InputStream $InputStream -RelatedPath $null -Hasher $hasher } else { $pathsToProcess = @() if($PSCmdlet.ParameterSetName -eq "LiteralPath") { $pathsToProcess += Resolve-Path -LiteralPath $LiteralPath | Foreach-Object { $_.ProviderPath } } if($PSCmdlet.ParameterSetName -eq "Path") { $pathsToProcess += Resolve-Path $Path | Foreach-Object { $_.ProviderPath } } foreach($filePath in $pathsToProcess) { if(Test-Path -LiteralPath $filePath -PathType Container) { continue } try { # Read the file specified in $FilePath as a Byte array [system.io.stream]$stream = [system.io.file]::OpenRead($filePath) Get-DIGSStreamHash -InputStream $stream -RelatedPath $filePath -Hasher $hasher } catch [Exception] { $errorMessage = 'FileReadError {0}:{1}' -f $FilePath, $_ Write-Error -Message $errorMessage -Category ReadError -ErrorId "FileReadError" -TargetObject $FilePath return } finally { if($stream) { $stream.Close() } } } } } } function Get-DIGSStreamHash { param( [System.IO.Stream] $InputStream, [System.String] $RelatedPath, [System.Security.Cryptography.HashAlgorithm] $Hasher) # Compute file-hash using the crypto object [Byte[]] $computedHash = $Hasher.ComputeHash($InputStream) [string] $hash = [BitConverter]::ToString($computedHash) -replace '-','' if ($RelatedPath -eq $null) { $retVal = [PSCustomObject] @{ Algorithm = $Algorithm.ToUpperInvariant() Hash = $hash } $retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash") $retVal } else { $retVal = [PSCustomObject] @{ Algorithm = $Algorithm.ToUpperInvariant() Hash = $hash Path = $RelatedPath } $retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash") $retVal } } $hashcache = @{} $objList = New-Object -TypeName "System.Collections.Generic.List[Object]" } Process { foreach($service in (Get-WmiObject win32_service)) { if($service.PathName -ne $null) { $path = Get-PathFromCommandLine -CommandLine $service.PathName } else { $path = $null } try { if($hashcache.ContainsKey($path)) { $md5 = $hashcache[$path].MD5 $sha256 = $hashcache[$path].SHA256 } else { $md5 = Get-DIGSFileHash -Path $path -Algorithm MD5 -ErrorAction Stop $sha256 = Get-DIGSFileHash -Path $path -Algorithm SHA256 -ErrorAction Stop $obj = @{ MD5 = $md5 SHA256 = $sha256 } $hashcache.Add($path, $obj) } } catch { $md5 = $null $sha256 = $null } $Props = @{ Name = $service.Name CommandLine = $service.PathName ExecutablePath = $path ServiceType = $service.ServiceType StartMode = $service.StartMode Caption = $service.Caption Description = $service.Description DisplayName = $service.DisplayName ProcessId = $service.ProcessId Started = $service.Started User = $service.StartName MD5Hash = $md5.Hash SHA256Hash = $sha256.Hash } if($ReturnHashtables) { $Props } else { New-Object -TypeName psobject -Property $Props } } } End { } } function Get-RegistryAutoRun { param ( [Parameter(ParameterSetName = 'SpecificCheck')] [Switch] $Logon, [Parameter(ParameterSetName = 'SpecificCheck')] [Switch] $BootExecute, [Parameter(ParameterSetName = 'SpecificCheck')] [Switch] $PrintMonitors, [Parameter(ParameterSetName = 'SpecificCheck')] [Switch] $NetworkProviders, [Parameter(ParameterSetName = 'SpecificCheck')] [Switch] $LSAProviders, [Parameter(ParameterSetName = 'SpecificCheck')] [Switch] $ImageHijacks, [Parameter(ParameterSetName = 'SpecificCheck')] [Switch] $AppInit, [Parameter(ParameterSetName = 'SpecificCheck')] [Switch] $KnownDLLs, [Parameter(ParameterSetName = 'SpecificCheck')] [Switch] $Winlogon ) $UserSIDS = (Get-ChildItem -Path Registry::HKU | Where-Object { $_.PSChildName -notmatch 'S-1-5-18|S-1-5-19|S-1-5-20|\.DEFAULT|^.*_Classes$' }).PSChildName if (($PSCmdlet.ParameterSetName -ne 'SpecificCheck') -or $PSBoundParameters['Logon']) { $Category = 'Logon' $RunKeyPaths = @( 'SOFTWARE\Microsoft\Windows\CurrentVersion\Run' 'SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce' 'SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run' 'SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\RunOnce' ) $KeyList = New-Object -TypeName System.Collections.Generic.List['string'] foreach ($RunKey in $RunKeyPaths) { $KeyList.Add("HKLM:\$($RunKey)") } foreach ($SID in $UserSIDS) { foreach ($RunKey in $RunKeyPaths) { $KeyList.Add("Registry::HKU\$($SID)\$($RunKey)") } } foreach($result in (Get-RegistryValue -Key $KeyList.ToArray())) { New-AutoRunEntry -Path $result.Path -Name $result.Name -ImagePath $result.Value -Category $Category } Get-RegistryValue -Key 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd' -Value StartupPrograms | New-AutoRunEntry -Category $Category Get-RegistryValue -Key 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Value VmApplet,Userinit,Shell,TaskMan,AppSetup | New-AutoRunEntry -Category $Category Get-RegistryValue -Key 'HKLM:\SYSTEM\CurrentControlSet\Control\SafeBoot' -Value AlternateShell | New-AutoRunEntry -Category $Category Get-RegistryValue -Key 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows' -Value IconServiceLib | New-AutoRunEntry -Category $Category $GPExtensionKey = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GPExtensions' Get-ChildItem -Path $GPExtensionKey | foreach { Get-RegistryValue -Key "$($GPExtensionKey)\$($_.PSChildName)" -Value DllName | New-AutoRunEntry -Name $_.PSChildName -Category $Category } <# $null, 'Wow6432Node\' | ForEach-Object { $InstalledComponents = "SOFTWARE\$($_)Microsoft\Active Setup\Installed Components" Get-RegistryValue -Key "HKLM:\$($InstalledComponents)" -Value StubPath | ForEach-Object { $AutoRunEntry = $_ | Get-CSRegistryValue -ValueName '' -ValueType REG_SZ @Timeout if ($AutoRunEntry.ValueContent) { $AutoRunEntryName = $AutoRunEntry.ValueContent } else { $AutoRunEntryName = 'n/a' } $_ | New-AutoRunsEntry -SubKey $InstalledComponents -AutoRunEntry $AutoRunEntryName -Category $Category } } #> } if (($PSCmdlet.ParameterSetName -ne 'SpecificCheck') -or $PSBoundParameters['BootExecute']) { $Category = 'BootExecute' $SessionManager = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager' foreach ($result in (Get-RegistryValue -Key $SessionManager -Value BootExecute,SetupExecute,Execute,S0InitialCommand)) { foreach ($val in $result.Value) { New-AutoRunEntry -Path $SessionManager -Name $result.Name -ImagePath $val -Category $Category } } Get-RegistryValue -Key 'HKLM:\SYSTEM\CurrentControlSet\Control' -Value ServiceControlManagerExtension | New-AutoRunEntry -Category $Category } if (($PSCmdlet.ParameterSetName -ne 'SpecificCheck') -or $PSBoundParameters['PrintMonitors']) { $Category = 'PrintMonitors' Get-RegistryValue -Key 'HKLM:\SYSTEM\CurrentControlSet\Control\Print\Monitors' -Value Driver | New-AutoRunEntry -Category $Category } if (($PSCmdlet.ParameterSetName -ne 'SpecificCheck') -or $PSBoundParameters['NetworkProviders']) { $Category = 'NetworkProviders' $Path = 'HKLM:\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order' $NetworkOrder = Get-RegistryValue -Key $Path -Value ProviderOrder if ($NetworkOrder.Value) { foreach($val in ($NetworkOrder.Value.Split(','))) { New-AutoRunEntry -Path $Path -Name ProviderOrder -ImagePath $val -Category $Category } } } if (($PSCmdlet.ParameterSetName -ne 'SpecificCheck') -or $PSBoundParameters['LSAProviders']) { $Category = 'LSAProviders' Get-RegistryValue -Key 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders' | New-AutoRunEntry -Category $Category $Path = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa' foreach($result in (Get-RegistryValue -Key $Path -Value 'Authentication Packages','Notification Packages')) { foreach($val in $result.Value) { New-AutoRunEntry -Path $Path -Name $result.Name -ImagePath $val -Category $Category } } Get-RegistryValue -Key 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\OSConfig' -Value 'Security Packages' | New-AutoRunEntry -Category $Category } if (($PSCmdlet.ParameterSetName -ne 'SpecificCheck') -or $PSBoundParameters['ImageHijacks']) { $Category = 'ImageHijacks' $CommonKeys = @( 'SOFTWARE\Classes\htmlfile\shell\open\command', 'SOFTWARE\Classes\htafile\shell\open\command', 'SOFTWARE\Classes\batfile\shell\open\command', 'SOFTWARE\Classes\comfile\shell\open\command', 'SOFTWARE\Classes\piffile\shell\open\command', 'SOFTWARE\Classes\exefile\shell\open\command' ) foreach ($CommonKey in $CommonKeys) { Get-RegistryValue -Key "HKLM:\$($CommonKey)" -Value '' | New-AutoRunsEntry -AutoRunEntry $CommonKey.Split('\')[2] -Category $Category # Iterate over each local user hive foreach ($SID in $HKUSIDs) { Get-CSRegistryValue -Hive HKU -SubKey "$SID\$CommonKey" -ValueName '' @CommonArgs @Timeout | New-AutoRunsEntry -AutoRunEntry $CommonKey.Split('\')[2] -Category $Category } } Get-RegistryValue -Key HKLM:\SOFTWARE\Classes\exefile\shell\open\command -Value IsolatedCommand | New-AutoRunEntry -Category $Category <# $null, 'Wow6432Node\' | ForEach-Object { Get-RegistryValue -Key "HKLM:\SOFTWARE\$($_)Microsoft\Windows NT\CurrentVersion\Image File Execution Options" -Value Debugger | ForEach-Object { $_ | New-AutoRunsEntry -AutoRunEntry $_.SubKey.Substring($_.SubKey.LastIndexOf('\') + 1) -Category $Category } Get-RegistryValue -Key "HKLM:\SOFTWARE\$($_)Microsoft\Command Processor" -ValueName Autorun | New-AutoRunsEntry -Category $Category } $Class_exe = Get-CSRegistryValue -Hive HKLM -SubKey 'HKLM:\SOFTWARE\Classes\.exe' -ValueName '' -ValueType REG_SZ @CommonArgs @Timeout if ($Class_exe.ValueContent) { $OpenCommand = Get-CSRegistryValue -Hive HKLM -SubKey "SOFTWARE\Classes\$($Class_exe.ValueContent)\Shell\Open\Command" -ValueName '' -ValueType REG_SZ @CommonArgs @Timeout if ($OpenCommand.ValueContent) { $OpenCommand | New-AutoRunsEntry -Hive $Class_exe.Hive -SubKey $Class_exe.SubKey -AutoRunEntry $Class_exe.ValueContent -Category $Category } } $Class_cmd = Get-CSRegistryValue -Hive HKLM -SubKey 'SOFTWARE\Classes\.cmd' -ValueName '' -ValueType REG_SZ @CommonArgs @Timeout if ($Class_cmd.ValueContent) { $OpenCommand = Get-CSRegistryValue -Hive HKLM -SubKey "SOFTWARE\Classes\$($Class_cmd.ValueContent)\Shell\Open\Command" -ValueName '' -ValueType REG_SZ @CommonArgs @Timeout if ($OpenCommand.ValueContent) { $OpenCommand | New-AutoRunsEntry -Hive $Class_cmd.Hive -SubKey $Class_cmd.SubKey -AutoRunEntry $Class_cmd.ValueContent -Category $Category } } foreach ($SID in $HKUSIDs) { Get-CSRegistryValue -Hive HKU -SubKey "$SID\SOFTWARE\Microsoft\Command Processor" -ValueName 'Autorun' @CommonArgs @Timeout | New-AutoRunsEntry -Category $Category $Class_exe = Get-CSRegistryValue -Hive HKU -SubKey "$SID\SOFTWARE\Classes\.exe" -ValueName '' -ValueType REG_SZ @CommonArgs @Timeout if ($Class_exe.ValueContent) { $OpenCommand = Get-CSRegistryValue -Hive HKU -SubKey "$SID\SOFTWARE\Classes\$($Class_exe.ValueContent)\Shell\Open\Command" -ValueName '' -ValueType REG_SZ @CommonArgs @Timeout if ($OpenCommand.ValueContent) { $OpenCommand | New-AutoRunsEntry -Hive $Class_exe.Hive -SubKey $Class_exe.SubKey -AutoRunEntry $Class_exe.ValueContent -Category $Category } } $Class_cmd = Get-CSRegistryValue -Hive HKU -SubKey "$SID\SOFTWARE\Classes\.cmd" -ValueName '' -ValueType REG_SZ @CommonArgs @Timeout if ($Class_cmd.ValueContent) { $OpenCommand = Get-CSRegistryValue -Hive HKU -SubKey "$SID\SOFTWARE\Classes\$($Class_cmd.ValueContent)\Shell\Open\Command" -ValueName '' -ValueType REG_SZ @CommonArgs @Timeout if ($OpenCommand.ValueContent) { $OpenCommand | New-AutoRunsEntry -Hive $Class_cmd.Hive -SubKey $Class_cmd.SubKey -AutoRunEntry $Class_cmd.ValueContent -Category $Category } } } #> } if (($PSCmdlet.ParameterSetName -ne 'SpecificCheck') -or $PSBoundParameters['AppInit']) { $Category = 'AppInit' $null,'Wow6432Node\' | ForEach-Object { Get-RegistryValue -Key "HKLM:\SOFTWARE\$($_)Microsoft\Windows NT\CurrentVersion\Windows" -Value 'AppInit_DLLs' | New-AutoRunEntry -Category $Category Get-RegistryValue -Key "HKLM:\SOFTWARE\$($_)Microsoft\Command Processor" -Value 'Autorun' | New-AutoRunEntry -Category $Category } Get-RegistryValue -Key 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\AppCertDlls' | New-AutoRunEntry -Category $Category } if (($PSCmdlet.ParameterSetName -ne 'SpecificCheck') -or $PSBoundParameters['KnownDLLs']) { $Category = 'KnownDLLs' Get-RegistryValue -Key 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs' | New-AutoRunEntry -Category $Category } <# if (($PSCmdlet.ParameterSetName -ne 'SpecificCheck') -or $PSBoundParameters['Winlogon']) { $Category = 'Winlogon' $CmdLine = Get-CSRegistryValue -Hive HKLM -SubKey 'SYSTEM\Setup' -ValueName 'CmdLine' @CommonArgs @Timeout if ($CmdLine -and $CmdLine.ValueContent) { $CmdLine | New-AutoRunsEntry -Category $Category } 'Credential Providers', 'Credential Provider Filters', 'PLAP Providers' | ForEach-Object { Get-CSRegistryKey -Hive HKLM -SubKey "SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\$_" @CommonArgs @Timeout } | ForEach-Object { $LastBSIndex = $_.SubKey.LastIndexOf('\') $ParentKey = $_.SubKey.Substring(0, $LastBSIndex) $Guid = $_.SubKey.Substring($LastBSIndex + 1) if ($Guid -as [Guid]) { $AutoRunEntry = Get-CSRegistryValue -Hive HKLM -SubKey "SOFTWARE\Classes\CLSID\$Guid" -ValueName '' -ValueType REG_SZ @CommonArgs @Timeout $InprocServer32 = Get-CSRegistryValue -Hive HKLM -SubKey "SOFTWARE\Classes\CLSID\$Guid\InprocServer32" -ValueName '' -ValueType REG_EXPAND_SZ @CommonArgs @Timeout New-AutoRunsEntry $_.Hive $ParentKey $AutoRunEntry.ValueContent $InprocServer32.ValueContent $Category $_.PSComputerName } } $BootVer = Get-CSRegistryValue -Hive HKLM -SubKey 'SYSTEM\CurrentControlSet\Control\BootVerificationProgram' -ValueName 'ImagePath' @CommonArgs @Timeout if ($BootVer) { $BootVer | New-AutoRunsEntry -Hive $BootVer.Hive -SubKey "$($BootVer.SubKey)\ImagePath" } foreach ($SID in $HKUSIDs) { $Scrnsave = Get-CSRegistryValue -Hive HKU -SubKey "$SID\SOFTWARE\Policies\Microsoft\Windows\Control Panel\Desktop" -ValueName 'Scrnsave.exe' @CommonArgs @Timeout if ($Scrnsave) { $Scrnsave | New-AutoRunsEntry } $Scrnsave = Get-CSRegistryValue -Hive HKU -SubKey "$SID\Control Panel\Desktop" -ValueName 'Scrnsave.exe' @CommonArgs @Timeout if ($Scrnsave) { $Scrnsave | New-AutoRunsEntry } } } #> } function Get-SecurityPackage { param ( [Parameter()] [switch] $ReturnHashtables ) <# .SYNOPSIS Enumerates Security Service Providers (SSP) t .DESCRIPTION .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .EXAMPLE PS > Get-SecurityPackage Name : Negotiate Comment : Microsoft Package Negotiator Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, NEGOTIABLE, GSS_COMPATIBLE, LOGON, RESTRICTED_TOKENS, APPCONTAINER_CHECKS Version : 1 RpcId : 9 MaxToken : 65791 Name : NegoExtender Comment : NegoExtender Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, IMPERSONATION, NEGOTIABLE, GSS_COMPATIBLE, LOGON, MUTUAL_AUTH, NEGO_EXTENDER, APPCONTAINER_CHECKS Version : 1 RpcId : 30 MaxToken : 12000 Name : Kerberos Comment : Microsoft Kerberos V1.0 Capabilities : INTEGRITY, PRIVACY, TOKEN_ONLY, DATAGRAM, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, NEGOTIABLE, GSS_COMPATIBLE, LOGON, MUTUAL_AUTH, DELEGATION, READONLY_WITH_CHECKSUM, RESTRICTED_TOKENS, APPCONTAINER_CHECKS Version : 1 RpcId : 16 MaxToken : 65535 Name : NTLM Comment : NTLM Security Package Capabilities : INTEGRITY, PRIVACY, TOKEN_ONLY, CONNECTION, MULTI_REQUIRED, IMPERSONATION, ACCEPT_WIN32_NAME, NEGOTIABLE, LOGON, RESTRICTED_TOKENS, APPCONTAINER_CHECKS Version : 1 RpcId : 10 MaxToken : 2888 Name : TSSSP Comment : TS Service Security Package Capabilities : CONNECTION, MULTI_REQUIRED, ACCEPT_WIN32_NAME, MUTUAL_AUTH, APPCONTAINER_CHECKS Version : 1 RpcId : 22 MaxToken : 13000 Name : pku2u Comment : PKU2U Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, IMPERSONATION, GSS_COMPATIBLE, MUTUAL_AUTH, NEGOTIABLE2, APPCONTAINER_CHECKS Version : 1 RpcId : 31 MaxToken : 12000 Name : CloudAP Comment : Cloud AP Security Package Capabilities : LOGON, NEGOTIABLE2 Version : 1 RpcId : 36 MaxToken : 0 Name : WDigest Comment : Digest Authentication for Windows Capabilities : TOKEN_ONLY, IMPERSONATION, ACCEPT_WIN32_NAME, APPCONTAINER_CHECKS Version : 1 RpcId : 21 MaxToken : 4096 Name : Schannel Comment : Schannel Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, STREAM, MUTUAL_AUTH, APPCONTAINER_PASSTHROUGH Version : 1 RpcId : 14 MaxToken : 24576 Name : Microsoft Unified Security Protocol Provider Comment : Schannel Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, STREAM, MUTUAL_AUTH, APPCONTAINER_PASSTHROUGH Version : 1 RpcId : 14 MaxToken : 24576 Name : CREDSSP Comment : Microsoft CredSSP Security Provider Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, IMPERSONATION, ACCEPT_WIN32_NAME, STREAM, MUTUAL_AUTH, APPCONTAINER_CHECKS Version : 1 RpcId : 65535 MaxToken : 90567 #> $obj = EnumerateSecurityPackages if($ReturnHashtables) { foreach($o in $obj) { $props = @{ Name = $o.Name Comment = $o.Comment Capabilities = $o.Capabilities Version = $o.Version RpcId = $o.RpcId MaxToken = $o.MaxToken } Write-Output $props } } else { Write-Output $obj } } function Get-SimpleNamedPipe { <# .SYNOPSIS Gets a list of open named pipes. Author: Greg Zakharov License: Required Dependencies: None Optional Dependencies: None .DESCRIPTION When defining custom enums, structs, and unmanaged functions, it is necessary to associate to an assembly module. This helper function creates an in-memory module that can be passed to the 'enum', 'struct', and Add-Win32Type functions. #> [CmdletBinding()] Param ( [switch] $ReturnHashtables ) Begin { $Mscorlib = [AppDomain]::CurrentDomain.GetAssemblies() | ? { $_.ManifestModule.ScopeName.Equals('CommonLanguageRuntimeLibrary') } $SafeFindHandle = $Mscorlib.GetType('Microsoft.Win32.SafeHandles.SafeFindHandle') $Win32Native = $Mscorlib.GetType('Microsoft.Win32.Win32Native') $WIN32_FIND_DATA = $Win32Native.GetNestedType( 'WIN32_FIND_DATA', [Reflection.BindingFlags]32 ) $FindFirstFile = $Win32Native.GetMethod( 'FindFirstFile', [Reflection.BindingFlags]40, $null, @([String], $WIN32_FIND_DATA), $null ) $FindNextFile = $Win32Native.GetMethod('FindNextFile', [Reflection.BindingFlags]40, $null, @($SafeFindHandle, $WIN32_FIND_DATA), $null) $Obj = $WIN32_FIND_DATA.GetConstructors()[0].Invoke($null) function Read-Field([String]$Field) { return $WIN32_FIND_DATA.GetField($Field, [Reflection.BindingFlags]36).GetValue($Obj) } } Process { $Handle = $FindFirstFile.Invoke($null, @('\\.\pipe\*', $obj)) $Output = @{ Name = [string](Read-Field cFileName) Instances = [UInt32](Read-Field nFileSizeLow) } do { $Output = @{ Name = [string](Read-Field cFileName) Instances = [UInt32](Read-Field nFileSizeLow) } if($ReturnHashtables) { $Output } else { New-Object PSObject -Property $Output } } while($FindNextFile.Invoke($null, @($Handle, $obj))) $Handle.Close() } End { } } function Get-WmiEventSubscription { foreach($o in (Get-WmiObject -Namespace root\subscription -Class __EventConsumer)) { $Sid = New-Object System.Security.Principal.SecurityIdentifier(@($o.CreatorSID,$null)) $UserName = $Sid.Translate([System.Security.Principal.NTAccount]) switch($o.__CLASS) { ActiveScriptEventConsumer { $props = @{ CreatorSid = $Sid.Value CreatorUserName = $UserName KillTimeout = $o.KillTimeout MachineName = $o.MachineName MaximumQueueSize = $o.MaximumQueueSize Name = $o.Name ScriptFilename = $o.ScriptFilename ScriptingEngine = $o.ScriptingEngine ScriptText = $o.ScriptText Class = $o.ClassPath.ClassName ClassPath = $o.ClassPath.Path } } CommandLineEventConsumer { $props = @{ CreatorSid = $Sid.Value CreatorUserName = $UserName MachineName = $o.MachineName MaximumQueueSize = $o.MaximumQueueSize CommandLineTemplate = $o.CommandLineTemplate CreateNewConsole = $o.CreateNewConsole CreateNewProcessGroup = $o.CreateNewProcessGroup CreateSeparateWowVdm = $o.CreateSeparateWowVdm CreateSharedWowVdm = $o.CreateSharedWowVdm DesktopName = $o.DesktopName ExecutablePath = $o.ExecutablePath FillAttributes = $o.FillAttributes ForceOffFeedback = $o.ForceOffFeedback ForceOnFeedback = $o.ForceOnFeedback KillTimeout = $o.KillTimeout Name = $o.Name Priority = $o.Priority RunInteractively = $o.RunInteractively ShowWindowCommand = $o.ShowWindowCommand UseDefaultErrorMode = $o.UseDefaultErrorMode WindowTitle = $o.WindowTitle WorkingDirectory = $o.WorkingDirectory XCoordinate = $o.XCoordinate XNumCharacters = $o.XNumCharacters XSize = $o.XSize YCoordinate = $o.YCoordinate YNumCharacters = $o.YNumCharacters YSize = $o.YSize FillAttribute = $o.FillAttribute Class = $o.ClassPath.ClassName ClassPath = $o.ClassPath.Path } } LogFileEventConsumer { $props = @{ CreatorSid = $Sid.Value CreatorUserName = $UserName MachineName = $o.MachineName MaximumQueueSize = $o.MaximumQueueSize Filename = $o.Filename IsUnicode = $o.IsUnicode MaximumFileSize = $o.MaximumFileSize Name = $o.Name Text = $o.Text Class = $o.ClassPath.ClassName ClassPath = $o.ClassPath.Path } } NtEventLogEventConsumer { $props = @{ Category = $o.Category CreatorSid = $Sid.Value CreatorUserName = $UserName EventId = $o.EventID EventType = $o.EventType InsertionStringTemplates = $o.InsertionStringTemplates MachineName = $o.MachineName MaximumQueueSize = $o.MaximumQueueSize Name = $o.Name NameOfRawDataProperty = $o.NameOfRawDataProperty NameOfUserSidProperty = $o.NameOfUserSIDProperty NumberOfInsertionStrings = $o.NumberOfInsertionStrings SourceName = $o.SourceName UncServerName = $o.UNCServerName Class = $o.ClassPath.ClassName ClassPath = $o.ClassPath.Path } } SMTPEventConsumer { $props = @{ CreatorSid = $Sid.Value CreatorUserName = $UserName MachineName = $o.MachineName MaximumQueueSize = $o.MaximumQueueSize BccLine = $o.BccLine CcLine = $o.CcLine FromLine = $o.FromLine HeaderFields = $o.HeaderFields Message = $o.Message Name = $o.Name ReplyToLine = $o.ReplyToLine SMTPServer = $o.SMTPServer Subject = $o.Subject ToLine = $o.ToLine Class = $o.ClassPath.ClassName ClassPath = $o.ClassPath.Path } } default { $props = @{ CreatorSid = $Sid.Value CreatorUserName = $UserName Name = $o.Name Class = $o.ClassPath.ClassName ClassPath = $o.ClassPath.Path } } } Write-Output $props } } #endregion Collection Functions #region Helper Functions function Get-System { <# .SYNOPSIS .DESCRIPTION .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK .EXAMPLE #> # Get a Process object for the winlogon process # The System.Diagnostics.Process class has a handle property that we can use # We know winlogon will be available and is running as NT AUTHORITY\SYSTEM $winlogons = Get-Process -Name winlogon try { $proc = $winlogons[0] } catch { $proc = $winlogons } # Open winlogon's Token with TOKEN_DUPLICATE Acess # This allows us to make a copy of the token with DuplicateToken $hToken = OpenProcessToken -ProcessHandle $proc.Handle -DesiredAccess TOKEN_DUPLICATE # Make a copy of the NT AUTHORITY\SYSTEM Token $hDupToken = DuplicateToken -TokenHandle $hToken # Apply our Duplicated Token to our Thread ImpersonateLoggedOnUser -TokenHandle $hDupToken # Clean up the handles we created CloseHandle -Handle $hToken CloseHandle -Handle $hDupToken if(-not [System.Security.Principal.WindowsIdentity]::GetCurrent().Name -eq 'NT AUTHORITY\SYSTEM') { throw "Unable to Impersonate System Token" } } function Get-RegistryValue { param ( [Parameter(Mandatory = $true)] [string[]] $Key, [Parameter()] [string[]] $Value ) foreach($k in $key) { try { foreach($val in ((Get-ItemProperty -Path $k -ErrorAction Stop).PSObject.Properties | Where-Object { $_.MemberType -eq 'NoteProperty' -and $_.Name -notmatch 'PS(Path|Drive|Provider|ParentPath|ChildName)|\(default\)' })) { if($PSBoundParameters.ContainsKey('Value')) { if($Value -contains $val.Name) { $props = @{ Path = $k Name = $val.Name Value = $val.Value } New-Object -TypeName psobject -Property $props } } else { $props = @{ Path = $k Name = $val.Name Value = $val.Value } New-Object -TypeName psobject -Property $props } } } catch { } } } function New-AutoRunEntry { param ( [Parameter(Position = 0, ValueFromPipelineByPropertyName = $true)] [string] $Path, [Parameter(Position = 1, ValueFromPipelineByPropertyName = $true)] [string] $Name, [Parameter(Position = 2, ValueFromPipelineByPropertyName = $true)] [Alias('Value')] [string] $ImagePath, [Parameter(Position = 3, ValueFromPipelineByPropertyName = $true)] [string] $Category ) process { if($ImagePath -ne $null) { @{ Path = $Path Name = $Name ImagePath = $ImagePath Type = $Category } } } } #endregion Helper Functions #region PSReflect function New-InMemoryModule { <# .SYNOPSIS Creates an in-memory assembly and module Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION When defining custom enums, structs, and unmanaged functions, it is necessary to associate to an assembly module. This helper function creates an in-memory module that can be passed to the 'enum', 'struct', and Add-Win32Type functions. .PARAMETER ModuleName Specifies the desired name for the in-memory assembly and module. If ModuleName is not provided, it will default to a GUID. .EXAMPLE $Module = New-InMemoryModule -ModuleName Win32 #> Param ( [Parameter(Position = 0)] [ValidateNotNullOrEmpty()] [String] $ModuleName = [Guid]::NewGuid().ToString() ) $AppDomain = [Reflection.Assembly].Assembly.GetType('System.AppDomain').GetProperty('CurrentDomain').GetValue($null, @()) $LoadedAssemblies = $AppDomain.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 $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, 'Run') $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule($ModuleName, $False) return $ModuleBuilder } # A helper function used to reduce typing while defining function # prototypes for Add-Win32Type. 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, [String] $EntryPoint, [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 } if ($EntryPoint) { $Properties['EntryPoint'] = $EntryPoint } New-Object PSObject -Property $Properties } function Add-Win32Type { <# .SYNOPSIS Creates a .NET type for an unmanaged Win32 function. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: func .DESCRIPTION Add-Win32Type enables you to easily interact with unmanaged (i.e. Win32 unmanaged) functions in PowerShell. After providing Add-Win32Type with a function signature, a .NET type is created using reflection (i.e. csc.exe is never called like with Add-Type). The 'func' helper function can be used to reduce typing when defining multiple function definitions. .PARAMETER DllName The name of the DLL. .PARAMETER FunctionName The name of the target function. .PARAMETER EntryPoint The DLL export function name. This argument should be specified if the specified function name is different than the name of the exported function. .PARAMETER ReturnType The return type of the function. .PARAMETER ParameterTypes The function parameters. .PARAMETER NativeCallingConvention Specifies the native calling convention of the function. Defaults to stdcall. .PARAMETER Charset If you need to explicitly call an 'A' or 'W' Win32 function, you can specify the character set. .PARAMETER SetLastError Indicates whether the callee calls the SetLastError Win32 API function before returning from the attributed method. .PARAMETER Module The in-memory module that will host the functions. Use New-InMemoryModule to define an in-memory module. .PARAMETER Namespace An optional namespace to prepend to the type. Add-Win32Type defaults to a namespace consisting only of the name of the DLL. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $FunctionDefinitions = @( (func kernel32 GetProcAddress ([IntPtr]) @([IntPtr], [String]) -Charset Ansi -SetLastError), (func kernel32 GetModuleHandle ([Intptr]) @([String]) -SetLastError), (func ntdll RtlGetCurrentPeb ([IntPtr]) @()) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32' $Kernel32 = $Types['kernel32'] $Ntdll = $Types['ntdll'] $Ntdll::RtlGetCurrentPeb() $ntdllbase = $Kernel32::GetModuleHandle('ntdll') $Kernel32::GetProcAddress($ntdllbase, 'RtlGetCurrentPeb') .NOTES Inspired by Lee Holmes' Invoke-WindowsApi http://poshcode.org/2189 When defining multiple function prototypes, it is ideal to provide Add-Win32Type with an array of function signatures. That way, they are all incorporated into the same in-memory module. #> [OutputType([Hashtable])] Param( [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $DllName, [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $FunctionName, [Parameter(ValueFromPipelineByPropertyName = $True)] [String] $EntryPoint, [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') $EntryPointField = $DllImport.GetField('EntryPoint') if ($SetLastError) { $SLEValue = $True } else { $SLEValue = $False } if ($PSBoundParameters['EntryPoint']) { $ExportedFuncName = $EntryPoint } else { $ExportedFuncName = $FunctionName } # 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, $EntryPointField), [Object[]] @($SLEValue, ([Runtime.InteropServices.CallingConvention] $NativeCallingConvention), ([Runtime.InteropServices.CharSet] $Charset), $ExportedFuncName)) $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 psenum { <# .SYNOPSIS Creates an in-memory enumeration for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION The 'psenum' function facilitates the creation of enums entirely in memory using as close to a "C style" as PowerShell will allow. .PARAMETER Module The in-memory module that will host the enum. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the enum. .PARAMETER Type The type of each enum element. .PARAMETER EnumElements A hashtable of enum elements. .PARAMETER Bitfield Specifies that the enum should be treated as a bitfield. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageSubsystem = psenum $Mod PE.IMAGE_SUBSYSTEM UInt16 @{ UNKNOWN = 0 NATIVE = 1 # Image doesn't require a subsystem. WINDOWS_GUI = 2 # Image runs in the Windows GUI subsystem. WINDOWS_CUI = 3 # Image runs in the Windows character subsystem. OS2_CUI = 5 # Image runs in the OS/2 character subsystem. POSIX_CUI = 7 # Image runs in the Posix character subsystem. NATIVE_WINDOWS = 8 # Image is a native Win9x driver. WINDOWS_CE_GUI = 9 # Image runs in the Windows CE subsystem. EFI_APPLICATION = 10 EFI_BOOT_SERVICE_DRIVER = 11 EFI_RUNTIME_DRIVER = 12 EFI_ROM = 13 XBOX = 14 WINDOWS_BOOT_APPLICATION = 16 } .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Enum. :P #> [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]) { return ($Module.GetType($FullName)) } $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 { <# .SYNOPSIS Creates an in-memory struct for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: field .DESCRIPTION The 'struct' function facilitates the creation of structs entirely in memory using as close to a "C style" as PowerShell will allow. Struct fields are specified using a hashtable where each field of the struct is comprosed of the order in which it should be defined, its .NET type, and optionally, its offset and special marshaling attributes. One of the features of 'struct' is that after your struct is defined, it will come with a built-in GetSize method as well as an explicit converter so that you can easily cast an IntPtr to the struct without relying upon calling SizeOf and/or PtrToStructure in the Marshal class. .PARAMETER Module The in-memory module that will host the struct. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the struct. .PARAMETER StructFields A hashtable of fields. Use the 'field' helper function to ease defining each field. .PARAMETER PackingSize Specifies the memory alignment of fields. .PARAMETER ExplicitLayout Indicates that an explicit offset for each field will be specified. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageDosSignature = psenum $Mod PE.IMAGE_DOS_SIGNATURE UInt16 @{ DOS_SIGNATURE = 0x5A4D OS2_SIGNATURE = 0x454E OS2_SIGNATURE_LE = 0x454C VXD_SIGNATURE = 0x454C } $ImageDosHeader = struct $Mod PE.IMAGE_DOS_HEADER @{ e_magic = field 0 $ImageDosSignature e_cblp = field 1 UInt16 e_cp = field 2 UInt16 e_crlc = field 3 UInt16 e_cparhdr = field 4 UInt16 e_minalloc = field 5 UInt16 e_maxalloc = field 6 UInt16 e_ss = field 7 UInt16 e_sp = field 8 UInt16 e_csum = field 9 UInt16 e_ip = field 10 UInt16 e_cs = field 11 UInt16 e_lfarlc = field 12 UInt16 e_ovno = field 13 UInt16 e_res = field 14 UInt16[] -MarshalAs @('ByValArray', 4) e_oemid = field 15 UInt16 e_oeminfo = field 16 UInt16 e_res2 = field 17 UInt16[] -MarshalAs @('ByValArray', 10) e_lfanew = field 18 Int32 } # Example of using an explicit layout in order to create a union. $TestUnion = struct $Mod TestUnion @{ field1 = field 0 UInt32 0 field2 = field 1 IntPtr 0 } -ExplicitLayout .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Struct. :P #> [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() } #endregion PSReflect $Module = New-InMemoryModule -ModuleName ACE #region Enums $KERB_PROTOCOL_MESSAGE_TYPE = psenum $Module KERB_PROTOCOL_MESSAGE_TYPE UInt32 @{ KerbDebugRequestMessage = 0 KerbQueryTicketCacheMessage = 1 KerbChangeMachinePasswordMessage = 2 KerbVerifyPacMessage = 3 KerbRetrieveTicketMessage = 4 KerbUpdateAddressesMessage = 5 KerbPurgeTicketCacheMessage = 6 KerbChangePasswordMessage = 7 KerbRetrieveEncodedTicketMessage = 8 KerbDecryptDataMessage = 9 KerbAddBindingCacheEntryMessage = 10 KerbSetPasswordMessage = 11 KerbSetPasswordExMessage = 12 KerbVerifyCredentialsMessage = 13 KerbQueryTicketCacheExMessage = 14 KerbPurgeTicketCacheExMessage = 15 KerbRefreshSmartcardCredentialsMessage = 16 KerbAddExtraCredentialsMessage = 17 KerbQuerySupplementalCredentialsMessage = 18 KerbTransferCredentialsMessage = 19 KerbQueryTicketCacheEx2Message = 20 KerbSubmitTicketMessage = 21 KerbAddExtraCredentialsExMessage = 22 KerbQueryKdcProxyCacheMessage = 23 KerbPurgeKdcProxyCacheMessage = 24 KerbQueryTicketCacheEx3Message = 25 KerbCleanupMachinePkinitCredsMessage = 26 KerbAddBindingCacheEntryExMessage = 27 KerbQueryBindingCacheMessage = 28 KerbPurgeBindingCacheMessage = 29 KerbQueryDomainExtendedPoliciesMessage = 30 KerbQueryS4U2ProxyCacheMessage = 31 } $KERB_CACHE_OPTIONS = psenum $Module KERB_CACHE_OPTIONS UInt64 @{ KERB_RETRIEVE_TICKET_DONT_USE_CACHE = 0x1 KERB_RETRIEVE_TICKET_USE_CACHE_ONLY = 0x2 KERB_RETRIEVE_TICKET_USE_CREDHANDLE = 0x4 KERB_RETRIEVE_TICKET_AS_KERB_CRED = 0x8 KERB_RETRIEVE_TICKET_WITH_SEC_CRED = 0x10 KERB_RETRIEVE_TICKET_CACHE_TICKET = 0x20 KERB_RETRIEVE_TICKET_MAX_LIFETIME = 0x40 } -Bitfield $KERB_ENCRYPTION_TYPE = psenum $Module KERB_ENCRYPTION_TYPE UInt32 @{ reserved0 = 0 des_cbc_crc = 1 des_cbc_md4 = 2 des_cbc_md5 = 3 reserved1 = 4 des3_cbc_md5 = 5 reserved2 = 6 des3_cbc_sha1 = 7 dsaWithSHA1_CmsOID = 9 md5WithRSAEncryption_CmsOID = 10 sha1WithRSAEncryption_CmsOID = 11 rc2CBC_EnvOID = 12 rsaEncryption_EnvOID = 13 rsaES_OAEP_ENV_OID = 14 des_ede3_cbc_Env_OID = 15 des3_cbc_sha1_kd = 16 aes128_cts_hmac_sha1_96 = 17 aes256_cts_hmac_sha1_96 = 18 aes128_cts_hmac_sha256_128 = 19 aes256_cts_hmac_sha384_192 = 20 rc4_hmac = 23 rc4_hmac_exp = 24 camellia128_cts_cmac = 25 camellia256_cts_cmac = 26 subkey_keymaterial = 65 } $KERB_TICKET_FLAGS = psenum $Module KERB_TICKET_FLAGS UInt32 @{ reserved = 2147483648 forwardable = 0x40000000 forwarded = 0x20000000 proxiable = 0x10000000 proxy = 0x08000000 may_postdate = 0x04000000 postdated = 0x02000000 invalid = 0x01000000 renewable = 0x00800000 initial = 0x00400000 pre_authent = 0x00200000 hw_authent = 0x00100000 ok_as_delegate = 0x00040000 name_canonicalize = 0x00010000 cname_in_pa_data = 0x00040000 enc_pa_rep = 0x00010000 reserved1 = 0x00000001 } -Bitfield $LuidAttributes = psenum $Module LuidAttributes UInt32 @{ DISABLED = 0x00000000 SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001 SE_PRIVILEGE_ENABLED = 0x00000002 SE_PRIVILEGE_REMOVED = 0x00000004 SE_PRIVILEGE_USED_FOR_ACCESS = 2147483648 } -Bitfield $MEMORY_PROTECTION = psenum $Module MEMORY_PROTECTION UInt32 @{ PAGE_NOACCESS = 0x00000001 PAGE_READONLY = 0x00000002 PAGE_READWRITE = 0x00000004 PAGE_WRITECOPY = 0x00000008 PAGE_EXECUTE = 0x00000010 PAGE_EXECUTE_READ = 0x00000020 PAGE_EXECUTE_READWRITE = 0x00000040 PAGE_EXECUTE_WRITECOPY = 0x00000080 PAGE_GUARD = 0x00000100 PAGE_NOCACHE = 0x00000200 PAGE_WRITECOMBINE = 0x00000400 PAGE_TARGETS_NO_UPDATE = 0x40000000 } -Bitfield $MEMORY_STATE = psenum $Module MEMORY_STATE UInt32 @{ MEM_COMMIT = 0x1000 MEM_RESERVE = 0x2000 MEM_FREE = 0x10000 } -Bitfield $MEMORY_TYPE = psenum $Module MEMORY_TYPE UInt32 @{ MEM_PRIVATE = 0x20000 MEM_MAPPED = 0x40000 MEM_IMAGE = 0x1000000 } -Bitfield $MIB_IPNET_TYPE = psenum $Module MIB_IPNET_TYPE UInt32 @{ OTHER = 1 INVALID = 2 DYNAMIC = 3 STATIC = 4 } $PROCESS_ACCESS = psenum $Module PROCESS_ACCESS UInt32 @{ PROCESS_TERMINATE = 0x00000001 PROCESS_CREATE_THREAD = 0x00000002 PROCESS_VM_OPERATION = 0x00000008 PROCESS_VM_READ = 0x00000010 PROCESS_VM_WRITE = 0x00000020 PROCESS_DUP_HANDLE = 0x00000040 PROCESS_CREATE_PROCESS = 0x00000080 PROCESS_SET_QUOTA = 0x00000100 PROCESS_SET_INFORMATION = 0x00000200 PROCESS_QUERY_INFORMATION = 0x00000400 PROCESS_SUSPEND_RESUME = 0x00000800 PROCESS_QUERY_LIMITED_INFORMATION = 0x00001000 DELETE = 0x00010000 READ_CONTROL = 0x00020000 WRITE_DAC = 0x00040000 WRITE_OWNER = 0x00080000 SYNCHRONIZE = 0x00100000 PROCESS_ALL_ACCESS = 0x001f1ffb } -Bitfield $SC_SERVICE_TAG_QUERY_TYPE = psenum $Module SC_SERVICE_TAG_QUERY_TYPE UInt16 @{ ServiceNameFromTagInformation = 1 ServiceNamesReferencingModuleInformation = 2 ServiceNameTagMappingInformation = 3 } $SE_GROUP = psenum $Module SE_GROUP UInt32 @{ DISABLED = 0x00000000 MANDATORY = 0x00000001 ENABLED_BY_DEFAULT = 0x00000002 ENABLED = 0x00000004 OWNER = 0x00000008 USE_FOR_DENY_ONLY = 0x00000010 INTEGRITY = 0x00000020 INTEGRITY_ENABLED = 0x00000040 RESOURCE = 0x20000000 LOGON_ID = 3221225472 } -Bitfield $SE_PRIVILEGE = psenum $Module SE_PRIVILEGE UInt32 @{ DISABLED = 0x00000000 ENABLED_BY_DEFAULT = 0x00000001 ENABLED = 0x00000002 REMOVED = 0x00000004 USED_FOR_ACCESS = 2147483648 } -Bitfield $SECPKG_FLAG = psenum $Module SECPKG_FLAG UInt32 @{ INTEGRITY = 0x1 PRIVACY = 0x2 TOKEN_ONLY = 0x4 DATAGRAM = 0x8 CONNECTION = 0x10 MULTI_REQUIRED = 0x20 CLIENT_ONLY = 0x40 EXTENDED_ERROR = 0x80 IMPERSONATION = 0x100 ACCEPT_WIN32_NAME = 0x200 STREAM = 0x400 NEGOTIABLE = 0X800 GSS_COMPATIBLE = 0x1000 LOGON = 0x2000 ASCII_BUFFERS = 0x4000 FRAGMENT = 0x8000 MUTUAL_AUTH = 0x10000 DELEGATION = 0x20000 READONLY_WITH_CHECKSUM = 0x40000 RESTRICTED_TOKENS = 0x80000 NEGO_EXTENDER = 0x00100000 NEGOTIABLE2 = 0x00200000 APPCONTAINER_PASSTHROUGH = 0x00400000 APPCONTAINER_CHECKS = 0x00800000 #SECPKG_CALLFLAGS_APPCONTAINER = 0x00000001 #SECPKG_CALLFLAGS_AUTHCAPABLE = 0x00000002 #SECPKG_CALLFLAGS_FORCE_SUPPLIED = 0x00000004 } -Bitfield $SECURITY_IMPERSONATION_LEVEL = psenum $Module SECURITY_IMPERSONATION_LEVEL UInt32 @{ SecurityAnonymous = 0 SecurityIdentification = 1 SecurityImpersonation = 2 SecurityDelegation = 3 } $SECURITY_LOGON_TYPE = psenum $Module SECURITY_LOGON_TYPE UInt32 @{ Interactive = 2 Network = 3 Batch = 4 Service = 5 Proxy = 6 Unlock = 7 NetworkCleartext = 8 NewCredentials = 9 RemoteInteractive = 10 CachedInteractive = 11 CachedRemoteInteractive = 12 CachedUnlock = 13 } $TAG_INFO_LEVEL = psenum $Module TAG_INFO_LEVEL UInt16 @{ eTagInfoLevelNameFromTag = 1 eTagInfoLevelNamesReferencingModule = 2 eTagInfoLevelNameTagMapping = 3 eTagInfoLevelMax = 4 } $TCP_STATE = psenum $Module TCP_STATE UInt16 @{ CLOSED = 1 LISTENING = 2 SYN_SENT = 3 SYN_RECEIVED = 4 ESTABLISHED = 5 FIN_WAIT1 = 6 FIN_WAIT2 = 7 CLOSE_WAIT = 8 CLOSING = 9 LAST_ACK = 10 TIME_WAIT = 11 DELETE_TCB = 12 } $TCP_TABLE_CLASS = psenum $Module TCP_TABLE_CLASS UInt16 @{ TCP_TABLE_BASIC_LISTENER = 0 TCP_TABLE_BASIC_CONNECTIONS = 1 TCP_TABLE_BASIC_ALL = 2 TCP_TABLE_OWNER_PID_LISTENER = 3 TCP_TABLE_OWNER_PID_CONNECTIONS = 4 TCP_TABLE_OWNER_PID_ALL = 5 TCP_TABLE_OWNER_MODULE_LISTENER = 6 TCP_TABLE_OWNER_MODULE_CONNECTIONS = 7 TCP_TABLE_OWNER_MODULE_ALL = 8 } $TH32CS = psenum $Module TH32CS UInt32 @{ SNAPHEAPLIST = 0x00000001 SNAPPROCESS = 0x00000002 SNAPTHREAD = 0x00000004 SNAPMODULE = 0x00000008 SNAPALL = 0x0000000F SNAPMODULE32 = 0x00000010 INHERIT = 2147483648 } -Bitfield $THREAD_ACCESS = psenum $Module THREAD_ACCESS UInt32 @{ THREAD_TERMINATE = 0x00000001 THREAD_SUSPEND_RESUME = 0x00000002 THREAD_GET_CONTEXT = 0x00000008 THREAD_SET_CONTEXT = 0x00000010 THREAD_SET_INFORMATION = 0x00000020 THREAD_QUERY_INFORMATION = 0x00000040 THREAD_SET_THREAD_TOKEN = 0x00000080 THREAD_IMPERSONATE = 0x00000100 THREAD_DIRECT_IMPERSONATION = 0x00000200 THREAD_SET_LIMITED_INFORMATION = 0x00000400 THREAD_QUERY_LIMITED_INFORMATION = 0x00000800 DELETE = 0x00010000 READ_CONTROL = 0x00020000 WRITE_DAC = 0x00040000 WRITE_OWNER = 0x00080000 SYNCHRONIZE = 0x00100000 THREAD_ALL_ACCESS = 0x001f0ffb } -Bitfield $THREADINFOCLASS = psenum $Module THREADINFOCLASS UInt32 @{ ThreadBasicInformation = 0x00 ThreadTimes = 0x01 ThreadPriority = 0x02 ThreadBasePriority = 0x03 ThreadAffinityMask = 0x04 ThreadImpersonationToken = 0x05 ThreadDescriptorTableEntry = 0x06 ThreadEnableAlignmentFaultFixup = 0x07 ThreadEventPair_Reusable = 0x08 ThreadQuerySetWin32StartAddress = 0x09 ThreadZeroTlsCell = 0x0A ThreadPerformanceCount = 0x0B ThreadAmILastThread = 0x0C ThreadIdealProcessor = 0x0D ThreadPriorityBoost = 0x0E ThreadSetTlsArrayAddress = 0x0F ThreadIsIoPending = 0x10 MaxThreadInfoClass = 0x11 } $TOKEN_ACCESS = psenum $Module TOKEN_ACCESS UInt32 @{ TOKEN_DUPLICATE = 0x00000002 TOKEN_IMPERSONATE = 0x00000004 TOKEN_QUERY = 0x00000008 TOKEN_QUERY_SOURCE = 0x00000010 TOKEN_ADJUST_PRIVILEGES = 0x00000020 TOKEN_ADJUST_GROUPS = 0x00000040 TOKEN_ADJUST_DEFAULT = 0x00000080 TOKEN_ADJUST_SESSIONID = 0x00000100 DELETE = 0x00010000 READ_CONTROL = 0x00020000 WRITE_DAC = 0x00040000 WRITE_OWNER = 0x00080000 SYNCHRONIZE = 0x00100000 STANDARD_RIGHTS_REQUIRED = 0x000F0000 TOKEN_ALL_ACCESS = 0x001f01ff } -Bitfield $TOKEN_ELEVATION_TYPE = psenum $Module TOKEN_ELEVATION_TYPE UInt32 @{ TokenElevationTypeDefault = 1 TokenElevationTypeFull = 2 TokenElevationTypeLimited = 3 } $TOKEN_INFORMATION_CLASS = psenum $Module TOKEN_INFORMATION_CLASS UInt16 @{ TokenUser = 1 TokenGroups = 2 TokenPrivileges = 3 TokenOwner = 4 TokenPrimaryGroup = 5 TokenDefaultDacl = 6 TokenSource = 7 TokenType = 8 TokenImpersonationLevel = 9 TokenStatistics = 10 TokenRestrictedSids = 11 TokenSessionId = 12 TokenGroupsAndPrivileges = 13 TokenSessionReference = 14 TokenSandBoxInert = 15 TokenAuditPolicy = 16 TokenOrigin = 17 TokenElevationType = 18 TokenLinkedToken = 19 TokenElevation = 20 TokenHasRestrictions = 21 TokenAccessInformation = 22 TokenVirtualizationAllowed = 23 TokenVirtualizationEnabled = 24 TokenIntegrityLevel = 25 TokenUIAccess = 26 TokenMandatoryPolicy = 27 TokenLogonSid = 28 TokenIsAppContainer = 29 TokenCapabilities = 30 TokenAppContainerSid = 31 TokenAppContainerNumber = 32 TokenUserClaimAttributes = 33 TokenDeviceClaimAttributes = 34 TokenRestrictedUserClaimAttributes = 35 TokenRestrictedDeviceClaimAttributes = 36 TokenDeviceGroups = 37 TokenRestrictedDeviceGroups = 38 TokenSecurityAttributes = 39 TokenIsRestricted = 40 MaxTokenInfoClass = 41 } $TOKENMANDATORYPOLICY = psenum $Module TOKENMANDATORYPOLICY UInt32 @{ OFF = 0x0 NO_WRITE_UP = 0x1 POLICY_NEW_PROCESS_MIN = 0x2 POLICY_VALID_MASK = 0x3 } $TOKEN_TYPE = psenum $Module TOKEN_TYPE UInt32 @{ TokenPrimary = 1 TokenImpersonation = 2 } $UDP_TABLE_CLASS = psenum $Module UDP_TABLE_CLASS UInt16 @{ UDP_TABLE_BASIC = 0 UDP_TABLE_OWNER_PID = 1 UDP_TABLE_OWNER_MODULE = 2 } #endregion Enums #region Structs $ACL = struct $Module ACL @{ AclRevision = field 0 Byte Sbz1 = field 1 Byte AclSize = field 2 UInt16 AceCount = field 3 UInt16 Sbz2 = field 4 UInt16 } $LUID = struct $Module LUID @{ LowPart = field 0 UInt32 HighPart = field 1 Int32 } $LUID_AND_ATTRIBUTES = struct $Module LUID_AND_ATTRIBUTES @{ Luid = field 0 $LUID Attributes = field 1 $SE_PRIVILEGE } $LSA_LAST_INTER_LOGON_INFO = struct $Module LSA_LAST_INTER_LOGON_INFO @{ LastSuccessfulLogon = field 0 Int64 LastFailedLogon = field 1 Int64 FailedAttemptCountSinceLastSuccessfulLogon = field 2 UInt64 } $LSA_STRING = struct $Module LSA_STRING @{ Length = field 0 UInt16 MaximumLength = field 1 UInt16 Buffer = field 2 IntPtr } $LSA_UNICODE_STRING = struct $Module LSA_UNICODE_STRING @{ Length = field 0 UInt16 MaximumLength = field 1 UInt16 Buffer = field 2 IntPtr } $MEMORY_BASIC_INFORMATION = struct $Module MEMORY_BASIC_INFORMATION @{ BaseAddress = field 0 UIntPtr AllocationBase = field 1 UIntPtr AllocationProtect = field 2 $MEMORY_PROTECTION RegionSize = field 3 UIntPtr State = field 4 $MEMORY_STATE Protect = field 5 $MEMORY_PROTECTION Type = field 6 $MEMORY_TYPE } $MIB_IPNETROW = struct $Module MIB_IPNETROW @{ dwIndex = field 0 UInt32 dwPhysAddrLen = field 1 UInt32 bPhysAddr = field 2 byte[] -MarshalAs @('ByValArray', 6) dwAddr = field 3 UInt32 dwType = field 4 UInt32 } $MIB_UDPROW_OWNER_MODULE = struct $Module MIB_UDPROW_OWNER_MODULE @{ LocalAddr = field 0 UInt32 0 LocalPort = field 1 UInt32 4 OwningPid = field 2 UInt32 8 CreateTimestamp = field 3 UInt64 16 SpecificPortBind = field 4 UInt32 24 # Union Flags = field 5 UInt32 24 OwningModuleInfo = field 6 UInt64[] -MarshalAs @('ByValArray', 16) 32 } -ExplicitLayout $MIB_UDP6ROW_OWNER_MODULE = struct $Module MIB_UDP6ROW_OWNER_MODULE @{ LocalAddr = field 0 Byte[] -MarshalAs @('ByValArray', 16) 0 LocalScopeId = field 1 UInt32 16 LocalPort = field 2 UInt32 20 OwningPid = field 3 UInt32 24 CreateTimestamp = field 4 UInt64 32 SpecificPortBind = field 5 UInt32 40 # Union Flags = field 6 UInt32 40 OwningModuleInfo = field 7 UInt64[] -MarshalAs @('ByValArray', 16) 48 } -ExplicitLayout $MIB_UDPTABLE_OWNER_MODULE = struct $Module MIB_UDPTABLE_OWNER_MODULE @{ NumEntries = field 0 UInt32 Table = field 1 $MIB_UDPROW_OWNER_MODULE } $MIB_UDP6TABLE_OWNER_MODULE = struct $Module MIB_UDP6TABLE_OWNER_MODULE @{ NumEntries = field 0 UInt32 Table = field 1 $MIB_UDPROW_OWNER_MODULE } $MIB_TCPROW_OWNER_MODULE = struct $Module MIB_TCPROW_OWNER_MODULE @{ State = field 0 $TCP_STATE LocalAddr = field 1 UInt32 LocalPort = field 2 UInt32 RemoteAddr = field 3 UInt32 RemotePort = field 4 UInt32 OwningPid = field 5 UInt32 CreateTimestamp = field 6 UInt64 OwningModuleInfo = field 7 UInt64[] -MarshalAs @('ByValArray', 16) } $MIB_TCP6ROW_OWNER_MODULE = struct $Module MIB_TCP6ROW_OWNER_MODULE @{ LocalAddr = field 0 Byte[] -MarshalAs @('ByValArray', 16) LocalScopeId = field 1 UInt32 LocalPort = field 2 UInt32 RemoteAddr = field 3 Byte[] -MarshalAs @('ByValArray', 16) RemoteScopeId = field 4 UInt32 RemotePort = field 5 UInt32 State = field 6 $TCP_STATE OwningPid = field 7 UInt32 CreateTimestamp = field 8 UInt64 OwningModuleInfo = field 9 UInt64[] -MarshalAs @('ByValArray', 16) } $MIB_TCPTABLE_OWNER_MODULE = struct $Module MIB_TCPTABLE_OWNER_MODULE @{ NumEntries = field 0 UInt32 Table = field 1 $MIB_TCPROW_OWNER_MODULE } $MIB_TCP6TABLE_OWNER_MODULE = struct $Module MIB_TCP6TABLE_OWNER_MODULE @{ NumEntries = field 0 UInt32 Table = field 1 $MIB_TCP6ROW_OWNER_MODULE } $KERB_CRYPTO_KEY = struct $Module KERB_CRYPTO_KEY @{ KeyType = field 0 Int32 Length = field 1 Int32 Value = field 2 IntPtr } $KERB_EXTERNAL_NAME = struct $Module KERB_EXTERNAL_NAME @{ NameType = field 0 Int16 NameCount = field 1 UInt16 Names = field 2 $LSA_UNICODE_STRING } $KERB_EXTERNAL_TICKET = struct $Module KERB_EXTERNAL_TICKET @{ ServiceName = field 0 IntPtr TargetName = field 1 IntPtr ClientName = field 2 IntPtr DomainName = field 3 $LSA_UNICODE_STRING TargetDomainName = field 4 $LSA_UNICODE_STRING AltTargetDomainName = field 5 $LSA_UNICODE_STRING SessionKey = field 6 $KERB_CRYPTO_KEY TicketFlags = field 7 UInt32 Flags = field 8 UInt32 KeyExpirationTime = field 9 Int64 StartTime = field 10 Int64 EndTime = field 11 Int64 RenewUntil = field 12 Int64 TimeSkew = field 13 Int64 EncodedTicketSize = field 14 Int32 EncodedTicket = field 15 IntPtr } $KERB_TICKET_CACHE_INFO = struct $Module KERB_TICKET_CACHE_INFO @{ ServerName = field 0 $LSA_UNICODE_STRING RealmName = field 1 $LSA_UNICODE_STRING StartTime = field 2 Int64 EndTime = field 3 Int64 RenewTime = field 4 Int64 EncryptionType = field 5 Int32 TicketFlags = field 6 UInt32 } $KERB_QUERY_TKT_CACHE_REQUEST = struct $Module KERB_QUERY_TKT_CACHE_REQUEST @{ MessageType = field 0 $KERB_PROTOCOL_MESSAGE_TYPE LogonId = field 1 $LUID } $KERB_QUERY_TKT_CACHE_RESPONSE = struct $Module KERB_QUERY_TKT_CACHE_RESPONSE @{ MessageType = field 0 $KERB_PROTOCOL_MESSAGE_TYPE CountOfTickets = field 1 UInt32 Tickets = field 2 $KERB_TICKET_CACHE_INFO.MakeArrayType() -MarshalAs @('ByValArray', 1) } $SecHandle = struct $Module SecHandle @{ dwLower = field 0 IntPtr dwUpper = field 1 IntPtr } $KERB_RETRIEVE_TKT_REQUEST = struct $Module KERB_RETRIEVE_TKT_REQUEST @{ MessageType = field 0 $KERB_PROTOCOL_MESSAGE_TYPE LogonId = field 1 $LUID TargetName = field 2 $LSA_UNICODE_STRING TicketFlags = field 3 UInt64 CacheOptions = field 4 $KERB_CACHE_OPTIONS EncryptionType = field 5 Int64 CredentialsHandle = field 6 $SecHandle } $KERB_RETRIEVE_TKT_RESPONSE = struct $Module KERB_RETRIEVE_TKT_RESPONSE @{ Ticket = field 0 $KERB_EXTERNAL_TICKET } $SC_SERVICE_TAG_QUERY = struct $Module SC_SERVICE_TAG_QUERY @{ ProcessId = field 0 UInt32 ServiceTag = field 1 UInt32 Unknown = field 2 UInt32 Buffer = field 3 IntPtr } $SECURITY_LOGON_SESSION_DATA = struct $Module SECURITY_LOGON_SESSION_DATA @{ Size = field 0 UInt32 LogonId = field 1 $LUID Username = field 2 $LSA_UNICODE_STRING LogonDomain = field 3 $LSA_UNICODE_STRING AuthenticationPackage = field 4 $LSA_UNICODE_STRING LogonType = field 5 UInt32 Session = field 6 UInt32 PSiD = field 7 IntPtr LogonTime = field 8 UInt64 LogonServer = field 9 $LSA_UNICODE_STRING DnsDomainName = field 10 $LSA_UNICODE_STRING Upn = field 11 $LSA_UNICODE_STRING UserFlags = field 12 UInt64 LastLogonInfo = field 13 $LSA_LAST_INTER_LOGON_INFO LogonScript = field 14 $LSA_UNICODE_STRING ProfilePath = field 15 $LSA_UNICODE_STRING HomeDirectory = field 16 $LSA_UNICODE_STRING HomeDirectoryDrive = field 17 $LSA_UNICODE_STRING LogoffTime = field 18 Int64 KickOffTime = field 19 Int64 PasswordLastSet = field 20 Int64 PasswordCanChange = field 21 Int64 PasswordMustChange = field 22 Int64 } $SecPkgInfo = struct $Module SecPkgInfo @{ Capabilities = field 0 $SECPKG_FLAG Version = field 1 UInt16 RPCID = field 2 UInt16 MaxToken = field 3 UInt32 Name = field 4 IntPtr Comment = field 5 IntPtr } $SID_AND_ATTRIBUTES = struct $Module SID_AND_ATTRIBUTES @{ Sid = field 0 IntPtr Attributes = field 1 $SE_GROUP } -PackingSize Size8 $THREADENTRY32 = struct $Module THREADENTRY32 @{ dwSize = field 0 UInt32 cntUsage = field 1 UInt32 th32ThreadID = field 2 UInt32 th32OwnerProcessID = field 3 UInt32 tpBasePri = field 4 UInt32 tpDeltaPri = field 5 UInt32 dwFlags = field 6 UInt32 } $TOKEN_APPCONTAINER_INFORMATION = struct $Module TOKEN_APPCONSTAINER_INFORMATION @{ TokenAppContainer = field 0 IntPtr } $TOKEN_DEFAULT_DACL = struct $Module TOKEN_DEFAULT_DACL @{ DefaultDacl = field 0 $ACL } $TOKEN_ELEVATION = struct $Module TOKEN_ELEVATION @{ TokenIsElevated = field 0 UInt32 } $TOKEN_GROUPS = struct $Module TOKEN_GROUPS @{ GroupCount = field 0 UInt32 Groups = field 1 $SID_AND_ATTRIBUTES.MakeArrayType() -MarshalAs ('ByValArray', 50) } $TOKEN_GROUPS_AND_PRIVILEGES = struct $Module TOKEN_GROUPS_AND_PRIVILEGES @{ SidCount = field 0 UInt32 SidLength = field 1 UInt32 Sids = field 2 IntPtr RestrictedSidCount = field 3 UInt32 RestrictedSidLength = field 4 UInt32 RestrictedSids = field 5 IntPtr PrivilegeCount = field 6 UInt32 PrivilegeLength = field 7 UInt32 Privileges = field 8 IntPtr AuthenticationId = field 9 $LUID } $TOKEN_LINKED_TOKEN = struct $Module TOKEN_LINKED_TOKEN @{ LinkedToken = field 0 IntPtr } $TOKEN_MANDATORY_LABEL = struct $Module TOKEN_MANDATORY_LABEL @{ Label = field 0 $SID_AND_ATTRIBUTES } $TOKEN_MANDATORY_POLICY = struct $Module TOKEN_MANDATORY_POLICY @{ Policy = field 0 $TOKENMANDATORYPOLICY } $TOKEN_OWNER = struct $Module TOKEN_OWNER @{ Owner = field 0 IntPtr } $TOKEN_PRIVILEGES = struct $Module TOKEN_PRIVILEGES @{ PrivilegeCount = field 0 UInt32 Privileges = field 1 $LUID_AND_ATTRIBUTES.MakeArrayType() -MarshalAs @('ByValArray', 50) } $TOKEN_SOURCE = struct $Module TOKEN_SOURCE @{ SourceName = field 0 string SourceIdentifier = field 1 $LUID } $TOKEN_STATISTICS = struct $Module TOKEN_STATISTICS @{ TokenId = field 0 $LUID AuthenticationId = field 1 $LUID ExpirationTime = field 2 UInt64 TokenType = field 3 $TOKEN_TYPE ImpersonationLevel = field 4 $SECURITY_IMPERSONATION_LEVEL DynamicCharged = field 5 UInt32 DynamicAvailable = field 6 UInt32 GroupCount = field 7 UInt32 PrivilegeCount = field 8 UInt32 ModifiedId = field 9 $LUID } $TOKEN_USER = struct $Module TOKEN_USER @{ User = field 0 $SID_AND_ATTRIBUTES } #endregion Structs #region Function Definitions $FunctionDefinitions = @( (func kernel32 CloseHandle ([bool]) @( [IntPtr] #_In_ HANDLE hObject ) -EntryPoint CloseHandle -SetLastError), (func advapi32 ConvertSidToStringSid ([bool]) @( [IntPtr], #_In_ PSID Sid [IntPtr].MakeByRefType() #_Out_ LPTSTR *StringSid ) -EntryPoint ConvertSidToStringSid -SetLastError), (func kernel32 CreateToolhelp32Snapshot ([IntPtr]) @( [UInt32], #_In_ DWORD dwFlags [UInt32] #_In_ DWORD th32ProcessID ) -EntryPoint CreateToolhelp32Snapshot -SetLastError), (func advapi32 DuplicateToken ([bool]) @( [IntPtr], #_In_ HANDLE ExistingTokenHandle, [UInt32], #_In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, [IntPtr].MakeByRefType() #_Out_ PHANDLE DuplicateTokenHandle ) -EntryPoint DuplicateToken -SetLastError), (func secur32 EnumerateSecurityPackages ([UInt32]) @( [UInt32].MakeByRefType(), #_In_ PULONG pcPackages [IntPtr].MakeByRefType() #_In_ PSecPkgInfo *ppPackageInfo ) -EntryPoint EnumerateSecurityPackages), (func secur32 FreeContextBuffer ([UInt32]) @( [IntPtr] #_In_ PVOID pvContextBuffer ) -EntryPoint FreeContextBuffer), (func iphlpapi GetExtendedTcpTable ([UInt32]) @([IntPtr], [Int32].MakeByRefType(), [Bool], [Int32], [Int32], [Int32]) -EntryPoint GetExtendedTcpTable), (func iphlpapi GetExtendedUdpTable ([UInt32]) @([IntPtr], [Int32].MakeByRefType(), [Bool], [Int32], [Int32], [Int32]) -EntryPoint GetExtendedUdpTable), (func iphlpapi GetIpNetTable ([Int32]) @( [IntPtr], #_Out_ PMIB_IPNETTABLE pIpNetTable [Int32].MakeByRefType(), #_Inout_ PULONG pdwSize [bool] #_In_ BOOL bOrder ) -EntryPoint GetIpNetTable), (func advapi32 GetTokenInformation ([bool]) @( [IntPtr], #_In_ HANDLE TokenHandle [Int32], #_In_ TOKEN_INFORMATION_CLASS TokenInformationClass [IntPtr], #_Out_opt_ LPVOID TokenInformation [UInt32], #_In_ DWORD TokenInformationLength [UInt32].MakeByRefType() #_Out_ PDWORD ReturnLength ) -EntryPoint GetTokenInformation -SetLastError), (func kernel32 GlobalGetAtomName ([UInt32]) @( [UInt16], #_In_ ATOM nAtom [IntPtr], #_Out_ LPTSTR lpBuffer [UInt32] #_In_ int nSize ) -EntryPoint GlobalGetAtomName -SetLastError), (func advapi32 ImpersonateLoggedOnUser ([bool]) @( [IntPtr] #_In_ HANDLE hToken ) -EntryPoint ImpersonateLoggedOnUser -SetLastError), (func advapi32 I_QueryTagInformation ([UInt32]) @([IntPtr], $SC_SERVICE_TAG_QUERY_TYPE, $SC_SERVICE_TAG_QUERY.MakeByRefType()) -EntryPoint I_QueryTagInformation), (func advapi32 LookupPrivilegeName ([bool]) @( [string], #_In_opt_ LPCTSTR lpSystemName [IntPtr], #_In_ PLUID lpLuid [sYstem.Text.StringBuilder], #_Out_opt_ LPTSTR lpName [UInt32].MakeByRefType() #_Inout_ LPDWORD cchName ) -EntryPoint LookupPrivilegeName -SetLastError), (func advapi32 LookupPrivilegeDisplayName ([bool]) @( [string], #_In_opt_ LPCTSTR lpSystemName, [string], #_In_ LPCTSTR lpName, [System.Text.StringBuilder], #_Out_opt_ LPTSTR lpDisplayName, [UInt32].MakeByRefType(), #_Inout_ LPDWORD cchDisplayName, [UInt32].MakeByRefType() #_Out_ LPDWORD lpLanguageId ) -EntryPoint LookupPrivilegeDisplayName -SetLastError), (func secur32 LsaCallAuthenticationPackage_KERB_QUERY_TKT_CACHE ([UInt32]) @( [IntPtr], #_In_ HANDLE LsaHandle [UInt64], #_In_ ULONG AuthenticationPackage $KERB_QUERY_TKT_CACHE_REQUEST.MakeByRefType(), #_In_ PVOID ProtocolSubmitBuffer [UInt64], #_In_ ULONG SubmitBufferLength [IntPtr].MakeByRefType(),#_Out_ PVOID *ProtocolReturnBuffer [UInt64].MakeByRefType(), #_Out_ PULONG *ReturnBufferLength [UInt32].MakeByRefType() #_Out_ PNTSTATUS ProtocolStatus ) -EntryPoint LsaCallAuthenticationPackage), (func secur32 LsaCallAuthenticationPackage_KERB_RETRIEVE_TKT ([UInt32]) @( [IntPtr], #_In_ HANDLE LsaHandle [UInt64], #_In_ ULONG AuthenticationPackage $KERB_RETRIEVE_TKT_REQUEST.MakeByRefType(), #_In_ PVOID ProtocolSubmitBuffer [UInt64], #_In_ ULONG SubmitBufferLength [IntPtr].MakeByRefType(),#_Out_ PVOID *ProtocolReturnBuffer [UInt64].MakeByRefType(), #_Out_ PULONG *ReturnBufferLength [UInt32].MakeByRefType() #_Out_ PNTSTATUS ProtocolStatus ) -EntryPoint LsaCallAuthenticationPackage), (func secur32 LsaConnectUntrusted ([UInt32]) @( [IntPtr].MakeByRefType() #_Out_ PHANDLE LsaHandle ) -EntryPoint LsaConnectUntrusted), (func secur32 LsaDeregisterLogonProcess ([UInt32]) @( [IntPtr] #_In_ HANDLE LsaHandle ) -EntryPoint LsaDeregisterLogonProcess), (func secur32 LsaEnumerateLogonSessions ([UInt32]) @( [UInt64].MakeByRefType(), #_Out_ PULONG LogonSessionCount, [IntPtr].MakeByRefType() #_Out_ PLUID *LogonSessionList ) -EntryPoint LsaEnumerateLogonSessions), (func secur32 LsaFreeReturnBuffer ([UInt32]) @( [IntPtr] #_In_ PVOID Buffer ) -EntryPoint LsaFreeReturnBuffer), (func secur32 LsaGetLogonSessionData ([UInt32]) @( [IntPtr], #_In_ PLUID LogonId, [IntPtr].MakeByRefType() #_Out_ PSECURITY_LOGON_SESSION_DATA *ppLogonSessionData ) -EntryPoint LsaGetLogonSessionData), (func secur32 LsaLookupAuthenticationPackage ([UInt32]) @( [IntPtr], #_In_ HANDLE LsaHandle, $LSA_STRING.MakeByRefType(), #_In_ PLSA_STRING PackageName, [UInt64].MakeByRefType() #_Out_ PULONG AuthenticationPackage ) -EntryPoint LsaLookupAuthenticationPackage), (func advapi32 LsaNtStatusToWinError ([UInt64]) @( [UInt32] #_In_ NTSTATUS Status ) -EntryPoint LsaNtStatusToWinError), (func secur32 LsaRegisterLogonProcess ([UInt32]) @( $LSA_STRING.MakeByRefType(), #_In_ PLSA_STRING LogonProcessName, [IntPtr].MakeByRefType(), #_Out_ PHANDLE LsaHandle, [UInt64].MakeByRefType() #_Out_ PLSA_OPERATIONAL_MODE SecurityMode ) -EntryPoint LsaRegisterLogonProcess), (func ntdll NtQueryInformationThread ([Int32]) @( [IntPtr], #_In_ HANDLE ThreadHandle, [Int32], #_In_ THREADINFOCLASS ThreadInformationClass, [IntPtr], #_Inout_ PVOID ThreadInformation, [Int32], #_In_ ULONG ThreadInformationLength, [IntPtr] #_Out_opt_ PULONG ReturnLength ) -EntryPoint NtQueryInformationThread), (func kernel32 OpenProcess ([IntPtr]) @( [UInt32], #_In_ DWORD dwDesiredAccess [bool], #_In_ BOOL bInheritHandle [UInt32] #_In_ DWORD dwProcessId ) -EntryPoint OpenProcess -SetLastError), (func advapi32 OpenProcessToken ([bool]) @( [IntPtr], #_In_ HANDLE ProcessHandle [UInt32], #_In_ DWORD DesiredAccess [IntPtr].MakeByRefType() #_Out_ PHANDLE TokenHandle ) -EntryPoint OpenProcessToken -SetLastError), (func kernel32 OpenThread ([IntPtr]) @( [UInt32], #_In_ DWORD dwDesiredAccess [bool], #_In_ BOOL bInheritHandle [UInt32] #_In_ DWORD dwThreadId ) -EntryPoint OpenThread -SetLastError), (func advapi32 OpenThreadToken ([bool]) @( [IntPtr], #_In_ HANDLE ThreadHandle [UInt32], #_In_ DWORD DesiredAccess [bool], #_In_ BOOL OpenAsSelf [IntPtr].MakeByRefType() #_Out_ PHANDLE TokenHandle ) -EntryPoint OpenThreadToken -SetLastError), (func kernel32 QueryFullProcessImageName ([bool]) @( [IntPtr], #_In_ HANDLE hProcess [UInt32], #_In_ DWORD dwFlags, [System.Text.StringBuilder], #_Out_ LPTSTR lpExeName, [UInt32].MakeByRefType() #_Inout_ PDWORD lpdwSize ) -EntryPoint QueryFullProcessImageName -SetLastError), (func kernel32 ReadProcessMemory ([Bool]) @( [IntPtr], # _In_ HANDLE hProcess [IntPtr], # _In_ LPCVOID lpBaseAddress [Byte[]], # _Out_ LPVOID lpBuffer [Int32], # _In_ SIZE_T nSize [Int32].MakeByRefType() # _Out_ SIZE_T *lpNumberOfBytesRead ) -EntryPoint ReadProcessMemory -SetLastError), (func advapi32 RevertToSelf ([bool]) @( # No Parameters ) -EntryPoint RevertToSelf -SetLastError), (func kernel32 Thread32First ([bool]) @( [IntPtr], #_In_ HANDLE hSnapshot, $THREADENTRY32.MakeByRefType() #_Inout_ LPTHREADENTRY32 lpte ) -EntryPoint Thread32First -SetLastError), (func kernel32 Thread32Next ([bool]) @( [IntPtr], #_In_ HANDLE hSnapshot, $THREADENTRY32.MakeByRefType() #_Out_ LPTHREADENTRY32 lpte ) -EntryPoint Thread32Next -SetLastError), (func kernel32 VirtualQueryEx ([Int32]) @( [IntPtr], #_In_ HANDLE hProcess, [IntPtr], #_In_opt_ LPCVOID lpAddress, $MEMORY_BASIC_INFORMATION.MakeByRefType(), #_Out_ PMEMORY_BASIC_INFORMATION lpBuffer, [UInt32] #_In_ SIZE_T dwLength ) -EntryPoint VirtualQueryEx -SetLastError) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Module -Namespace ACE $advapi32 = $Types['advapi32'] $iphlpapi = $Types['iphlpapi'] $kernel32 = $Types['kernel32'] $ntdll = $Types['ntdll'] $secur32 = $Types['secur32'] #endregion Function Definitions #region API Abstractions function CloseHandle { <# .SYNOPSIS Closes an open object handle. .DESCRIPTION The CloseHandle function closes handles to the following objects: - Access token - Communications device - Console input - Console screen buffer - Event - File - File mapping - I/O completion port - Job - Mailslot - Memory resource notification - Mutex - Named pipe - Pipe - Process - Semaphore - Thread - Transaction - Waitable timer The documentation for the functions that create these objects indicates that CloseHandle should be used when you are finished with the object, and what happens to pending operations on the object after the handle is closed. In general, CloseHandle invalidates the specified object handle, decrements the object's handle count, and performs object retention checks. After the last handle to an object is closed, the object is removed from the system. .PARAMETER Handle A valid handle to an open object. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect Optional Dependencies: None (func kernel32 CloseHandle ([bool]) @( [IntPtr] #_In_ HANDLE hObject ) -EntryPoint CloseHandle -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $Handle ) $SUCCESS = $Kernel32::CloseHandle($Handle); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $SUCCESS) { Write-Debug "CloseHandle Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } } function ConvertSidToStringSid { <# .SYNOPSIS The ConvertSidToStringSid function converts a security identifier (SID) to a string format suitable for display, storage, or transmission. .DESCRIPTION The ConvertSidToStringSid function uses the standard S-R-I-S-S… format for SID strings. .PARAMETER SidPointer A pointer to the SID structure to be converted. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect Optional Dependencies: None (func advapi32 ConvertSidToStringSid ([bool]) @( [IntPtr] #_In_ PSID Sid, [IntPtr].MakeByRefType() #_Out_ LPTSTR *StringSid ) -EntryPoint ConvertSidToStringSid -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa376399(v=vs.85).aspx .EXAMPLE #> [OutputType([string])] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [IntPtr] $SidPointer ) $StringPtr = [IntPtr]::Zero $Success = $Advapi32::ConvertSidToStringSid($SidPointer, [ref]$StringPtr); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { Write-Verbose "ConvertSidToStringSid Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto($StringPtr)) } function CreateToolhelp32Snapshot { <# .SYNOPSIS Takes a snapshot of the specified processes, as well as the heaps, modules, and threads used by these processes. .DESCRIPTION The snapshot taken by this function is examined by the other tool help functions to provide their results. Access to the snapshot is read only. The snapshot handle acts as an object handle and is subject to the same rules regarding which processes and threads it is valid in. To enumerate the heap or module states for all processes, specify TH32CS_SNAPALL and set th32ProcessID to zero. Then, for each additional process in the snapshot, call CreateToolhelp32Snapshot again, specifying its process identifier and the TH32CS_SNAPHEAPLIST or TH32_SNAPMODULE value. When taking snapshots that include heaps and modules for a process other than the current process, the CreateToolhelp32Snapshot function can fail or return incorrect information for a variety of reasons. For example, if the loader data table in the target process is corrupted or not initialized, or if the module list changes during the function call as a result of DLLs being loaded or unloaded, the function might fail with ERROR_BAD_LENGTH or other error code. Ensure that the target process was not started in a suspended state, and try calling the function again. If the function fails with ERROR_BAD_LENGTH when called with TH32CS_SNAPMODULE or TH32CS_SNAPMODULE32, call the function again until it succeeds. The TH32CS_SNAPMODULE and TH32CS_SNAPMODULE32 flags do not retrieve handles for modules that were loaded with the LOAD_LIBRARY_AS_DATAFILE or similar flags. For more information, see LoadLibraryEx. To destroy the snapshot, use the CloseHandle function. Note that you can use the QueryFullProcessImageName function to retrieve the full name of an executable image for both 32- and 64-bit processes from a 32-bit process. .PARAMETER ProcessId The process identifier of the process to be included in the snapshot. This parameter can be zero to indicate the current process. This parameter is used when the TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, TH32CS_SNAPMODULE32, or TH32CS_SNAPALL value is specified. Otherwise, it is ignored and all processes are included in the snapshot. If the specified process is the Idle process or one of the CSRSS processes, this function fails and the last error code is ERROR_ACCESS_DENIED because their access restrictions prevent user-level code from opening them. If the specified process is a 64-bit process and the caller is a 32-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299). .PARAMETER Flags The portions of the system to be included in the snapshot. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect Optional Dependencies: TH32CS (Enumeration) (func kernel32 CreateToolhelp32Snapshot ([IntPtr]) @( [UInt32], #_In_ DWORD dwFlags, [UInt32] #_In_ DWORD th32ProcessID ) -EntryPoint CreateToolhelp32Snapshot -SetLastError) .LINK .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [UInt32] $ProcessId, [Parameter(Mandatory = $true)] [UInt32] $Flags ) $hSnapshot = $Kernel32::CreateToolhelp32Snapshot($Flags, $ProcessId); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $hSnapshot) { Write-Debug "CreateToolhelp32Snapshot Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hSnapshot } function DuplicateToken { <# .SYNOPSIS The DuplicateToken function creates a new access token that duplicates one already in existence. .DESCRIPTION The DuplicateToken function creates an impersonation token, which you can use in functions such as SetThreadToken and ImpersonateLoggedOnUser. The token created by DuplicateToken cannot be used in the CreateProcessAsUser function, which requires a primary token. To create a token that you can pass to CreateProcessAsUser, use the DuplicateTokenEx function. .PARAMETER TokenHandle A handle to an access token opened with TOKEN_DUPLICATE access. .PARAMETER ImpersonationLevel Specifies a SECURITY_IMPERSONATION_LEVEL enumerated type that supplies the impersonation level of the new token. The Default is SecurityImpersonation. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, SECURITY_IMPERSONATION_LEVEL (Enumeration) Optional Dependencies: None (func advapi32 DuplicateToken ([bool]) @( [IntPtr] #_In_ HANDLE ExistingTokenHandle, [UInt32] #_In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, [IntPtr].MakeByRefType() #_Out_ PHANDLE DuplicateTokenHandle ) -EntryPoint DuplicateToken -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa446616(v=vs.85).aspx .EXAMPLE #> [OutputType([IntPtr])] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [IntPtr] $TokenHandle, [Parameter()] [ValidateSet('None','SecurityAnonymous','SecurityIdentification','SecurityImpersonation','SecurityDelegation')] [string] $ImpersonationLevel = 'SecurityImpersonation' ) $DuplicateTokenHandle = [IntPtr]::Zero $success = $Advapi32::DuplicateToken($TokenHandle, $SECURITY_IMPERSONATION_LEVEL::$ImpersonationLevel, [ref]$DuplicateTokenHandle); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $success) { Write-Debug "DuplicateToken Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $DuplicateTokenHandle } function EnumerateSecurityPackages { <# .SYNOPSIS The EnumerateSecurityPackages function returns an array of SecPkgInfo structures that provide information about the security packages available to the client. .DESCRIPTION The caller can use the Name member of a SecPkgInfo structure to specify a security package in a call to the AcquireCredentialsHandle (General) function. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: FreeContextBuffer (function), SecPkgInfo (Structure), SECPKG_FLAG (Enumeration) Optional Dependencies: None (func secur32 EnumerateSecurityPackages ([UInt32]) @( [UInt32].MakeByRefType(), #_In_ PULONG pcPackages [IntPtr].MakeByRefType() #_In_ PSecPkgInfo *ppPackageInfo ) -EntryPoint EnumerateSecurityPackages) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa375397(v=vs.85).aspx .EXAMPLE PS > EnumerateSecurityPackages Name : Negotiate Comment : Microsoft Package Negotiator Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, NEGOTIABLE, GSS_COMPATIBLE, LOGON, RESTRICTED_TOKENS, APPCONTAINER_CHECKS Version : 1 RpcId : 9 MaxToken : 65791 Name : NegoExtender Comment : NegoExtender Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, IMPERSONATION, NEGOTIABLE, GSS_COMPATIBLE, LOGON, MUTUAL_AUTH, NEGO_EXTENDER, APPCONTAINER_CHECKS Version : 1 RpcId : 30 MaxToken : 12000 Name : Kerberos Comment : Microsoft Kerberos V1.0 Capabilities : INTEGRITY, PRIVACY, TOKEN_ONLY, DATAGRAM, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, NEGOTIABLE, GSS_COMPATIBLE, LOGON, MUTUAL_AUTH, DELEGATION, READONLY_WITH_CHECKSUM, RESTRICTED_TOKENS, APPCONTAINER_CHECKS Version : 1 RpcId : 16 MaxToken : 65535 Name : NTLM Comment : NTLM Security Package Capabilities : INTEGRITY, PRIVACY, TOKEN_ONLY, CONNECTION, MULTI_REQUIRED, IMPERSONATION, ACCEPT_WIN32_NAME, NEGOTIABLE, LOGON, RESTRICTED_TOKENS, APPCONTAINER_CHECKS Version : 1 RpcId : 10 MaxToken : 2888 Name : TSSSP Comment : TS Service Security Package Capabilities : CONNECTION, MULTI_REQUIRED, ACCEPT_WIN32_NAME, MUTUAL_AUTH, APPCONTAINER_CHECKS Version : 1 RpcId : 22 MaxToken : 13000 Name : pku2u Comment : PKU2U Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, IMPERSONATION, GSS_COMPATIBLE, MUTUAL_AUTH, NEGOTIABLE2, APPCONTAINER_CHECKS Version : 1 RpcId : 31 MaxToken : 12000 Name : CloudAP Comment : Cloud AP Security Package Capabilities : LOGON, NEGOTIABLE2 Version : 1 RpcId : 36 MaxToken : 0 Name : WDigest Comment : Digest Authentication for Windows Capabilities : TOKEN_ONLY, IMPERSONATION, ACCEPT_WIN32_NAME, APPCONTAINER_CHECKS Version : 1 RpcId : 21 MaxToken : 4096 Name : Schannel Comment : Schannel Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, STREAM, MUTUAL_AUTH, APPCONTAINER_PASSTHROUGH Version : 1 RpcId : 14 MaxToken : 24576 Name : Microsoft Unified Security Protocol Provider Comment : Schannel Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, STREAM, MUTUAL_AUTH, APPCONTAINER_PASSTHROUGH Version : 1 RpcId : 14 MaxToken : 24576 Name : CREDSSP Comment : Microsoft CredSSP Security Provider Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, IMPERSONATION, ACCEPT_WIN32_NAME, STREAM, MUTUAL_AUTH, APPCONTAINER_CHECKS Version : 1 RpcId : 65535 MaxToken : 90567 #> $PackageCount = 0 $PackageInfo = [IntPtr]::Zero $SUCCESS = $Secur32::EnumerateSecurityPackages([ref]$PackageCount, [ref]$PackageInfo) if($SUCCESS -ne 0) { throw "EnumerateSecurityPackages Error: $($SUCCESS)" } for($i = 0; $i -lt $PackageCount; $i++) { $PackagePtr = [IntPtr]($PackageInfo.ToInt64() + ($SecPkgInfo::GetSize() * $i)) $Package = $PackagePtr -as $SecPkgInfo $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Name -Value ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto($Package.Name)) $obj | Add-Member -MemberType NoteProperty -Name Comment -Value ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto($Package.Comment)) $obj | Add-Member -MemberType NoteProperty -Name Capabilities -Value $Package.Capabilities $obj | Add-Member -MemberType NoteProperty -Name Version -Value $Package.Version $obj | Add-Member -MemberType NoteProperty -Name RpcId -Value $Package.RPCID $obj | Add-Member -MemberType NoteProperty -Name MaxToken -Value $Package.MaxToken Write-Output $obj } FreeContextBuffer -Buffer $PackageInfo } function FreeContextBuffer { <# .SYNOPSIS The FreeContextBuffer function enables callers of security package functions to free memory buffers allocated by the security package. .DESCRIPTION Memory buffers are typically allocated by the InitializeSecurityContext (General) and AcceptSecurityContext (General) functions. The FreeContextBuffer function can free any memory allocated by a security package. .PARAMETER Buffer A pointer to memory to be freed. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None (func secur32 FreeContextBuffer ([UInt32]) @( [IntPtr] #_In_ PVOID pvContextBuffer ) -EntryPoint FreeContextBuffer) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa375416(v=vs.85).aspx .EXAMPLE PS > $PackageCount = 0 PS > $PackageInfo = [IntPtr]::Zero PS > $SUCCESS = $Secur32::EnumerateSecurityPackages([ref]$PackageCount, [ref]$PackageInfo) # # Do Stuff ... # PS > FreeContextBuffer -Buffer $PackageInfo #> param ( [Parameter(Mandatory = $true)] [IntPtr] $Buffer ) $SUCCESS = $Secur32::FreeContextBuffer($Buffer) if($SUCCESS -ne 0) { throw "FreeContextBuffer Error: $($SUCCESS)" } } function GetIpNetTable { <# .SYNOPSIS Retreives the IPv4 to physical address mapping table. .DESCRIPTION The GetIpNetTable function enumerates the Address Resolution Protocol (ARP) entries for IPv4 on a local system from the IPv4 to physical address mapping table and returns this information in a MIB_IPNETTABLE structure. on Windows Vista and later, the GetIpNetTable2 function can be used to retrieve the neighbor IP addresses for both IPv6 and IPv4. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: MIB_IPNETROW (Struct), MIB_IPNET_TYPE (Enum) Optional Dependencies: None (func iphlpapi GetIpNetTable ([Int32]) @( [IntPtr], #_Out_ PMIB_IPNETTABLE pIpNetTable [Int32].MakeByRefType(), #_Inout_ PULONG pdwSize [bool] #_In_ BOOL bOrder )) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa365956%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 .EXAMPLE GetIpNetTable AdapterIndex PhysicalAddress IpAddress Type ------------ --------------- --------- ---- 14 00-50-56-C0-00-08 192.168.1.1 DYNAMIC 14 00-50-56-F8-64-30 192.168.1.2 DYNAMIC 14 00-0C-29-BB-51-6D 192.168.1.137 DYNAMIC 14 00-00-00-00-00-00 192.168.1.254 INVALID 14 FF-FF-FF-FF-FF-FF 192.168.1.255 STATIC 14 01-00-5E-00-00-16 224.0.0.22 STATIC 14 01-00-5E-00-00-FC 224.0.0.252 STATIC 14 01-00-5E-7F-FF-FA 239.255.255.250 STATIC 14 FF-FF-FF-FF-FF-FF 255.255.255.255 STATIC 1 00-00-00-00-00-00 224.0.0.22 STATIC 1 00-00-00-00-00-00 224.0.0.252 STATIC 1 00-00-00-00-00-00 239.255.255.250 STATIC 11 01-00-5E-00-00-16 224.0.0.22 STATIC 10 01-00-5E-00-00-16 224.0.0.22 STATIC #> $pThrowAway = [IntPtr]::Zero $dwSize = [Int32]0 # Run the function once to get the size of the MIB_NETTABLE Structure $SUCCESS = $iphlpapi::GetIpNetTable($pThrowAway, [ref]$dwSize, $false) # ERROR_INSUFFICIENT_BUFFER means that $dwSize now contains the size of the stucture if($SUCCESS -eq 122) { $pIpNetTable = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($dwSize) $SUCCESS = $iphlpapi::GetIpNetTable($pIpNetTable, [ref]$dwSize, $false) if($SUCCESS -eq 0) { $count = [System.Runtime.InteropServices.Marshal]::ReadInt32($pIpNetTable) for($i = 0; $i -lt $count; $i++) { $CurrentPtr = [IntPtr]($pIpNetTable.ToInt64() + 4 + ($i * 24)) $IpNetRow = $CurrentPtr -as $MIB_IPNETROW [byte[]]$bAddress = $IpNetRow.bPhysAddr $obj = @{ AdapterIndex = $IpNetRow.dwIndex PhysicalAddress = [System.BitConverter]::ToString($bAddress).Replace('-',':') IpAddress = [string]((New-Object -TypeName System.Net.IPAddress($IpNetRow.dwAddr)).IPAddressToString) Type = [string]($IpNetRow.dwType -as $MIB_IPNET_TYPE) } Write-Output $obj } } } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($pIpNetTable) } function GetTokenInformation { <# .SYNOPSIS The GetTokenInformation function retrieves a specified type of information about an access token. The calling process must have appropriate access rights to obtain the information. To determine if a user is a member of a specific group, use the CheckTokenMembership function. To determine group membership for app container tokens, use the CheckTokenMembershipEx function. .PARAMETER TokenHandle A handle to an access token from which information is retrieved. If TokenInformationClass specifies TokenSource, the handle must have TOKEN_QUERY_SOURCE access. For all other TokenInformationClass values, the handle must have TOKEN_QUERY access. .PARAMETER TokenInformationClass Specifies a value from the TOKEN_INFORMATION_CLASS enumerated type to identify the type of information the function retrieves. Any callers who check the TokenIsAppContainer and have it return 0 should also verify that the caller token is not an identify level impersonation token. If the current token is not an app container but is an identity level token, you should return AccessDenied. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Module Dependencies: PSReflect Required Function Dependencies: ConvertSidToStringSid Required Structure Dependencies: TOKEN_USER, SID_AND_ATTRIBUTES, TOKEN_PRIVILEGES, TOKEN_OWNER, TOKEN_SOURCE, LUID, TOKEN_MANDATORY_LABEL Required Enumeration Dependencies: LuidAttributes, TOKEN_TYPE, SECURITY_IMPERSONATION_LEVEL Optional Dependencies: TokenInformationClass (Enum) (func advapi32 GetTokenInformation ([bool]) @( [IntPtr], #_In_ HANDLE TokenHandle [Int32], #_In_ TOKEN_INFORMATION_CLASS TokenInformationClass [IntPtr], #_Out_opt_ LPVOID TokenInformation [UInt32], #_In_ DWORD TokenInformationLength [UInt32].MakeByRefType() #_Out_ PDWORD ReturnLength ) -EntryPoint GetTokenInformation -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa446671(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $TokenHandle, [Parameter(Mandatory = $true)] [ValidateSet('TokenUser','TokenGroups','TokenPrivileges','TokenOwner','TokenPrimaryGroup','TokenDefaultDacl','TokenSource','TokenType','TokenImpersonationLevel','TokenStatistics','TokenRestrictedSids','TokenSessionId','TokenGroupsAndPrivileges','TokenSandBoxInert','TokenOrigin','TokenElevationType','TokenLinkedToken','TokenElevation','TokenHasRestrictions','TokenAccessInformation','TokenVirtualizationAllowed','TokenVirtualizationEnabled','TokenIntegrityLevel','TokenUIAccess','TokenMandatoryPolicy','TokenLogonSid','TokenIsAppContainer','TokenCapabilities','TokenAppContainerSid','TokenAppContainerNumber','TokenUserClaimAttributes','TokenDeviceClaimAttributes','TokenDeviceGroups','TokenRestrictedDeviceGroups')] [string] $TokenInformationClass ) # initial query to determine the necessary buffer size $TokenPtrSize = 0 $SUCCESS = $Advapi32::GetTokenInformation($TokenHandle, $TOKEN_INFORMATION_CLASS::$TokenInformationClass, [IntPtr]::Zero, $TokenPtrSize, [ref]$TokenPtrSize); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() [IntPtr]$TokenPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenPtrSize) # retrieve the proper buffer value $SUCCESS = $Advapi32::GetTokenInformation($TokenHandle, $TOKEN_INFORMATION_CLASS::$TokenInformationClass, $TokenPtr, $TokenPtrSize, [ref]$TokenPtrSize); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $SUCCESS) { [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPtr) throw "GetTokenInformation Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } switch($TokenInformationClass) { TokenUser { <# The buffer receives a TOKEN_USER structure that contains the user account of the token. ConvertSidToStringSid (Function) TOKEN_USER (Structure) SID_AND_ATTRIBUTES (Structure) #> $TokenUser = $TokenPtr -as $TOKEN_USER $UserSid = ConvertSidToStringSid -SidPointer $TokenUser.User.Sid $Sid = New-Object System.Security.Principal.SecurityIdentifier($UserSid) $UserName = $Sid.Translate([System.Security.Principal.NTAccount]) $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value $UserSid $obj | Add-Member -MemberType NoteProperty -Name Name -Value $UserName Write-Output $obj } TokenGroups { <# The buffer receives a TOKEN_GROUPS structure that contains the group accounts associated with the token. TOKEN_GROUPS (Structure) SID_AND_ATTRIBUTES (Structure) #> $TokenGroups = ($TokenPtr -as $TOKEN_GROUPS) for($i = 0; $i -lt $TokenGroups.GroupCount; $i++) { $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value (ConvertSidToStringSid -SidPointer $TokenGroups.Groups[$i].Sid) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $TokenGroups.Groups[$i].Attributes Write-Output $obj } } TokenPrivileges { <# The buffer receives a TOKEN_PRIVILEGES structure that contains the privileges of the token. TOKEN_PRIVILEGES (Structure) LUID_AND_ATTRIBUTES (Structure) LuidAttributes (Enumeration) #> $TokenPrivileges = $TokenPtr -as $TOKEN_PRIVILEGES for($i = 0; $i -lt $TokenPrivileges.PrivilegeCount; $i++) { $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Privilege -Value (LookupPrivilegeName -PrivilegeValue $TokenPrivileges.Privileges[$i].Luid.LowPart) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $TokenPrivileges.Privileges[$i].Attributes Write-Output $obj } } TokenOwner { <# The buffer receives a TOKEN_OWNER structure that contains the default owner security identifier (SID) for newly created objects. ConvertSidToStringSid (Function) TOKEN_OWNER (Structure) #> $TokenOwner = $TokenPtr -as $TOKEN_OWNER if($TokenOwner.Owner -ne $null) { $OwnerSid = ConvertSidToStringSid -SidPointer $TokenOwner.Owner $Sid = New-Object System.Security.Principal.SecurityIdentifier($OwnerSid) $OwnerName = $Sid.Translate([System.Security.Principal.NTAccount]) $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value $OwnerSid $obj | Add-Member -MemberType NoteProperty -Name Name -Value $OwnerName Write-Output $obj } else { Write-Output $null } } TokenPrimaryGroup { <# The buffer receives a TOKEN_PRIMARY_GROUP structure that contains the default primary group SID for newly created objects. TOKEN_PRIMARY_GROUP (Structure) #> throw [System.NotImplementedException]"The $($TokenInformationClass) class is not implemented yet." } TokenDefaultDacl { <# The buffer receives a TOKEN_DEFAULT_DACL structure that contains the default DACL for newly created objects. TOKEN_DEFAULT_DACL (Structure) ACL (Structure) #> $Dacl = $TokenPtr -as $TOKEN_DEFAULT_DACL Write-Output $Dacl.DefaultDacl } TokenSource { <# The buffer receives a TOKEN_SOURCE structure that contains the source of the token. TOKEN_QUERY_SOURCE access is needed to retrieve this information. TOKEN_SOURCE (Structure) LUID (Structure) #> Write-Output $TokenPtr #$TokenSource = $TokenPtr -as $TOKEN_SOURCE #Write-Output ($TokenSource.SourceName -join "") } TokenType { <# The buffer receives a TOKEN_TYPE value that indicates whether the token is a primary or impersonation token. TOKEN_TYPE (Enumeration) #> if($TokenPtr -ne $null) { Write-Output ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr) -as $TOKEN_TYPE) } } TokenImpersonationLevel { <# The buffer receives a SECURITY_IMPERSONATION_LEVEL value that indicates the impersonation level of the token. If the access token is not an impersonation token, the function fails. SECURITY_IMPERSONATION_LEVEL (Enumeration) #> Write-Output ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr) -as $SECURITY_IMPERSONATION_LEVEL) } TokenStatistics { <# The buffer receives a TOKEN_STATISTICS structure that contains various token statistics. TOKEN_STATISTICS (Structure) LUID (Structure) TOKEN_TYPE (Enumeration) SECURITY_IMPERSONATION_LEVEL (Enumeration) #> $TokenStats = $TokenPtr -as $TOKEN_STATISTICS $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name TokenId -Value $TokenStats.TokenId.LowPart $obj | Add-Member -MemberType NoteProperty -Name AuthenticationId -Value $TokenStats.AuthenticationId.LowPart $obj | Add-Member -MemberType NoteProperty -Name TokenType -Value $TokenStats.TokenType $obj | Add-Member -MemberType NoteProperty -Name ImpersonationLevel -Value $TokenStats.ImpersonationLevel $obj | Add-Member -MemberType NoteProperty -Name DynamicCharged -Value $TokenStats.DynamicCharged $obj | Add-Member -MemberType NoteProperty -Name DynamicAvailable -Value $TokenStats.DynamicAvailable $obj | Add-Member -MemberType NoteProperty -Name GroupCount -Value $TokenStats.GroupCount $obj | Add-Member -MemberType NoteProperty -Name PrivilegeCount -Value $TokenStats.PrivilegeCount $obj | Add-Member -MemberType NoteProperty -Name ModifiedId -Value $TokenStats.ModifiedId.LowPart Write-Output $obj } TokenRestrictedSids { <# The buffer receives a TOKEN_GROUPS structure that contains the list of restricting SIDs in a restricted token. TOKEN_GROUPS (Structure) SID_AND_ATTRIBUTES (Structure) #> $TokenGroups = ($TokenPtr -as $TOKEN_GROUPS) for($i = 0; $i -lt $TokenGroups.GroupCount; $i++) { $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value (ConvertSidToStringSid -SidPointer $TokenGroups.Groups[$i].Sid) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $TokenGroups.Groups[$i].Attributes Write-Output $obj } } TokenSessionId { # The buffer receives a DWORD value that indicates the Terminal Services session identifier that is associated with the token. # If the token is associated with the terminal server client session, the session identifier is nonzero. # Windows Server 2003 and Windows XP: If the token is associated with the terminal server console session, the session identifier is zero. # In a non-Terminal Services environment, the session identifier is zero. # If TokenSessionId is set with SetTokenInformation, the application must have the Act As Part Of the Operating System privilege, and the application must be enabled to set the session ID in a token. Write-Output ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr)) } TokenGroupsAndPrivileges { <# The buffer receives a TOKEN_GROUPS_AND_PRIVILEGES structure that contains the user SID, the group accounts, the restricted SIDs, and the authentication ID associated with the token. TOKEN_GROUPS_AND_PRIVILEGES (Structure) SID_AND_ATTRIBUTES (Structure) LUID (Structure) #> $GroupsAndPrivs = ($TokenPtr -as $TOKEN_GROUPS_AND_PRIVILEGES) $SidList = New-Object -TypeName 'System.Collections.Generic.List[System.Object]' for($i = 0; $i -lt $GroupsAndPrivs.SidCount; $i++) { $currentPtr = [IntPtr]($GroupsAndPrivs.Sids.ToInt64() + ($SID_AND_ATTRIBUTES::GetSize() * $i)) $SidAndAttr = $currentPtr -as $SID_AND_ATTRIBUTES $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value (ConvertSidToStringSid -SidPointer $SidAndAttr.Sid) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $SidAndAttr.Attributes $SidList.Add($obj) } $PrivList = New-Object -TypeName 'System.Collections.Generic.List[System.Object]' for($i = 0; $i -lt $GroupsAndPrivs.PrivilegeCount; $i++) { $currentPtr = [IntPtr]($GroupsAndPrivs.Privileges.ToInt64() + ($LUID_AND_ATTRIBUTES::GetSize() * $i)) $LuidAndAttr = ($currentPtr -as $LUID_AND_ATTRIBUTES) $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Privilege -Value $LuidAndAttr.Luid.LowPart $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $LuidAndAttr.Attributes $PrivList.Add($obj) } $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sids -Value $SidList.ToArray() $obj | Add-Member -MemberType NoteProperty -Name Privilegs -Value $PrivList.ToArray() Write-Output $obj } TokenSandBoxInert { # The buffer receives a DWORD value that is nonzero if the token includes the SANDBOX_INERT flag. Write-Output (0 -ne ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr))) } TokenOrigin { <# The buffer receives a TOKEN_ORIGIN value. If the token resulted from a logon that used explicit credentials, such as passing a name, domain, and password to the LogonUser function, then the TOKEN_ORIGIN structure will contain the ID of the logon session that created it. If the token resulted from network authentication, such as a call to AcceptSecurityContext or a call to LogonUser with dwLogonType set to LOGON32_LOGON_NETWORK or LOGON32_LOGON_NETWORK_CLEARTEXT, then this value will be zero. TOKEN_ORIGIN (Structure) LUID (Structure) #> $TokenOrigin = $TokenPtr -as $LUID Write-Output $TokenOrigin.LowPart } TokenElevationType { <# The buffer receives a TOKEN_ELEVATION_TYPE value that specifies the elevation level of the token. TOKEN_ELEVATION_TYPE (Enumeration) #> Write-Output ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr) -as $TOKEN_ELEVATION_TYPE) } TokenLinkedToken { <# The buffer receives a TOKEN_LINKED_TOKEN structure that contains a handle to another token that is linked to this token. TOKEN_LINKED_TOKEN (Structure) #> Write-Output ($TokenPtr -as $TOKEN_LINKED_TOKEN).LinkedToken } TokenElevation { <# The buffer receives a TOKEN_ELEVATION structure that specifies whether the token is elevated. TOKEN_ELEVATION (Structure) #> Write-Output (($TokenPtr -as $TOKEN_ELEVATION).TokenIsElevated -ne 0) } TokenHasRestrictions { # The buffer receives a DWORD value that is nonzero if the token has ever been filtered. Write-Output (0 -ne ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr))) } TokenAccessInformation { <# The buffer receives a TOKEN_ACCESS_INFORMATION structure that specifies security information contained in the token. TOKEN_ACCESS_INFORMATION (Structure) SID_AND_ATTRIBUTES_HASH (Structure) SID_HASH_ENTRY (Structure) TOKEN_PRIVILEGES (Structure) LUID_AND_ATTRIBUTES (Structure) LUID (Structure) TOKEN_TYPE (Enumeration) SECURITY_IMPERSONATION_LEVEL (Enumeration) TOKEN_MANDATORY_POLICY (Structure) #> <# $TokenAccessInfo = ($TokenPtr -as $TOKEN_ACCESS_INFORMATION) $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name SidHash -Value ($TokenAccessInfo.SidHash -as $SID_AND_ATTRIBUTES_HASH) $obj | Add-Member -MemberType NoteProperty -Name RestrictedSidHash -Value ($TokenAccessInfo.RestrictedSidHash -as $SID_AND_ATTRIBUTES_HASH) $obj | Add-Member -MemberType NoteProperty -Name Privileges -Value ($TokenAccessInfo.Privileges -as $TOKEN_PRIVILEGES) $obj | Add-Member -MemberType NoteProperty -Name AuthenticationId -Value $TokenAccessInfo.AuthenticationId.LowPart $obj | Add-Member -MemberType NoteProperty -Name TokenType -Value $TokenAccessInfo.TokenType $obj | Add-Member -MemberType NoteProperty -Name ImpersonationLevel -Value $TokenAccessInfo.ImpersonationLevel $obj | Add-Member -MemberType NoteProperty -Name AppContainerNumber -Value $TokenAccessInfo.AppContainerNumber $obj | Add-Member -MemberType NoteProperty -Name PackageSid -Value (ConvertSidToStringSid -SidPointer $TokenAccessInfo.PackageSid) $obj | Add-Member -MemberType NoteProperty -Name CapabilitiesHash -Value ($TokenAccessInfo.CapabilitiesHash -as $SID_AND_ATTRIBUTES_HASH) $obj | Add-Member -MemberType NoteProperty -Name TrustLevelSid -Value (ConvertSidToStringSid -SidPointer $TokenAccessInfo.TrustLevelSid) Write-Output $obj #> Write-Output $TokenPtr #throw [System.NotImplementedException]"The $($TokenInformationClass) class is not implemented yet." } TokenVirtualizationAllowed { # The buffer receives a DWORD value that is nonzero if virtualization is allowed for the token. Write-Output (0 -ne ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr))) } TokenVirtualizationEnabled { # The buffer receives a DWORD value that is nonzero if virtualization is enabled for the token. Write-Output (0 -ne ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr))) } TokenIntegrityLevel { <# The buffer receives a TOKEN_MANDATORY_LABEL structure that specifies the token's integrity level. TOKEN_MANDATORY_LABEL ConvertSidToStringSid #> $TokenIntegrity = $TokenPtr -as $TOKEN_MANDATORY_LABEL switch(ConvertSidToStringSid -SidPointer $TokenIntegrity.Label.Sid) { S-1-16-0 { Write-Output "UNTRUSTED_MANDATORY_LEVEL" } S-1-16-4096 { Write-Output "LOW_MANDATORY_LEVEL" } S-1-16-8192 { Write-Output "MEDIUM_MANDATORY_LEVEL" } S-1-16-8448 { Write-Output "MEDIUM_PLUS_MANDATORY_LEVEL" } S-1-16-12288 { Write-Output "HIGH_MANDATORY_LEVEL" } S-1-16-16384 { Write-Output "SYSTEM_MANDATORY_LEVEL" } S-1-16-20480 { Write-Output "PROTECTED_PROCESS_MANDATORY_LEVEL" } S-1-16-28672 { Write-Output "SECURE_PROCESS_MANDATORY_LEVEL" } } } TokenUIAccess { # The buffer receives a DWORD value that is nonzero if the token has the UIAccess flag set. Write-Output (0 -ne ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr))) } TokenMandatoryPolicy { <# The buffer receives a TOKEN_MANDATORY_POLICY structure that specifies the token's mandatory integrity policy. TOKEN_MANDATORY_POLICY TOKENMANDATORYPOLICY #> $MandatoryPolicy = $TokenPtr -as $TOKEN_MANDATORY_POLICY Write-Output $MandatoryPolicy.Policy } TokenLogonSid { <# The buffer receives a TOKEN_GROUPS structure that specifies the token's logon SID. TOKEN_GROUPS (Structure) SID_AND_ATTRIBUTES (Structure) #> $TokenGroups = ($TokenPtr -as $TOKEN_GROUPS) for($i = 0; $i -lt $TokenGroups.GroupCount; $i++) { $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value (ConvertSidToStringSid -SidPointer $TokenGroups.Groups[$i].Sid) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $TokenGroups.Groups[$i].Attributes Write-Output $obj } } TokenIsAppContainer { # The buffer receives a DWORD value that is nonzero if the token is an app container token. Any callers who check the TokenIsAppContainer and have it return 0 should also verify that the caller token is not an identify level impersonation token. If the current token is not an app container but is an identity level token, you should return AccessDenied. Write-Output (0 -ne ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr))) } TokenCapabilities { <# The buffer receives a TOKEN_GROUPS structure that contains the capabilities associated with the token. TOKEN_GROUPS (Structure) SID_AND_ATTRIBUTES (Structure) #> $TokenGroups = ($TokenPtr -as $TOKEN_GROUPS) for($i = 0; $i -lt $TokenGroups.GroupCount; $i++) { $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value (ConvertSidToStringSid -SidPointer $TokenGroups.Groups[$i].Sid) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $TokenGroups.Groups[$i].Attributes Write-Output $obj } } TokenAppContainerSid { <# The buffer receives a TOKEN_APPCONTAINER_INFORMATION structure that contains the AppContainerSid associated with the token. If the token is not associated with an app container, the TokenAppContainer member of the TOKEN_APPCONTAINER_INFORMATION structure points to NULL. TOKEN_APPCONTAINER_INFORMATION (Structure) #> Write-Output ($TokenPtr -as $TOKEN_APPCONTAINER_INFORMATION) } TokenAppContainerNumber { # The buffer receives a DWORD value that includes the app container number for the token. For tokens that are not app container tokens, this value is zero. Write-Output ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr)) } TokenUserClaimAttributes { <# The buffer receives a CLAIM_SECURITY_ATTRIBUTES_INFORMATION structure that contains the user claims associated with the token. CLAIM_SECURITY_ATTRIBUTES_INFORMATION (Structure) CLAIM_SECURITY_ATTRIBUTE_V1 (Structure) CLAIM_SECURITY_ATTRIBUTE_FQBN_VALUE (Structure) CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE (Structure) #> <# $AttributeInformation = $TokenPtr -as $CLAIM_SECURITY_ATTRIBUTES_INFORMATION if($AttributeInformation.AttributeCount -ne 0) { } #> throw [System.NotImplementedException]"The $($TokenInformationClass) class is not implemented yet." } TokenDeviceClaimAttributes { <# The buffer receives a CLAIM_SECURITY_ATTRIBUTES_INFORMATION structure that contains the device claims associated with the token. CLAIM_SECURITY_ATTRIBUTES_INFORMATION (Structure) CLAIM_SECURITY_ATTRIBUTE_V1 (Structure) CLAIM_SECURITY_ATTRIBUTE_FQBN_VALUE (Structure) CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE (Structure) #> <# $AttributeInformation = $TokenPtr -as $CLAIM_SECURITY_ATTRIBUTES_INFORMATION if($AttributeInformation.AttributeCount -ne 0) { } #> throw [System.NotImplementedException]"The $($TokenInformationClass) class is not implemented yet." } TokenDeviceGroups { <# The buffer receives a TOKEN_GROUPS structure that contains the device groups that are associated with the token. TOKEN_GROUPS (Structure) SID_AND_ATTRIBUTES (Structure) #> #Write-Output ($TokenPtr -as $TOKEN_GROUPS) $TokenGroups = ($TokenPtr -as $TOKEN_GROUPS) for($i = 0; $i -lt $TokenGroups.GroupCount; $i++) { $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value (ConvertSidToStringSid -SidPointer $TokenGroups.Groups[$i].Sid) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $TokenGroups.Groups[$i].Attributes Write-Output $obj } } TokenRestrictedDeviceGroups { <# The buffer receives a TOKEN_GROUPS structure that contains the restricted device groups that are associated with the token. TOKEN_GROUPS (Structure) SID_AND_ATTRIBUTES (Structure) #> $TokenGroups = ($TokenPtr -as $TOKEN_GROUPS) for($i = 0; $i -lt $TokenGroups.GroupCount; $i++) { $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value (ConvertSidToStringSid -SidPointer $TokenGroups.Groups[$i].Sid) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $TokenGroups.Groups[$i].Attributes Write-Output $obj } } } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPtr) } function GlobalGetAtomName { <# .SYNOPSIS Retrieves a copy of the character string associated with the specified global atom. .DESCRIPTION The string returned for an integer atom (an atom whose value is in the range 0x0001 to 0xBFFF) is a null-terminated string in which the first character is a pound sign (#) and the remaining characters represent the unsigned integer atom value. .PARAMETER AtomIndex The global atom (index) associated with the character string to be retrieved. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect Optional Dependencies: None (func kernel32 GlobalGetAtomName ([UInt32]) @( [UInt16], #_In_ ATOM nAtom [string].MakeByRefType(), #_Out_ LPTSTR lpBuffer [UInt16] #_In_ int nSize ) -EntryPoint GlobalGetAtomName -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms649063(v=vs.85).aspx .EXAMPLE #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [UInt16] $AtomIndex ) $AtomName = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(1024) $SUCCESS = $kernel32::GlobalGetAtomName($AtomIndex, $AtomName, 1024); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if($SUCCESS -eq 0) { throw "[GlobalGetAtomName]: Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output ([System.Runtime.InteropServices.Marshal]::PtrToStringUni($AtomName)) } function ImpersonateLoggedOnUser { <# .SYNOPSIS The ImpersonateLoggedOnUser function lets the calling thread impersonate the security context of a logged-on user. The user is represented by a token handle. .DESCRIPTION The impersonation lasts until the thread exits or until it calls RevertToSelf. The calling thread does not need to have any particular privileges to call ImpersonateLoggedOnUser. If the call to ImpersonateLoggedOnUser fails, the client connection is not impersonated and the client request is made in the security context of the process. If the process is running as a highly privileged account, such as LocalSystem, or as a member of an administrative group, the user may be able to perform actions they would otherwise be disallowed. Therefore, it is important to always check the return value of the call, and if it fails, raise an error; do not continue execution of the client request. All impersonate functions, including ImpersonateLoggedOnUser allow the requested impersonation if one of the following is true: - The requested impersonation level of the token is less than SecurityImpersonation, such as SecurityIdentification or SecurityAnonymous. - The caller has the SeImpersonatePrivilege privilege. - A process (or another process in the caller's logon session) created the token using explicit credentials through LogonUser or LsaLogonUser function. - The authenticated identity is same as the caller. Windows XP with SP1 and earlier: The SeImpersonatePrivilege privilege is not supported. .PARAMETER TokenHandle A handle to a primary or impersonation access token that represents a logged-on user. This can be a token handle returned by a call to LogonUser, CreateRestrictedToken, DuplicateToken, DuplicateTokenEx, OpenProcessToken, or OpenThreadToken functions. If hToken is a handle to a primary token, the token must have TOKEN_QUERY and TOKEN_DUPLICATE access. If hToken is a handle to an impersonation token, the token must have TOKEN_QUERY and TOKEN_IMPERSONATE access. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect Optional Dependencies: None (func advapi32 ImpersonateLoggedOnUser ([bool]) @( [IntPtr] #_In_ HANDLE hToken ) -EntryPoint ImpersonateLoggedOnUser -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378612(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $TokenHandle ) $SUCCESS = $Advapi32::ImpersonateLoggedOnUser($TokenHandle); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $SUCCESS) { throw "ImpersonateLoggedOnUser Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } } function LookupPrivilegeName { param ( [Parameter(Mandatory = $true)] [UInt32] $PrivilegeValue ) $L = [Activator]::CreateInstance($LUID) $L.LowPart = $PrivilegeValue $lpLuid = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($LUID::GetSize()) [System.Runtime.InteropServices.Marshal]::StructureToPtr($L, $lpLuid, $true) $lpName = New-Object -TypeName System.Text.StringBuilder $cchName = 0 $SUCCESS = $Advapi32::LookupPrivilegeName($null, $lpLuid, $lpName, [ref]$cchName); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() $lpName.EnsureCapacity($cchName + 1) | Out-Null $SUCCESS = $Advapi32::LookupPrivilegeName($null, $lpLuid, $lpName, [ref]$cchName); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $SUCCESS) { Write-Error "[LookupPrivilegeName] Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output ($lpName.ToString()) } function LookupPrivilegeDisplayName { param ( [Parameter(Mandatory = $true)] [string] $Privilege ) $lpDisplayName = New-Object -TypeName System.Text.StringBuilder $cchDisplayName = 0 $lpLanguageId = 0 $SUCCESS = $Advapi32::LookupPrivilegeDisplayName($null, $Privilege, $lpDisplayName, [ref]$cchDisplayName, [ref]$lpLanguageId) $lpDisplayName.EnsureCapacity($cchDisplayName + 1) | Out-Null $SUCCESS = $Advapi32::LookupPrivilegeDisplayName($null, $Privilege, $lpDisplayName, [ref]$cchDisplayName, [ref]$lpLanguageId); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $SUCCESS) { Write-Error "[LookupPrivilegeDisplayName] Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output ($lpDisplayName.ToString()) } function LsaCallAuthenticationPackage { <# .SYNOPSIS The LsaCallAuthenticationPackage function is used by a logon application to communicate with an authentication package. This function is typically used to access services provided by the authentication package. .DESCRIPTION Logon applications can call LsaCallAuthenticationPackage to communicate with an authentication package. There are several reasons why an application may do this: - To implement multiple-message authentication protocols, such as the NTLM Challenge-Response protocol. - To pass state change information to the authentication package. For example, the NTLM might notify the MSV1_0 package that a previously unreachable domain controller is now reachable. The authentication package would then re-logon any users logged on to that domain controller. Typically, this function is used to exchange information with a custom authentication package. This function is not needed by an application that is using one of the authentication packages supplied with Windows, such as MSV1_0 or Kerberos. You must call LsaCallAuthenticationPackage to clean up PKINIT device credentials for LOCAL_SYSTEM and NETWORK_SERVICE. When there is no PKINIT device credential, a successful call does no operation. When there is a PKINIT device credential, a successful call cleans up the PKINIT device credential so that only the password credential remains. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378261(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $LsaHandle, [Parameter()] [ValidateSet('MSV1_0_PACKAGE_NAME', 'MICROSOFT_KERBEROS_NAME_A', 'NEGOSSP_NAME_A', 'NTLMSP_NAME_A')] [string] $AuthenticationPackageName = 'MICROSOFT_KERBEROS_NAME_A', [Parameter(Mandatory = $true)] [UInt32] $LogonId ) <# (func secur32 LsaCallAuthenticationPackage ([UInt32]) @( [IntPtr], #_In_ HANDLE LsaHandle [UInt64], #_In_ ULONG AuthenticationPackage $KERB_RETRIEVE_TKT_REQUEST.MakeByRefType(),#_In_ PVOID ProtocolSubmitBuffer [UInt64], #_In_ ULONG SubmitBufferLength [IntPtr], #_Out_ PVOID *ProtocolReturnBuffer [UInt64].MakeByRefType(), #_Out_ PULONG *ReturnBufferLength [UInt32].MakeByRefType() #_Out_ PNTSTATUS ProtocolStatus )) #> $AuthenticationPackage = LsaLookupAuthenticationPackage -LsaHandle $LsaHandle -PackageName $AuthenticationPackageName switch($AuthenticationPackageName) { MSV1_0_PACKAGE_NAME { throw New-Object -TypeName System.NotImplementedException("MSV1_0_PACKAGE_NAME Package has not been implemented yet.") } MICROSOFT_KERBEROS_NAME_A { # Request information about all of the cached tickets for the specified user logon session <# $KERB_QUERY_TKT_CACHE_REQUEST = struct $Mod Kerberos.KERB_QUERY_TKT_CACHE_REQUEST @{ MessageType = field 0 $KERB_PROTOCOL_MESSAGE_TYPE LogonId = field 1 $LUID } #> $ProtocolSubmitBuffer = [Activator]::CreateInstance($KERB_QUERY_TKT_CACHE_REQUEST) $ProtocolSubmitBuffer.MessageType = $KERB_PROTOCOL_MESSAGE_TYPE::KerbQueryTicketCacheMessage $LogonIdLuid = [Activator]::CreateInstance($LUID) $LogonIdLuid.LowPart = $LogonId $LogonIdLuid.HighPart = 0 $ProtocolSubmitBuffer.LogonId = $LogonIdLuid $ProtocolReturnBuffer = [IntPtr]::Zero $ReturnBufferLength = [UInt64]0 $ProtocolStatus = [UInt32]0 $SUCCESS = $Secur32::LsaCallAuthenticationPackage_KERB_QUERY_TKT_CACHE($LsaHandle, $AuthenticationPackage, [ref]$ProtocolSubmitBuffer, $KERB_RETRIEVE_TKT_REQUEST::GetSize(), [ref]$ProtocolReturnBuffer, [ref]$ReturnBufferLength, [ref]$ProtocolStatus) if($SUCCESS -eq 0) { if($ProtocolStatus -eq 0) { $Response = $ProtocolReturnBuffer -as $KERB_QUERY_TKT_CACHE_RESPONSE for($i = 0; $i -lt $Response.CountOfTickets; $i++) { $currentTicketPtr = [IntPtr]::Add($ProtocolReturnBuffer, (8 + ($i * $KERB_TICKET_CACHE_INFO::GetSize()))) $data = $currentTicketPtr -as $KERB_TICKET_CACHE_INFO $StartTime = [DateTime]::FromFileTime($data.StartTime) $EndTime = [DateTime]::FromFileTime($data.EndTime) [timespan]$TicketLength = $EndTime.Subtract($StartTime) $props = @{ ServerName = ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto($data.ServerName.Buffer, $data.ServerName.Length / 2)) RealmName = ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto($data.RealmName.Buffer, $data.RealmName.Length / 2)) StartTime = $StartTime EndTime = $EndTime TicketLength = $TicketLength RenewTime = ([datetime]::FromFileTime($data.RenewTime)) EncryptionType = ($data.EncryptionType -as $KERB_ENCRYPTION_TYPE).ToString() TicketFlags = ($data.TicketFlags -as $KERB_TICKET_FLAGS).ToString() } Write-Output $props } } else { $WinErrorCode = LsaNtStatusToWinError -NtStatus $ProtocolStatus $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaCallAuthenticationPackage Error: $($LastError.Message)" } } else { $WinErrorCode = LsaNtStatusToWinError -NtStatus $SUCCESS $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaCallAuthenticationPackage Error: $($LastError.Message)" } } NEGOSSP_NAME_A { throw New-Object -TypeName System.NotImplementedException("NEGOSSP_NAME_A Package has not been implemented yet.") } NTLMSP_NAME_A { throw New-Object -TypeName System.NotImplementedException("NTLMSP_NAME_A Package has not been implemented yet.") } } } function LsaConnectUntrusted { <# .SYNOPSIS The LsaConnectUntrusted function establishes an untrusted connection to the LSA server. .DESCRIPTION LsaConnectUntrusted returns a handle to an untrusted connection; it does not verify any information about the caller. The handle should be closed using the LsaDeregisterLogonProcess function. If your application simply needs to query information from authentication packages, you can use the handle returned by this function in calls to LsaCallAuthenticationPackage and LsaLookupAuthenticationPackage. Applications with the SeTcbPrivilege privilege may create a trusted connection by calling LsaRegisterLogonProcess. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378265(v=vs.85).aspx .EXAMPLE $hLsa = LsaConnectUntrusted #> param ( ) <# (func secur32 LsaConnectUntrusted ([UInt32]) @( [IntPtr].MakeByRefType() #_Out_ PHANDLE LsaHandle )) #> $LsaHandle = [IntPtr]::Zero $SUCCESS = $Secur32::LsaConnectUntrusted([ref]$LsaHandle) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaConnectUntrusted Error: $($LastError.Message)" } Write-Output $LsaHandle } function LsaDeregisterLogonProcess { <# .SYNOPSIS The LsaDeregisterLogonProcess function deletes the caller's logon application context and closes the connection to the LSA server. .DESCRIPTION If your logon application references the connection handle after calling the LsaDeregisterLogonProcess function, unexpected behavior can result. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378269(v=vs.85).aspx .EXAMPLE $hLsa = LsaConnectUntrusted # # Do Somthing with the LSA Handle # LsaDeregisterLogonProcess -LsaHandle $hLsa #> param ( [Parameter(Mandatory = $true)] [IntPtr] $LsaHandle ) <# (func secur32 LsaDeregisterLogonProcess ([UInt32]) @( [IntPtr] #_In_ HANDLE LsaHandle )) #> $SUCCESS = $Secur32::LsaDeregisterLogonProcess($LsaHandle) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaDeregisterLogonProcess Error: $($LastError.Message)" } } function LsaEnumerateLogonSessions { <# .SYNOPSIS The LsaEnumerateLogonSessions function retrieves the set of existing logon session identifiers (LUIDs) and the number of sessions. .DESCRIPTION To retrieve information about the logon sessions returned by LsaEnumerateLogonSessions, call the LsaGetLogonSessionData function. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, LsaNtStatusToWinError (Function) Optional Dependencies: None (func secur32 LsaEnumerateLogonSessions ([UInt32]) @( [UInt64].MakeByRefType(), #_Out_ PULONG LogonSessionCount, [IntPtr].MakeByRefType() #_Out_ PLUID *LogonSessionList ) -EntryPoint LsaEnumerateLogonSessions) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378275(v=vs.85).aspx .EXAMPLE LsaEnumerateLogonSessions 8 2390553591808 .EXAMPLE $SessionCount, $LogonSessionListPtr = LsaEnumerateLogonSessions #> $LogonSessionCount = [UInt64]0 $LogonSessionList = [IntPtr]::Zero $SUCCESS = $Secur32::LsaEnumerateLogonSessions([ref]$LogonSessionCount, [ref]$LogonSessionList) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaEnumerateLogonSessions Error: $($LastError.Message)" } $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name SessionCount -Value $LogonSessionCount $obj | Add-Member -MemberType NoteProperty -Name SessionListPointer -Value $LogonSessionList Write-Output $obj } function LsaFreeReturnBuffer { <# .SYNOPSIS The LsaFreeReturnBuffer function frees the memory used by a buffer previously allocated by the LSA. .DESCRIPTION Some of the LSA authentication functions allocate memory buffers to hold returned information, for example, LsaLogonUser and LsaCallAuthenticationPackage. Your application should call LsaFreeReturnBuffer to free these buffers when they are no longer needed. .PARAMETER Buffer Pointer to the buffer to be freed. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, LsaNtStatusToWinError (Function) Optional Dependencies: None (func secur32 LsaFreeReturnBuffer ([UInt32]) @( [IntPtr] #_In_ PVOID Buffer ) -EntryPoint LsaFreeReturnBuffer) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378279(v=vs.85).aspx .EXAMPLE LsaFreeReturnBuffer -Buffer $Buffer #> param ( [Parameter(Mandatory = $true)] [IntPtr] $Buffer ) $SUCCESS = $Secur32::LsaFreeReturnBuffer($Buffer) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaFreeReturnBuffer Error: $($LastError.Message)" } } function LsaGetLogonSessionData { <# .SYNOPSIS The LsaGetLogonSessionData function retrieves information about a specified logon session. .DESCRIPTION .Parameter LuidPtr .Parameter SessionCount .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, LsaFreeReturnBuffer (Function), LsaNtStatusToWinError (Function), SECURITY_LOGON_SESSION_DATA (Structure), LUID (Structure), LSA_UNICODE_STRING (Structure), LSA_LAST_INTER_LOGON_INFO (Structure), SecurityEntity (Enumeration), SECURITY_LOGON_TYPE (Enumeration) Optional Dependencies: None (func secur32 LsaGetLogonSessionData ([UInt32]) @( [IntPtr], #_In_ PLUID LogonId, [IntPtr].MakeByRefType() #_Out_ PSECURITY_LOGON_SESSION_DATA *ppLogonSessionData ) -EntryPoint LsaGetLogonSessionData) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378290(v=vs.85).aspx .EXAMPLE $SessionCount, $LogonSessionListPtr = LsaEnumerateLogonSessions LsaGetLogonSessionData -LuidPtr $LogonSessionListPtr -SessionCount $SessionCount #> param ( [Parameter(Mandatory = $true)] [IntPtr] $LuidPtr, [Parameter(Mandatory = $true)] [UInt32] $SessionCount ) $CurrentLuidPtr = $LuidPtr for($i = 0; $i -lt $SessionCount; $i++) { $sessionDataPtr = [IntPtr]::Zero $SUCCESS = $Secur32::LsaGetLogonSessionData($CurrentLuidPtr, [ref]$sessionDataPtr) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaGetLogonSessionData Error: $($LastError.Message)" } try { $sessionData = $sessionDataPtr -as $SECURITY_LOGON_SESSION_DATA $props = @{ LogonId = $sessionData.LogonId.LowPart UserName = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.Username.Buffer, $sessionData.Username.Length / 2) LogonDomain = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.LogonDomain.Buffer, $sessionData.LognDomain.Length / 2) AuthenticationPackage = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.AuthenticationPackage.Buffer, $sessionData.AuthenticationPackage.Length / 2) LogonType = ($sessionData.LogonType -as $SECURITY_LOGON_TYPE).ToString() Session = $sessionData.Session Sid = (New-Object -TypeName System.Security.Principal.SecurityIdentifier($sessionData.PSiD)).ToString() LogonTime = [datetime]::FromFileTime($sessionData.LogonTime) LogonServer = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.LogonServer.Buffer, $sessionData.LogonServer.Length / 2) DnsDomainName = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.DnsDomainName.Buffer, $sessionData.DnsDomainName.Length / 2) Upn = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.Upn.Buffer, $sessionData.Upn.Length / 2) UserFlags = $sessionData.UserFlags LastSuccessfulLogon = $sessionData.LastLogonInfo.LastSuccessfulLogon LastFailedLogon = $sessionData.LastLogonInfo.LastFailedLogon FailedAttemptCountSinceLastSuccessfulLogon = $sessionData.LastLogonInfo.FailedAttemptCountSinceLastSuccessfulLogon LogonScript = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.LogonScript.Buffer, $sessionData.LogonScript.Length / 2) ProfilePath = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.ProfilePath.Buffer, $sessionData.ProfilePath.Length / 2) HomeDirectory = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.HomeDirectory.Buffer, $sessionData.HomeDirectory.Length / 2) HomeDirectoryDrive = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.HomeDirectoryDrive.Buffer, $sessionData.HomeDirectoryDrive.Length / 2) LogoffTime = $sessionData.LogoffTime KickOffTime = $sessionData.KickOffTime PasswordLastSet = [datetime]::FromFileTime($sessionData.PasswordLastSet) PasswordCanChange = [datetime]::FromFileTime($sessionData.PasswordCanChange) PasswordMustChange = $sessionData.PasswordMustChange } Write-Output $props } catch { } LsaFreeReturnBuffer -Buffer $sessionDataPtr $CurrentLuidPtr = [IntPtr]($CurrentLuidPtr.ToInt64() + $LUID::GetSize()) } } function LsaLookupAuthenticationPackage { <# .SYNOPSIS The LsaLookupAuthenticationPackage function obtains the unique identifier of an authentication package. .DESCRIPTION The authentication package identifier is used in calls to authentication functions such as LsaLogonUser and LsaCallAuthenticationPackage. .PARAMETER LsaHandle Handle obtained from a previous call to LsaRegisterLogonProcess or LsaConnectUntrusted. .PARAMETER PackageName Specifies the name of the authentication package. Supported packages are 'MSV1_0_PACKAGE_NAME', 'MICROSOFT_KERBEROS_NAME_A', 'NEGOSSP_NAME_A', and 'NTLMSP_NAME_A'. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378297(v=vs.85).aspx .EXAMPLE $hLsa = LsaConnectUntrusted LsaLookupAuthenticationPackage -LsaHandle $hLsa -PackageName MICROSOFT_KERBEROS_NAME_A 2 #> param ( [Parameter(Mandatory = $true)] [IntPtr] $LsaHandle, [Parameter(Mandatory = $true)] [ValidateSet('MSV1_0_PACKAGE_NAME', 'MICROSOFT_KERBEROS_NAME_A', 'NEGOSSP_NAME_A', 'NTLMSP_NAME_A')] [string] $PackageName ) <# (func secur32 LsaLookupAuthenticationPackage ([UInt32]) @( [IntPtr], #_In_ HANDLE LsaHandle, $LSA_UNICODE_STRING.MakeByRefType() #_In_ PLSA_STRING PackageName, [UInt64].MakeByRefType() #_Out_ PULONG AuthenticationPackage )) #> switch($PackageName) { MSV1_0_PACKAGE_NAME {$authPackageName = 'NTLM'; break} MICROSOFT_KERBEROS_NAME_A {$authPackageName = 'Kerberos'; break} NEGOSSP_NAME_A {$authPackageName = 'Negotiate'; break} NTLMSP_NAME_A {$authPackageName = 'NTLM'; break} } $authPackageArray = [System.Text.Encoding]::ASCII.GetBytes($authPackageName) [int]$size = $authPackageArray.Length [IntPtr]$pnt = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($size) [System.Runtime.InteropServices.Marshal]::Copy($authPackageArray, 0, $pnt, $authPackageArray.Length) $lsaString = [Activator]::CreateInstance($LSA_STRING) $lsaString.Length = [UInt16]$authPackageArray.Length $lsaString.MaximumLength = [UInt16]$authPackageArray.Length $lsaString.Buffer = $pnt $AuthenticationPackage = [UInt64]0 $SUCCESS = $Secur32::LsaLookupAuthenticationPackage($LsaHandle, [ref]$lsaString, [ref]$AuthenticationPackage) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaLookupAuthenticationPackage Error: $($LastError.Message)" } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($pnt) Write-Output $AuthenticationPackage } function LsaNtStatusToWinError { <# .SYNOPSIS The LsaNtStatusToWinError function converts an NTSTATUS code returned by an LSA function to a Windows error code. .PARAMETER NtStatus An NTSTATUS code returned by an LSA function call. This value will be converted to a System error code. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect Optional Dependencies: None (func advapi32 LsaNtStatusToWinError ([UInt64]) @( [UInt32] #_In_ NTSTATUS Status ) -EntryPoint LsaNtStatusToWinError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms721800(v=vs.85).aspx .EXAMPLE #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [UInt32] $NtStatus ) $STATUS = $Advapi32::LsaNtStatusToWinError($NtStatus) Write-Output $STATUS } function LsaRegisterLogonProcess { <# .SYNOPSIS The LsaLookupAuthenticationPackage function obtains the unique identifier of an authentication package. .DESCRIPTION The authentication package identifier is used in calls to authentication functions such as LsaLogonUser and LsaCallAuthenticationPackage. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378297(v=vs.85).aspx .EXAMPLE $hLsa = LsaRegisterLogonProcess #> <# (func secur32 LsaRegisterLogonProcess ([UInt32]) @( $LSA_STRING.MakeByRefType() #_In_ PLSA_STRING LogonProcessName, [IntPtr].MakeByRefType() #_Out_ PHANDLE LsaHandle, [UInt64].MakeByRefType() #_Out_ PLSA_OPERATIONAL_MODE SecurityMode )) #> $lsaStringArray = [System.Text.Encoding]::ASCII.GetBytes("INVOKE-IR") [int]$size = $lsaStringArray.Length [IntPtr]$pnt = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($size) [System.Runtime.InteropServices.Marshal]::Copy($lsaStringArray, 0, $pnt, $lsaStringArray.Length) $lsaString = [Activator]::CreateInstance($LSA_STRING) $lsaString.Length = [UInt16]$lsaStringArray.Length $lsaString.MaximumLength = [UInt16]$lsaStringArray.Length $lsaString.Buffer = $pnt $LsaHandle = [IntPtr]::Zero $SecurityMode = [UInt64]0 $SUCCESS = $Secur32::LsaRegisterLogonProcess([ref]$lsaString, [ref]$LsaHandle, [ref]$SecurityMode) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaRegisterLogonProcess Error: $($LastError.Message)" } Write-Output $LsaHandle } function NtQueryInformationThread { <# .SYNOPSIS Retrieves information about the specified thread. .PARAMETER ThreadHandle A handle to the thread about which information is being requested. .PARAMETER ThreadInformationClass If this parameter is the ThreadIsIoPending value of the THREADINFOCLASS enumeration, the function determines whether the thread has any I/O operations pending. Use the public function GetThreadIOPendingFlag instead to obtain this information. If this parameter is the ThreadQuerySetWin32StartAddress value of the THREADINFOCLASS enumeration, the function returns the start address of the thread. Note that on versions of Windows prior to Windows Vista, the returned start address is only reliable before the thread starts running. If this parameter is the ThreadSubsystemInformation value of the THREADINFOCLASS enumeration, the function retrieves a SUBSYSTEM_INFORMATION_TYPE value indicating the subsystem type of the thread. The buffer pointed to by the ThreadInformation parameter should be large enough to hold a single SUBSYSTEM_INFORMATION_TYPE enumeration. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, THREADINFOCLASS (Enumeration) Optional Dependencies: None (func ntdll NtQueryInformationThread ([Int32]) @( [IntPtr], #_In_ HANDLE ThreadHandle, [Int32], #_In_ THREADINFOCLASS ThreadInformationClass, [IntPtr], #_Inout_ PVOID ThreadInformation, [Int32], #_In_ ULONG ThreadInformationLength, [IntPtr] #_Out_opt_ PULONG ReturnLength ) -EntryPoint NtQueryInformationThread) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms684283(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $ThreadHandle, [Parameter(Mandatory = $true)] [ValidateSet('ThreadBasicInformation','ThreadTimes','ThreadPriority','ThreadBasePriority','ThreadAffinityMask','ThreadImpersonationToken','ThreadDescriptorTableEntry','ThreadEnableAlignmentFaultFixup','ThreadEventPair_Reusable','ThreadQuerySetWin32StartAddress','ThreadZeroTlsCell','ThreadPerformanceCount','ThreadAmILastThread','ThreadIdealProcessor','ThreadPriorityBoost','ThreadSetTlsArrayAddress','ThreadIsIoPending','ThreadHideFromDebugger','ThreadBreakOnTermination','ThreadSwitchLegacyState','ThreadIsTerminated','ThreadLastSystemCall','ThreadIoPriority','ThreadCycleTime','ThreadPagePriority','ThreadActualBasePriority','ThreadTebInformation','ThreadCSwitchMon','ThreadCSwitchPmu','ThreadWow64Context','ThreadGroupInformation','ThreadUmsInformation','ThreadCounterProfiling','ThreadIdealProcessorEx','ThreadCpuAccountingInformation','ThreadSuspendCount','ThreadHeterogeneousCpuPolicy','ThreadContainerId','ThreadNameInformation','ThreadSelectedCpuSets','ThreadSystemThreadInformation','ThreadActualGroupAffinity','ThreadDynamicCodePolicyInfo','ThreadExplicitCaseSensitivity','ThreadWorkOnBehalfTicket','ThreadSubsystemInformation','ThreadDbgkWerReportActive','ThreadAttachContainer','MaxThreadInfoClass')] [string] $ThreadInformationClass ) $buf = [System.Runtime.InteropServices.Marshal]::AllocHGlobal([IntPtr]::Size) $Success = $Ntdll::NtQueryInformationThread($ThreadHandle, $THREADINFOCLASS::$ThreadInformationClass, $buf, [IntPtr]::Size, [IntPtr]::Zero); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { Write-Debug "[NtQueryInformationThread] Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } switch($ThreadInformationClass) { ThreadBasicInformation { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadTimes { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadPriority { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadBasePriority { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadAffinityMask { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadImpersonationToken { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadDescriptorTableEntry { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadEnableAlignmentFaultFixup { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadEventPair_Reusable { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadQuerySetWin32StartAddress { Write-Output ([System.Runtime.InteropServices.Marshal]::ReadIntPtr($buf)) } ThreadZeroTlsCell { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadPerformanceCount { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadAmILastThread { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadIdealProcessor { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadPriorityBoost { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadSetTlsArrayAddress { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadIsIoPending { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadHideFromDebugger { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadBreakOnTermination { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadSwitchLegacyState { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadIsTerminated { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadLastSystemCall { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadIoPriority { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadCycleTime { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadPagePriority { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadActualBasePriority { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadTebInformation { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadCSwitchMon { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadCSwitchPmu { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadWow64Context { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadGroupInformation { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadUmsInformation { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadCounterProfiling { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadIdealProcessorEx { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadCpuAccountingInformation { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadSuspendCount { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadHeterogeneousCpuPolicy { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadContainerId { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadNameInformation { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadSelectedCpuSets { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadSystemThreadInformation { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadActualGroupAffinity { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadDynamicCodePolicyInfo { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadExplicitCaseSensitivity { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadWorkOnBehalfTicket { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadSubsystemInformation { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadDbgkWerReportActive { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } ThreadAttachContainer { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } MaxThreadInfoClass { throw [System.NotImplementedException]"The $($ThreadInformationClass) class is not implemented yet." } } } function OpenProcess { <# .SYNOPSIS Opens an existing local process object. .DESCRIPTION To open a handle to another local process and obtain full access rights, you must enable the SeDebugPrivilege privilege. The handle returned by the OpenProcess function can be used in any function that requires a handle to a process, such as the wait functions, provided the appropriate access rights were requested. When you are finished with the handle, be sure to close it using the CloseHandle function. .PARAMETER ProcessId The identifier of the local process to be opened. If the specified process is the System Process (0x00000000), the function fails and the last error code is ERROR_INVALID_PARAMETER. If the specified process is the Idle process or one of the CSRSS processes, this function fails and the last error code is ERROR_ACCESS_DENIED because their access restrictions prevent user-level code from opening them. .PARAMETER DesiredAccess The access to the process object. This access right is checked against the security descriptor for the process. This parameter can be one or more of the process access rights. If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the contents of the security descriptor. .PARAMETER InheritHandle If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, PROCESS_ACCESS (Enumeration) Optional Dependencies: None (func kernel32 OpenProcess ([IntPtr]) @( [UInt32], #_In_ DWORD dwDesiredAccess [bool], #_In_ BOOL bInheritHandle [UInt32] #_In_ DWORD dwProcessId ) -EntryPoint OpenProcess -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320(v=vs.85).aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms684880(v=vs.85).aspx .EXAMPLE #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [UInt32] $ProcessId, [Parameter(Mandatory = $true)] [ValidateSet('PROCESS_TERMINATE','PROCESS_CREATE_THREAD','PROCESS_VM_OPERATION','PROCESS_VM_READ','PROCESS_VM_WRITE','PROCESS_DUP_HANDLE','PROCESS_CREATE_PROCESS','PROCESS_SET_QUOTA','PROCESS_SET_INFORMATION','PROCESS_QUERY_INFORMATION','PROCESS_SUSPEND_RESUME','PROCESS_QUERY_LIMITED_INFORMATION','DELETE','READ_CONTROL','WRITE_DAC','WRITE_OWNER','SYNCHRONIZE','PROCESS_ALL_ACCESS')] [string[]] $DesiredAccess, [Parameter()] [bool] $InheritHandle = $false ) # Calculate Desired Access Value $dwDesiredAccess = 0 foreach($val in $DesiredAccess) { $dwDesiredAccess = $dwDesiredAccess -bor $PROCESS_ACCESS::$val } $hProcess = $Kernel32::OpenProcess($dwDesiredAccess, $InheritHandle, $ProcessId); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if($hProcess -eq 0) { throw "OpenProcess Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hProcess } function OpenProcessToken { <# .SYNOPSIS The OpenProcessToken function opens the access token associated with a process. .PARAMETER ProcessHandle A handle to the process whose access token is opened. The process must have the PROCESS_QUERY_INFORMATION access permission. .PARAMETER DesiredAccess Specifies an access mask that specifies the requested types of access to the access token. These requested access types are compared with the discretionary access control list (DACL) of the token to determine which accesses are granted or denied. For a list of access rights for access tokens, see Access Rights for Access-Token Objects. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, TOKEN_ACCESS (Enumeration) Optional Dependencies: None (func advapi32 OpenProcessToken ([bool]) @( [IntPtr], #_In_ HANDLE ProcessHandle [UInt32], #_In_ DWORD DesiredAccess [IntPtr].MakeByRefType() #_Out_ PHANDLE TokenHandle ) -EntryPoint OpenProcessToken -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa379295(v=vs.85).aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa374905(v=vs.85).aspx .EXAMPLE #> [OutputType([IntPtr])] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [IntPtr] $ProcessHandle, [Parameter(Mandatory = $true)] [ValidateSet('TOKEN_ASSIGN_PRIMARY','TOKEN_DUPLICATE','TOKEN_IMPERSONATE','TOKEN_QUERY','TOKEN_QUERY_SOURCE','TOKEN_ADJUST_PRIVILEGES','TOKEN_ADJUST_GROUPS','TOKEN_ADJUST_DEFAULT','TOKEN_ADJUST_SESSIONID','DELETE','READ_CONTROL','WRITE_DAC','WRITE_OWNER','SYNCHRONIZE','STANDARD_RIGHTS_REQUIRED','TOKEN_ALL_ACCESS')] [string[]] $DesiredAccess ) # Calculate Desired Access Value $dwDesiredAccess = 0 foreach($val in $DesiredAccess) { $dwDesiredAccess = $dwDesiredAccess -bor $TOKEN_ACCESS::$val } $hToken = [IntPtr]::Zero $Success = $Advapi32::OpenProcessToken($ProcessHandle, $dwDesiredAccess, [ref]$hToken); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { throw "OpenProcessToken Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hToken } function OpenThread { <# .SYNOPSIS Opens an existing thread object. .DESCRIPTION The handle returned by OpenThread can be used in any function that requires a handle to a thread, such as the wait functions, provided you requested the appropriate access rights. The handle is granted access to the thread object only to the extent it was specified in the dwDesiredAccess parameter. When you are finished with the handle, be sure to close it by using the CloseHandle function. .PARAMETER ThreadId The identifier of the thread to be opened. .PARAMETER DesiredAccess The access to the thread object. This access right is checked against the security descriptor for the thread. This parameter can be one or more of the thread access rights. If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the contents of the security descriptor. .PARAMETER InheritHandle If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, THREAD_ACCESS (Enumeration) Optional Dependencies: None (func kernel32 OpenThread ([IntPtr]) @( [UInt32], #_In_ DWORD dwDesiredAccess [bool], #_In_ BOOL bInheritHandle [UInt32] #_In_ DWORD dwThreadId ) -EntryPoint OpenThread -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms684335(v=vs.85).aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms686769(v=vs.85).aspx .EXAMPLE #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [UInt32] $ThreadId, [Parameter(Mandatory = $true)] [ValidateSet('THREAD_TERMINATE','THREAD_SUSPEND_RESUME','THREAD_GET_CONTEXT','THREAD_SET_CONTEXT','THREAD_SET_INFORMATION','THREAD_QUERY_INFORMATION','THREAD_SET_THREAD_TOKEN','THREAD_IMPERSONATE','THREAD_DIRECT_IMPERSONATION','THREAD_SET_LIMITED_INFORMATION','THREAD_QUERY_LIMITED_INFORMATION','DELETE','READ_CONTROL','WRITE_DAC','WRITE_OWNER','SYNCHRONIZE','THREAD_ALL_ACCESS')] [string[]] $DesiredAccess, [Parameter()] [bool] $InheritHandle = $false ) # Calculate Desired Access Value $dwDesiredAccess = 0 foreach($val in $DesiredAccess) { $dwDesiredAccess = $dwDesiredAccess -bor $THREAD_ACCESS::$val } $hThread = $Kernel32::OpenThread($dwDesiredAccess, $InheritHandle, $ThreadId); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if($hThread -eq 0) { throw "OpenThread Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hThread } function OpenThreadToken { <# .SYNOPSIS The OpenThreadToken function opens the access token associated with a thread .DESCRIPTION Tokens with the anonymous impersonation level cannot be opened. Close the access token handle returned through the Handle parameter by calling CloseHandle. .PARAMETER ThreadHandle A handle to the thread whose access token is opened. .PARAMETER DesiredAccess Specifies an access mask that specifies the requested types of access to the access token. These requested access types are reconciled against the token's discretionary access control list (DACL) to determine which accesses are granted or denied. .PARAMETER OpenAsSelf TRUE if the access check is to be made against the process-level security context. FALSE if the access check is to be made against the current security context of the thread calling the OpenThreadToken function. The OpenAsSelf parameter allows the caller of this function to open the access token of a specified thread when the caller is impersonating a token at SecurityIdentification level. Without this parameter, the calling thread cannot open the access token on the specified thread because it is impossible to open executive-level objects by using the SecurityIdentification impersonation level. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, $TOKEN_ACCESS (Enumeration) Optional Dependencies: None (func advapi32 OpenThreadToken ([bool]) @( [IntPtr], #_In_ HANDLE ThreadHandle [UInt32], #_In_ DWORD DesiredAccess [bool], #_In_ BOOL OpenAsSelf [IntPtr].MakeByRefType() #_Out_ PHANDLE TokenHandle ) -EntryPoint OpenThreadToken -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa379296(v=vs.85).aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa374905(v=vs.85).aspx .EXAMPLE #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [IntPtr] $ThreadHandle, [Parameter(Mandatory = $true)] [ValidateSet('TOKEN_ASSIGN_PRIMARY','TOKEN_DUPLICATE','TOKEN_IMPERSONATE','TOKEN_QUERY','TOKEN_QUERY_SOURCE','TOKEN_ADJUST_PRIVILEGES','TOKEN_ADJUST_GROUPS','TOKEN_ADJUST_DEFAULT','TOKEN_ADJUST_SESSIONID','DELETE','READ_CONTROL','WRITE_DAC','WRITE_OWNER','SYNCHRONIZE','STANDARD_RIGHTS_REQUIRED','TOKEN_ALL_ACCESS')] [string[]] $DesiredAccess, [Parameter()] [bool] $OpenAsSelf = $false ) # Calculate Desired Access Value $dwDesiredAccess = 0 foreach($val in $DesiredAccess) { $dwDesiredAccess = $dwDesiredAccess -bor $TOKEN_ACCESS::$val } $hToken = [IntPtr]::Zero $Success = $Advapi32::OpenThreadToken($ThreadHandle, $dwDesiredAccess, $OpenAsSelf, [ref]$hToken); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { throw "[OpenThreadToken] Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hToken } function RevertToSelf { <# .SYNOPSIS The RevertToSelf function terminates the impersonation of a client application. .DESCRIPTION A process should call the RevertToSelf function after finishing any impersonation begun by using the DdeImpersonateClient, ImpersonateDdeClientWindow, ImpersonateLoggedOnUser, ImpersonateNamedPipeClient, ImpersonateSelf, ImpersonateAnonymousToken or SetThreadToken function. An RPC server that used the RpcImpersonateClient function to impersonate a client must call the RpcRevertToSelf or RpcRevertToSelfEx to end the impersonation. If RevertToSelf fails, your application continues to run in the context of the client, which is not appropriate. You should shut down the process if RevertToSelf fails. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa379317(v=vs.85).aspx .EXAMPLE RevertToSelf #> <# (func advapi32 RevertToSelf ([bool]) @() -SetLastError) #> $SUCCESS = $Advapi32::RevertToSelf(); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $SUCCESS) { throw "[RevertToSelf] Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } } function Thread32First { <# .SYNOPSIS Retrieves information about the first thread of any process encountered in a system snapshot. .PARAMETER SnapshotHandle A handle to the snapshot returned from a previous call to the CreateToolhelp32Snapshot function. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect Optional Dependencies: None (func kernel32 Thread32First ([bool]) @( [IntPtr], #_In_ HANDLE hSnapshot $THREADENTRY32.MakeByRefType() #_Inout_ LPTHREADENTRY32 lpte ) -EntryPoint Thread32First -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms686728(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $SnapshotHandle ) $Thread = [Activator]::CreateInstance($THREADENTRY32) $Thread.dwSize = $THREADENTRY32::GetSize() $Success = $Kernel32::Thread32First($hSnapshot, [Ref]$Thread); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { Write-Debug "Thread32First Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $Thread } #region Lee's Code... function Get-ServiceNameFromTag($ProcessId, $ServiceTag) { $NTVersion = [System.Environment]::OSVersion.Version if($NTVersion.Major -ge 6 -and $NTVersion.Minor -ge 1) { # Based off of https://wj32.org/wp/2010/03/30/howto-use-i_querytaginformation/ $ServiceTagQuery = [Activator]::CreateInstance($SC_SERVICE_TAG_QUERY) # New-Object doesn't work on PSv2 for some reason. Thanks @mattifestation! $ServiceTagQuery.ProcessId = $ProcessId $ServiceTagQuery.ServiceTag = $ServiceTag $Res = $Advapi32::I_QueryTagInformation([IntPtr]::Zero, $SC_SERVICE_TAG_QUERY_TYPE::ServiceNameFromTagInformation, [Ref] $ServiceTagQuery) if($Res -eq 0) { $ServiceStr = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($ServiceTagQuery.Buffer) $ServiceStr } else { #"Error: $Res" } } } function Get-Tcp4Connections { Param ( # Attempt to resolve the hostnames of each IP address [switch] $ResolveHostnames, [switch] $ReturnHashTables ) $AF_INET = 2 $TableBufferSize = 0 $null = $iphlpapi::GetExtendedTcpTable([IntPtr]::Zero, [ref]$TableBufferSize, $true, $AF_INET, $TCP_TABLE_CLASS::TCP_TABLE_OWNER_MODULE_ALL, 0) $TableBuffer = [Runtime.InteropServices.Marshal]::AllocHGlobal($TableBufferSize) try { $Ret = $iphlpapi::GetExtendedTcpTable($TableBuffer, [ref] $TableBufferSize, $true, $AF_INET, $TCP_TABLE_CLASS::TCP_TABLE_OWNER_MODULE_ALL, 0); if ($Ret -ne 0) { Write-Error "Failed to get TCP connection information. GetExtendedTcpTable's return code: $Ret" return } $OwnerModuleTable = $TableBuffer -as $MIB_TCPTABLE_OWNER_MODULE $RowPtr = [IntPtr]($TableBuffer.ToInt64() + [Runtime.InteropServices.Marshal]::OffsetOf($MIB_TCPTABLE_OWNER_MODULE, "Table").ToInt64()) for($i=0; $i -lt $OwnerModuleTable.NumEntries; $i++) { $TcpRow = $RowPtr -as $MIB_TCPROW_OWNER_MODULE # Get the properties we want $LocalAddr = [System.Net.IPAddress]$TcpRow.LocalAddr $PortBytes = [System.BitConverter]::GetBytes($TcpRow.LocalPort) $LocalPort = $PortBytes[0]*256 + $PortBytes[1] $RemoteAddr = [System.Net.IPAddress]$TcpRow.RemoteAddr $PortBytes = [System.BitConverter]::GetBytes($TcpRow.RemotePort) $RemotePort = $PortBytes[0]*256 + $PortBytes[1] $ServiceTag = $TcpRow.OwningModuleInfo[0] $RemoteHostname = $null if($ResolveHostnames) { try { $RemoteHostname = [System.Net.Dns]::GetHostEntry($RemoteAddr).HostName } catch { # Couldn't resolve the host name, so keep the IP } } $Output = @{ LocalAddress = [string]$LocalAddr LocalPort = $LocalPort RemoteAddress = [string]$RemoteAddr RemoteHostname = $RemoteHostname RemotePort = $RemotePort #Process = Get-Process -Id $TcpRow.OwningPid -ErrorAction SilentlyContinue Process = (Get-Process -Id $TcpRow.OwningPid -ErrorAction SilentlyContinue).Name ProcessId = $TcpRow.OwningPid Protocol = "TCP" State = $TcpRow.State.ToString() Service = [string](Get-ServiceNameFromTag -ProcessId $TcpRow.OwningPid -ServiceTag $ServiceTag) } if($ReturnHashtables) { $Output } else { New-Object PSObject -Property $Output } # Move to the next row in the TCP table $RowPtr = [IntPtr]($RowPtr.ToInt64() + [Runtime.InteropServices.Marshal]::SizeOf($TcpRow)) } } catch { Write-Error $_ } finally { [Runtime.InteropServices.Marshal]::FreeHGlobal($TableBuffer) } } function Get-Tcp6Connections { Param ( # Attempt to resolve the hostnames of each IP address [switch] $ResolveHostnames, [switch] $ReturnHashTables ) $AF_INET6 = 23 $TableBufferSize = 0 $null = $iphlpapi::GetExtendedTcpTable([IntPtr]::Zero, [ref]$TableBufferSize, $true, $AF_INET6, $TCP_TABLE_CLASS::TCP_TABLE_OWNER_MODULE_ALL, 0) $TableBuffer = [Runtime.InteropServices.Marshal]::AllocHGlobal($TableBufferSize) try { $Ret = $iphlpapi::GetExtendedTcpTable($TableBuffer, [ref] $TableBufferSize, $true, $AF_INET6, $TCP_TABLE_CLASS::TCP_TABLE_OWNER_MODULE_ALL, 0); if($Ret -eq 50) { # IPv6 is not supported return } elseif ($Ret -ne 0) { Write-Error "Failed to get TCP connection information. GetExtendedTcpTable's return code: $Ret" return } $OwnerModuleTable = $TableBuffer -as $MIB_TCP6TABLE_OWNER_MODULE $RowPtr = [IntPtr]($TableBuffer.ToInt64() + [Runtime.InteropServices.Marshal]::OffsetOf($MIB_TCPTABLE_OWNER_MODULE, "Table").ToInt64()) for($i=0; $i -lt $OwnerModuleTable.NumEntries; $i++) { $TcpRow = $RowPtr -as $MIB_TCP6ROW_OWNER_MODULE # Get the properties we want $LocalAddr = [System.Net.IPAddress]$TcpRow.LocalAddr $PortBytes = [System.BitConverter]::GetBytes($TcpRow.LocalPort) $LocalPort = $PortBytes[0]*256 + $PortBytes[1] $RemoteAddr = [System.Net.IPAddress]$TcpRow.RemoteAddr $PortBytes = [System.BitConverter]::GetBytes($TcpRow.RemotePort) $RemotePort = $PortBytes[0]*256 + $PortBytes[1] $ServiceTag = $TcpRow.OwningModuleInfo[0] $RemoteHostname = $null; if($ResolveHostnames) { try { $RemoteHostname = [System.Net.Dns]::GetHostEntry($RemoteAddr).HostName } catch { # Couldn't resolve the host name, so keep the IP } } $Output = @{ LocalAddress = [string]$LocalAddr LocalPort = $LocalPort RemoteAddress = [string]$RemoteAddr RemoteHostname = $RemoteHostname RemotePort = $RemotePort Process = (Get-Process -Id $TcpRow.OwningPid -ErrorAction SilentlyContinue).Name ProcessId = $TcpRow.OwningPid Protocol = "TCP" State = $TcpRow.State.ToString() Service = [string](Get-ServiceNameFromTag -ProcessId $TcpRow.OwningPid -ServiceTag $ServiceTag) } if($ReturnHashtables) { $Output } else { New-Object PSObject -Property $Output } # Move to the next row in the TCP table $RowPtr = [IntPtr]($RowPtr.ToInt64() + [Runtime.InteropServices.Marshal]::SizeOf($TcpRow)) } } catch { Write-Error $_ } finally { [Runtime.InteropServices.Marshal]::FreeHGlobal($TableBuffer) } } function Get-Udp4Connections { Param ( # Attempt to resolve the hostnames of each IP address [switch] $ResolveHostnames, [switch] $ReturnHashTables ) $AF_INET = 2 $TableBufferSize = 0 $null = $iphlpapi::GetExtendedUdpTable([IntPtr]::Zero, [ref]$TableBufferSize, $true, $AF_INET, $UDP_TABLE_CLASS::UDP_TABLE_OWNER_MODULE, 0) $TableBuffer = [Runtime.InteropServices.Marshal]::AllocHGlobal($TableBufferSize) try { $Ret = $iphlpapi::GetExtendedUdpTable($TableBuffer, [ref] $TableBufferSize, $true, $AF_INET, $UDP_TABLE_CLASS::UDP_TABLE_OWNER_MODULE, 0); if ($Ret -ne 0) { Write-Error "Failed to get UDP connection information. GetExtendedUdpTable's return code: $Ret" return } $OwnerModuleTable = $TableBuffer -as $MIB_UDPTABLE_OWNER_MODULE $RowPtr = [IntPtr]($TableBuffer.ToInt64() + [Runtime.InteropServices.Marshal]::OffsetOf($MIB_UDPTABLE_OWNER_MODULE, "Table").ToInt64()) for($i=0; $i -lt $OwnerModuleTable.NumEntries; $i++) { $UdpRow = $RowPtr -as $MIB_UDPROW_OWNER_MODULE # Get the properties we want $LocalAddr = [System.Net.IPAddress]$UdpRow.LocalAddr $PortBytes = [System.BitConverter]::GetBytes($UdpRow.LocalPort) $LocalPort = $PortBytes[0]*256 + $PortBytes[1] $ServiceTag = $UdpRow.OwningModuleInfo[0] $Output = @{ LocalAddress = [string]$LocalAddr LocalPort = $LocalPort Process = (Get-Process -Id $UdpRow.OwningPid -ErrorAction SilentlyContinue).Name ProcessId = $UdpRow.OwningPid Protocol = "UDP" Service = [string](Get-ServiceNameFromTag -ProcessId $UdpRow.OwningPid -ServiceTag $ServiceTag) } if($ReturnHashtables) { $Output } else { New-Object PSObject -Property $Output } # Move to the next row in the UDP table $RowPtr = [IntPtr]($RowPtr.ToInt64() + ([Runtime.InteropServices.Marshal]::SizeOf($UdpRow))) } } catch { Write-Error $_ } finally { [Runtime.InteropServices.Marshal]::FreeHGlobal($TableBuffer) } } function Get-Udp6Connections { Param ( # Attempt to resolve the hostnames of each IP address [switch] $ResolveHostnames, [switch] $ReturnHashTables ) $AF_INET6 = 23 $TableBufferSize = 0 $null = $iphlpapi::GetExtendedUdpTable([IntPtr]::Zero, [ref]$TableBufferSize, $true, $AF_INET6, $UDP_TABLE_CLASS::UDP_TABLE_OWNER_MODULE, 0) $TableBuffer = [Runtime.InteropServices.Marshal]::AllocHGlobal($TableBufferSize) try { $Ret = $iphlpapi::GetExtendedUdpTable($TableBuffer, [ref] $TableBufferSize, $true, $AF_INET6, $UDP_TABLE_CLASS::UDP_TABLE_OWNER_MODULE, 0); if($Ret -eq 50) # ERROR_NOT_SUPPORTED { # IPv6 is not supported return } elseif ($Ret -ne 0) { Write-Error "Failed to get TCP connection information. GetExtendedTcpTable's return code: $Ret" return } $OwnerModuleTable = $TableBuffer -as $MIB_UDP6TABLE_OWNER_MODULE $RowPtr = [IntPtr]($TableBuffer.ToInt64() + [Runtime.InteropServices.Marshal]::OffsetOf($MIB_UDPTABLE_OWNER_MODULE, "Table").ToInt64()) for($i=0; $i -lt $OwnerModuleTable.NumEntries; $i++) { $UdpRow = $RowPtr -as $MIB_UDP6ROW_OWNER_MODULE $LocalAddr = [System.Net.IPAddress]$UdpRow.LocalAddr $PortBytes = [System.BitConverter]::GetBytes($UdpRow.LocalPort) $LocalPort = $PortBytes[0]*256 + $PortBytes[1] $ServiceTag = $UdpRow.OwningModuleInfo[0] if($ResolveHostnames) { try { $RemoteIP = [System.Net.Dns]::GetHostEntry($LocalAddr).HostName } catch { } } $Output = @{ LocalAddress = [string]$LocalAddr LocalPort = $LocalPort Process = (Get-Process -Id $UdpRow.OwningPid -ErrorAction SilentlyContinue).Name ProcessId = $UdpRow.OwningPid Protocol = "UDP" Service = [string](Get-ServiceNameFromTag -ProcessId $UdpRow.OwningPid -ServiceTag $ServiceTag) } if($ReturnHashtables) { $Output } else { New-Object PSObject -Property $Output } # Move to the next row in the UDP table $RowPtr = [IntPtr]($RowPtr.ToInt64() + ([Runtime.InteropServices.Marshal]::SizeOf($UdpRow))) } } catch { Write-Error $_ } finally { [Runtime.InteropServices.Marshal]::FreeHGlobal($TableBuffer) } } #endregion Lee's code... #endregion API Abstractions #Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE -ScanType RegistryAutoRun #Start-AceScript -Uri https://10.182.18.200 -SweepId ([Guid]::NewGuid()) -ScanId ([Guid]::NewGuid()) -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE -ScanType All ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-AccessToken.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-AccessToken)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'AccessToken') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'AccessToken' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) #Write-Output $body | ConvertFrom-Json Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-AccessToken { param ( [Parameter()] [System.Diagnostics.Process[]] $Process ) begin { <# try { Get-System } catch { Write-Error "Unable to Impersonate NT AUTHORITY\SYSTEM token" } #> if(-not ($PSBoundParameters.ContainsKey('Process'))) { $Process = Get-Process } } process { foreach($proc in $Process) { if($proc.Id -ne 0 -and $proc.Id -ne 4 -and $proc.Id -ne $PID) { $ProcessGuid = [Guid]::NewGuid() try { $hProcess = OpenProcess -ProcessId $proc.Id -DesiredAccess PROCESS_QUERY_LIMITED_INFORMATION } catch { if($_.Exception.Message -ne "OpenProcess Error: The parameter is incorrect") { Write-Warning "Process Handle: $($proc.Id)" Write-Warning $_.Exception.Message } } try { $hToken = OpenProcessToken -ProcessHandle $hProcess -DesiredAccess TOKEN_QUERY } catch { #Write-Warning "Process Token Handle: $($proc.Id)" #Write-Warning $_.Exception.Message } try { $TokenUser = GetTokenInformation -TokenInformationClass TokenUser -TokenHandle $hToken $TokenGroup = GetTokenInformation -TokenInformationClass TokenGroups -TokenHandle $hToken $TokenOwner = GetTokenInformation -TokenInformationClass TokenOwner -TokenHandle $hToken $TokenIntegrityLevel = GetTokenInformation -TokenInformationClass TokenIntegrityLevel -TokenHandle $hToken $TokenType = GetTokenInformation -TokenInformationClass TokenType -TokenHandle $hToken $TokenSessionId = GetTokenInformation -TokenInformationClass TokenSessionId -TokenHandle $hToken $TokenOrigin = GetTokenInformation -TokenInformationClass TokenOrigin -TokenHandle $hToken $TokenPrivileges = (GetTokenInformation -TokenInformationClass TokenPrivileges -TokenHandle $hToken | Where-Object {$_.Attributes -like "*ENABLED*"} | select -ExpandProperty Privilege) -join ";" $TokenElevation = GetTokenInformation -TokenInformationClass TokenElevation -TokenHandle $hToken $TokenElevationType = GetTokenInformation -TokenInformationClass TokenElevationType -TokenHandle $hToken $props = @{ ProcessGuid = $ProcessGuid ProcessName = $proc.Name ProcessId = $proc.Id ThreadId = 0 UserSid = $TokenUser.Sid.ToString() UserName = $TokenUser.Name.Value OwnerSid = $TokenOwner.Sid.ToString() OwnerName = $TokenOwner.Name.Value #Groups = $TokenGroup IntegrityLevel = $TokenIntegrityLevel.ToString() Type = $TokenType.ToString() ImpersonationLevel = 'None' SessionId = $TokenSessionId -as ([Int32]) Origin = $TokenOrigin -as ([Int32]) Privileges = $TokenPrivileges IsElevated = $TokenElevation -as ([bool]) ElevationType = $TokenElevationType.ToString() } Write-Output $props CloseHandle -Handle $hProcess CloseHandle -Handle $hToken } catch { #Write-Warning "Process Token Query: $($proc.Id)" #Write-Warning $_.Exception.Message } foreach($thread in $proc.Threads) { try { $hThread = OpenThread -ThreadId $thread.Id -DesiredAccess THREAD_QUERY_LIMITED_INFORMATION try { $hToken = OpenThreadToken -ThreadHandle $hThread -DesiredAccess TOKEN_QUERY $TokenUser = GetTokenInformation -TokenInformationClass TokenUser -TokenHandle $hToken $TokenGroup = GetTokenInformation -TokenInformationClass TokenGroups -TokenHandle $hToken $TokenOwner = GetTokenInformation -TokenInformationClass TokenOwner -TokenHandle $hToken $TokenIntegrityLevel = GetTokenInformation -TokenInformationClass TokenIntegrityLevel -TokenHandle $hToken $TokenType = GetTokenInformation -TokenInformationClass TokenType -TokenHandle $hToken if($TokenType -eq 'TokenImpersonation') { $TokenImpersonationLevel = GetTokenInformation -TokenInformationClass TokenImpersonationLevel -TokenHandle $hToken } else { $TokenImpersonationLevel = 'None' } $TokenSessionId = GetTokenInformation -TokenInformationClass TokenSessionId -TokenHandle $hToken $TokenOrigin = GetTokenInformation -TokenInformationClass TokenOrigin -TokenHandle $hToken $TokenPrivileges = (GetTokenInformation -TokenInformationClass TokenPrivileges -TokenHandle $hToken | Where-Object {$_.Attributes -like "*ENABLED*"} | select -ExpandProperty Privilege) -join ";" $TokenElevation = GetTokenInformation -TokenInformationClass TokenElevation -TokenHandle $hToken $TokenElevationType = GetTokenInformation -TokenInformationClass TokenElevationType -TokenHandle $hToken $props = @{ ProcessGuid = $ProcessGuid ProcessName = $proc.Name ProcessId = $proc.Id ThreadId = $thread.Id UserSid = $TokenUser.Sid.ToString() UserName = $TokenUser.Name.Value OwnerSid = $TokenOwner.Sid.ToString() OwnerName = $TokenOwner.Name.Value #Groups = $TokenGroup IntegrityLevel = $TokenIntegrityLevel.ToString() Type = $TokenType.ToString() ImpersonationLevel = $TokenImpersonationLevel.ToString() SessionId = $TokenSessionId -as ([Int32]) Origin = $TokenOrigin -as ([Int32]) Privileges = $TokenPrivileges IsElevated = $TokenElevation -as ([bool]) ElevationType = $TokenElevationType.ToString() } Write-Output $props CloseHandle -Handle $hThread CloseHandle -Handle $hToken } catch { if($_.Exception.Message -ne 'OpenThreadToken Error: An attempt was made to reference a token that does not exist') { #Write-Warning "Thread Token Handle" #Write-Warning $_.Exception.Message } } } catch { #Write-Warning "Thread Handle: [Proc] $($proc.Id) [THREAD] $($thread.Id)" #Write-Warning $_.Exception.Message } } } } } end { RevertToSelf } } #region Helper Functions function Get-System { <# .SYNOPSIS Impersonate the NT AUTHORITY\SYSTEM account's token. .DESCRIPTION .NOTES Author: Jared Atkinson (@jaredcatkinson) License: Required Dependencies: PSReflect, OpenProcessToken (Function), DuplicateToken (Function), ImpersonateLoggedOnUser (Function), CloseHandle (Function) Optional Dependencies: None .EXAMPLE Get-System #> # Get a Process object for the winlogon process # The System.Diagnostics.Process class has a handle property that we can use # We know winlogon will be available and is running as NT AUTHORITY\SYSTEM $proc = (Get-Process -Name winlogon)[0] # Open winlogon's Token with TOKEN_DUPLICATE Acess # This allows us to make a copy of the token with DuplicateToken $hToken = OpenProcessToken -ProcessHandle $proc.Handle -DesiredAccess $TOKEN_ACCESS::TOKEN_DUPLICATE # Make a copy of the NT AUTHORITY\SYSTEM Token $hDupToken = DuplicateToken -TokenHandle $hToken # Apply our Duplicated Token to our Thread ImpersonateLoggedOnUser -TokenHandle $hDupToken # Clean up the handles we created CloseHandle -Handle $hToken CloseHandle -Handle $hDupToken if(-not [System.Security.Principal.WindowsIdentity]::GetCurrent().Name -eq 'NT AUTHORITY\SYSTEM') { throw "Unable to Impersonate System Token" } } #endregion Helper Functions #region PSReflect #Requires -Version 2 function New-InMemoryModule { <# .SYNOPSIS Creates an in-memory assembly and module Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION When defining custom enums, structs, and unmanaged functions, it is necessary to associate to an assembly module. This helper function creates an in-memory module that can be passed to the 'enum', 'struct', and Add-Win32Type functions. .PARAMETER ModuleName Specifies the desired name for the in-memory assembly and module. If ModuleName is not provided, it will default to a GUID. .EXAMPLE $Module = New-InMemoryModule -ModuleName Win32 #> Param ( [Parameter(Position = 0)] [ValidateNotNullOrEmpty()] [String] $ModuleName = [Guid]::NewGuid().ToString() ) $AppDomain = [Reflection.Assembly].Assembly.GetType('System.AppDomain').GetProperty('CurrentDomain').GetValue($null, @()) $LoadedAssemblies = $AppDomain.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 $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, 'Run') $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule($ModuleName, $False) return $ModuleBuilder } # A helper function used to reduce typing while defining function # prototypes for Add-Win32Type. 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, [String] $EntryPoint, [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 } if ($EntryPoint) { $Properties['EntryPoint'] = $EntryPoint } New-Object PSObject -Property $Properties } function Add-Win32Type { <# .SYNOPSIS Creates a .NET type for an unmanaged Win32 function. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: func .DESCRIPTION Add-Win32Type enables you to easily interact with unmanaged (i.e. Win32 unmanaged) functions in PowerShell. After providing Add-Win32Type with a function signature, a .NET type is created using reflection (i.e. csc.exe is never called like with Add-Type). The 'func' helper function can be used to reduce typing when defining multiple function definitions. .PARAMETER DllName The name of the DLL. .PARAMETER FunctionName The name of the target function. .PARAMETER EntryPoint The DLL export function name. This argument should be specified if the specified function name is different than the name of the exported function. .PARAMETER ReturnType The return type of the function. .PARAMETER ParameterTypes The function parameters. .PARAMETER NativeCallingConvention Specifies the native calling convention of the function. Defaults to stdcall. .PARAMETER Charset If you need to explicitly call an 'A' or 'W' Win32 function, you can specify the character set. .PARAMETER SetLastError Indicates whether the callee calls the SetLastError Win32 API function before returning from the attributed method. .PARAMETER Module The in-memory module that will host the functions. Use New-InMemoryModule to define an in-memory module. .PARAMETER Namespace An optional namespace to prepend to the type. Add-Win32Type defaults to a namespace consisting only of the name of the DLL. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $FunctionDefinitions = @( (func kernel32 GetProcAddress ([IntPtr]) @([IntPtr], [String]) -Charset Ansi -SetLastError), (func kernel32 GetModuleHandle ([Intptr]) @([String]) -SetLastError), (func ntdll RtlGetCurrentPeb ([IntPtr]) @()) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32' $Kernel32 = $Types['kernel32'] $Ntdll = $Types['ntdll'] $Ntdll::RtlGetCurrentPeb() $ntdllbase = $Kernel32::GetModuleHandle('ntdll') $Kernel32::GetProcAddress($ntdllbase, 'RtlGetCurrentPeb') .NOTES Inspired by Lee Holmes' Invoke-WindowsApi http://poshcode.org/2189 When defining multiple function prototypes, it is ideal to provide Add-Win32Type with an array of function signatures. That way, they are all incorporated into the same in-memory module. #> [OutputType([Hashtable])] Param( [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $DllName, [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $FunctionName, [Parameter(ValueFromPipelineByPropertyName = $True)] [String] $EntryPoint, [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') $EntryPointField = $DllImport.GetField('EntryPoint') if ($SetLastError) { $SLEValue = $True } else { $SLEValue = $False } if ($PSBoundParameters['EntryPoint']) { $ExportedFuncName = $EntryPoint } else { $ExportedFuncName = $FunctionName } # 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, $EntryPointField), [Object[]] @($SLEValue, ([Runtime.InteropServices.CallingConvention] $NativeCallingConvention), ([Runtime.InteropServices.CharSet] $Charset), $ExportedFuncName)) $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 psenum { <# .SYNOPSIS Creates an in-memory enumeration for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION The 'psenum' function facilitates the creation of enums entirely in memory using as close to a "C style" as PowerShell will allow. .PARAMETER Module The in-memory module that will host the enum. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the enum. .PARAMETER Type The type of each enum element. .PARAMETER EnumElements A hashtable of enum elements. .PARAMETER Bitfield Specifies that the enum should be treated as a bitfield. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageSubsystem = psenum $Mod PE.IMAGE_SUBSYSTEM UInt16 @{ UNKNOWN = 0 NATIVE = 1 # Image doesn't require a subsystem. WINDOWS_GUI = 2 # Image runs in the Windows GUI subsystem. WINDOWS_CUI = 3 # Image runs in the Windows character subsystem. OS2_CUI = 5 # Image runs in the OS/2 character subsystem. POSIX_CUI = 7 # Image runs in the Posix character subsystem. NATIVE_WINDOWS = 8 # Image is a native Win9x driver. WINDOWS_CE_GUI = 9 # Image runs in the Windows CE subsystem. EFI_APPLICATION = 10 EFI_BOOT_SERVICE_DRIVER = 11 EFI_RUNTIME_DRIVER = 12 EFI_ROM = 13 XBOX = 14 WINDOWS_BOOT_APPLICATION = 16 } .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Enum. :P #> [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]) { return ($Module.GetType($FullName)) } $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 { <# .SYNOPSIS Creates an in-memory struct for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: field .DESCRIPTION The 'struct' function facilitates the creation of structs entirely in memory using as close to a "C style" as PowerShell will allow. Struct fields are specified using a hashtable where each field of the struct is comprosed of the order in which it should be defined, its .NET type, and optionally, its offset and special marshaling attributes. One of the features of 'struct' is that after your struct is defined, it will come with a built-in GetSize method as well as an explicit converter so that you can easily cast an IntPtr to the struct without relying upon calling SizeOf and/or PtrToStructure in the Marshal class. .PARAMETER Module The in-memory module that will host the struct. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the struct. .PARAMETER StructFields A hashtable of fields. Use the 'field' helper function to ease defining each field. .PARAMETER PackingSize Specifies the memory alignment of fields. .PARAMETER ExplicitLayout Indicates that an explicit offset for each field will be specified. .PARAMETER CharSet Dictates which character set marshaled strings should use. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageDosSignature = psenum $Mod PE.IMAGE_DOS_SIGNATURE UInt16 @{ DOS_SIGNATURE = 0x5A4D OS2_SIGNATURE = 0x454E OS2_SIGNATURE_LE = 0x454C VXD_SIGNATURE = 0x454C } $ImageDosHeader = struct $Mod PE.IMAGE_DOS_HEADER @{ e_magic = field 0 $ImageDosSignature e_cblp = field 1 UInt16 e_cp = field 2 UInt16 e_crlc = field 3 UInt16 e_cparhdr = field 4 UInt16 e_minalloc = field 5 UInt16 e_maxalloc = field 6 UInt16 e_ss = field 7 UInt16 e_sp = field 8 UInt16 e_csum = field 9 UInt16 e_ip = field 10 UInt16 e_cs = field 11 UInt16 e_lfarlc = field 12 UInt16 e_ovno = field 13 UInt16 e_res = field 14 UInt16[] -MarshalAs @('ByValArray', 4) e_oemid = field 15 UInt16 e_oeminfo = field 16 UInt16 e_res2 = field 17 UInt16[] -MarshalAs @('ByValArray', 10) e_lfanew = field 18 Int32 } # Example of using an explicit layout in order to create a union. $TestUnion = struct $Mod TestUnion @{ field1 = field 0 UInt32 0 field2 = field 1 IntPtr 0 } -ExplicitLayout .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Struct. :P #> [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, [System.Runtime.InteropServices.CharSet] $CharSet = [System.Runtime.InteropServices.CharSet]::Ansi ) if ($Module -is [Reflection.Assembly]) { return ($Module.GetType($FullName)) } [Reflection.TypeAttributes] $StructAttributes = 'Class, Public, Sealed, BeforeFieldInit' if ($ExplicitLayout) { $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::ExplicitLayout } else { $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::SequentialLayout } switch($CharSet) { Ansi { $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::AnsiClass } Auto { $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::AutoClass } Unicode { $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::UnicodeClass } } $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() } #endregion PSReflect $Module = New-InMemoryModule -ModuleName AccessToken #region Enums $LuidAttributes = psenum $Module LuidAttributes UInt32 @{ DISABLED = 0x00000000 SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001 SE_PRIVILEGE_ENABLED = 0x00000002 SE_PRIVILEGE_REMOVED = 0x00000004 SE_PRIVILEGE_USED_FOR_ACCESS = 2147483648 } -Bitfield $PROCESS_ACCESS = psenum $Module PROCESS_ACCESS UInt32 @{ PROCESS_TERMINATE = 0x00000001 PROCESS_CREATE_THREAD = 0x00000002 PROCESS_VM_OPERATION = 0x00000008 PROCESS_VM_READ = 0x00000010 PROCESS_VM_WRITE = 0x00000020 PROCESS_DUP_HANDLE = 0x00000040 PROCESS_CREATE_PROCESS = 0x00000080 PROCESS_SET_QUOTA = 0x00000100 PROCESS_SET_INFORMATION = 0x00000200 PROCESS_QUERY_INFORMATION = 0x00000400 PROCESS_SUSPEND_RESUME = 0x00000800 PROCESS_QUERY_LIMITED_INFORMATION = 0x00001000 DELETE = 0x00010000 READ_CONTROL = 0x00020000 WRITE_DAC = 0x00040000 WRITE_OWNER = 0x00080000 SYNCHRONIZE = 0x00100000 PROCESS_ALL_ACCESS = 0x001f1ffb } -Bitfield $SE_GROUP = psenum $Module SE_GROUP UInt32 @{ DISABLED = 0x00000000 MANDATORY = 0x00000001 ENABLED_BY_DEFAULT = 0x00000002 ENABLED = 0x00000004 OWNER = 0x00000008 USE_FOR_DENY_ONLY = 0x00000010 INTEGRITY = 0x00000020 INTEGRITY_ENABLED = 0x00000040 RESOURCE = 0x20000000 LOGON_ID = 3221225472 } -Bitfield $SE_PRIVILEGE = psenum $Module SE_PRIVILEGE UInt32 @{ DISABLED = 0x00000000 ENABLED_BY_DEFAULT = 0x00000001 ENABLED = 0x00000002 REMOVED = 0x00000004 USED_FOR_ACCESS = 2147483648 } -Bitfield $SECURITY_IMPERSONATION_LEVEL = psenum $Module SECURITY_IMPERSONATION_LEVEL UInt32 @{ SecurityAnonymous = 0 SecurityIdentification = 1 SecurityImpersonation = 2 SecurityDelegation = 3 } $SecurityEntity = psenum $Module SecurityEntity UInt32 @{ SeCreateTokenPrivilege = 1 SeAssignPrimaryTokenPrivilege = 2 SeLockMemoryPrivilege = 3 SeIncreaseQuotaPrivilege = 4 SeUnsolicitedInputPrivilege = 5 SeMachineAccountPrivilege = 6 SeTcbPrivilege = 7 SeSecurityPrivilege = 8 SeTakeOwnershipPrivilege = 9 SeLoadDriverPrivilege = 10 SeSystemProfilePrivilege = 11 SeSystemtimePrivilege = 12 SeProfileSingleProcessPrivilege = 13 SeIncreaseBasePriorityPrivilege = 14 SeCreatePagefilePrivilege = 15 SeCreatePermanentPrivilege = 16 SeBackupPrivilege = 17 SeRestorePrivilege = 18 SeShutdownPrivilege = 19 SeDebugPrivilege = 20 SeAuditPrivilege = 21 SeSystemEnvironmentPrivilege = 22 SeChangeNotifyPrivilege = 23 SeRemoteShutdownPrivilege = 24 SeUndockPrivilege = 25 SeSyncAgentPrivilege = 26 SeEnableDelegationPrivilege = 27 SeManageVolumePrivilege = 28 SeImpersonatePrivilege = 29 SeCreateGlobalPrivilege = 30 SeTrustedCredManAccessPrivilege = 31 SeRelabelPrivilege = 32 SeIncreaseWorkingSetPrivilege = 33 SeTimeZonePrivilege = 34 SeCreateSymbolicLinkPrivilege = 35 } $THREAD_ACCESS = psenum $Module THREAD_ACCESS UInt32 @{ THREAD_TERMINATE = 0x00000001 THREAD_SUSPEND_RESUME = 0x00000002 THREAD_GET_CONTEXT = 0x00000008 THREAD_SET_CONTEXT = 0x00000010 THREAD_SET_INFORMATION = 0x00000020 THREAD_QUERY_INFORMATION = 0x00000040 THREAD_SET_THREAD_TOKEN = 0x00000080 THREAD_IMPERSONATE = 0x00000100 THREAD_DIRECT_IMPERSONATION = 0x00000200 THREAD_SET_LIMITED_INFORMATION = 0x00000400 THREAD_QUERY_LIMITED_INFORMATION = 0x00000800 DELETE = 0x00010000 READ_CONTROL = 0x00020000 WRITE_DAC = 0x00040000 WRITE_OWNER = 0x00080000 SYNCHRONIZE = 0x00100000 THREAD_ALL_ACCESS = 0x001f0ffb } -Bitfield $TOKEN_ACCESS = psenum $Module TOKEN_ACCESS UInt32 @{ TOKEN_DUPLICATE = 0x00000002 TOKEN_IMPERSONATE = 0x00000004 TOKEN_QUERY = 0x00000008 TOKEN_QUERY_SOURCE = 0x00000010 TOKEN_ADJUST_PRIVILEGES = 0x00000020 TOKEN_ADJUST_GROUPS = 0x00000040 TOKEN_ADJUST_DEFAULT = 0x00000080 TOKEN_ADJUST_SESSIONID = 0x00000100 DELETE = 0x00010000 READ_CONTROL = 0x00020000 WRITE_DAC = 0x00040000 WRITE_OWNER = 0x00080000 SYNCHRONIZE = 0x00100000 STANDARD_RIGHTS_REQUIRED = 0x000F0000 TOKEN_ALL_ACCESS = 0x001f01ff } -Bitfield $TOKEN_ELEVATION_TYPE = psenum $Module TOKEN_ELEVATION_TYPE UInt32 @{ TokenElevationTypeDefault = 1 TokenElevationTypeFull = 2 TokenElevationTypeLimited = 3 } $TOKEN_INFORMATION_CLASS = psenum $Module TOKEN_INFORMATION_CLASS UInt16 @{ TokenUser = 1 TokenGroups = 2 TokenPrivileges = 3 TokenOwner = 4 TokenPrimaryGroup = 5 TokenDefaultDacl = 6 TokenSource = 7 TokenType = 8 TokenImpersonationLevel = 9 TokenStatistics = 10 TokenRestrictedSids = 11 TokenSessionId = 12 TokenGroupsAndPrivileges = 13 TokenSessionReference = 14 TokenSandBoxInert = 15 TokenAuditPolicy = 16 TokenOrigin = 17 TokenElevationType = 18 TokenLinkedToken = 19 TokenElevation = 20 TokenHasRestrictions = 21 TokenAccessInformation = 22 TokenVirtualizationAllowed = 23 TokenVirtualizationEnabled = 24 TokenIntegrityLevel = 25 TokenUIAccess = 26 TokenMandatoryPolicy = 27 TokenLogonSid = 28 TokenIsAppContainer = 29 TokenCapabilities = 30 TokenAppContainerSid = 31 TokenAppContainerNumber = 32 TokenUserClaimAttributes = 33 TokenDeviceClaimAttributes = 34 TokenRestrictedUserClaimAttributes = 35 TokenRestrictedDeviceClaimAttributes = 36 TokenDeviceGroups = 37 TokenRestrictedDeviceGroups = 38 TokenSecurityAttributes = 39 TokenIsRestricted = 40 MaxTokenInfoClass = 41 } $TOKENMANDATORYPOLICY = psenum $Module TOKENMANDATORYPOLICY UInt32 @{ OFF = 0x0 NO_WRITE_UP = 0x1 POLICY_NEW_PROCESS_MIN = 0x2 POLICY_VALID_MASK = 0x3 } $TOKEN_TYPE = psenum $Module TOKEN_TYPE UInt32 @{ TokenPrimary = 1 TokenImpersonation = 2 } #endregion Enums #region Structs $ACL = struct $Module ACL @{ AclRevision = field 0 Byte Sbz1 = field 1 Byte AclSize = field 2 UInt16 AceCount = field 3 UInt16 Sbz2 = field 4 UInt16 } $LUID = struct $Module LUID @{ LowPart = field 0 $SecurityEntity HighPart = field 1 Int32 } $LUID_AND_ATTRIBUTES = struct $Module LUID_AND_ATTRIBUTES @{ Luid = field 0 $LUID Attributes = field 1 $SE_PRIVILEGE } $SID_AND_ATTRIBUTES = struct $Module SID_AND_ATTRIBUTES @{ Sid = field 0 IntPtr Attributes = field 1 $SE_GROUP } -PackingSize Size8 $TOKEN_APPCONTAINER_INFORMATION = struct $Module TOKEN_APPCONSTAINER_INFORMATION @{ TokenAppContainer = field 0 IntPtr } $TOKEN_DEFAULT_DACL = struct $Module TOKEN_DEFAULT_DACL @{ DefaultDacl = field 0 $ACL } $TOKEN_ELEVATION = struct $Module TOKEN_ELEVATION @{ TokenIsElevated = field 0 UInt32 } $TOKEN_GROUPS = struct $Module TOKEN_GROUPS @{ GroupCount = field 0 UInt32 Groups = field 1 $SID_AND_ATTRIBUTES.MakeArrayType() -MarshalAs ('ByValArray', 50) } $TOKEN_GROUPS_AND_PRIVILEGES = struct $Module TOKEN_GROUPS_AND_PRIVILEGES @{ SidCount = field 0 UInt32 SidLength = field 1 UInt32 Sids = field 2 IntPtr RestrictedSidCount = field 3 UInt32 RestrictedSidLength = field 4 UInt32 RestrictedSids = field 5 IntPtr PrivilegeCount = field 6 UInt32 PrivilegeLength = field 7 UInt32 Privileges = field 8 IntPtr AuthenticationId = field 9 $LUID } $TOKEN_LINKED_TOKEN = struct $Module TOKEN_LINKED_TOKEN @{ LinkedToken = field 0 IntPtr } $TOKEN_MANDATORY_LABEL = struct $Module TOKEN_MANDATORY_LABEL @{ Label = field 0 $SID_AND_ATTRIBUTES } $TOKEN_MANDATORY_POLICY = struct $Module TOKEN_MANDATORY_POLICY @{ Policy = field 0 $TOKENMANDATORYPOLICY } $TOKEN_OWNER = struct $Module TOKEN_OWNER @{ Owner = field 0 IntPtr } $TOKEN_PRIVILEGES = struct $Module TOKEN_PRIVILEGES @{ PrivilegeCount = field 0 UInt32 Privileges = field 1 $LUID_AND_ATTRIBUTES.MakeArrayType() -MarshalAs @('ByValArray', 50) } $TOKEN_SOURCE = struct $Module TOKEN_SOURCE @{ SourceName = field 0 string SourceIdentifier = field 1 $LUID } $TOKEN_STATISTICS = struct $Module TOKEN_STATISTICS @{ TokenId = field 0 $LUID AuthenticationId = field 1 $LUID ExpirationTime = field 2 UInt64 TokenType = field 3 $TOKEN_TYPE ImpersonationLevel = field 4 $SECURITY_IMPERSONATION_LEVEL DynamicCharged = field 5 UInt32 DynamicAvailable = field 6 UInt32 GroupCount = field 7 UInt32 PrivilegeCount = field 8 UInt32 ModifiedId = field 9 $LUID } $TOKEN_USER = struct $Module TOKEN_USER @{ User = field 0 $SID_AND_ATTRIBUTES } #endregion Structs #region FunctionDefinitions $FunctionDefinitions = @( (func kernel32 CloseHandle ([bool]) @( [IntPtr] #_In_ HANDLE hObject ) -EntryPoint CloseHandle -SetLastError), (func advapi32 ConvertSidToStringSid ([bool]) @( [IntPtr] #_In_ PSID Sid, [IntPtr].MakeByRefType() #_Out_ LPTSTR *StringSid ) -EntryPoint ConvertSidToStringSid -SetLastError), (func advapi32 DuplicateToken ([bool]) @( [IntPtr], #_In_ HANDLE ExistingTokenHandle, [UInt32], #_In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, [IntPtr].MakeByRefType() #_Out_ PHANDLE DuplicateTokenHandle ) -EntryPoint DuplicateToken -SetLastError), (func advapi32 GetTokenInformation ([bool]) @( [IntPtr], #_In_ HANDLE TokenHandle [Int32], #_In_ TOKEN_INFORMATION_CLASS TokenInformationClass [IntPtr], #_Out_opt_ LPVOID TokenInformation [UInt32], #_In_ DWORD TokenInformationLength [UInt32].MakeByRefType() #_Out_ PDWORD ReturnLength ) -EntryPoint GetTokenInformation -SetLastError), (func advapi32 ImpersonateLoggedOnUser ([bool]) @( [IntPtr] #_In_ HANDLE hToken ) -EntryPoint ImpersonateLoggedOnUser -SetLastError), (func kernel32 OpenProcess ([IntPtr]) @( [UInt32], #_In_ DWORD dwDesiredAccess [bool], #_In_ BOOL bInheritHandle [UInt32] #_In_ DWORD dwProcessId ) -EntryPoint OpenProcess -SetLastError), (func advapi32 OpenProcessToken ([bool]) @( [IntPtr], #_In_ HANDLE ProcessHandle [UInt32], #_In_ DWORD DesiredAccess [IntPtr].MakeByRefType() #_Out_ PHANDLE TokenHandle ) -EntryPoint OpenProcessToken -SetLastError), (func kernel32 OpenThread ([IntPtr]) @( [UInt32], #_In_ DWORD dwDesiredAccess [bool], #_In_ BOOL bInheritHandle [UInt32] #_In_ DWORD dwThreadId ) -EntryPoint OpenThread -SetLastError), (func advapi32 OpenThreadToken ([bool]) @( [IntPtr], #_In_ HANDLE ThreadHandle [UInt32], #_In_ DWORD DesiredAccess [bool], #_In_ BOOL OpenAsSelf [IntPtr].MakeByRefType() #_Out_ PHANDLE TokenHandle ) -EntryPoint OpenThreadToken -SetLastError), (func advapi32 RevertToSelf ([bool]) @( # No Parameters ) -EntryPoint RevertToSelf -SetLastError) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Module -Namespace AccessToken $Advapi32 = $Types['advapi32'] $Kernel32 = $Types['kernel32'] #endregion FunctionDefinitions #region Windows API Functions function CloseHandle { <# .SYNOPSIS Closes an open object handle. .DESCRIPTION The CloseHandle function closes handles to the following objects: - Access token - Communications device - Console input - Console screen buffer - Event - File - File mapping - I/O completion port - Job - Mailslot - Memory resource notification - Mutex - Named pipe - Pipe - Process - Semaphore - Thread - Transaction - Waitable timer The documentation for the functions that create these objects indicates that CloseHandle should be used when you are finished with the object, and what happens to pending operations on the object after the handle is closed. In general, CloseHandle invalidates the specified object handle, decrements the object's handle count, and performs object retention checks. After the last handle to an object is closed, the object is removed from the system. .PARAMETER Handle A valid handle to an open object. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect Optional Dependencies: None (func kernel32 CloseHandle ([bool]) @( [IntPtr] #_In_ HANDLE hObject ) -EntryPoint CloseHandle -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $Handle ) $SUCCESS = $Kernel32::CloseHandle($Handle); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $SUCCESS) { Write-Debug "CloseHandle Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } } function ConvertSidToStringSid { <# .SYNOPSIS The ConvertSidToStringSid function converts a security identifier (SID) to a string format suitable for display, storage, or transmission. .DESCRIPTION The ConvertSidToStringSid function uses the standard S-R-I-S-S… format for SID strings. .PARAMETER SidPointer A pointer to the SID structure to be converted. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect Optional Dependencies: None (func advapi32 ConvertSidToStringSid ([bool]) @( [IntPtr] #_In_ PSID Sid, [IntPtr].MakeByRefType() #_Out_ LPTSTR *StringSid ) -EntryPoint ConvertSidToStringSid -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa376399(v=vs.85).aspx .EXAMPLE #> [OutputType([string])] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [IntPtr] $SidPointer ) $StringPtr = [IntPtr]::Zero $Success = $Advapi32::ConvertSidToStringSid($SidPointer, [ref]$StringPtr); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { Write-Verbose "ConvertSidToStringSid Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto($StringPtr)) } function DuplicateToken { <# .SYNOPSIS The DuplicateToken function creates a new access token that duplicates one already in existence. .DESCRIPTION The DuplicateToken function creates an impersonation token, which you can use in functions such as SetThreadToken and ImpersonateLoggedOnUser. The token created by DuplicateToken cannot be used in the CreateProcessAsUser function, which requires a primary token. To create a token that you can pass to CreateProcessAsUser, use the DuplicateTokenEx function. .PARAMETER TokenHandle A handle to an access token opened with TOKEN_DUPLICATE access. .PARAMETER ImpersonationLevel Specifies a SECURITY_IMPERSONATION_LEVEL enumerated type that supplies the impersonation level of the new token. The Default is SecurityImpersonation. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, SECURITY_IMPERSONATION_LEVEL (Enumeration) Optional Dependencies: None (func advapi32 DuplicateToken ([bool]) @( [IntPtr] #_In_ HANDLE ExistingTokenHandle, [UInt32] #_In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, [IntPtr].MakeByRefType() #_Out_ PHANDLE DuplicateTokenHandle ) -EntryPoint DuplicateToken -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa446616(v=vs.85).aspx .EXAMPLE #> [OutputType([IntPtr])] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [IntPtr] $TokenHandle, [Parameter()] [ValidateSet('None','SecurityAnonymous','SecurityIdentification','SecurityImpersonation','SecurityDelegation')] [string] $ImpersonationLevel = 'SecurityImpersonation' ) $DuplicateTokenHandle = [IntPtr]::Zero $success = $Advapi32::DuplicateToken($TokenHandle, $SECURITY_IMPERSONATION_LEVEL::$ImpersonationLevel, [ref]$DuplicateTokenHandle); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $success) { Write-Debug "DuplicateToken Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $DuplicateTokenHandle } function GetTokenInformation { <# .SYNOPSIS The GetTokenInformation function retrieves a specified type of information about an access token. The calling process must have appropriate access rights to obtain the information. To determine if a user is a member of a specific group, use the CheckTokenMembership function. To determine group membership for app container tokens, use the CheckTokenMembershipEx function. .PARAMETER TokenHandle A handle to an access token from which information is retrieved. If TokenInformationClass specifies TokenSource, the handle must have TOKEN_QUERY_SOURCE access. For all other TokenInformationClass values, the handle must have TOKEN_QUERY access. .PARAMETER TokenInformationClass Specifies a value from the TOKEN_INFORMATION_CLASS enumerated type to identify the type of information the function retrieves. Any callers who check the TokenIsAppContainer and have it return 0 should also verify that the caller token is not an identify level impersonation token. If the current token is not an app container but is an identity level token, you should return AccessDenied. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Module Dependencies: PSReflect Required Function Dependencies: ConvertSidToStringSid Required Structure Dependencies: TOKEN_USER, SID_AND_ATTRIBUTES, TOKEN_PRIVILEGES, TOKEN_OWNER, TOKEN_SOURCE, LUID, TOKEN_MANDATORY_LABEL Required Enumeration Dependencies: LuidAttributes, TOKEN_TYPE, SECURITY_IMPERSONATION_LEVEL Optional Dependencies: TokenInformationClass (Enum) (func advapi32 GetTokenInformation ([bool]) @( [IntPtr], #_In_ HANDLE TokenHandle [Int32], #_In_ TOKEN_INFORMATION_CLASS TokenInformationClass [IntPtr], #_Out_opt_ LPVOID TokenInformation [UInt32], #_In_ DWORD TokenInformationLength [UInt32].MakeByRefType() #_Out_ PDWORD ReturnLength ) -EntryPoint GetTokenInformation -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa446671(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $TokenHandle, [Parameter(Mandatory = $true)] [ValidateSet('TokenUser','TokenGroups','TokenPrivileges','TokenOwner','TokenPrimaryGroup','TokenDefaultDacl','TokenSource','TokenType','TokenImpersonationLevel','TokenStatistics','TokenRestrictedSids','TokenSessionId','TokenGroupsAndPrivileges','TokenSandBoxInert','TokenOrigin','TokenElevationType','TokenLinkedToken','TokenElevation','TokenHasRestrictions','TokenAccessInformation','TokenVirtualizationAllowed','TokenVirtualizationEnabled','TokenIntegrityLevel','TokenUIAccess','TokenMandatoryPolicy','TokenLogonSid','TokenIsAppContainer','TokenCapabilities','TokenAppContainerSid','TokenAppContainerNumber','TokenUserClaimAttributes','TokenDeviceClaimAttributes','TokenDeviceGroups','TokenRestrictedDeviceGroups')] [string] $TokenInformationClass ) # initial query to determine the necessary buffer size $TokenPtrSize = 0 $SUCCESS = $Advapi32::GetTokenInformation($TokenHandle, $TOKEN_INFORMATION_CLASS::$TokenInformationClass, [IntPtr]::Zero, $TokenPtrSize, [ref]$TokenPtrSize); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() [IntPtr]$TokenPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenPtrSize) # retrieve the proper buffer value $SUCCESS = $Advapi32::GetTokenInformation($TokenHandle, $TOKEN_INFORMATION_CLASS::$TokenInformationClass, $TokenPtr, $TokenPtrSize, [ref]$TokenPtrSize); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $SUCCESS) { [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPtr) throw "GetTokenInformation Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } switch($TokenInformationClass) { TokenUser { <# The buffer receives a TOKEN_USER structure that contains the user account of the token. ConvertSidToStringSid (Function) TOKEN_USER (Structure) SID_AND_ATTRIBUTES (Structure) #> $TokenUser = $TokenPtr -as $TOKEN_USER $UserSid = ConvertSidToStringSid -SidPointer $TokenUser.User.Sid $Sid = New-Object System.Security.Principal.SecurityIdentifier($UserSid) $UserName = $Sid.Translate([System.Security.Principal.NTAccount]) $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value $UserSid $obj | Add-Member -MemberType NoteProperty -Name Name -Value $UserName Write-Output $obj } TokenGroups { <# The buffer receives a TOKEN_GROUPS structure that contains the group accounts associated with the token. TOKEN_GROUPS (Structure) SID_AND_ATTRIBUTES (Structure) #> $TokenGroups = ($TokenPtr -as $TOKEN_GROUPS) for($i = 0; $i -lt $TokenGroups.GroupCount; $i++) { $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value (ConvertSidToStringSid -SidPointer $TokenGroups.Groups[$i].Sid) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $TokenGroups.Groups[$i].Attributes Write-Output $obj } } TokenPrivileges { <# The buffer receives a TOKEN_PRIVILEGES structure that contains the privileges of the token. TOKEN_PRIVILEGES (Structure) LUID_AND_ATTRIBUTES (Structure) LuidAttributes (Enumeration) #> $TokenPrivileges = $TokenPtr -as $TOKEN_PRIVILEGES for($i = 0; $i -lt $TokenPrivileges.PrivilegeCount; $i++) { $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Privilege -Value $TokenPrivileges.Privileges[$i].Luid.LowPart $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $TokenPrivileges.Privileges[$i].Attributes Write-Output $obj } } TokenOwner { <# The buffer receives a TOKEN_OWNER structure that contains the default owner security identifier (SID) for newly created objects. ConvertSidToStringSid (Function) TOKEN_OWNER (Structure) #> $TokenOwner = $TokenPtr -as $TOKEN_OWNER if($TokenOwner.Owner -ne $null) { $OwnerSid = ConvertSidToStringSid -SidPointer $TokenOwner.Owner $Sid = New-Object System.Security.Principal.SecurityIdentifier($OwnerSid) $OwnerName = $Sid.Translate([System.Security.Principal.NTAccount]) $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value $OwnerSid $obj | Add-Member -MemberType NoteProperty -Name Name -Value $OwnerName Write-Output $obj } else { Write-Output $null } } TokenPrimaryGroup { <# The buffer receives a TOKEN_PRIMARY_GROUP structure that contains the default primary group SID for newly created objects. TOKEN_PRIMARY_GROUP (Structure) #> throw [System.NotImplementedException]"The $($TokenInformationClass) class is not implemented yet." } TokenDefaultDacl { <# The buffer receives a TOKEN_DEFAULT_DACL structure that contains the default DACL for newly created objects. TOKEN_DEFAULT_DACL (Structure) ACL (Structure) #> $Dacl = $TokenPtr -as $TOKEN_DEFAULT_DACL Write-Output $Dacl.DefaultDacl } TokenSource { <# The buffer receives a TOKEN_SOURCE structure that contains the source of the token. TOKEN_QUERY_SOURCE access is needed to retrieve this information. TOKEN_SOURCE (Structure) LUID (Structure) #> Write-Output $TokenPtr #$TokenSource = $TokenPtr -as $TOKEN_SOURCE #Write-Output ($TokenSource.SourceName -join "") } TokenType { <# The buffer receives a TOKEN_TYPE value that indicates whether the token is a primary or impersonation token. TOKEN_TYPE (Enumeration) #> if($TokenPtr -ne $null) { Write-Output ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr) -as $TOKEN_TYPE) } } TokenImpersonationLevel { <# The buffer receives a SECURITY_IMPERSONATION_LEVEL value that indicates the impersonation level of the token. If the access token is not an impersonation token, the function fails. SECURITY_IMPERSONATION_LEVEL (Enumeration) #> Write-Output ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr) -as $SECURITY_IMPERSONATION_LEVEL) } TokenStatistics { <# The buffer receives a TOKEN_STATISTICS structure that contains various token statistics. TOKEN_STATISTICS (Structure) LUID (Structure) TOKEN_TYPE (Enumeration) SECURITY_IMPERSONATION_LEVEL (Enumeration) #> $TokenStats = $TokenPtr -as $TOKEN_STATISTICS $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name TokenId -Value $TokenStats.TokenId.LowPart $obj | Add-Member -MemberType NoteProperty -Name AuthenticationId -Value $TokenStats.AuthenticationId.LowPart $obj | Add-Member -MemberType NoteProperty -Name TokenType -Value $TokenStats.TokenType $obj | Add-Member -MemberType NoteProperty -Name ImpersonationLevel -Value $TokenStats.ImpersonationLevel $obj | Add-Member -MemberType NoteProperty -Name DynamicCharged -Value $TokenStats.DynamicCharged $obj | Add-Member -MemberType NoteProperty -Name DynamicAvailable -Value $TokenStats.DynamicAvailable $obj | Add-Member -MemberType NoteProperty -Name GroupCount -Value $TokenStats.GroupCount $obj | Add-Member -MemberType NoteProperty -Name PrivilegeCount -Value $TokenStats.PrivilegeCount $obj | Add-Member -MemberType NoteProperty -Name ModifiedId -Value $TokenStats.ModifiedId.LowPart Write-Output $obj } TokenRestrictedSids { <# The buffer receives a TOKEN_GROUPS structure that contains the list of restricting SIDs in a restricted token. TOKEN_GROUPS (Structure) SID_AND_ATTRIBUTES (Structure) #> $TokenGroups = ($TokenPtr -as $TOKEN_GROUPS) for($i = 0; $i -lt $TokenGroups.GroupCount; $i++) { $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value (ConvertSidToStringSid -SidPointer $TokenGroups.Groups[$i].Sid) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $TokenGroups.Groups[$i].Attributes Write-Output $obj } } TokenSessionId { # The buffer receives a DWORD value that indicates the Terminal Services session identifier that is associated with the token. # If the token is associated with the terminal server client session, the session identifier is nonzero. # Windows Server 2003 and Windows XP: If the token is associated with the terminal server console session, the session identifier is zero. # In a non-Terminal Services environment, the session identifier is zero. # If TokenSessionId is set with SetTokenInformation, the application must have the Act As Part Of the Operating System privilege, and the application must be enabled to set the session ID in a token. Write-Output ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr)) } TokenGroupsAndPrivileges { <# The buffer receives a TOKEN_GROUPS_AND_PRIVILEGES structure that contains the user SID, the group accounts, the restricted SIDs, and the authentication ID associated with the token. TOKEN_GROUPS_AND_PRIVILEGES (Structure) SID_AND_ATTRIBUTES (Structure) LUID (Structure) #> $GroupsAndPrivs = ($TokenPtr -as $TOKEN_GROUPS_AND_PRIVILEGES) $SidList = New-Object -TypeName 'System.Collections.Generic.List[System.Object]' for($i = 0; $i -lt $GroupsAndPrivs.SidCount; $i++) { $currentPtr = [IntPtr]($GroupsAndPrivs.Sids.ToInt64() + ($SID_AND_ATTRIBUTES::GetSize() * $i)) $SidAndAttr = $currentPtr -as $SID_AND_ATTRIBUTES $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value (ConvertSidToStringSid -SidPointer $SidAndAttr.Sid) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $SidAndAttr.Attributes $SidList.Add($obj) } $PrivList = New-Object -TypeName 'System.Collections.Generic.List[System.Object]' for($i = 0; $i -lt $GroupsAndPrivs.PrivilegeCount; $i++) { $currentPtr = [IntPtr]($GroupsAndPrivs.Privileges.ToInt64() + ($LUID_AND_ATTRIBUTES::GetSize() * $i)) $LuidAndAttr = ($currentPtr -as $LUID_AND_ATTRIBUTES) $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Privilege -Value $LuidAndAttr.Luid.LowPart $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $LuidAndAttr.Attributes $PrivList.Add($obj) } $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sids -Value $SidList.ToArray() $obj | Add-Member -MemberType NoteProperty -Name Privilegs -Value $PrivList.ToArray() Write-Output $obj } TokenSandBoxInert { # The buffer receives a DWORD value that is nonzero if the token includes the SANDBOX_INERT flag. Write-Output (0 -ne ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr))) } TokenOrigin { <# The buffer receives a TOKEN_ORIGIN value. If the token resulted from a logon that used explicit credentials, such as passing a name, domain, and password to the LogonUser function, then the TOKEN_ORIGIN structure will contain the ID of the logon session that created it. If the token resulted from network authentication, such as a call to AcceptSecurityContext or a call to LogonUser with dwLogonType set to LOGON32_LOGON_NETWORK or LOGON32_LOGON_NETWORK_CLEARTEXT, then this value will be zero. TOKEN_ORIGIN (Structure) LUID (Structure) #> $TokenOrigin = $TokenPtr -as $LUID Write-Output $TokenOrigin.LowPart } TokenElevationType { <# The buffer receives a TOKEN_ELEVATION_TYPE value that specifies the elevation level of the token. TOKEN_ELEVATION_TYPE (Enumeration) #> Write-Output ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr) -as $TOKEN_ELEVATION_TYPE) } TokenLinkedToken { <# The buffer receives a TOKEN_LINKED_TOKEN structure that contains a handle to another token that is linked to this token. TOKEN_LINKED_TOKEN (Structure) #> Write-Output ($TokenPtr -as $TOKEN_LINKED_TOKEN).LinkedToken } TokenElevation { <# The buffer receives a TOKEN_ELEVATION structure that specifies whether the token is elevated. TOKEN_ELEVATION (Structure) #> Write-Output (($TokenPtr -as $TOKEN_ELEVATION).TokenIsElevated -ne 0) } TokenHasRestrictions { # The buffer receives a DWORD value that is nonzero if the token has ever been filtered. Write-Output (0 -ne ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr))) } TokenAccessInformation { <# The buffer receives a TOKEN_ACCESS_INFORMATION structure that specifies security information contained in the token. TOKEN_ACCESS_INFORMATION (Structure) SID_AND_ATTRIBUTES_HASH (Structure) SID_HASH_ENTRY (Structure) TOKEN_PRIVILEGES (Structure) LUID_AND_ATTRIBUTES (Structure) LUID (Structure) TOKEN_TYPE (Enumeration) SECURITY_IMPERSONATION_LEVEL (Enumeration) TOKEN_MANDATORY_POLICY (Structure) #> <# $TokenAccessInfo = ($TokenPtr -as $TOKEN_ACCESS_INFORMATION) $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name SidHash -Value ($TokenAccessInfo.SidHash -as $SID_AND_ATTRIBUTES_HASH) $obj | Add-Member -MemberType NoteProperty -Name RestrictedSidHash -Value ($TokenAccessInfo.RestrictedSidHash -as $SID_AND_ATTRIBUTES_HASH) $obj | Add-Member -MemberType NoteProperty -Name Privileges -Value ($TokenAccessInfo.Privileges -as $TOKEN_PRIVILEGES) $obj | Add-Member -MemberType NoteProperty -Name AuthenticationId -Value $TokenAccessInfo.AuthenticationId.LowPart $obj | Add-Member -MemberType NoteProperty -Name TokenType -Value $TokenAccessInfo.TokenType $obj | Add-Member -MemberType NoteProperty -Name ImpersonationLevel -Value $TokenAccessInfo.ImpersonationLevel $obj | Add-Member -MemberType NoteProperty -Name AppContainerNumber -Value $TokenAccessInfo.AppContainerNumber $obj | Add-Member -MemberType NoteProperty -Name PackageSid -Value (ConvertSidToStringSid -SidPointer $TokenAccessInfo.PackageSid) $obj | Add-Member -MemberType NoteProperty -Name CapabilitiesHash -Value ($TokenAccessInfo.CapabilitiesHash -as $SID_AND_ATTRIBUTES_HASH) $obj | Add-Member -MemberType NoteProperty -Name TrustLevelSid -Value (ConvertSidToStringSid -SidPointer $TokenAccessInfo.TrustLevelSid) Write-Output $obj #> Write-Output $TokenPtr #throw [System.NotImplementedException]"The $($TokenInformationClass) class is not implemented yet." } TokenVirtualizationAllowed { # The buffer receives a DWORD value that is nonzero if virtualization is allowed for the token. Write-Output (0 -ne ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr))) } TokenVirtualizationEnabled { # The buffer receives a DWORD value that is nonzero if virtualization is enabled for the token. Write-Output (0 -ne ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr))) } TokenIntegrityLevel { <# The buffer receives a TOKEN_MANDATORY_LABEL structure that specifies the token's integrity level. TOKEN_MANDATORY_LABEL ConvertSidToStringSid #> $TokenIntegrity = $TokenPtr -as $TOKEN_MANDATORY_LABEL switch(ConvertSidToStringSid -SidPointer $TokenIntegrity.Label.Sid) { S-1-16-0 { Write-Output "UNTRUSTED_MANDATORY_LEVEL" } S-1-16-4096 { Write-Output "LOW_MANDATORY_LEVEL" } S-1-16-8192 { Write-Output "MEDIUM_MANDATORY_LEVEL" } S-1-16-8448 { Write-Output "MEDIUM_PLUS_MANDATORY_LEVEL" } S-1-16-12288 { Write-Output "HIGH_MANDATORY_LEVEL" } S-1-16-16384 { Write-Output "SYSTEM_MANDATORY_LEVEL" } S-1-16-20480 { Write-Output "PROTECTED_PROCESS_MANDATORY_LEVEL" } S-1-16-28672 { Write-Output "SECURE_PROCESS_MANDATORY_LEVEL" } } } TokenUIAccess { # The buffer receives a DWORD value that is nonzero if the token has the UIAccess flag set. Write-Output (0 -ne ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr))) } TokenMandatoryPolicy { <# The buffer receives a TOKEN_MANDATORY_POLICY structure that specifies the token's mandatory integrity policy. TOKEN_MANDATORY_POLICY TOKENMANDATORYPOLICY #> $MandatoryPolicy = $TokenPtr -as $TOKEN_MANDATORY_POLICY Write-Output $MandatoryPolicy.Policy } TokenLogonSid { <# The buffer receives a TOKEN_GROUPS structure that specifies the token's logon SID. TOKEN_GROUPS (Structure) SID_AND_ATTRIBUTES (Structure) #> $TokenGroups = ($TokenPtr -as $TOKEN_GROUPS) for($i = 0; $i -lt $TokenGroups.GroupCount; $i++) { $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value (ConvertSidToStringSid -SidPointer $TokenGroups.Groups[$i].Sid) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $TokenGroups.Groups[$i].Attributes Write-Output $obj } } TokenIsAppContainer { # The buffer receives a DWORD value that is nonzero if the token is an app container token. Any callers who check the TokenIsAppContainer and have it return 0 should also verify that the caller token is not an identify level impersonation token. If the current token is not an app container but is an identity level token, you should return AccessDenied. Write-Output (0 -ne ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr))) } TokenCapabilities { <# The buffer receives a TOKEN_GROUPS structure that contains the capabilities associated with the token. TOKEN_GROUPS (Structure) SID_AND_ATTRIBUTES (Structure) #> $TokenGroups = ($TokenPtr -as $TOKEN_GROUPS) for($i = 0; $i -lt $TokenGroups.GroupCount; $i++) { $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value (ConvertSidToStringSid -SidPointer $TokenGroups.Groups[$i].Sid) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $TokenGroups.Groups[$i].Attributes Write-Output $obj } } TokenAppContainerSid { <# The buffer receives a TOKEN_APPCONTAINER_INFORMATION structure that contains the AppContainerSid associated with the token. If the token is not associated with an app container, the TokenAppContainer member of the TOKEN_APPCONTAINER_INFORMATION structure points to NULL. TOKEN_APPCONTAINER_INFORMATION (Structure) #> Write-Output ($TokenPtr -as $TOKEN_APPCONTAINER_INFORMATION) } TokenAppContainerNumber { # The buffer receives a DWORD value that includes the app container number for the token. For tokens that are not app container tokens, this value is zero. Write-Output ([System.Runtime.InteropServices.Marshal]::ReadInt32($TokenPtr)) } TokenUserClaimAttributes { <# The buffer receives a CLAIM_SECURITY_ATTRIBUTES_INFORMATION structure that contains the user claims associated with the token. CLAIM_SECURITY_ATTRIBUTES_INFORMATION (Structure) CLAIM_SECURITY_ATTRIBUTE_V1 (Structure) CLAIM_SECURITY_ATTRIBUTE_FQBN_VALUE (Structure) CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE (Structure) #> <# $AttributeInformation = $TokenPtr -as $CLAIM_SECURITY_ATTRIBUTES_INFORMATION if($AttributeInformation.AttributeCount -ne 0) { } #> throw [System.NotImplementedException]"The $($TokenInformationClass) class is not implemented yet." } TokenDeviceClaimAttributes { <# The buffer receives a CLAIM_SECURITY_ATTRIBUTES_INFORMATION structure that contains the device claims associated with the token. CLAIM_SECURITY_ATTRIBUTES_INFORMATION (Structure) CLAIM_SECURITY_ATTRIBUTE_V1 (Structure) CLAIM_SECURITY_ATTRIBUTE_FQBN_VALUE (Structure) CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE (Structure) #> <# $AttributeInformation = $TokenPtr -as $CLAIM_SECURITY_ATTRIBUTES_INFORMATION if($AttributeInformation.AttributeCount -ne 0) { } #> throw [System.NotImplementedException]"The $($TokenInformationClass) class is not implemented yet." } TokenDeviceGroups { <# The buffer receives a TOKEN_GROUPS structure that contains the device groups that are associated with the token. TOKEN_GROUPS (Structure) SID_AND_ATTRIBUTES (Structure) #> #Write-Output ($TokenPtr -as $TOKEN_GROUPS) $TokenGroups = ($TokenPtr -as $TOKEN_GROUPS) for($i = 0; $i -lt $TokenGroups.GroupCount; $i++) { $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value (ConvertSidToStringSid -SidPointer $TokenGroups.Groups[$i].Sid) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $TokenGroups.Groups[$i].Attributes Write-Output $obj } } TokenRestrictedDeviceGroups { <# The buffer receives a TOKEN_GROUPS structure that contains the restricted device groups that are associated with the token. TOKEN_GROUPS (Structure) SID_AND_ATTRIBUTES (Structure) #> $TokenGroups = ($TokenPtr -as $TOKEN_GROUPS) for($i = 0; $i -lt $TokenGroups.GroupCount; $i++) { $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Sid -Value (ConvertSidToStringSid -SidPointer $TokenGroups.Groups[$i].Sid) $obj | Add-Member -MemberType NoteProperty -Name Attributes -Value $TokenGroups.Groups[$i].Attributes Write-Output $obj } } } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPtr) } function ImpersonateLoggedOnUser { <# .SYNOPSIS The ImpersonateLoggedOnUser function lets the calling thread impersonate the security context of a logged-on user. The user is represented by a token handle. .DESCRIPTION The impersonation lasts until the thread exits or until it calls RevertToSelf. The calling thread does not need to have any particular privileges to call ImpersonateLoggedOnUser. If the call to ImpersonateLoggedOnUser fails, the client connection is not impersonated and the client request is made in the security context of the process. If the process is running as a highly privileged account, such as LocalSystem, or as a member of an administrative group, the user may be able to perform actions they would otherwise be disallowed. Therefore, it is important to always check the return value of the call, and if it fails, raise an error; do not continue execution of the client request. All impersonate functions, including ImpersonateLoggedOnUser allow the requested impersonation if one of the following is true: - The requested impersonation level of the token is less than SecurityImpersonation, such as SecurityIdentification or SecurityAnonymous. - The caller has the SeImpersonatePrivilege privilege. - A process (or another process in the caller's logon session) created the token using explicit credentials through LogonUser or LsaLogonUser function. - The authenticated identity is same as the caller. Windows XP with SP1 and earlier: The SeImpersonatePrivilege privilege is not supported. .PARAMETER TokenHandle A handle to a primary or impersonation access token that represents a logged-on user. This can be a token handle returned by a call to LogonUser, CreateRestrictedToken, DuplicateToken, DuplicateTokenEx, OpenProcessToken, or OpenThreadToken functions. If hToken is a handle to a primary token, the token must have TOKEN_QUERY and TOKEN_DUPLICATE access. If hToken is a handle to an impersonation token, the token must have TOKEN_QUERY and TOKEN_IMPERSONATE access. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect Optional Dependencies: None (func advapi32 ImpersonateLoggedOnUser ([bool]) @( [IntPtr] #_In_ HANDLE hToken ) -EntryPoint ImpersonateLoggedOnUser -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378612(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $TokenHandle ) $SUCCESS = $Advapi32::ImpersonateLoggedOnUser($TokenHandle); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $SUCCESS) { throw "ImpersonateLoggedOnUser Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } } function OpenProcess { <# .SYNOPSIS Opens an existing local process object. .DESCRIPTION To open a handle to another local process and obtain full access rights, you must enable the SeDebugPrivilege privilege. The handle returned by the OpenProcess function can be used in any function that requires a handle to a process, such as the wait functions, provided the appropriate access rights were requested. When you are finished with the handle, be sure to close it using the CloseHandle function. .PARAMETER ProcessId The identifier of the local process to be opened. If the specified process is the System Process (0x00000000), the function fails and the last error code is ERROR_INVALID_PARAMETER. If the specified process is the Idle process or one of the CSRSS processes, this function fails and the last error code is ERROR_ACCESS_DENIED because their access restrictions prevent user-level code from opening them. .PARAMETER DesiredAccess The access to the process object. This access right is checked against the security descriptor for the process. This parameter can be one or more of the process access rights. If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the contents of the security descriptor. .PARAMETER InheritHandle If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, PROCESS_ACCESS (Enumeration) Optional Dependencies: None (func kernel32 OpenProcess ([IntPtr]) @( [UInt32], #_In_ DWORD dwDesiredAccess [bool], #_In_ BOOL bInheritHandle [UInt32] #_In_ DWORD dwProcessId ) -EntryPoint OpenProcess -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320(v=vs.85).aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms684880(v=vs.85).aspx .EXAMPLE #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [UInt32] $ProcessId, [Parameter(Mandatory = $true)] [ValidateSet('PROCESS_TERMINATE','PROCESS_CREATE_THREAD','PROCESS_VM_OPERATION','PROCESS_VM_READ','PROCESS_VM_WRITE','PROCESS_DUP_HANDLE','PROCESS_CREATE_PROCESS','PROCESS_SET_QUOTA','PROCESS_SET_INFORMATION','PROCESS_QUERY_INFORMATION','PROCESS_SUSPEND_RESUME','PROCESS_QUERY_LIMITED_INFORMATION','DELETE','READ_CONTROL','WRITE_DAC','WRITE_OWNER','SYNCHRONIZE','PROCESS_ALL_ACCESS')] [string[]] $DesiredAccess, [Parameter()] [bool] $InheritHandle = $false ) # Calculate Desired Access Value $dwDesiredAccess = 0 foreach($val in $DesiredAccess) { $dwDesiredAccess = $dwDesiredAccess -bor $PROCESS_ACCESS::$val } $hProcess = $Kernel32::OpenProcess($dwDesiredAccess, $InheritHandle, $ProcessId); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if($hProcess -eq 0) { throw "OpenProcess Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hProcess } function OpenProcessToken { <# .SYNOPSIS The OpenProcessToken function opens the access token associated with a process. .PARAMETER ProcessHandle A handle to the process whose access token is opened. The process must have the PROCESS_QUERY_INFORMATION access permission. .PARAMETER DesiredAccess Specifies an access mask that specifies the requested types of access to the access token. These requested access types are compared with the discretionary access control list (DACL) of the token to determine which accesses are granted or denied. For a list of access rights for access tokens, see Access Rights for Access-Token Objects. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, TOKEN_ACCESS (Enumeration) Optional Dependencies: None (func advapi32 OpenProcessToken ([bool]) @( [IntPtr], #_In_ HANDLE ProcessHandle [UInt32], #_In_ DWORD DesiredAccess [IntPtr].MakeByRefType() #_Out_ PHANDLE TokenHandle ) -EntryPoint OpenProcessToken -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa379295(v=vs.85).aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa374905(v=vs.85).aspx .EXAMPLE #> [OutputType([IntPtr])] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [IntPtr] $ProcessHandle, [Parameter(Mandatory = $true)] [ValidateSet('TOKEN_ASSIGN_PRIMARY','TOKEN_DUPLICATE','TOKEN_IMPERSONATE','TOKEN_QUERY','TOKEN_QUERY_SOURCE','TOKEN_ADJUST_PRIVILEGES','TOKEN_ADJUST_GROUPS','TOKEN_ADJUST_DEFAULT','TOKEN_ADJUST_SESSIONID','DELETE','READ_CONTROL','WRITE_DAC','WRITE_OWNER','SYNCHRONIZE','STANDARD_RIGHTS_REQUIRED','TOKEN_ALL_ACCESS')] [string[]] $DesiredAccess ) # Calculate Desired Access Value $dwDesiredAccess = 0 foreach($val in $DesiredAccess) { $dwDesiredAccess = $dwDesiredAccess -bor $TOKEN_ACCESS::$val } $hToken = [IntPtr]::Zero $Success = $Advapi32::OpenProcessToken($ProcessHandle, $dwDesiredAccess, [ref]$hToken); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { throw "OpenProcessToken Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hToken } function OpenThread { <# .SYNOPSIS Opens an existing thread object. .DESCRIPTION The handle returned by OpenThread can be used in any function that requires a handle to a thread, such as the wait functions, provided you requested the appropriate access rights. The handle is granted access to the thread object only to the extent it was specified in the dwDesiredAccess parameter. When you are finished with the handle, be sure to close it by using the CloseHandle function. .PARAMETER ThreadId The identifier of the thread to be opened. .PARAMETER DesiredAccess The access to the thread object. This access right is checked against the security descriptor for the thread. This parameter can be one or more of the thread access rights. If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the contents of the security descriptor. .PARAMETER InheritHandle If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, THREAD_ACCESS (Enumeration) Optional Dependencies: None (func kernel32 OpenThread ([IntPtr]) @( [UInt32], #_In_ DWORD dwDesiredAccess [bool], #_In_ BOOL bInheritHandle [UInt32] #_In_ DWORD dwThreadId ) -EntryPoint OpenThread -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms684335(v=vs.85).aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms686769(v=vs.85).aspx .EXAMPLE #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [UInt32] $ThreadId, [Parameter(Mandatory = $true)] [ValidateSet('THREAD_TERMINATE','THREAD_SUSPEND_RESUME','THREAD_GET_CONTEXT','THREAD_SET_CONTEXT','THREAD_SET_INFORMATION','THREAD_QUERY_INFORMATION','THREAD_SET_THREAD_TOKEN','THREAD_IMPERSONATE','THREAD_DIRECT_IMPERSONATION','THREAD_SET_LIMITED_INFORMATION','THREAD_QUERY_LIMITED_INFORMATION','DELETE','READ_CONTROL','WRITE_DAC','WRITE_OWNER','SYNCHRONIZE','THREAD_ALL_ACCESS')] [string[]] $DesiredAccess, [Parameter()] [bool] $InheritHandle = $false ) # Calculate Desired Access Value $dwDesiredAccess = 0 foreach($val in $DesiredAccess) { $dwDesiredAccess = $dwDesiredAccess -bor $THREAD_ACCESS::$val } $hThread = $Kernel32::OpenThread($dwDesiredAccess, $InheritHandle, $ThreadId); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if($hThread -eq 0) { throw "OpenThread Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hThread } function OpenThreadToken { <# .SYNOPSIS The OpenThreadToken function opens the access token associated with a thread .DESCRIPTION Tokens with the anonymous impersonation level cannot be opened. Close the access token handle returned through the Handle parameter by calling CloseHandle. .PARAMETER ThreadHandle A handle to the thread whose access token is opened. .PARAMETER DesiredAccess Specifies an access mask that specifies the requested types of access to the access token. These requested access types are reconciled against the token's discretionary access control list (DACL) to determine which accesses are granted or denied. .PARAMETER OpenAsSelf TRUE if the access check is to be made against the process-level security context. FALSE if the access check is to be made against the current security context of the thread calling the OpenThreadToken function. The OpenAsSelf parameter allows the caller of this function to open the access token of a specified thread when the caller is impersonating a token at SecurityIdentification level. Without this parameter, the calling thread cannot open the access token on the specified thread because it is impossible to open executive-level objects by using the SecurityIdentification impersonation level. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, $TOKEN_ACCESS (Enumeration) Optional Dependencies: None (func advapi32 OpenThreadToken ([bool]) @( [IntPtr], #_In_ HANDLE ThreadHandle [UInt32], #_In_ DWORD DesiredAccess [bool], #_In_ BOOL OpenAsSelf [IntPtr].MakeByRefType() #_Out_ PHANDLE TokenHandle ) -EntryPoint OpenThreadToken -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa379296(v=vs.85).aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa374905(v=vs.85).aspx .EXAMPLE #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [IntPtr] $ThreadHandle, [Parameter(Mandatory = $true)] [ValidateSet('TOKEN_ASSIGN_PRIMARY','TOKEN_DUPLICATE','TOKEN_IMPERSONATE','TOKEN_QUERY','TOKEN_QUERY_SOURCE','TOKEN_ADJUST_PRIVILEGES','TOKEN_ADJUST_GROUPS','TOKEN_ADJUST_DEFAULT','TOKEN_ADJUST_SESSIONID','DELETE','READ_CONTROL','WRITE_DAC','WRITE_OWNER','SYNCHRONIZE','STANDARD_RIGHTS_REQUIRED','TOKEN_ALL_ACCESS')] [string[]] $DesiredAccess, [Parameter()] [bool] $OpenAsSelf = $false ) # Calculate Desired Access Value $dwDesiredAccess = 0 foreach($val in $DesiredAccess) { $dwDesiredAccess = $dwDesiredAccess -bor $TOKEN_ACCESS::$val } $hToken = [IntPtr]::Zero $Success = $Advapi32::OpenThreadToken($ThreadHandle, $dwDesiredAccess, $OpenAsSelf, [ref]$hToken); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { throw "OpenThreadToken Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hToken } function RevertToSelf { <# .SYNOPSIS The RevertToSelf function terminates the impersonation of a client application. .DESCRIPTION A process should call the RevertToSelf function after finishing any impersonation begun by using the DdeImpersonateClient, ImpersonateDdeClientWindow, ImpersonateLoggedOnUser, ImpersonateNamedPipeClient, ImpersonateSelf, ImpersonateAnonymousToken or SetThreadToken function. An RPC server that used the RpcImpersonateClient function to impersonate a client must call the RpcRevertToSelf or RpcRevertToSelfEx to end the impersonation. If RevertToSelf fails, your application continues to run in the context of the client, which is not appropriate. You should shut down the process if RevertToSelf fails. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect Optional Dependencies: None (func advapi32 RevertToSelf ([bool]) @( ) -EntryPoint RevertToSelf -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa379317(v=vs.85).aspx .EXAMPLE [System.Security.Principal.WindowsIdentity]::GetCurrent().Name NT AUTHORITY\SYSTEM RevertToSelf [System.Security.Principal.WindowsIdentity]::GetCurrent().Name hunt.local\jared #> [CmdletBinding()] param ( ) $SUCCESS = $Advapi32::RevertToSelf(); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $SUCCESS) { throw "RevertToSelf Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } } #endregion Windows API Functions Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-ArpCache.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-ArpCache)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'ArpCache') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'ArpCache' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) #Write-Output $body Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-ArpCache { <# .SYNOPSIS Gets the contents of the ARP Cache. .DESCRIPTION The Get-ArpCache function retreives the contents of the system's ARP Cache. The ARP Cache contains cached mappings from IPv4 Addresses to their Physical Address (MAC Address). .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .EXAMPLE Get-ArpCache AdapterIndex : 1 PhysicalAddress : 00-00-00-00-00-00 IpAddress : 224.0.0.22 Type : STATIC AdapterServiceName : e1iexpress AdapterMacAddress : 00:0C:29:3A:DF:39 AdapterType : Ethernet 802.3 AdapterName : Intel(R) 82574L Gigabit Network Connection AdapterSpeed : 1000000000 AdapterIndex : 1 PhysicalAddress : 00-00-00-00-00-00 IpAddress : 224.0.0.252 Type : STATIC AdapterServiceName : e1iexpress AdapterMacAddress : 00:0C:29:3A:DF:39 AdapterType : Ethernet 802.3 AdapterName : Intel(R) 82574L Gigabit Network Connection AdapterSpeed : 1000000000 AdapterIndex : 1 PhysicalAddress : 00-00-00-00-00-00 IpAddress : 239.255.255.250 Type : STATIC AdapterServiceName : e1iexpress AdapterMacAddress : 00:0C:29:3A:DF:39 AdapterType : Ethernet 802.3 AdapterName : Intel(R) 82574L Gigabit Network Connection AdapterSpeed : 1000000000 #> $Entries = GetIpNetTable foreach($Entry in $Entries) { $Adapter = Get-WmiObject -Class win32_networkadapter -Filter "DeviceID = $($Entry.AdapterIndex)" $Entry.Add('AdapterServiceName', $Adapter.ServiceName) $Entry.Add('AdapterMacAddress', $Adapter.MACAddress) $Entry.Add('AdapterType', $Adapter.AdapterType) $Entry.Add('AdapterName', $Adapter.Name) $Entry.Add('AdapterSpeed', $Adapter.Speed) Write-Output $Entry } } function GetIpNetTable { <# .SYNOPSIS Retreives the IPv4 to physical address mapping table. .DESCRIPTION The GetIpNetTable function enumerates the Address Resolution Protocol (ARP) entries for IPv4 on a local system from the IPv4 to physical address mapping table and returns this information in a MIB_IPNETTABLE structure. on Windows Vista and later, the GetIpNetTable2 function can be used to retrieve the neighbor IP addresses for both IPv6 and IPv4. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: MIB_IPNETROW (Struct), MIB_IPNET_TYPE (Enum) Optional Dependencies: None (func iphlpapi GetIpNetTable ([Int32]) @( [IntPtr], #_Out_ PMIB_IPNETTABLE pIpNetTable [Int32].MakeByRefType(), #_Inout_ PULONG pdwSize [bool] #_In_ BOOL bOrder )) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa365956%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 .EXAMPLE GetIpNetTable AdapterIndex PhysicalAddress IpAddress Type ------------ --------------- --------- ---- 14 00-50-56-C0-00-08 192.168.1.1 DYNAMIC 14 00-50-56-F8-64-30 192.168.1.2 DYNAMIC 14 00-0C-29-BB-51-6D 192.168.1.137 DYNAMIC 14 00-00-00-00-00-00 192.168.1.254 INVALID 14 FF-FF-FF-FF-FF-FF 192.168.1.255 STATIC 14 01-00-5E-00-00-16 224.0.0.22 STATIC 14 01-00-5E-00-00-FC 224.0.0.252 STATIC 14 01-00-5E-7F-FF-FA 239.255.255.250 STATIC 14 FF-FF-FF-FF-FF-FF 255.255.255.255 STATIC 1 00-00-00-00-00-00 224.0.0.22 STATIC 1 00-00-00-00-00-00 224.0.0.252 STATIC 1 00-00-00-00-00-00 239.255.255.250 STATIC 11 01-00-5E-00-00-16 224.0.0.22 STATIC 10 01-00-5E-00-00-16 224.0.0.22 STATIC #> $pThrowAway = [IntPtr]::Zero $dwSize = [Int32]0 # Run the function once to get the size of the MIB_NETTABLE Structure $SUCCESS = $iphlpapi::GetIpNetTable($pThrowAway, [ref]$dwSize, $false) # ERROR_INSUFFICIENT_BUFFER means that $dwSize now contains the size of the stucture if($SUCCESS -eq 122) { $pIpNetTable = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($dwSize) $SUCCESS = $iphlpapi::GetIpNetTable($pIpNetTable, [ref]$dwSize, $false) if($SUCCESS -eq 0) { $count = [System.Runtime.InteropServices.Marshal]::ReadInt32($pIpNetTable) for($i = 0; $i -lt $count; $i++) { $CurrentPtr = [IntPtr]($pIpNetTable.ToInt64() + 4 + ($i * 24)) $IpNetRow = $CurrentPtr -as $MIB_IPNETROW [byte[]]$bAddress = $IpNetRow.bPhysAddr $obj = @{ AdapterIndex = $IpNetRow.dwIndex PhysicalAddress = [System.BitConverter]::ToString($bAddress).Replace('-',':') IpAddress = [string]([System.Net.IPAddress]::new($IpNetRow.dwAddr).IPAddressToString) Type = [string]($IpNetRow.dwType -as $MIB_IPNET_TYPE) } Write-Output $obj } } } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($pIpNetTable) } #region PSReflect function New-InMemoryModule { <# .SYNOPSIS Creates an in-memory assembly and module Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION When defining custom enums, structs, and unmanaged functions, it is necessary to associate to an assembly module. This helper function creates an in-memory module that can be passed to the 'enum', 'struct', and Add-Win32Type functions. .PARAMETER ModuleName Specifies the desired name for the in-memory assembly and module. If ModuleName is not provided, it will default to a GUID. .EXAMPLE $Module = New-InMemoryModule -ModuleName Win32 #> Param ( [Parameter(Position = 0)] [ValidateNotNullOrEmpty()] [String] $ModuleName = [Guid]::NewGuid().ToString() ) $AppDomain = [Reflection.Assembly].Assembly.GetType('System.AppDomain').GetProperty('CurrentDomain').GetValue($null, @()) $LoadedAssemblies = $AppDomain.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 $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, 'Run') $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule($ModuleName, $False) return $ModuleBuilder } # A helper function used to reduce typing while defining function # prototypes for Add-Win32Type. 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, [String] $EntryPoint, [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 } if ($EntryPoint) { $Properties['EntryPoint'] = $EntryPoint } New-Object PSObject -Property $Properties } function Add-Win32Type { <# .SYNOPSIS Creates a .NET type for an unmanaged Win32 function. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: func .DESCRIPTION Add-Win32Type enables you to easily interact with unmanaged (i.e. Win32 unmanaged) functions in PowerShell. After providing Add-Win32Type with a function signature, a .NET type is created using reflection (i.e. csc.exe is never called like with Add-Type). The 'func' helper function can be used to reduce typing when defining multiple function definitions. .PARAMETER DllName The name of the DLL. .PARAMETER FunctionName The name of the target function. .PARAMETER EntryPoint The DLL export function name. This argument should be specified if the specified function name is different than the name of the exported function. .PARAMETER ReturnType The return type of the function. .PARAMETER ParameterTypes The function parameters. .PARAMETER NativeCallingConvention Specifies the native calling convention of the function. Defaults to stdcall. .PARAMETER Charset If you need to explicitly call an 'A' or 'W' Win32 function, you can specify the character set. .PARAMETER SetLastError Indicates whether the callee calls the SetLastError Win32 API function before returning from the attributed method. .PARAMETER Module The in-memory module that will host the functions. Use New-InMemoryModule to define an in-memory module. .PARAMETER Namespace An optional namespace to prepend to the type. Add-Win32Type defaults to a namespace consisting only of the name of the DLL. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $FunctionDefinitions = @( (func kernel32 GetProcAddress ([IntPtr]) @([IntPtr], [String]) -Charset Ansi -SetLastError), (func kernel32 GetModuleHandle ([Intptr]) @([String]) -SetLastError), (func ntdll RtlGetCurrentPeb ([IntPtr]) @()) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32' $Kernel32 = $Types['kernel32'] $Ntdll = $Types['ntdll'] $Ntdll::RtlGetCurrentPeb() $ntdllbase = $Kernel32::GetModuleHandle('ntdll') $Kernel32::GetProcAddress($ntdllbase, 'RtlGetCurrentPeb') .NOTES Inspired by Lee Holmes' Invoke-WindowsApi http://poshcode.org/2189 When defining multiple function prototypes, it is ideal to provide Add-Win32Type with an array of function signatures. That way, they are all incorporated into the same in-memory module. #> [OutputType([Hashtable])] Param( [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $DllName, [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $FunctionName, [Parameter(ValueFromPipelineByPropertyName = $True)] [String] $EntryPoint, [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') $EntryPointField = $DllImport.GetField('EntryPoint') if ($SetLastError) { $SLEValue = $True } else { $SLEValue = $False } if ($PSBoundParameters['EntryPoint']) { $ExportedFuncName = $EntryPoint } else { $ExportedFuncName = $FunctionName } # 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, $EntryPointField), [Object[]] @($SLEValue, ([Runtime.InteropServices.CallingConvention] $NativeCallingConvention), ([Runtime.InteropServices.CharSet] $Charset), $ExportedFuncName)) $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 psenum { <# .SYNOPSIS Creates an in-memory enumeration for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION The 'psenum' function facilitates the creation of enums entirely in memory using as close to a "C style" as PowerShell will allow. .PARAMETER Module The in-memory module that will host the enum. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the enum. .PARAMETER Type The type of each enum element. .PARAMETER EnumElements A hashtable of enum elements. .PARAMETER Bitfield Specifies that the enum should be treated as a bitfield. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageSubsystem = psenum $Mod PE.IMAGE_SUBSYSTEM UInt16 @{ UNKNOWN = 0 NATIVE = 1 # Image doesn't require a subsystem. WINDOWS_GUI = 2 # Image runs in the Windows GUI subsystem. WINDOWS_CUI = 3 # Image runs in the Windows character subsystem. OS2_CUI = 5 # Image runs in the OS/2 character subsystem. POSIX_CUI = 7 # Image runs in the Posix character subsystem. NATIVE_WINDOWS = 8 # Image is a native Win9x driver. WINDOWS_CE_GUI = 9 # Image runs in the Windows CE subsystem. EFI_APPLICATION = 10 EFI_BOOT_SERVICE_DRIVER = 11 EFI_RUNTIME_DRIVER = 12 EFI_ROM = 13 XBOX = 14 WINDOWS_BOOT_APPLICATION = 16 } .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Enum. :P #> [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]) { return ($Module.GetType($FullName)) } $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 { <# .SYNOPSIS Creates an in-memory struct for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: field .DESCRIPTION The 'struct' function facilitates the creation of structs entirely in memory using as close to a "C style" as PowerShell will allow. Struct fields are specified using a hashtable where each field of the struct is comprosed of the order in which it should be defined, its .NET type, and optionally, its offset and special marshaling attributes. One of the features of 'struct' is that after your struct is defined, it will come with a built-in GetSize method as well as an explicit converter so that you can easily cast an IntPtr to the struct without relying upon calling SizeOf and/or PtrToStructure in the Marshal class. .PARAMETER Module The in-memory module that will host the struct. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the struct. .PARAMETER StructFields A hashtable of fields. Use the 'field' helper function to ease defining each field. .PARAMETER PackingSize Specifies the memory alignment of fields. .PARAMETER ExplicitLayout Indicates that an explicit offset for each field will be specified. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageDosSignature = psenum $Mod PE.IMAGE_DOS_SIGNATURE UInt16 @{ DOS_SIGNATURE = 0x5A4D OS2_SIGNATURE = 0x454E OS2_SIGNATURE_LE = 0x454C VXD_SIGNATURE = 0x454C } $ImageDosHeader = struct $Mod PE.IMAGE_DOS_HEADER @{ e_magic = field 0 $ImageDosSignature e_cblp = field 1 UInt16 e_cp = field 2 UInt16 e_crlc = field 3 UInt16 e_cparhdr = field 4 UInt16 e_minalloc = field 5 UInt16 e_maxalloc = field 6 UInt16 e_ss = field 7 UInt16 e_sp = field 8 UInt16 e_csum = field 9 UInt16 e_ip = field 10 UInt16 e_cs = field 11 UInt16 e_lfarlc = field 12 UInt16 e_ovno = field 13 UInt16 e_res = field 14 UInt16[] -MarshalAs @('ByValArray', 4) e_oemid = field 15 UInt16 e_oeminfo = field 16 UInt16 e_res2 = field 17 UInt16[] -MarshalAs @('ByValArray', 10) e_lfanew = field 18 Int32 } # Example of using an explicit layout in order to create a union. $TestUnion = struct $Mod TestUnion @{ field1 = field 0 UInt32 0 field2 = field 1 IntPtr 0 } -ExplicitLayout .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Struct. :P #> [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() } #endregion PSReflect #region PSReflect Definitions $mod = New-InMemoryModule -ModuleName ArpCache $MIB_IPNET_TYPE = psenum $mod MIB_IPNET_TYPE UInt32 @{ OTHER = 1 INVALID = 2 DYNAMIC = 3 STATIC = 4 } $MIB_IPNETROW = struct $mod MIB_IPNETROW @{ dwIndex = field 0 UInt32 dwPhysAddrLen = field 1 UInt32 bPhysAddr = field 2 byte[] -MarshalAs @('ByValArray', 6) dwAddr = field 3 UInt32 dwType = field 4 UInt32 } $FunctionDefinitions = @( (func iphlpapi GetIpNetTable ([Int32]) @( [IntPtr], #_Out_ PMIB_IPNETTABLE pIpNetTable [Int32].MakeByRefType(), #_Inout_ PULONG pdwSize [bool] #_In_ BOOL bOrder )) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $mod -Namespace ArpCache $Iphlpapi = $Types['iphlpapi'] #endregion PSReflect Definitions Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-Atom.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-Atom)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'Atom') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'Atom' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) Write-Output $body #Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-Atom { [CmdletBinding()] param ( [Parameter()] [UInt16] $AtomIndex ) if($PSBoundParameters.ContainsKey('AtomIndex')) { GlobalGetAtomName -AtomIndex $AtomIndex } else { $atomList = New-Object -TypeName System.Collections.Generic.List['string'] for($i = 0xC000; $i -lt [UInt16]::MaxValue; $i++) { try { $atomname = GlobalGetAtomName -AtomIndex $i -ErrorAction Stop $props = @{ Index = $i Name = $atomname.ToString() } Write-Output $props } catch { } } } } #region PSReflect function New-InMemoryModule { <# .SYNOPSIS Creates an in-memory assembly and module Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION When defining custom enums, structs, and unmanaged functions, it is necessary to associate to an assembly module. This helper function creates an in-memory module that can be passed to the 'enum', 'struct', and Add-Win32Type functions. .PARAMETER ModuleName Specifies the desired name for the in-memory assembly and module. If ModuleName is not provided, it will default to a GUID. .EXAMPLE $Module = New-InMemoryModule -ModuleName Win32 #> Param ( [Parameter(Position = 0)] [ValidateNotNullOrEmpty()] [String] $ModuleName = [Guid]::NewGuid().ToString() ) $AppDomain = [Reflection.Assembly].Assembly.GetType('System.AppDomain').GetProperty('CurrentDomain').GetValue($null, @()) $LoadedAssemblies = $AppDomain.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 $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, 'Run') $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule($ModuleName, $False) return $ModuleBuilder } # A helper function used to reduce typing while defining function # prototypes for Add-Win32Type. 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, [String] $EntryPoint, [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 } if ($EntryPoint) { $Properties['EntryPoint'] = $EntryPoint } New-Object PSObject -Property $Properties } function Add-Win32Type { <# .SYNOPSIS Creates a .NET type for an unmanaged Win32 function. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: func .DESCRIPTION Add-Win32Type enables you to easily interact with unmanaged (i.e. Win32 unmanaged) functions in PowerShell. After providing Add-Win32Type with a function signature, a .NET type is created using reflection (i.e. csc.exe is never called like with Add-Type). The 'func' helper function can be used to reduce typing when defining multiple function definitions. .PARAMETER DllName The name of the DLL. .PARAMETER FunctionName The name of the target function. .PARAMETER EntryPoint The DLL export function name. This argument should be specified if the specified function name is different than the name of the exported function. .PARAMETER ReturnType The return type of the function. .PARAMETER ParameterTypes The function parameters. .PARAMETER NativeCallingConvention Specifies the native calling convention of the function. Defaults to stdcall. .PARAMETER Charset If you need to explicitly call an 'A' or 'W' Win32 function, you can specify the character set. .PARAMETER SetLastError Indicates whether the callee calls the SetLastError Win32 API function before returning from the attributed method. .PARAMETER Module The in-memory module that will host the functions. Use New-InMemoryModule to define an in-memory module. .PARAMETER Namespace An optional namespace to prepend to the type. Add-Win32Type defaults to a namespace consisting only of the name of the DLL. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $FunctionDefinitions = @( (func kernel32 GetProcAddress ([IntPtr]) @([IntPtr], [String]) -Charset Ansi -SetLastError), (func kernel32 GetModuleHandle ([Intptr]) @([String]) -SetLastError), (func ntdll RtlGetCurrentPeb ([IntPtr]) @()) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32' $Kernel32 = $Types['kernel32'] $Ntdll = $Types['ntdll'] $Ntdll::RtlGetCurrentPeb() $ntdllbase = $Kernel32::GetModuleHandle('ntdll') $Kernel32::GetProcAddress($ntdllbase, 'RtlGetCurrentPeb') .NOTES Inspired by Lee Holmes' Invoke-WindowsApi http://poshcode.org/2189 When defining multiple function prototypes, it is ideal to provide Add-Win32Type with an array of function signatures. That way, they are all incorporated into the same in-memory module. #> [OutputType([Hashtable])] Param( [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $DllName, [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $FunctionName, [Parameter(ValueFromPipelineByPropertyName = $True)] [String] $EntryPoint, [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') $EntryPointField = $DllImport.GetField('EntryPoint') if ($SetLastError) { $SLEValue = $True } else { $SLEValue = $False } if ($PSBoundParameters['EntryPoint']) { $ExportedFuncName = $EntryPoint } else { $ExportedFuncName = $FunctionName } # 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, $EntryPointField), [Object[]] @($SLEValue, ([Runtime.InteropServices.CallingConvention] $NativeCallingConvention), ([Runtime.InteropServices.CharSet] $Charset), $ExportedFuncName)) $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 psenum { <# .SYNOPSIS Creates an in-memory enumeration for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION The 'psenum' function facilitates the creation of enums entirely in memory using as close to a "C style" as PowerShell will allow. .PARAMETER Module The in-memory module that will host the enum. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the enum. .PARAMETER Type The type of each enum element. .PARAMETER EnumElements A hashtable of enum elements. .PARAMETER Bitfield Specifies that the enum should be treated as a bitfield. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageSubsystem = psenum $Mod PE.IMAGE_SUBSYSTEM UInt16 @{ UNKNOWN = 0 NATIVE = 1 # Image doesn't require a subsystem. WINDOWS_GUI = 2 # Image runs in the Windows GUI subsystem. WINDOWS_CUI = 3 # Image runs in the Windows character subsystem. OS2_CUI = 5 # Image runs in the OS/2 character subsystem. POSIX_CUI = 7 # Image runs in the Posix character subsystem. NATIVE_WINDOWS = 8 # Image is a native Win9x driver. WINDOWS_CE_GUI = 9 # Image runs in the Windows CE subsystem. EFI_APPLICATION = 10 EFI_BOOT_SERVICE_DRIVER = 11 EFI_RUNTIME_DRIVER = 12 EFI_ROM = 13 XBOX = 14 WINDOWS_BOOT_APPLICATION = 16 } .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Enum. :P #> [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]) { return ($Module.GetType($FullName)) } $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 { <# .SYNOPSIS Creates an in-memory struct for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: field .DESCRIPTION The 'struct' function facilitates the creation of structs entirely in memory using as close to a "C style" as PowerShell will allow. Struct fields are specified using a hashtable where each field of the struct is comprosed of the order in which it should be defined, its .NET type, and optionally, its offset and special marshaling attributes. One of the features of 'struct' is that after your struct is defined, it will come with a built-in GetSize method as well as an explicit converter so that you can easily cast an IntPtr to the struct without relying upon calling SizeOf and/or PtrToStructure in the Marshal class. .PARAMETER Module The in-memory module that will host the struct. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the struct. .PARAMETER StructFields A hashtable of fields. Use the 'field' helper function to ease defining each field. .PARAMETER PackingSize Specifies the memory alignment of fields. .PARAMETER ExplicitLayout Indicates that an explicit offset for each field will be specified. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageDosSignature = psenum $Mod PE.IMAGE_DOS_SIGNATURE UInt16 @{ DOS_SIGNATURE = 0x5A4D OS2_SIGNATURE = 0x454E OS2_SIGNATURE_LE = 0x454C VXD_SIGNATURE = 0x454C } $ImageDosHeader = struct $Mod PE.IMAGE_DOS_HEADER @{ e_magic = field 0 $ImageDosSignature e_cblp = field 1 UInt16 e_cp = field 2 UInt16 e_crlc = field 3 UInt16 e_cparhdr = field 4 UInt16 e_minalloc = field 5 UInt16 e_maxalloc = field 6 UInt16 e_ss = field 7 UInt16 e_sp = field 8 UInt16 e_csum = field 9 UInt16 e_ip = field 10 UInt16 e_cs = field 11 UInt16 e_lfarlc = field 12 UInt16 e_ovno = field 13 UInt16 e_res = field 14 UInt16[] -MarshalAs @('ByValArray', 4) e_oemid = field 15 UInt16 e_oeminfo = field 16 UInt16 e_res2 = field 17 UInt16[] -MarshalAs @('ByValArray', 10) e_lfanew = field 18 Int32 } # Example of using an explicit layout in order to create a union. $TestUnion = struct $Mod TestUnion @{ field1 = field 0 UInt32 0 field2 = field 1 IntPtr 0 } -ExplicitLayout .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Struct. :P #> [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() } #endregion PSReflect $mod = New-InMemoryModule -ModuleName Atom #region FunctionDefinitions $FunctionDefinitions = @( (func kernel32 GlobalGetAtomName ([UInt32]) @( [UInt16], #_In_ ATOM nAtom [IntPtr], #_Out_ LPTSTR lpBuffer [UInt32] #_In_ int nSize ) -EntryPoint GlobalGetAtomName -SetLastError) ) #endregion FunctionDefinitions #region Windows API Functions function GlobalGetAtomName { <# .SYNOPSIS Retrieves a copy of the character string associated with the specified global atom. .DESCRIPTION The string returned for an integer atom (an atom whose value is in the range 0x0001 to 0xBFFF) is a null-terminated string in which the first character is a pound sign (#) and the remaining characters represent the unsigned integer atom value. .PARAMETER AtomIndex The global atom (index) associated with the character string to be retrieved. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect Optional Dependencies: None (func kernel32 GlobalGetAtomName ([UInt32]) @( [UInt16], #_In_ ATOM nAtom [string].MakeByRefType(), #_Out_ LPTSTR lpBuffer [UInt16] #_In_ int nSize ) -EntryPoint GlobalGetAtomName -SetLastError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms649063(v=vs.85).aspx .EXAMPLE #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [UInt16] $AtomIndex ) $AtomName = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(1024) $SUCCESS = $kernel32::GlobalGetAtomName($AtomIndex, $AtomName, 1024); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if($SUCCESS -eq 0) { throw "[GlobalGetAtomName]: Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output ([System.Runtime.InteropServices.Marshal]::PtrToStringUni($AtomName)) } #endregion Windows API Functions $Types = $FunctionDefinitions | Add-Win32Type -Module $mod -Namespace ArpCache $kernel32 = $Types['kernel32'] Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-InjectedThread.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-InjectedThread)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'InjectedThread') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'InjectedThread' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) Write-Host $body Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-InjectedThread { <# .SYNOPSIS Looks for threads that were created as a result of code injection. .DESCRIPTION Memory resident malware (fileless malware) often uses a form of memory injection to get code execution. Get-InjectedThread looks at each running thread to determine if it is the result of memory injection. Common memory injection techniques that *can* be caught using this method include: - Classic Injection (OpenProcess, VirtualAllocEx, WriteProcessMemory, CreateRemoteThread) - Reflective DLL Injection - Process Hollowing NOTE: Nothing in security is a silver bullet. An attacker could modify their tactics to avoid detection using this methodology. .NOTES Author - Jared Atkinson (@jaredcatkinson) .EXAMPLE PS > Get-InjectedThread ProcessName : ThreadStart.exe ProcessId : 7784 Path : C:\Users\tester\Desktop\ThreadStart.exe KernelPath : C:\Users\tester\Desktop\ThreadStart.exe CommandLine : "C:\Users\tester\Desktop\ThreadStart.exe" PathMismatch : False ThreadId : 14512 AllocatedMemoryProtection : PAGE_EXECUTE_READWRITE MemoryProtection : PAGE_EXECUTE_READWRITE MemoryState : MEM_COMMIT MemoryType : MEM_PRIVATE BasePriority : 8 IsUniqueThreadToken : False Integrity : MEDIUM_MANDATORY_LEVEL Privilege : SeChangeNotifyPrivilege LogonId : 999 SecurityIdentifier : S-1-5-21-386661145-2656271985-3844047388-1001 UserName : DESKTOP-HMTGQ0R\SYSTEM LogonSessionStartTime : 3/15/2017 5:45:38 PM LogonType : System AuthenticationPackage : NTLM BaseAddress : 4390912 Size : 4096 Bytes : {144, 195, 0, 0...} #> [CmdletBinding()] param ( ) $hSnapshot = CreateToolhelp32Snapshot -ProcessId 0 -Flags 4 $Thread = Thread32First -SnapshotHandle $hSnapshot do { $proc = Get-Process -Id $Thread.th32OwnerProcessId -ErrorAction SilentlyContinue if($Thread.th32OwnerProcessId -ne 0 -and $Thread.th32OwnerProcessId -ne 4) { $hThread = OpenThread -ThreadId $Thread.th32ThreadID -DesiredAccess $THREAD_ALL_ACCESS -InheritHandle $false if($hThread -ne 0) { $BaseAddress = NtQueryInformationThread -ThreadHandle $hThread $hProcess = OpenProcess -ProcessId $Thread.th32OwnerProcessID -DesiredAccess $PROCESS_ALL_ACCESS -InheritHandle $false if($hProcess -ne 0) { $memory_basic_info = VirtualQueryEx -ProcessHandle $hProcess -BaseAddress $BaseAddress $AllocatedMemoryProtection = $memory_basic_info.AllocationProtect -as $MemProtection $MemoryProtection = $memory_basic_info.Protect -as $MemProtection $MemoryState = $memory_basic_info.State -as $MemState $MemoryType = $memory_basic_info.Type -as $MemType if($MemoryState -eq $MemState::MEM_COMMIT -and $MemoryType -ne $MemType::MEM_IMAGE) { $buf = ReadProcessMemory -ProcessHandle $hProcess -BaseAddress $BaseAddress -Size 100 $proc = Get-WmiObject Win32_Process -Filter "ProcessId = '$($Thread.th32OwnerProcessID)'" $KernelPath = QueryFullProcessImageName -ProcessHandle $hProcess $PathMismatch = $proc.Path.ToLower() -ne $KernelPath.ToLower() # check if thread has unique token try { $hThreadToken = OpenThreadToken -ThreadHandle $hThread -DesiredAccess $TOKEN_ALL_ACCESS $SID = GetTokenInformation -TokenHandle $hThreadToken -TokenInformationClass 1 $Privs = GetTokenInformation -TokenHandle $hThreadToken -TokenInformationClass 3 $LogonSession = GetTokenInformation -TokenHandle $hThreadToken -TokenInformationClass 17 $Integrity = GetTokenInformation -TokenHandle $hThreadToken -TokenInformationClass 25 $IsUniqueThreadToken = $true } catch { $hProcessToken = OpenProcessToken -ProcessHandle $hProcess -DesiredAccess $TOKEN_ALL_ACCESS $SID = GetTokenInformation -TokenHandle $hProcessToken -TokenInformationClass 1 $Privs = GetTokenInformation -TokenHandle $hProcessToken -TokenInformationClass 3 $LogonSession = GetTokenInformation -TokenHandle $hProcessToken -TokenInformationClass 17 $Integrity = GetTokenInformation -TokenHandle $hProcessToken -TokenInformationClass 25 $IsUniqueThreadToken = $false } $props = @{ ProcessName = [string]$proc.Name ProcessId = $proc.ProcessId Path = [string]$proc.Path KernelPath = [string]$KernelPath CommandLine = [string]$proc.CommandLine PathMismatch = [string]$PathMismatch ThreadId = $Thread.th32ThreadId AllocatedMemoryProtection = [string]$AllocatedMemoryProtection MemoryProtection = [string]$MemoryProtection MemoryState = [string]$MemoryState MemoryType = [string]$MemoryType BasePriority = [string]$Thread.tpBasePri IsUniqueThreadToken = $IsUniqueThreadToken Integrity = [string]$Integrity Privilege = [string]$Privs LogonId = $LogonSession.LogonId SecurityIdentifier = [string]$SID UserName = "$($LogonSession.Domain)\$($LogonSession.UserName)" LogonSessionStartTime = [string]$LogonSession.StartTime LogonType = [string]$LogonSession.LogonType AuthenticationPackage = [string]$LogonSession.AuthenticationPackage BaseAddress = [string]$BaseAddress Size = $memory_basic_info.RegionSize } Write-Output $props } CloseHandle($hProcess) } } CloseHandle($hThread) } } while($Kernel32::Thread32Next($hSnapshot, [ref]$Thread)) CloseHandle($hSnapshot) } function Stop-Thread { <# .SYNOPSIS Terminates a specified Thread. .DESCRIPTION The Stop-Thread function can stop an individual thread in a process. This is quite useful in situations where code injection (dll injection) techniques have been used by attackers. If an attacker runs their malicious code in a thread within a critical process, then Stop-Thread can kill the malicious thread without hurting the critical process. .NOTES Author - Jared Atkinson (@jaredcatkinson) .EXAMPLE PS > Stop-Thread -ThreadId 1776 #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [UInt32] $ThreadId ) $hThread = OpenThread -ThreadId $ThreadId -DesiredAccess $THREAD_TERMINATE TerminateThread -ThreadHandle $hThread CloseHandle -Handle $hThread } <# Author: Lee Christensen (@tifkin_) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None #> function Get-LogonSession { param ( [Parameter(Mandatory = $true)] [UInt32] $LogonId ) $LogonMap = @{} Get-WmiObject Win32_LoggedOnUser | %{ $Identity = $_.Antecedent | Select-String 'Domain="(.*)",Name="(.*)"' $LogonSession = $_.Dependent | Select-String 'LogonId="(\d+)"' $LogonMap[$LogonSession.Matches[0].Groups[1].Value] = New-Object PSObject -Property @{ Domain = $Identity.Matches[0].Groups[1].Value UserName = $Identity.Matches[0].Groups[2].Value } } Get-WmiObject Win32_LogonSession -Filter "LogonId = `"$($LogonId)`"" | %{ $LogonType = $Null switch($_.LogonType) { $null {$LogonType = 'None'} 0 { $LogonType = 'System' } 2 { $LogonType = 'Interactive' } 3 { $LogonType = 'Network' } 4 { $LogonType = 'Batch' } 5 { $LogonType = 'Service' } 6 { $LogonType = 'Proxy' } 7 { $LogonType = 'Unlock' } 8 { $LogonType = 'NetworkCleartext' } 9 { $LogonType = 'NewCredentials' } 10 { $LogonType = 'RemoteInteractive' } 11 { $LogonType = 'CachedInteractive' } 12 { $LogonType = 'CachedRemoteInteractive' } 13 { $LogonType = 'CachedUnlock' } default { $LogonType = $_.LogonType} } New-Object PSObject -Property @{ UserName = $LogonMap[$_.LogonId].UserName Domain = $LogonMap[$_.LogonId].Domain LogonId = $_.LogonId LogonType = $LogonType AuthenticationPackage = $_.AuthenticationPackage Caption = $_.Caption Description = $_.Description InstallDate = $_.InstallDate Name = $_.Name StartTime = $_.ConvertToDateTime($_.StartTime) } } } #region PSReflect function New-InMemoryModule { <# .SYNOPSIS Creates an in-memory assembly and module Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION When defining custom enums, structs, and unmanaged functions, it is necessary to associate to an assembly module. This helper function creates an in-memory module that can be passed to the 'enum', 'struct', and Add-Win32Type functions. .PARAMETER ModuleName Specifies the desired name for the in-memory assembly and module. If ModuleName is not provided, it will default to a GUID. .EXAMPLE $Module = New-InMemoryModule -ModuleName Win32 #> Param ( [Parameter(Position = 0)] [ValidateNotNullOrEmpty()] [String] $ModuleName = [Guid]::NewGuid().ToString() ) $AppDomain = [Reflection.Assembly].Assembly.GetType('System.AppDomain').GetProperty('CurrentDomain').GetValue($null, @()) $LoadedAssemblies = $AppDomain.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 $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, 'Run') $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule($ModuleName, $False) return $ModuleBuilder } # A helper function used to reduce typing while defining function # prototypes for Add-Win32Type. 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, [String] $EntryPoint, [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 } if ($EntryPoint) { $Properties['EntryPoint'] = $EntryPoint } New-Object PSObject -Property $Properties } function Add-Win32Type { <# .SYNOPSIS Creates a .NET type for an unmanaged Win32 function. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: func .DESCRIPTION Add-Win32Type enables you to easily interact with unmanaged (i.e. Win32 unmanaged) functions in PowerShell. After providing Add-Win32Type with a function signature, a .NET type is created using reflection (i.e. csc.exe is never called like with Add-Type). The 'func' helper function can be used to reduce typing when defining multiple function definitions. .PARAMETER DllName The name of the DLL. .PARAMETER FunctionName The name of the target function. .PARAMETER EntryPoint The DLL export function name. This argument should be specified if the specified function name is different than the name of the exported function. .PARAMETER ReturnType The return type of the function. .PARAMETER ParameterTypes The function parameters. .PARAMETER NativeCallingConvention Specifies the native calling convention of the function. Defaults to stdcall. .PARAMETER Charset If you need to explicitly call an 'A' or 'W' Win32 function, you can specify the character set. .PARAMETER SetLastError Indicates whether the callee calls the SetLastError Win32 API function before returning from the attributed method. .PARAMETER Module The in-memory module that will host the functions. Use New-InMemoryModule to define an in-memory module. .PARAMETER Namespace An optional namespace to prepend to the type. Add-Win32Type defaults to a namespace consisting only of the name of the DLL. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $FunctionDefinitions = @( (func kernel32 GetProcAddress ([IntPtr]) @([IntPtr], [String]) -Charset Ansi -SetLastError), (func kernel32 GetModuleHandle ([Intptr]) @([String]) -SetLastError), (func ntdll RtlGetCurrentPeb ([IntPtr]) @()) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32' $Kernel32 = $Types['kernel32'] $Ntdll = $Types['ntdll'] $Ntdll::RtlGetCurrentPeb() $ntdllbase = $Kernel32::GetModuleHandle('ntdll') $Kernel32::GetProcAddress($ntdllbase, 'RtlGetCurrentPeb') .NOTES Inspired by Lee Holmes' Invoke-WindowsApi http://poshcode.org/2189 When defining multiple function prototypes, it is ideal to provide Add-Win32Type with an array of function signatures. That way, they are all incorporated into the same in-memory module. #> [OutputType([Hashtable])] Param( [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $DllName, [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $FunctionName, [Parameter(ValueFromPipelineByPropertyName = $True)] [String] $EntryPoint, [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') $EntryPointField = $DllImport.GetField('EntryPoint') if ($SetLastError) { $SLEValue = $True } else { $SLEValue = $False } if ($PSBoundParameters['EntryPoint']) { $ExportedFuncName = $EntryPoint } else { $ExportedFuncName = $FunctionName } # 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, $EntryPointField), [Object[]] @($SLEValue, ([Runtime.InteropServices.CallingConvention] $NativeCallingConvention), ([Runtime.InteropServices.CharSet] $Charset), $ExportedFuncName)) $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 psenum { <# .SYNOPSIS Creates an in-memory enumeration for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION The 'psenum' function facilitates the creation of enums entirely in memory using as close to a "C style" as PowerShell will allow. .PARAMETER Module The in-memory module that will host the enum. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the enum. .PARAMETER Type The type of each enum element. .PARAMETER EnumElements A hashtable of enum elements. .PARAMETER Bitfield Specifies that the enum should be treated as a bitfield. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageSubsystem = psenum $Mod PE.IMAGE_SUBSYSTEM UInt16 @{ UNKNOWN = 0 NATIVE = 1 # Image doesn't require a subsystem. WINDOWS_GUI = 2 # Image runs in the Windows GUI subsystem. WINDOWS_CUI = 3 # Image runs in the Windows character subsystem. OS2_CUI = 5 # Image runs in the OS/2 character subsystem. POSIX_CUI = 7 # Image runs in the Posix character subsystem. NATIVE_WINDOWS = 8 # Image is a native Win9x driver. WINDOWS_CE_GUI = 9 # Image runs in the Windows CE subsystem. EFI_APPLICATION = 10 EFI_BOOT_SERVICE_DRIVER = 11 EFI_RUNTIME_DRIVER = 12 EFI_ROM = 13 XBOX = 14 WINDOWS_BOOT_APPLICATION = 16 } .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Enum. :P #> [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]) { return ($Module.GetType($FullName)) } $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 { <# .SYNOPSIS Creates an in-memory struct for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: field .DESCRIPTION The 'struct' function facilitates the creation of structs entirely in memory using as close to a "C style" as PowerShell will allow. Struct fields are specified using a hashtable where each field of the struct is comprosed of the order in which it should be defined, its .NET type, and optionally, its offset and special marshaling attributes. One of the features of 'struct' is that after your struct is defined, it will come with a built-in GetSize method as well as an explicit converter so that you can easily cast an IntPtr to the struct without relying upon calling SizeOf and/or PtrToStructure in the Marshal class. .PARAMETER Module The in-memory module that will host the struct. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the struct. .PARAMETER StructFields A hashtable of fields. Use the 'field' helper function to ease defining each field. .PARAMETER PackingSize Specifies the memory alignment of fields. .PARAMETER ExplicitLayout Indicates that an explicit offset for each field will be specified. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageDosSignature = psenum $Mod PE.IMAGE_DOS_SIGNATURE UInt16 @{ DOS_SIGNATURE = 0x5A4D OS2_SIGNATURE = 0x454E OS2_SIGNATURE_LE = 0x454C VXD_SIGNATURE = 0x454C } $ImageDosHeader = struct $Mod PE.IMAGE_DOS_HEADER @{ e_magic = field 0 $ImageDosSignature e_cblp = field 1 UInt16 e_cp = field 2 UInt16 e_crlc = field 3 UInt16 e_cparhdr = field 4 UInt16 e_minalloc = field 5 UInt16 e_maxalloc = field 6 UInt16 e_ss = field 7 UInt16 e_sp = field 8 UInt16 e_csum = field 9 UInt16 e_ip = field 10 UInt16 e_cs = field 11 UInt16 e_lfarlc = field 12 UInt16 e_ovno = field 13 UInt16 e_res = field 14 UInt16[] -MarshalAs @('ByValArray', 4) e_oemid = field 15 UInt16 e_oeminfo = field 16 UInt16 e_res2 = field 17 UInt16[] -MarshalAs @('ByValArray', 10) e_lfanew = field 18 Int32 } # Example of using an explicit layout in order to create a union. $TestUnion = struct $Mod TestUnion @{ field1 = field 0 UInt32 0 field2 = field 1 IntPtr 0 } -ExplicitLayout .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Struct. :P #> [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() } #endregion PSReflect #region PSReflect Definitions (Thread) $Module = New-InMemoryModule -ModuleName Thread $LuidAttributes = psenum $Module LuidAttributes UInt32 @{ DISABLED = '0x00000000' SE_PRIVILEGE_ENABLED_BY_DEFAULT = '0x00000001' SE_PRIVILEGE_ENABLED = '0x00000002' SE_PRIVILEGE_REMOVED = '0x00000004' SE_PRIVILEGE_USED_FOR_ACCESS = '0x80000000' } -Bitfield $MemProtection = psenum $Module MemProtection UInt32 @{ PAGE_EXECUTE = 0x10 PAGE_EXECUTE_READ = 0x20 PAGE_EXECUTE_READWRITE = 0x40 PAGE_EXECUTE_WRITECOPY = 0x80 PAGE_NOACCESS = 0x01 PAGE_READONLY = 0x02 PAGE_READWRITE = 0x04 PAGE_WRITECOPY = 0x08 PAGE_TARGETS_INVALID = 0x40000000 PAGE_TARGETS_NO_UPDATE = 0x40000000 PAGE_GUARD = 0x100 PAGE_NOCACHE = 0x200 PAGE_WRITECOMBINE = 0x400 } -Bitfield $MemState = psenum $Module MemState UInt32 @{ MEM_COMMIT = 0x1000 MEM_RESERVE = 0x2000 MEM_FREE = 0x10000 } $MemType = psenum $Module MemType UInt32 @{ MEM_PRIVATE = 0x20000 MEM_MAPPED = 0x40000 MEM_IMAGE = 0x1000000 } $SecurityEntity = psenum $Module SecurityEntity UInt32 @{ SeCreateTokenPrivilege = 1 SeAssignPrimaryTokenPrivilege = 2 SeLockMemoryPrivilege = 3 SeIncreaseQuotaPrivilege = 4 SeUnsolicitedInputPrivilege = 5 SeMachineAccountPrivilege = 6 SeTcbPrivilege = 7 SeSecurityPrivilege = 8 SeTakeOwnershipPrivilege = 9 SeLoadDriverPrivilege = 10 SeSystemProfilePrivilege = 11 SeSystemtimePrivilege = 12 SeProfileSingleProcessPrivilege = 13 SeIncreaseBasePriorityPrivilege = 14 SeCreatePagefilePrivilege = 15 SeCreatePermanentPrivilege = 16 SeBackupPrivilege = 17 SeRestorePrivilege = 18 SeShutdownPrivilege = 19 SeDebugPrivilege = 20 SeAuditPrivilege = 21 SeSystemEnvironmentPrivilege = 22 SeChangeNotifyPrivilege = 23 SeRemoteShutdownPrivilege = 24 SeUndockPrivilege = 25 SeSyncAgentPrivilege = 26 SeEnableDelegationPrivilege = 27 SeManageVolumePrivilege = 28 SeImpersonatePrivilege = 29 SeCreateGlobalPrivilege = 30 SeTrustedCredManAccessPrivilege = 31 SeRelabelPrivilege = 32 SeIncreaseWorkingSetPrivilege = 33 SeTimeZonePrivilege = 34 SeCreateSymbolicLinkPrivilege = 35 } $SidNameUser = psenum $Module SID_NAME_USE UInt32 @{ SidTypeUser = 1 SidTypeGroup = 2 SidTypeDomain = 3 SidTypeAlias = 4 SidTypeWellKnownGroup = 5 SidTypeDeletedAccount = 6 SidTypeInvalid = 7 SidTypeUnknown = 8 SidTypeComputer = 9 } $TokenInformationClass = psenum $Module TOKEN_INFORMATION_CLASS UInt16 @{ TokenUser = 1 TokenGroups = 2 TokenPrivileges = 3 TokenOwner = 4 TokenPrimaryGroup = 5 TokenDefaultDacl = 6 TokenSource = 7 TokenType = 8 TokenImpersonationLevel = 9 TokenStatistics = 10 TokenRestrictedSids = 11 TokenSessionId = 12 TokenGroupsAndPrivileges = 13 TokenSessionReference = 14 TokenSandBoxInert = 15 TokenAuditPolicy = 16 TokenOrigin = 17 TokenElevationType = 18 TokenLinkedToken = 19 TokenElevation = 20 TokenHasRestrictions = 21 TokenAccessInformation = 22 TokenVirtualizationAllowed = 23 TokenVirtualizationEnabled = 24 TokenIntegrityLevel = 25 TokenUIAccess = 26 TokenMandatoryPolicy = 27 TokenLogonSid = 28 TokenIsAppContainer = 29 TokenCapabilities = 30 TokenAppContainerSid = 31 TokenAppContainerNumber = 32 TokenUserClaimAttributes = 33 TokenDeviceClaimAttributes = 34 TokenRestrictedUserClaimAttributes = 35 TokenRestrictedDeviceClaimAttributes = 36 TokenDeviceGroups = 37 TokenRestrictedDeviceGroups = 38 TokenSecurityAttributes = 39 TokenIsRestricted = 40 MaxTokenInfoClass = 41 } $LUID = struct $Module Luid @{ LowPart = field 0 $SecurityEntity HighPart = field 1 Int32 } $LUID_AND_ATTRIBUTES = struct $Module LuidAndAttributes @{ Luid = field 0 $LUID Attributes = field 1 UInt32 } $MEMORYBASICINFORMATION = struct $Module MEMORY_BASIC_INFORMATION @{ BaseAddress = field 0 UIntPtr AllocationBase = field 1 UIntPtr AllocationProtect = field 2 UInt32 RegionSize = field 3 UIntPtr State = field 4 UInt32 Protect = field 5 UInt32 Type = field 6 UInt32 } $SID_AND_ATTRIBUTES = struct $Module SidAndAttributes @{ Sid = field 0 IntPtr Attributes = field 1 UInt32 } $THREADENTRY32 = struct $Module THREADENTRY32 @{ dwSize = field 0 UInt32 cntUsage = field 1 UInt32 th32ThreadID = field 2 UInt32 th32OwnerProcessID = field 3 UInt32 tpBasePri = field 4 UInt32 tpDeltaPri = field 5 UInt32 dwFlags = field 6 UInt32 } $TOKEN_MANDATORY_LABEL = struct $Module TokenMandatoryLabel @{ Label = field 0 $SID_AND_ATTRIBUTES; } $TOKEN_ORIGIN = struct $Module TokenOrigin @{ OriginatingLogonSession = field 0 UInt64 } $TOKEN_PRIVILEGES = struct $Module TokenPrivileges @{ PrivilegeCount = field 0 UInt32 Privileges = field 1 $LUID_AND_ATTRIBUTES.MakeArrayType() -MarshalAs @('ByValArray', 50) } $TOKEN_USER = struct $Module TOKEN_USER @{ User = field 0 $SID_AND_ATTRIBUTES } $FunctionDefinitions = @( (func kernel32 CloseHandle ([bool]) @( [IntPtr] #_In_ HANDLE hObject ) -SetLastError), (func advapi32 ConvertSidToStringSid ([bool]) @( [IntPtr] #_In_ PSID Sid, [IntPtr].MakeByRefType() #_Out_ LPTSTR *StringSid ) -SetLastError), (func kernel32 CreateToolhelp32Snapshot ([IntPtr]) @( [UInt32], #_In_ DWORD dwFlags, [UInt32] #_In_ DWORD th32ProcessID ) -SetLastError), (func advapi32 GetTokenInformation ([bool]) @( [IntPtr], #_In_ HANDLE TokenHandle [Int32], #_In_ TOKEN_INFORMATION_CLASS TokenInformationClass [IntPtr], #_Out_opt_ LPVOID TokenInformation [UInt32], #_In_ DWORD TokenInformationLength [UInt32].MakeByRefType() #_Out_ PDWORD ReturnLength ) -SetLastError), (func ntdll NtQueryInformationThread ([UInt32]) @( [IntPtr], #_In_ HANDLE ThreadHandle, [Int32], #_In_ THREADINFOCLASS ThreadInformationClass, [IntPtr], #_Inout_ PVOID ThreadInformation, [Int32], #_In_ ULONG ThreadInformationLength, [IntPtr] #_Out_opt_ PULONG ReturnLength )), (func kernel32 OpenProcess ([IntPtr]) @( [UInt32], #_In_ DWORD dwDesiredAccess, [bool], #_In_ BOOL bInheritHandle, [UInt32] #_In_ DWORD dwProcessId ) -SetLastError), (func advapi32 OpenProcessToken ([bool]) @( [IntPtr], #_In_ HANDLE ProcessHandle [UInt32], #_In_ DWORD DesiredAccess [IntPtr].MakeByRefType() #_Out_ PHANDLE TokenHandle ) -SetLastError), (func kernel32 OpenThread ([IntPtr]) @( [UInt32], #_In_ DWORD dwDesiredAccess, [bool], #_In_ BOOL bInheritHandle, [UInt32] #_In_ DWORD dwThreadId ) -SetLastError), (func advapi32 OpenThreadToken ([bool]) @( [IntPtr], #_In_ HANDLE ThreadHandle [UInt32], #_In_ DWORD DesiredAccess [bool], #_In_ BOOL OpenAsSelf [IntPtr].MakeByRefType() #_Out_ PHANDLE TokenHandle ) -SetLastError), (func kernel32 QueryFullProcessImageName ([bool]) @( [IntPtr] #_In_ HANDLE hProcess [UInt32] #_In_ DWORD dwFlags, [System.Text.StringBuilder] #_Out_ LPTSTR lpExeName, [UInt32].MakeByRefType() #_Inout_ PDWORD lpdwSize ) -SetLastError), (func kernel32 ReadProcessMemory ([Bool]) @( [IntPtr], # _In_ HANDLE hProcess [IntPtr], # _In_ LPCVOID lpBaseAddress [Byte[]], # _Out_ LPVOID lpBuffer [Int], # _In_ SIZE_T nSize [Int].MakeByRefType() # _Out_ SIZE_T *lpNumberOfBytesRead ) -SetLastError), (func kernel32 TerminateThread ([bool]) @( [IntPtr], # _InOut_ HANDLE hThread [UInt32] # _In_ DWORD dwExitCode ) -SetLastError), (func kernel32 Thread32First ([bool]) @( [IntPtr], #_In_ HANDLE hSnapshot, $THREADENTRY32.MakeByRefType() #_Inout_ LPTHREADENTRY32 lpte ) -SetLastError) (func kernel32 Thread32Next ([bool]) @( [IntPtr], #_In_ HANDLE hSnapshot, $THREADENTRY32.MakeByRefType() #_Out_ LPTHREADENTRY32 lpte ) -SetLastError), (func kernel32 VirtualQueryEx ([Int32]) @( [IntPtr], #_In_ HANDLE hProcess, [IntPtr], #_In_opt_ LPCVOID lpAddress, $MEMORYBASICINFORMATION.MakeByRefType(), #_Out_ PMEMORY_BASIC_INFORMATION lpBuffer, [UInt32] #_In_ SIZE_T dwLength ) -SetLastError) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Module -Namespace 'Win32SysInfo' $Advapi32 = $Types['advapi32'] $Kernel32 = $Types['kernel32'] $Ntdll = $Types['ntdll'] $DELETE = 0x00010000 $READ_CONTROL = 0x00020000 $SYNCHRONIZE = 0x00100000 $WRITE_DAC = 0x00040000 $WRITE_OWNER = 0x00080000 $PROCESS_CREATE_PROCESS = 0x0080 $PROCESS_CREATE_THREAD = 0x0002 $PROCESS_DUP_HANDLE = 0x0040 $PROCESS_QUERY_INFORMATION = 0x0400 $PROCESS_QUERY_LIMITED_INFORMATION = 0x1000 $PROCESS_SET_INFORMATION = 0x0200 $PROCESS_SET_QUOTA = 0x0100 $PROCESS_SUSPEND_RESUME = 0x0800 $PROCESS_TERMINATE = 0x0001 $PROCESS_VM_OPERATION = 0x0008 $PROCESS_VM_READ = 0x0010 $PROCESS_VM_WRITE = 0x0020 $PROCESS_ALL_ACCESS = $DELETE -bor $READ_CONTROL -bor $SYNCHRONIZE -bor $WRITE_DAC -bor $WRITE_OWNER -bor $PROCESS_CREATE_PROCESS -bor $PROCESS_CREATE_THREAD -bor $PROCESS_DUP_HANDLE -bor $PROCESS_QUERY_INFORMATION -bor $PROCESS_QUERY_LIMITED_INFORMATION -bor $PROCESS_SET_INFORMATION -bor $PROCESS_SET_QUOTA -bor $PROCESS_SUSPEND_RESUME -bor $PROCESS_TERMINATE -bor $PROCESS_VM_OPERATION -bor $PROCESS_VM_READ -bor $PROCESS_VM_WRITE $THREAD_DIRECT_IMPERSONATION = 0x0200 $THREAD_GET_CONTEXT = 0x0008 $THREAD_IMPERSONATE = 0x0100 $THREAD_QUERY_INFORMATION = 0x0040 $THREAD_QUERY_LIMITED_INFORMATION = 0x0800 $THREAD_SET_CONTEXT = 0x0010 $THREAD_SET_INFORMATION = 0x0020 $THREAD_SET_LIMITED_INFORMATION = 0x0400 $THREAD_SET_THREAD_TOKEN = 0x0080 $THREAD_SUSPEND_RESUME = 0x0002 $THREAD_TERMINATE = 0x0001 $THREAD_ALL_ACCESS = $DELETE -bor $READ_CONTROL -bor $SYNCHRONIZE -bor $WRITE_DAC -bor $WRITE_OWNER -bor $THREAD_DIRECT_IMPERSONATION -bor $THREAD_GET_CONTEXT -bor $THREAD_IMPERSONATE -bor $THREAD_QUERY_INFORMATION -bor $THREAD_QUERY_LIMITED_INFORMATION -bor $THREAD_SET_CONTEXT -bor $THREAD_SET_LIMITED_INFORMATION -bor $THREAD_SET_THREAD_TOKEN -bor $THREAD_SUSPEND_RESUME -bor $THREAD_TERMINATE $STANDARD_RIGHTS_REQUIRED = 0x000F0000 $TOKEN_ASSIGN_PRIMARY = 0x0001 $TOKEN_DUPLICATE = 0x0002 $TOKEN_IMPERSONATE = 0x0004 $TOKEN_QUERY = 0x0008 $TOKEN_QUERY_SOURCE = 0x0010 $TOKEN_ADJUST_PRIVILEGES = 0x0020 $TOKEN_ADJUST_GROUPS = 0x0040 $TOKEN_ADJUST_DEFAULT = 0x0080 $TOKEN_ADJUST_SESSIONID = 0x0100 $TOKEN_ALL_ACCESS = $STANDARD_RIGHTS_REQUIRED -bor $TOKEN_ASSIGN_PRIMARY -bor $TOKEN_DUPLICATE -bor $TOKEN_IMPERSONATE -bor $TOKEN_QUERY -bor $TOKEN_QUERY_SOURCE -bor $TOKEN_ADJUST_PRIVILEGES -bor $TOKEN_ADJUST_GROUPS -bor $TOKEN_ADJUST_DEFAULT $UNTRUSTED_MANDATORY_LEVEL = "S-1-16-0" $LOW_MANDATORY_LEVEL = "S-1-16-4096" $MEDIUM_MANDATORY_LEVEL = "S-1-16-8192" $MEDIUM_PLUS_MANDATORY_LEVEL = "S-1-16-8448" $HIGH_MANDATORY_LEVEL = "S-1-16-12288" $SYSTEM_MANDATORY_LEVEL = "S-1-16-16384" $PROTECTED_PROCESS_MANDATORY_LEVEL = "S-1-16-20480" $SECURE_PROCESS_MANDATORY_LEVEL = "S-1-16-28672" #endregion PSReflect Definitions (Thread) #region Win32 API Abstractions function CloseHandle { <# .SYNOPSIS Closes an open object handle. .DESCRIPTION The CloseHandle function closes handles to the following objects: - Access token - Communications device - Console input - Console screen buffer - Event - File - File mapping - I/O completion port - Job - Mailslot - Memory resource notification - Mutex - Named pipe - Pipe - Process - Semaphore - Thread - Transaction - Waitable timer The documentation for the functions that create these objects indicates that CloseHandle should be used when you are finished with the object, and what happens to pending operations on the object after the handle is closed. In general, CloseHandle invalidates the specified object handle, decrements the object's handle count, and performs object retention checks. After the last handle to an object is closed, the object is removed from the system. .PARAMETER Handle A valid handle to an open object. .NOTES Author - Jared Atkinson (@jaredcatkinson) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $Handle ) <# (func kernel32 CloseHandle ([bool]) @( [IntPtr] #_In_ HANDLE hObject ) -SetLastError) #> $Success = $Kernel32::CloseHandle($Handle); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { Write-Debug "Close Handle Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } } function ConvertSidToStringSid { <# .SYNOPSIS The ConvertSidToStringSid function converts a security identifier (SID) to a string format suitable for display, storage, or transmission. .DESCRIPTION The ConvertSidToStringSid function uses the standard S-R-I-S-S… format for SID strings. .PARAMETER SidPointer A pointer to the SID structure to be converted. .NOTES Author - Jared Atkinson (@jaredcatkinson) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa376399(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $SidPointer ) <# (func advapi32 ConvertSidToStringSid ([bool]) @( [IntPtr] #_In_ PSID Sid, [IntPtr].MakeByRefType() #_Out_ LPTSTR *StringSid ) -SetLastError) #> $StringPtr = [IntPtr]::Zero $Success = $Advapi32::ConvertSidToStringSid($SidPointer, [ref]$StringPtr); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { Write-Debug "ConvertSidToStringSid Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto($StringPtr)) } function CreateToolhelp32Snapshot { <# .SYNOPSIS Takes a snapshot of the specified processes, as well as the heaps, modules, and threads used by these processes. .DESCRIPTION .PARAMETER ProcessId .PARAMETER Flags .NOTES Author - Jared Atkinson (@jaredcatkinson) .LINK .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [UInt32] $ProcessId, [Parameter(Mandatory = $true)] [UInt32] $Flags ) <# (func kernel32 CreateToolhelp32Snapshot ([IntPtr]) @( [UInt32], #_In_ DWORD dwFlags, [UInt32] #_In_ DWORD th32ProcessID ) -SetLastError) #> $hSnapshot = $Kernel32::CreateToolhelp32Snapshot($Flags, $ProcessId); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $hSnapshot) { Write-Debug "CreateToolhelp32Snapshot Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hSnapshot } function GetTokenInformation { <# .SYNOPSIS .DESCRIPTION .PARAMETER TokenHandle .PARAMETER TokenInformationClass .NOTES Author - Jared Atkinson (@jaredcatkinson) .LINK .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $TokenHandle, [Parameter(Mandatory = $true)] $TokenInformationClass ) <# (func advapi32 GetTokenInformation ([bool]) @( [IntPtr], #_In_ HANDLE TokenHandle [Int32], #_In_ TOKEN_INFORMATION_CLASS TokenInformationClass [IntPtr], #_Out_opt_ LPVOID TokenInformation [UInt32], #_In_ DWORD TokenInformationLength [UInt32].MakeByRefType() #_Out_ PDWORD ReturnLength ) -SetLastError) #> # initial query to determine the necessary buffer size $TokenPtrSize = 0 $Success = $Advapi32::GetTokenInformation($TokenHandle, $TokenInformationClass, 0, $TokenPtrSize, [ref]$TokenPtrSize) [IntPtr]$TokenPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($TokenPtrSize) # retrieve the proper buffer value $Success = $Advapi32::GetTokenInformation($TokenHandle, $TokenInformationClass, $TokenPtr, $TokenPtrSize, [ref]$TokenPtrSize); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if($Success) { switch($TokenInformationClass) { 1 # TokenUser { $TokenUser = $TokenPtr -as $TOKEN_USER ConvertSidToStringSid -SidPointer $TokenUser.User.Sid } 3 # TokenPrivilege { # query the process token with the TOKEN_INFORMATION_CLASS = 3 enum to retrieve a TOKEN_PRIVILEGES structure $TokenPrivileges = $TokenPtr -as $TOKEN_PRIVILEGES $sb = New-Object System.Text.StringBuilder for($i=0; $i -lt $TokenPrivileges.PrivilegeCount; $i++) { if((($TokenPrivileges.Privileges[$i].Attributes -as $LuidAttributes) -band $LuidAttributes::SE_PRIVILEGE_ENABLED) -eq $LuidAttributes::SE_PRIVILEGE_ENABLED) { $sb.Append(", $($TokenPrivileges.Privileges[$i].Luid.LowPart.ToString())") | Out-Null } } Write-Output $sb.ToString().TrimStart(', ') } 17 # TokenOrigin { $TokenOrigin = $TokenPtr -as $LUID Write-Output (Get-LogonSession -LogonId $TokenOrigin.LowPart) } 22 # TokenAccessInformation { } 25 # TokenIntegrityLevel { $TokenIntegrity = $TokenPtr -as $TOKEN_MANDATORY_LABEL switch(ConvertSidToStringSid -SidPointer $TokenIntegrity.Label.Sid) { $UNTRUSTED_MANDATORY_LEVEL { Write-Output "UNTRUSTED_MANDATORY_LEVEL" } $LOW_MANDATORY_LEVEL { Write-Output "LOW_MANDATORY_LEVEL" } $MEDIUM_MANDATORY_LEVEL { Write-Output "MEDIUM_MANDATORY_LEVEL" } $MEDIUM_PLUS_MANDATORY_LEVEL { Write-Output "MEDIUM_PLUS_MANDATORY_LEVEL" } $HIGH_MANDATORY_LEVEL { Write-Output "HIGH_MANDATORY_LEVEL" } $SYSTEM_MANDATORY_LEVEL { Write-Output "SYSTEM_MANDATORY_LEVEL" } $PROTECTED_PROCESS_MANDATORY_LEVEL { Write-Output "PROTECTED_PROCESS_MANDATORY_LEVEL" } $SECURE_PROCESS_MANDATORY_LEVEL { Write-Output "SECURE_PROCESS_MANDATORY_LEVEL" } } } } } else { Write-Debug "GetTokenInformation Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } try { [System.Runtime.InteropServices.Marshal]::FreeHGlobal($TokenPtr) } catch { } } function NtQueryInformationThread { <# .SYNOPSIS Retrieves information about the specified thread. .DESCRIPTION .PARAMETER ThreadHandle .NOTES Author - Jared Atkinson (@jaredcatkinson) .LINK .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $ThreadHandle ) <# (func ntdll NtQueryInformationThread ([Int32]) @( [IntPtr], #_In_ HANDLE ThreadHandle, [Int32], #_In_ THREADINFOCLASS ThreadInformationClass, [IntPtr], #_Inout_ PVOID ThreadInformation, [Int32], #_In_ ULONG ThreadInformationLength, [IntPtr] #_Out_opt_ PULONG ReturnLength )) #> $buf = [System.Runtime.InteropServices.Marshal]::AllocHGlobal([IntPtr]::Size) $Success = $Ntdll::NtQueryInformationThread($ThreadHandle, 9, $buf, [IntPtr]::Size, [IntPtr]::Zero); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { Write-Debug "NtQueryInformationThread Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output ([System.Runtime.InteropServices.Marshal]::ReadIntPtr($buf)) } function OpenProcess { <# .SYNOPSIS Opens an existing local process object. .DESCRIPTION To open a handle to another local process and obtain full access rights, you must enable the SeDebugPrivilege privilege. The handle returned by the OpenProcess function can be used in any function that requires a handle to a process, such as the wait functions, provided the appropriate access rights were requested. When you are finished with the handle, be sure to close it using the CloseHandle function. .PARAMETER ProcessId The identifier of the local process to be opened. If the specified process is the System Process (0x00000000), the function fails and the last error code is ERROR_INVALID_PARAMETER. If the specified process is the Idle process or one of the CSRSS processes, this function fails and the last error code is ERROR_ACCESS_DENIED because their access restrictions prevent user-level code from opening them. .PARAMETER DesiredAccess The access to the process object. This access right is checked against the security descriptor for the process. This parameter can be one or more of the process access rights. If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the contents of the security descriptor. .PARAMETER InheritHandle If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle. .NOTES Author - Jared Atkinson (@jaredcatkinson) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320(v=vs.85).aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms684880(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [UInt32] $ProcessId, [Parameter(Mandatory = $true)] [UInt32] $DesiredAccess, [Parameter()] [bool] $InheritHandle = $false ) <# (func kernel32 OpenProcess ([IntPtr]) @( [UInt32], #_In_ DWORD dwDesiredAccess, [bool], #_In_ BOOL bInheritHandle, [UInt32] #_In_ DWORD dwProcessId ) -SetLastError) #> $hProcess = $Kernel32::OpenProcess($DesiredAccess, $InheritHandle, $ProcessId); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if($hProcess -eq 0) { Write-Debug "OpenProcess Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hProcess } function OpenProcessToken { <# .SYNOPSIS The OpenProcessToken function opens the access token associated with a process. .PARAMETER ProcessHandle A handle to the process whose access token is opened. The process must have the PROCESS_QUERY_INFORMATION access permission. .PARAMETER DesiredAccess Specifies an access mask that specifies the requested types of access to the access token. These requested access types are compared with the discretionary access control list (DACL) of the token to determine which accesses are granted or denied. For a list of access rights for access tokens, see Access Rights for Access-Token Objects. .NOTES Author - Jared Atkinson (@jaredcatkinson) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa379295(v=vs.85).aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa374905(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $ProcessHandle, [Parameter(Mandatory = $true)] [UInt32] $DesiredAccess ) <# (func advapi32 OpenProcessToken ([bool]) @( [IntPtr], #_In_ HANDLE ProcessHandle [UInt32], #_In_ DWORD DesiredAccess [IntPtr].MakeByRefType() #_Out_ PHANDLE TokenHandle ) -SetLastError) #> $hToken = [IntPtr]::Zero $Success = $Advapi32::OpenProcessToken($ProcessHandle, $DesiredAccess, [ref]$hToken); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { Write-Debug "OpenProcessToken Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hToken } function OpenThread { <# .SYNOPSIS Opens an existing thread object. .DESCRIPTION The handle returned by OpenThread can be used in any function that requires a handle to a thread, such as the wait functions, provided you requested the appropriate access rights. The handle is granted access to the thread object only to the extent it was specified in the dwDesiredAccess parameter. When you are finished with the handle, be sure to close it by using the CloseHandle function. .PARAMETER ThreadId The identifier of the thread to be opened. .PARAMETER DesiredAccess The access to the thread object. This access right is checked against the security descriptor for the thread. This parameter can be one or more of the thread access rights. If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the contents of the security descriptor. .PARAMETER InheritHandle If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle. .NOTES Author - Jared Atkinson (@jaredcatkinson) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms684335(v=vs.85).aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms686769(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [UInt32] $ThreadId, [Parameter(Mandatory = $true)] [UInt32] $DesiredAccess, [Parameter()] [bool] $InheritHandle = $false ) <# (func kernel32 OpenThread ([IntPtr]) @( [UInt32], #_In_ DWORD dwDesiredAccess, [bool], #_In_ BOOL bInheritHandle, [UInt32] #_In_ DWORD dwThreadId ) -SetLastError) #> $hThread = $Kernel32::OpenThread($DesiredAccess, $InheritHandle, $ThreadId); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if($hThread -eq 0) { Write-Debug "OpenThread Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hThread } function OpenThreadToken { <# .SYNOPSIS The OpenThreadToken function opens the access token associated with a thread .DESCRIPTION Tokens with the anonymous impersonation level cannot be opened. Close the access token handle returned through the Handle parameter by calling CloseHandle. .PARAMETER ThreadHandle A handle to the thread whose access token is opened. .PARAMETER DesiredAccess Specifies an access mask that specifies the requested types of access to the access token. These requested access types are reconciled against the token's discretionary access control list (DACL) to determine which accesses are granted or denied. .PARAMETER OpenAsSelf TRUE if the access check is to be made against the process-level security context. FALSE if the access check is to be made against the current security context of the thread calling the OpenThreadToken function. The OpenAsSelf parameter allows the caller of this function to open the access token of a specified thread when the caller is impersonating a token at SecurityIdentification level. Without this parameter, the calling thread cannot open the access token on the specified thread because it is impossible to open executive-level objects by using the SecurityIdentification impersonation level. .NOTES Author - Jared Atkinson (@jaredcatkinson) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa379296(v=vs.85).aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa374905(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $ThreadHandle, [Parameter(Mandatory = $true)] [UInt32] $DesiredAccess, [Parameter()] [bool] $OpenAsSelf = $false ) <# (func advapi32 OpenThreadToken ([bool]) @( [IntPtr], #_In_ HANDLE ThreadHandle [UInt32], #_In_ DWORD DesiredAccess [bool], #_In_ BOOL OpenAsSelf [IntPtr].MakeByRefType() #_Out_ PHANDLE TokenHandle ) -SetLastError) #> $hToken = [IntPtr]::Zero $Success = $Advapi32::OpenThreadToken($ThreadHandle, $DesiredAccess, $OpenAsSelf, [ref]$hToken); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { Write-Debug "OpenThreadToken Error: $(([ComponentModel.Win32Exception] $LastError).Message)" throw "OpenThreadToken Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hToken } function QueryFullProcessImageName { <# .SYNOPSIS Retrieves the full name of the executable image for the specified process. .PARAMETER ProcessHandle A handle to the process. This handle must be created with the PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION access right. .PARAMETER Flags This parameter can be one of the following values. 0x00 - The name should use the Win32 path format. 0x01 - The name should use the native system path format. .NOTES Author - Jared Atkinson (@jaredcatkinson) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms684919(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $ProcessHandle, [Parameter()] [UInt32] $Flags = 0 ) $capacity = 2048 $sb = New-Object -TypeName System.Text.StringBuilder($capacity) $Success = $Kernel32::QueryFullProcessImageName($ProcessHandle, $Flags, $sb, [ref]$capacity); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { Write-Debug "QueryFullProcessImageName Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $sb.ToString() } function ReadProcessMemory { <# .SYNOPSIS Reads data from an area of memory in a specified process. The entire area to be read must be accessible or the operation fails. .DESCRIPTION ReadProcessMemory copies the data in the specified address range from the address space of the specified process into the specified buffer of the current process. Any process that has a handle with PROCESS_VM_READ access can call the function. The entire area to be read must be accessible, and if it is not accessible, the function fails. .PARAMETER ProcessHandle A handle to the process with memory that is being read. The handle must have PROCESS_VM_READ access to the process. .PARAMETER BaseAddress The base address in the specified process from which to read. Before any data transfer occurs, the system verifies that all data in the base address and memory of the specified size is accessible for read access, and if it is not accessible the function fails. .PARAMETER Size The number of bytes to be read from the specified process. .NOTES Author - Jared Atkinson (@jaredcatkinson) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms680553(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $ProcessHandle, [Parameter(Mandatory = $true)] [IntPtr] $BaseAddress, [Parameter(Mandatory = $true)] [Int] $Size ) <# (func kernel32 ReadProcessMemory ([Bool]) @( [IntPtr], # _In_ HANDLE hProcess [IntPtr], # _In_ LPCVOID lpBaseAddress [Byte[]], # _Out_ LPVOID lpBuffer [Int], # _In_ SIZE_T nSize [Int].MakeByRefType() # _Out_ SIZE_T *lpNumberOfBytesRead ) -SetLastError) # MSDN states to call GetLastError if the return value is false. #> $buf = New-Object byte[]($Size) [Int32]$NumberOfBytesRead = 0 $Success = $Kernel32::ReadProcessMemory($ProcessHandle, $BaseAddress, $buf, $buf.Length, [ref]$NumberOfBytesRead); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { Write-Debug "ReadProcessMemory Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $buf } function TerminateThread { <# .SYNOPSIS Terminates a thread. .DESCRIPTION TerminateThread is used to cause a thread to exit. When this occurs, the target thread has no chance to execute any user-mode code. DLLs attached to the thread are not notified that the thread is terminating. The system frees the thread's initial stack. .PARAMETER ThreadHandle A handle to the thread to be terminated. The handle must have the THREAD_TERMINATE access right. .PARAMETER ExitCode The exit code for the thread. .NOTES Author - Jared Atkinson (@jaredcatkinson) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms686717(v=vs.85).aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms686769(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $ThreadHandle, [Parameter()] [UInt32] $ExitCode = 0 ) <# (func kernel32 TerminateThread ([bool]) @( [IntPtr], # _InOut_ HANDLE hThread [UInt32] # _In_ DWORD dwExitCode ) -SetLastError) #> $Success = $Kernel32::TerminateThread($ThreadHandle, $ExitCode); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { Write-Debug "TerminateThread Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } } function Thread32First { <# .SYNOPSIS Retrieves information about the first thread of any process encountered in a system snapshot. .PARAMETER SnapshotHandle A handle to the snapshot returned from a previous call to the CreateToolhelp32Snapshot function. .NOTES Author - Jared Atkinson (@jaredcatkinson) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms686728(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $SnapshotHandle ) <# (func kernel32 Thread32First ([bool]) @( [IntPtr], #_In_ HANDLE hSnapshot, $THREADENTRY32.MakeByRefType() #_Inout_ LPTHREADENTRY32 lpte ) -SetLastError) #> $Thread = [Activator]::CreateInstance($THREADENTRY32) $Thread.dwSize = $THREADENTRY32::GetSize() $Success = $Kernel32::Thread32First($hSnapshot, [Ref]$Thread); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { Write-Debug "Thread32First Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $Thread } function VirtualQueryEx { <# .SYNOPSIS Retrieves information about a range of pages within the virtual address space of a specified process. .PARAMETER ProcessHandle A handle to the process whose memory information is queried. The handle must have been opened with the PROCESS_QUERY_INFORMATION access right, which enables using the handle to read information from the process object. .PARAMETER BaseAddress The base address of the region of pages to be queried. This value is rounded down to the next page boundary. .NOTES Author - Jared Atkinson (@jaredcatkinson) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa366907(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $ProcessHandle, [Parameter(Mandatory = $true)] [IntPtr] $BaseAddress ) <# (func kernel32 VirtualQueryEx ([Int32]) @( [IntPtr], #_In_ HANDLE hProcess, [IntPtr], #_In_opt_ LPCVOID lpAddress, $MEMORYBASICINFORMATION.MakeByRefType(), #_Out_ PMEMORY_BASIC_INFORMATION lpBuffer, [UInt32] #_In_ SIZE_T dwLength ) -SetLastError) #> $memory_basic_info = [Activator]::CreateInstance($MEMORYBASICINFORMATION) $Success = $Kernel32::VirtualQueryEx($ProcessHandle, $BaseAddress, [Ref]$memory_basic_info, $MEMORYBASICINFORMATION::GetSize()); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $Success) { Write-Debug "VirtualQueryEx Error: $(([ComponentModel.Win32Exception] $LastError).Message)" #Write-Host "ProcessHandle: $($ProcessHandle)" #Write-Host "BaseAddress: $($BaseAddress)" } Write-Output $memory_basic_info } #endregion Win32 API Abstractions Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-KerberosTicketCache.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-KerberosTicketCache)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'KerberosTicket') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'KerberosTicket' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) #Write-Output $body Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-KerberosTicketCache { <# .SYNOPSIS .DESCRIPTION .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .EXAMPLE #> [CmdletBinding()] param ( ) try { # We need a Handle to LSA to list Kerberos tickets # If we want to look at tickets from a session other than our own # Then we need to use LsaRegisterLogonProcess instead of LsaConnectUntrusted $hLsa = LsaRegisterLogonProcess } catch { # If the original call fails then it is likely we don't have SeTcbPrivilege # To get SeTcbPrivilege we can Impersonate a NT AUTHORITY\SYSTEM Token Get-System # We should now have the proper privileges to get a Handle to LSA $hLsa = LsaRegisterLogonProcess # We don't need our NT AUTHORITY\SYSTEM Token anymore # So we can revert to our original token RevertToSelf } # Enumerate all Logon Sessions # We need the sessions' LogonIds to enumerate it $Sessions = Get-LogonSession foreach($Session in $Sessions) { try { # Get the tickets from the LSA provider $ticket = LsaCallAuthenticationPackage -LsaHandle $hLsa -AuthenticationPackageName MICROSOFT_KERBEROS_NAME_A -LogonId $Session.LogonId if($ticket -ne $null) { # Add properties from the Logon Session to the ticket foreach($t in $ticket) { $t.Add('SessionLogonId', $Session.LogonId) $t.Add('SessionUserName', $Session.UserName) $t.Add('SessionLogonDomain', $Session.LogonDomain) $t.Add('SessionAuthenticationPackage', $Session.AuthenticationPackage) $t.Add('SessionSid', $Session.Sid.ToString()) $t.Add('SessionLogonType', $Session.LogonType) $t.Add('SessionUserPrincipalName', $Session.Upn) } # Output the ticket Write-Output $ticket } } catch { } } # Cleanup our LSA Handle LsaDeregisterLogonProcess -LsaHandle $hLsa } #region Helper Functions function Get-LogonSession { <# .SYNOPSIS .DESCRIPTION .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK .EXAMPLE #> [CmdletBinding()] param ( ) $SessionCount, $LuidPtr = LsaEnumerateLogonSessions $Sessions = LsaGetLogonSessionData -LuidPtr $LuidPtr -SessionCount $SessionCount Write-Output $Sessions } function Get-System { <# .SYNOPSIS .DESCRIPTION .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK .EXAMPLE #> # Get a Process object for the winlogon process # The System.Diagnostics.Process class has a handle property that we can use # We know winlogon will be available and is running as NT AUTHORITY\SYSTEM $winlogons = Get-Process -Name winlogon try { $proc = $winlogons[0] } catch { $proc = $winlogons } # Open winlogon's Token with TOKEN_DUPLICATE Acess # This allows us to make a copy of the token with DuplicateToken $hToken = OpenProcessToken -ProcessHandle $proc.Handle -DesiredAccess $TOKEN_DUPLICATE -Debug # Make a copy of the NT AUTHORITY\SYSTEM Token $hDupToken = DuplicateToken -TokenHandle $hToken # Apply our Duplicated Token to our Thread ImpersonateLoggedOnUser -TokenHandle $hDupToken # Clean up the handles we created CloseHandle -Handle $hToken CloseHandle -Handle $hDupToken if(-not [System.Security.Principal.WindowsIdentity]::GetCurrent().Name -eq 'NT AUTHORITY\SYSTEM') { throw "Unable to Impersonate System Token" } } #endregion Helper Functions #region PSReflect function New-InMemoryModule { <# .SYNOPSIS Creates an in-memory assembly and module Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION When defining custom enums, structs, and unmanaged functions, it is necessary to associate to an assembly module. This helper function creates an in-memory module that can be passed to the 'enum', 'struct', and Add-Win32Type functions. .PARAMETER ModuleName Specifies the desired name for the in-memory assembly and module. If ModuleName is not provided, it will default to a GUID. .EXAMPLE $Module = New-InMemoryModule -ModuleName Win32 #> Param ( [Parameter(Position = 0)] [ValidateNotNullOrEmpty()] [String] $ModuleName = [Guid]::NewGuid().ToString() ) $AppDomain = [Reflection.Assembly].Assembly.GetType('System.AppDomain').GetProperty('CurrentDomain').GetValue($null, @()) $LoadedAssemblies = $AppDomain.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 $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, 'Run') $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule($ModuleName, $False) return $ModuleBuilder } # A helper function used to reduce typing while defining function # prototypes for Add-Win32Type. 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, [String] $EntryPoint, [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 } if ($EntryPoint) { $Properties['EntryPoint'] = $EntryPoint } New-Object PSObject -Property $Properties } function Add-Win32Type { <# .SYNOPSIS Creates a .NET type for an unmanaged Win32 function. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: func .DESCRIPTION Add-Win32Type enables you to easily interact with unmanaged (i.e. Win32 unmanaged) functions in PowerShell. After providing Add-Win32Type with a function signature, a .NET type is created using reflection (i.e. csc.exe is never called like with Add-Type). The 'func' helper function can be used to reduce typing when defining multiple function definitions. .PARAMETER DllName The name of the DLL. .PARAMETER FunctionName The name of the target function. .PARAMETER EntryPoint The DLL export function name. This argument should be specified if the specified function name is different than the name of the exported function. .PARAMETER ReturnType The return type of the function. .PARAMETER ParameterTypes The function parameters. .PARAMETER NativeCallingConvention Specifies the native calling convention of the function. Defaults to stdcall. .PARAMETER Charset If you need to explicitly call an 'A' or 'W' Win32 function, you can specify the character set. .PARAMETER SetLastError Indicates whether the callee calls the SetLastError Win32 API function before returning from the attributed method. .PARAMETER Module The in-memory module that will host the functions. Use New-InMemoryModule to define an in-memory module. .PARAMETER Namespace An optional namespace to prepend to the type. Add-Win32Type defaults to a namespace consisting only of the name of the DLL. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $FunctionDefinitions = @( (func kernel32 GetProcAddress ([IntPtr]) @([IntPtr], [String]) -Charset Ansi -SetLastError), (func kernel32 GetModuleHandle ([Intptr]) @([String]) -SetLastError), (func ntdll RtlGetCurrentPeb ([IntPtr]) @()) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32' $Kernel32 = $Types['kernel32'] $Ntdll = $Types['ntdll'] $Ntdll::RtlGetCurrentPeb() $ntdllbase = $Kernel32::GetModuleHandle('ntdll') $Kernel32::GetProcAddress($ntdllbase, 'RtlGetCurrentPeb') .NOTES Inspired by Lee Holmes' Invoke-WindowsApi http://poshcode.org/2189 When defining multiple function prototypes, it is ideal to provide Add-Win32Type with an array of function signatures. That way, they are all incorporated into the same in-memory module. #> [OutputType([Hashtable])] Param( [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $DllName, [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $FunctionName, [Parameter(ValueFromPipelineByPropertyName = $True)] [String] $EntryPoint, [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') $EntryPointField = $DllImport.GetField('EntryPoint') if ($SetLastError) { $SLEValue = $True } else { $SLEValue = $False } if ($PSBoundParameters['EntryPoint']) { $ExportedFuncName = $EntryPoint } else { $ExportedFuncName = $FunctionName } # 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, $EntryPointField), [Object[]] @($SLEValue, ([Runtime.InteropServices.CallingConvention] $NativeCallingConvention), ([Runtime.InteropServices.CharSet] $Charset), $ExportedFuncName)) $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 psenum { <# .SYNOPSIS Creates an in-memory enumeration for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION The 'psenum' function facilitates the creation of enums entirely in memory using as close to a "C style" as PowerShell will allow. .PARAMETER Module The in-memory module that will host the enum. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the enum. .PARAMETER Type The type of each enum element. .PARAMETER EnumElements A hashtable of enum elements. .PARAMETER Bitfield Specifies that the enum should be treated as a bitfield. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageSubsystem = psenum $Mod PE.IMAGE_SUBSYSTEM UInt16 @{ UNKNOWN = 0 NATIVE = 1 # Image doesn't require a subsystem. WINDOWS_GUI = 2 # Image runs in the Windows GUI subsystem. WINDOWS_CUI = 3 # Image runs in the Windows character subsystem. OS2_CUI = 5 # Image runs in the OS/2 character subsystem. POSIX_CUI = 7 # Image runs in the Posix character subsystem. NATIVE_WINDOWS = 8 # Image is a native Win9x driver. WINDOWS_CE_GUI = 9 # Image runs in the Windows CE subsystem. EFI_APPLICATION = 10 EFI_BOOT_SERVICE_DRIVER = 11 EFI_RUNTIME_DRIVER = 12 EFI_ROM = 13 XBOX = 14 WINDOWS_BOOT_APPLICATION = 16 } .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Enum. :P #> [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]) { return ($Module.GetType($FullName)) } $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 { <# .SYNOPSIS Creates an in-memory struct for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: field .DESCRIPTION The 'struct' function facilitates the creation of structs entirely in memory using as close to a "C style" as PowerShell will allow. Struct fields are specified using a hashtable where each field of the struct is comprosed of the order in which it should be defined, its .NET type, and optionally, its offset and special marshaling attributes. One of the features of 'struct' is that after your struct is defined, it will come with a built-in GetSize method as well as an explicit converter so that you can easily cast an IntPtr to the struct without relying upon calling SizeOf and/or PtrToStructure in the Marshal class. .PARAMETER Module The in-memory module that will host the struct. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the struct. .PARAMETER StructFields A hashtable of fields. Use the 'field' helper function to ease defining each field. .PARAMETER PackingSize Specifies the memory alignment of fields. .PARAMETER ExplicitLayout Indicates that an explicit offset for each field will be specified. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageDosSignature = psenum $Mod PE.IMAGE_DOS_SIGNATURE UInt16 @{ DOS_SIGNATURE = 0x5A4D OS2_SIGNATURE = 0x454E OS2_SIGNATURE_LE = 0x454C VXD_SIGNATURE = 0x454C } $ImageDosHeader = struct $Mod PE.IMAGE_DOS_HEADER @{ e_magic = field 0 $ImageDosSignature e_cblp = field 1 UInt16 e_cp = field 2 UInt16 e_crlc = field 3 UInt16 e_cparhdr = field 4 UInt16 e_minalloc = field 5 UInt16 e_maxalloc = field 6 UInt16 e_ss = field 7 UInt16 e_sp = field 8 UInt16 e_csum = field 9 UInt16 e_ip = field 10 UInt16 e_cs = field 11 UInt16 e_lfarlc = field 12 UInt16 e_ovno = field 13 UInt16 e_res = field 14 UInt16[] -MarshalAs @('ByValArray', 4) e_oemid = field 15 UInt16 e_oeminfo = field 16 UInt16 e_res2 = field 17 UInt16[] -MarshalAs @('ByValArray', 10) e_lfanew = field 18 Int32 } # Example of using an explicit layout in order to create a union. $TestUnion = struct $Mod TestUnion @{ field1 = field 0 UInt32 0 field2 = field 1 IntPtr 0 } -ExplicitLayout .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Struct. :P #> [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() } #endregion PSReflect $Module = New-InMemoryModule -ModuleName KerberosTicket #region Constants $STANDARD_RIGHTS_REQUIRED = 0x000F0000 $TOKEN_ASSIGN_PRIMARY = 0x0001 $TOKEN_DUPLICATE = 0x0002 $TOKEN_IMPERSONATE = 0x0004 $TOKEN_QUERY = 0x0008 $TOKEN_QUERY_SOURCE = 0x0010 $TOKEN_ADJUST_PRIVILEGES = 0x0020 $TOKEN_ADJUST_GROUPS = 0x0040 $TOKEN_ADJUST_DEFAULT = 0x0080 $TOKEN_ADJUST_SESSIONID = 0x0100 $TOKEN_ALL_ACCESS = $STANDARD_RIGHTS_REQUIRED -bor $TOKEN_ASSIGN_PRIMARY -bor $TOKEN_DUPLICATE -bor $TOKEN_IMPERSONATE -bor $TOKEN_QUERY -bor $TOKEN_QUERY_SOURCE -bor $TOKEN_ADJUST_PRIVILEGES -bor $TOKEN_ADJUST_GROUPS -bor $TOKEN_ADJUST_DEFAULT #endregion Constants #region Enums $KERB_PROTOCOL_MESSAGE_TYPE = psenum $Module KERB_PROTOCOL_MESSAGE_TYPE UInt32 @{ KerbDebugRequestMessage = 0 KerbQueryTicketCacheMessage = 1 KerbChangeMachinePasswordMessage = 2 KerbVerifyPacMessage = 3 KerbRetrieveTicketMessage = 4 KerbUpdateAddressesMessage = 5 KerbPurgeTicketCacheMessage = 6 KerbChangePasswordMessage = 7 KerbRetrieveEncodedTicketMessage = 8 KerbDecryptDataMessage = 9 KerbAddBindingCacheEntryMessage = 10 KerbSetPasswordMessage = 11 KerbSetPasswordExMessage = 12 KerbVerifyCredentialsMessage = 13 KerbQueryTicketCacheExMessage = 14 KerbPurgeTicketCacheExMessage = 15 KerbRefreshSmartcardCredentialsMessage = 16 KerbAddExtraCredentialsMessage = 17 KerbQuerySupplementalCredentialsMessage = 18 KerbTransferCredentialsMessage = 19 KerbQueryTicketCacheEx2Message = 20 KerbSubmitTicketMessage = 21 KerbAddExtraCredentialsExMessage = 22 KerbQueryKdcProxyCacheMessage = 23 KerbPurgeKdcProxyCacheMessage = 24 KerbQueryTicketCacheEx3Message = 25 KerbCleanupMachinePkinitCredsMessage = 26 KerbAddBindingCacheEntryExMessage = 27 KerbQueryBindingCacheMessage = 28 KerbPurgeBindingCacheMessage = 29 KerbQueryDomainExtendedPoliciesMessage = 30 KerbQueryS4U2ProxyCacheMessage = 31 } $KERB_CACHE_OPTIONS = psenum $Module KERB_CACHE_OPTIONS UInt64 @{ KERB_RETRIEVE_TICKET_DONT_USE_CACHE = 0x1 KERB_RETRIEVE_TICKET_USE_CACHE_ONLY = 0x2 KERB_RETRIEVE_TICKET_USE_CREDHANDLE = 0x4 KERB_RETRIEVE_TICKET_AS_KERB_CRED = 0x8 KERB_RETRIEVE_TICKET_WITH_SEC_CRED = 0x10 KERB_RETRIEVE_TICKET_CACHE_TICKET = 0x20 KERB_RETRIEVE_TICKET_MAX_LIFETIME = 0x40 } -Bitfield $KERB_ENCRYPTION_TYPE = psenum $Module KERB_ENCRYPTION_TYPE UInt32 @{ reserved0 = 0 des_cbc_crc = 1 des_cbc_md4 = 2 des_cbc_md5 = 3 reserved1 = 4 des3_cbc_md5 = 5 reserved2 = 6 des3_cbc_sha1 = 7 dsaWithSHA1_CmsOID = 9 md5WithRSAEncryption_CmsOID = 10 sha1WithRSAEncryption_CmsOID = 11 rc2CBC_EnvOID = 12 rsaEncryption_EnvOID = 13 rsaES_OAEP_ENV_OID = 14 des_ede3_cbc_Env_OID = 15 des3_cbc_sha1_kd = 16 aes128_cts_hmac_sha1_96 = 17 aes256_cts_hmac_sha1_96 = 18 aes128_cts_hmac_sha256_128 = 19 aes256_cts_hmac_sha384_192 = 20 rc4_hmac = 23 rc4_hmac_exp = 24 camellia128_cts_cmac = 25 camellia256_cts_cmac = 26 subkey_keymaterial = 65 } $KERB_TICKET_FLAGS = psenum $Module KERB_TICKET_FLAGS UInt32 @{ reserved = 2147483648 forwardable = 0x40000000 forwarded = 0x20000000 proxiable = 0x10000000 proxy = 0x08000000 may_postdate = 0x04000000 postdated = 0x02000000 invalid = 0x01000000 renewable = 0x00800000 initial = 0x00400000 pre_authent = 0x00200000 hw_authent = 0x00100000 ok_as_delegate = 0x00040000 name_canonicalize = 0x00010000 cname_in_pa_data = 0x00040000 enc_pa_rep = 0x00010000 reserved1 = 0x00000001 } -Bitfield $SECURITY_LOGON_TYPE = psenum $Module SECURITY_LOGON_TYPE UInt32 @{ Interactive = 2 Network = 3 Batch = 4 Service = 5 Proxy = 6 Unlock = 7 NetworkCleartext = 8 NewCredentials = 9 RemoteInteractive = 10 CachedInteractive = 11 CachedRemoteInteractive = 12 CachedUnlock = 13 } $SECURITY_IMPERSONATION_LEVEL = psenum $Module SECURITY_IMPERSONATION_LEVEL UInt32 @{ SecurityAnonymous = 0 SecurityIdentification = 1 SecurityImpersonation = 2 SecurityDelegation = 3 } #endregion Enums #region Structs $LSA_STRING = struct $Module LSA_STRING @{ Length = field 0 UInt16 MaximumLength = field 1 UInt16 Buffer = field 2 IntPtr } $LSA_UNICODE_STRING = struct $Module LSA_UNICODE_STRING @{ Length = field 0 UInt16 MaximumLength = field 1 UInt16 Buffer = field 2 IntPtr } $LUID = struct $Module LUID @{ LowPart = field 0 UInt32 HighPart = field 1 UInt32 } $LUID_AND_ATTRIBUTES = struct $Module LUID_AND_ATTRIBUTES @{ Luid = field 0 $LUID Attributes = field 1 UInt32 } $SecHandle = struct $Module SecHandle @{ dwLower = field 0 IntPtr dwUpper = field 1 IntPtr } $KERB_CRYPTO_KEY = struct $Module KERB_CRYPTO_KEY @{ KeyType = field 0 Int32 Length = field 1 Int32 Value = field 2 IntPtr } $KERB_EXTERNAL_NAME = struct $Module KERB_EXTERNAL_NAME @{ NameType = field 0 Int16 NameCount = field 1 UInt16 Names = field 2 $LSA_UNICODE_STRING } $KERB_EXTERNAL_TICKET = struct $Module KERB_EXTERNAL_TICKET @{ ServiceName = field 0 IntPtr TargetName = field 1 IntPtr ClientName = field 2 IntPtr DomainName = field 3 $LSA_UNICODE_STRING TargetDomainName = field 4 $LSA_UNICODE_STRING AltTargetDomainName = field 5 $LSA_UNICODE_STRING SessionKey = field 6 $KERB_CRYPTO_KEY TicketFlags = field 7 UInt32 Flags = field 8 UInt32 KeyExpirationTime = field 9 Int64 StartTime = field 10 Int64 EndTime = field 11 Int64 RenewUntil = field 12 Int64 TimeSkew = field 13 Int64 EncodedTicketSize = field 14 Int32 EncodedTicket = field 15 IntPtr } $KERB_TICKET_CACHE_INFO = struct $Module KERB_TICKET_CACHE_INFO @{ ServerName = field 0 $LSA_UNICODE_STRING RealmName = field 1 $LSA_UNICODE_STRING StartTime = field 2 Int64 EndTime = field 3 Int64 RenewTime = field 4 Int64 EncryptionType = field 5 Int32 TicketFlags = field 6 UInt32 } $KERB_QUERY_TKT_CACHE_REQUEST = struct $Module KERB_QUERY_TKT_CACHE_REQUEST @{ MessageType = field 0 $KERB_PROTOCOL_MESSAGE_TYPE LogonId = field 1 $LUID } $KERB_QUERY_TKT_CACHE_RESPONSE = struct $Module KERB_QUERY_TKT_CACHE_RESPONSE @{ MessageType = field 0 $KERB_PROTOCOL_MESSAGE_TYPE CountOfTickets = field 1 UInt32 Tickets = field 2 $KERB_TICKET_CACHE_INFO.MakeArrayType() -MarshalAs @('ByValArray', 1) } $KERB_RETRIEVE_TKT_REQUEST = struct $Module KERB_RETRIEVE_TKT_REQUEST @{ MessageType = field 0 $KERB_PROTOCOL_MESSAGE_TYPE LogonId = field 1 $LUID TargetName = field 2 $LSA_UNICODE_STRING TicketFlags = field 3 UInt64 CacheOptions = field 4 $KERB_CACHE_OPTIONS EncryptionType = field 5 Int64 CredentialsHandle = field 6 $SecHandle } $KERB_RETRIEVE_TKT_RESPONSE = struct $Module KERB_RETRIEVE_TKT_RESPONSE @{ Ticket = field 0 $KERB_EXTERNAL_TICKET } $LSA_LAST_INTER_LOGON_INFO = struct $Module LSA_LAST_INTER_LOGON_INFO @{ LastSuccessfulLogon = field 0 Int64 LastFailedLogon = field 1 Int64 FailedAttemptCountSinceLastSuccessfulLogon = field 2 UInt64 } $SECURITY_LOGON_SESSION_DATA = struct $Module SECURITY_LOGON_SESSION_DATA @{ Size = field 0 UInt32 LogonId = field 1 $LUID Username = field 2 $LSA_UNICODE_STRING LogonDomain = field 3 $LSA_UNICODE_STRING AuthenticationPackage = field 4 $LSA_UNICODE_STRING LogonType = field 5 UInt32 Session = field 6 UInt32 PSiD = field 7 IntPtr LogonTime = field 8 UInt64 LogonServer = field 9 $LSA_UNICODE_STRING DnsDomainName = field 10 $LSA_UNICODE_STRING Upn = field 11 $LSA_UNICODE_STRING UserFlags = field 12 UInt64 LastLogonInfo = field 13 $LSA_LAST_INTER_LOGON_INFO LogonScript = field 14 $LSA_UNICODE_STRING ProfilePath = field 15 $LSA_UNICODE_STRING HomeDirectory = field 16 $LSA_UNICODE_STRING HomeDirectoryDrive = field 17 $LSA_UNICODE_STRING LogoffTime = field 18 Int64 KickOffTime = field 19 Int64 PasswordLastSet = field 20 Int64 PasswordCanChange = field 21 Int64 PasswordMustChange = field 22 Int64 } $SID_AND_ATTRIBUTES = struct $Module SID_AND_ATTRIBUTES @{ Sid = field 0 IntPtr Attributes = field 1 UInt32 } #endregion Structs #region Function Definitions $FunctionDefinitions = @( (func kernel32 CloseHandle ([bool]) @( [IntPtr] #_In_ HANDLE hObject ) -EntryPoint CloseHandle -SetLastError), (func advapi32 DuplicateToken ([bool]) @( [IntPtr], #_In_ HANDLE ExistingTokenHandle, [UInt32], #_In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, [IntPtr].MakeByRefType() #_Out_ PHANDLE DuplicateTokenHandle ) -EntryPoint DuplicateToken -SetLastError), (func advapi32 ImpersonateLoggedOnUser ([bool]) @( [IntPtr] #_In_ HANDLE hToken ) -EntryPoint ImpersonateLoggedOnUser -SetLastError), (func secur32 LsaCallAuthenticationPackage_KERB_QUERY_TKT_CACHE ([UInt32]) @( [IntPtr], #_In_ HANDLE LsaHandle [UInt64], #_In_ ULONG AuthenticationPackage $KERB_QUERY_TKT_CACHE_REQUEST.MakeByRefType(), #_In_ PVOID ProtocolSubmitBuffer [UInt64], #_In_ ULONG SubmitBufferLength [IntPtr].MakeByRefType(),#_Out_ PVOID *ProtocolReturnBuffer [UInt64].MakeByRefType(), #_Out_ PULONG *ReturnBufferLength [UInt32].MakeByRefType() #_Out_ PNTSTATUS ProtocolStatus ) -EntryPoint LsaCallAuthenticationPackage), (func secur32 LsaCallAuthenticationPackage_KERB_RETRIEVE_TKT ([UInt32]) @( [IntPtr], #_In_ HANDLE LsaHandle [UInt64], #_In_ ULONG AuthenticationPackage $KERB_RETRIEVE_TKT_REQUEST.MakeByRefType(), #_In_ PVOID ProtocolSubmitBuffer [UInt64], #_In_ ULONG SubmitBufferLength [IntPtr].MakeByRefType(),#_Out_ PVOID *ProtocolReturnBuffer [UInt64].MakeByRefType(), #_Out_ PULONG *ReturnBufferLength [UInt32].MakeByRefType() #_Out_ PNTSTATUS ProtocolStatus ) -EntryPoint LsaCallAuthenticationPackage), (func secur32 LsaConnectUntrusted ([UInt32]) @( [IntPtr].MakeByRefType() #_Out_ PHANDLE LsaHandle ) -EntryPoint LsaConnectUntrusted), (func secur32 LsaDeregisterLogonProcess ([UInt32]) @( [IntPtr] #_In_ HANDLE LsaHandle ) -EntryPoint LsaDeregisterLogonProcess), (func secur32 LsaEnumerateLogonSessions ([UInt32]) @( [UInt64].MakeByRefType(), #_Out_ PULONG LogonSessionCount, [IntPtr].MakeByRefType() #_Out_ PLUID *LogonSessionList ) -EntryPoint LsaEnumerateLogonSessions), (func secur32 LsaFreeReturnBuffer ([UInt32]) @( [IntPtr].MakeByRefType() #_In_ PVOID Buffer ) -EntryPoint LsaFreeReturnBuffer), (func secur32 LsaGetLogonSessionData ([UInt32]) @( [IntPtr], #_In_ PLUID LogonId, [IntPtr].MakeByRefType() #_Out_ PSECURITY_LOGON_SESSION_DATA *ppLogonSessionData ) -EntryPoint LsaGetLogonSessionData), (func secur32 LsaLookupAuthenticationPackage ([UInt32]) @( [IntPtr], #_In_ HANDLE LsaHandle, $LSA_STRING.MakeByRefType() #_In_ PLSA_STRING PackageName, [UInt64].MakeByRefType() #_Out_ PULONG AuthenticationPackage ) -EntryPoint LsaLookupAuthenticationPackage), (func advapi32 LsaNtStatusToWinError ([UInt64]) @( [UInt32] #_In_ NTSTATUS Status ) -EntryPoint LsaNtStatusToWinError), (func secur32 LsaRegisterLogonProcess ([UInt32]) @( $LSA_STRING.MakeByRefType() #_In_ PLSA_STRING LogonProcessName, [IntPtr].MakeByRefType() #_Out_ PHANDLE LsaHandle, [UInt64].MakeByRefType() #_Out_ PLSA_OPERATIONAL_MODE SecurityMode ) -EntryPoint LsaRegisterLogonProcess), (func advapi32 OpenProcessToken ([bool]) @( [IntPtr], #_In_ HANDLE ProcessHandle [UInt32], #_In_ DWORD DesiredAccess [IntPtr].MakeByRefType() #_Out_ PHANDLE TokenHandle ) -EntryPoint OpenProcessToken -SetLastError), (func advapi32 RevertToSelf ([bool]) @() -EntryPoint RevertToSelf -SetLastError) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Module -Namespace 'Kerberos' $Advapi32 = $Types['advapi32'] $Kernel32 = $Types['kernel32'] $Secur32 = $Types['secur32'] #endregion Function Definitions #region Win32 function abstractions function CloseHandle { <# .SYNOPSIS Closes an open object handle. .DESCRIPTION The CloseHandle function closes handles to the following objects: - Access token - Communications device - Console input - Console screen buffer - Event - File - File mapping - I/O completion port - Job - Mailslot - Memory resource notification - Mutex - Named pipe - Pipe - Process - Semaphore - Thread - Transaction - Waitable timer The documentation for the functions that create these objects indicates that CloseHandle should be used when you are finished with the object, and what happens to pending operations on the object after the handle is closed. In general, CloseHandle invalidates the specified object handle, decrements the object's handle count, and performs object retention checks. After the last handle to an object is closed, the object is removed from the system. .PARAMETER Handle A valid handle to an open object. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $Handle ) <# (func kernel32 CloseHandle ([bool]) @( [IntPtr] #_In_ HANDLE hObject ) -SetLastError) #> $SUCCESS = $Kernel32::CloseHandle($Handle); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $SUCCESS) { Write-Debug "CloseHandle Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } } function DuplicateToken { <# .SYNOPSIS The DuplicateToken function creates a new access token that duplicates one already in existence. .DESCRIPTION The DuplicateToken function creates an impersonation token, which you can use in functions such as SetThreadToken and ImpersonateLoggedOnUser. The token created by DuplicateToken cannot be used in the CreateProcessAsUser function, which requires a primary token. To create a token that you can pass to CreateProcessAsUser, use the DuplicateTokenEx function. .PARAMETER TokenHandle A handle to an access token opened with TOKEN_DUPLICATE access. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa446616(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $TokenHandle ) <# (func advapi32 DuplicateToken ([bool]) @( [IntPtr] #_In_ HANDLE ExistingTokenHandle, [UInt32] #_In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, [IntPtr].MakeByRefType() #_Out_ PHANDLE DuplicateTokenHandle ) -SetLastError) #> $DuplicateTokenHandle = [IntPtr]::Zero $success = $Advapi32::DuplicateToken($TokenHandle, $SECURITY_IMPERSONATION_LEVEL::SecurityImpersonation, [ref]$DuplicateTokenHandle); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $success) { Write-Debug "DuplicateToken Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $DuplicateTokenHandle } function ImpersonateLoggedOnUser { <# .SYNOPSIS The ImpersonateLoggedOnUser function lets the calling thread impersonate the security context of a logged-on user. The user is represented by a token handle. .DESCRIPTION The impersonation lasts until the thread exits or until it calls RevertToSelf. The calling thread does not need to have any particular privileges to call ImpersonateLoggedOnUser. If the call to ImpersonateLoggedOnUser fails, the client connection is not impersonated and the client request is made in the security context of the process. If the process is running as a highly privileged account, such as LocalSystem, or as a member of an administrative group, the user may be able to perform actions they would otherwise be disallowed. Therefore, it is important to always check the return value of the call, and if it fails, raise an error; do not continue execution of the client request. All impersonate functions, including ImpersonateLoggedOnUser allow the requested impersonation if one of the following is true: - The requested impersonation level of the token is less than SecurityImpersonation, such as SecurityIdentification or SecurityAnonymous. - The caller has the SeImpersonatePrivilege privilege. - A process (or another process in the caller's logon session) created the token using explicit credentials through LogonUser or LsaLogonUser function. - The authenticated identity is same as the caller. Windows XP with SP1 and earlier: The SeImpersonatePrivilege privilege is not supported. .PARAMETER TokenHandle A handle to a primary or impersonation access token that represents a logged-on user. This can be a token handle returned by a call to LogonUser, CreateRestrictedToken, DuplicateToken, DuplicateTokenEx, OpenProcessToken, or OpenThreadToken functions. If hToken is a handle to a primary token, the token must have TOKEN_QUERY and TOKEN_DUPLICATE access. If hToken is a handle to an impersonation token, the token must have TOKEN_QUERY and TOKEN_IMPERSONATE access. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378612(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $TokenHandle ) <# (func advapi32 ImpersonateLoggedOnUser ([bool]) @( [IntPtr] #_In_ HANDLE hToken ) -SetLastError), #> $SUCCESS = $Advapi32::ImpersonateLoggedOnUser($TokenHandle); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $SUCCESS) { throw "ImpersonateLoggedOnUser Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } } function LsaCallAuthenticationPackage { <# .SYNOPSIS The LsaCallAuthenticationPackage function is used by a logon application to communicate with an authentication package. This function is typically used to access services provided by the authentication package. .DESCRIPTION Logon applications can call LsaCallAuthenticationPackage to communicate with an authentication package. There are several reasons why an application may do this: - To implement multiple-message authentication protocols, such as the NTLM Challenge-Response protocol. - To pass state change information to the authentication package. For example, the NTLM might notify the MSV1_0 package that a previously unreachable domain controller is now reachable. The authentication package would then re-logon any users logged on to that domain controller. Typically, this function is used to exchange information with a custom authentication package. This function is not needed by an application that is using one of the authentication packages supplied with Windows, such as MSV1_0 or Kerberos. You must call LsaCallAuthenticationPackage to clean up PKINIT device credentials for LOCAL_SYSTEM and NETWORK_SERVICE. When there is no PKINIT device credential, a successful call does no operation. When there is a PKINIT device credential, a successful call cleans up the PKINIT device credential so that only the password credential remains. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378261(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $LsaHandle, [Parameter()] [ValidateSet('MSV1_0_PACKAGE_NAME', 'MICROSOFT_KERBEROS_NAME_A', 'NEGOSSP_NAME_A', 'NTLMSP_NAME_A')] [string] $AuthenticationPackageName = 'MICROSOFT_KERBEROS_NAME_A', [Parameter(Mandatory = $true)] [UInt32] $LogonId ) <# (func secur32 LsaCallAuthenticationPackage ([UInt32]) @( [IntPtr], #_In_ HANDLE LsaHandle [UInt64], #_In_ ULONG AuthenticationPackage $KERB_RETRIEVE_TKT_REQUEST.MakeByRefType(),#_In_ PVOID ProtocolSubmitBuffer [UInt64], #_In_ ULONG SubmitBufferLength [IntPtr], #_Out_ PVOID *ProtocolReturnBuffer [UInt64].MakeByRefType(), #_Out_ PULONG *ReturnBufferLength [UInt32].MakeByRefType() #_Out_ PNTSTATUS ProtocolStatus )) #> $AuthenticationPackage = LsaLookupAuthenticationPackage -LsaHandle $LsaHandle -PackageName $AuthenticationPackageName switch($AuthenticationPackageName) { MSV1_0_PACKAGE_NAME { throw New-Object -TypeName System.NotImplementedException("MSV1_0_PACKAGE_NAME Package has not been implemented yet.") } MICROSOFT_KERBEROS_NAME_A { # Request information about all of the cached tickets for the specified user logon session <# $KERB_QUERY_TKT_CACHE_REQUEST = struct $Mod Kerberos.KERB_QUERY_TKT_CACHE_REQUEST @{ MessageType = field 0 $KERB_PROTOCOL_MESSAGE_TYPE LogonId = field 1 $LUID } #> $ProtocolSubmitBuffer = [Activator]::CreateInstance($KERB_QUERY_TKT_CACHE_REQUEST) $ProtocolSubmitBuffer.MessageType = $KERB_PROTOCOL_MESSAGE_TYPE::KerbQueryTicketCacheMessage $LogonIdLuid = [Activator]::CreateInstance($LUID) $LogonIdLuid.LowPart = $LogonId $LogonIdLuid.HighPart = 0 $ProtocolSubmitBuffer.LogonId = $LogonIdLuid $ProtocolReturnBuffer = [IntPtr]::Zero $ReturnBufferLength = [UInt64]0 $ProtocolStatus = [UInt32]0 $SUCCESS = $Secur32::LsaCallAuthenticationPackage_KERB_QUERY_TKT_CACHE($LsaHandle, $AuthenticationPackage, [ref]$ProtocolSubmitBuffer, $KERB_RETRIEVE_TKT_REQUEST::GetSize(), [ref]$ProtocolReturnBuffer, [ref]$ReturnBufferLength, [ref]$ProtocolStatus) if($SUCCESS -eq 0) { if($ProtocolStatus -eq 0) { $Response = $ProtocolReturnBuffer -as $KERB_QUERY_TKT_CACHE_RESPONSE for($i = 0; $i -lt $Response.CountOfTickets; $i++) { $currentTicketPtr = [IntPtr]::Add($ProtocolReturnBuffer, (8 + ($i * $KERB_TICKET_CACHE_INFO::GetSize()))) $data = $currentTicketPtr -as $KERB_TICKET_CACHE_INFO $StartTime = [DateTime]::FromFileTime($data.StartTime) $EndTime = [DateTime]::FromFileTime($data.EndTime) [timespan]$TicketLength = $EndTime.Subtract($StartTime) $props = @{ ServerName = ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto($data.ServerName.Buffer, $data.ServerName.Length / 2)) RealmName = ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto($data.RealmName.Buffer, $data.RealmName.Length / 2)) StartTime = $StartTime EndTime = $EndTime TicketLength = $TicketLength RenewTime = ([datetime]::FromFileTime($data.RenewTime)) EncryptionType = ($data.EncryptionType -as $KERB_ENCRYPTION_TYPE).ToString() TicketFlags = ($data.TicketFlags -as $KERB_TICKET_FLAGS).ToString() } Write-Output $props } } else { $WinErrorCode = LsaNtStatusToWinError -NtStatus $ProtocolStatus $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaCallAuthenticationPackage Error: $($LastError.Message)" } } else { $WinErrorCode = LsaNtStatusToWinError -NtStatus $SUCCESS $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaCallAuthenticationPackage Error: $($LastError.Message)" } } NEGOSSP_NAME_A { throw New-Object -TypeName System.NotImplementedException("NEGOSSP_NAME_A Package has not been implemented yet.") } NTLMSP_NAME_A { throw New-Object -TypeName System.NotImplementedException("NTLMSP_NAME_A Package has not been implemented yet.") } } } function LsaConnectUntrusted { <# .SYNOPSIS The LsaConnectUntrusted function establishes an untrusted connection to the LSA server. .DESCRIPTION LsaConnectUntrusted returns a handle to an untrusted connection; it does not verify any information about the caller. The handle should be closed using the LsaDeregisterLogonProcess function. If your application simply needs to query information from authentication packages, you can use the handle returned by this function in calls to LsaCallAuthenticationPackage and LsaLookupAuthenticationPackage. Applications with the SeTcbPrivilege privilege may create a trusted connection by calling LsaRegisterLogonProcess. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378265(v=vs.85).aspx .EXAMPLE $hLsa = LsaConnectUntrusted #> param ( ) <# (func secur32 LsaConnectUntrusted ([UInt32]) @( [IntPtr].MakeByRefType() #_Out_ PHANDLE LsaHandle )) #> $LsaHandle = [IntPtr]::Zero $SUCCESS = $Secur32::LsaConnectUntrusted([ref]$LsaHandle) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaConnectUntrusted Error: $($LastError.Message)" } Write-Output $LsaHandle } function LsaDeregisterLogonProcess { <# .SYNOPSIS The LsaDeregisterLogonProcess function deletes the caller's logon application context and closes the connection to the LSA server. .DESCRIPTION If your logon application references the connection handle after calling the LsaDeregisterLogonProcess function, unexpected behavior can result. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378269(v=vs.85).aspx .EXAMPLE $hLsa = LsaConnectUntrusted # # Do Somthing with the LSA Handle # LsaDeregisterLogonProcess -LsaHandle $hLsa #> param ( [Parameter(Mandatory = $true)] [IntPtr] $LsaHandle ) <# (func secur32 LsaDeregisterLogonProcess ([UInt32]) @( [IntPtr] #_In_ HANDLE LsaHandle )) #> $SUCCESS = $Secur32::LsaDeregisterLogonProcess($LsaHandle) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaDeregisterLogonProcess Error: $($LastError.Message)" } } function LsaEnumerateLogonSessions { <# .SYNOPSIS The LsaEnumerateLogonSessions function retrieves the set of existing logon session identifiers (LUIDs) and the number of sessions. .DESCRIPTION To retrieve information about the logon sessions returned by LsaEnumerateLogonSessions, call the LsaGetLogonSessionData function. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378275(v=vs.85).aspx .EXAMPLE LsaEnumerateLogonSessions 8 2390553591808 .EXAMPLE $SessionCount, $LogonSessionListPtr = LsaEnumerateLogonSessions #> <# (func secur32 LsaEnumerateLogonSessions ([UInt32]) @( [UInt64].MakeByRefType(), #_Out_ PULONG LogonSessionCount, [IntPtr].MakeByRefType() #_Out_ PLUID *LogonSessionList )) #> $LogonSessionCount = [UInt64]0 $LogonSessionList = [IntPtr]::Zero $SUCCESS = $Secur32::LsaEnumerateLogonSessions([ref]$LogonSessionCount, [ref]$LogonSessionList) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaEnumerateLogonSessions Error: $($LastError.Message)" } return $LogonSessionCount, $LogonSessionList } function LsaFreeReturnBuffer { <# .SYNOPSIS The LsaFreeReturnBuffer function frees the memory used by a buffer previously allocated by the LSA. .DESCRIPTION Some of the LSA authentication functions allocate memory buffers to hold returned information, for example, LsaLogonUser and LsaCallAuthenticationPackage. Your application should call LsaFreeReturnBuffer to free these buffers when they are no longer needed. .PARAMETER Buffer Pointer to the buffer to be freed. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378279(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $Buffer ) <# (func secur32 LsaFreeReturnBuffer ([UInt32]) @( [IntPtr].MakeByRefType() #_In_ PVOID Buffer )) #> $SUCCESS = $Secur32::LsaFreeReturnBuffer([ref]$Buffer) if($SUCCESS -ne 0) { Write-Host "Buffer: $($Buffer)" $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaFreeReturnBuffer Error: $($LastError.Message)" } } function LsaGetLogonSessionData { <# .SYNOPSIS The LsaGetLogonSessionData function retrieves information about a specified logon session. .DESCRIPTION .Parameter LuidPtr .Parameter SessionCount .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378290(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $LuidPtr, [Parameter(Mandatory = $true)] [UInt32] $SessionCount ) <# (func secur32 LsaGetLogonSessionData ([UInt32]) @( [IntPtr], #_In_ PLUID LogonId, [IntPtr].MakeByRefType() #_Out_ PSECURITY_LOGON_SESSION_DATA *ppLogonSessionData )) #> $CurrentLuidPtr = $LuidPtr for($i = 0; $i -lt $SessionCount; $i++) { $sessionDataPtr = [IntPtr]::Zero $SUCCESS = $Secur32::LsaGetLogonSessionData($CurrentLuidPtr, [ref]$sessionDataPtr) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaGetLogonSessionData Error: $($LastError.Message)" } try { $sessionData = $sessionDataPtr -as $SECURITY_LOGON_SESSION_DATA $props = @{ LogonId = $sessionData.LogonId.LowPart UserName = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.Username.Buffer, $sessionData.Username.Length / 2) LogonDomain = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.LogonDomain.Buffer, $sessionData.LognDomain.Length / 2) AuthenticationPackage = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.AuthenticationPackage.Buffer, $sessionData.AuthenticationPackage.Length / 2) LogonType = $sessionData.LogonType -as $SECURITY_LOGON_TYPE Session = $sessionData.Session Sid = New-Object -TypeName System.Security.Principal.SecurityIdentifier($sessionData.PSiD) LogonTime = [datetime]::FromFileTime($sessionData.LogonTime) LogonServer = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.LogonServer.Buffer, $sessionData.LogonServer.Length / 2) DnsDomainName = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.DnsDomainName.Buffer, $sessionData.DnsDomainName.Length / 2) Upn = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.Upn.Buffer, $sessionData.Upn.Length / 2) UserFlags = $sessionData.UserFlags LastSuccessfulLogon = $sessionData.LastLogonInfo.LastSuccessfulLogon LastFailedLogon = $sessionData.LastLogonInfo.LastFailedLogon FailedAttemptCountSinceLastSuccessfulLogon = $sessionData.LastLogonInfo.FailedAttemptCountSinceLastSuccessfulLogon LogonScript = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.LogonScript.Buffer, $sessionData.LogonScript.Length / 2) ProfilePath = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.ProfilePath.Buffer, $sessionData.ProfilePath.Length / 2) HomeDirectory = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.HomeDirectory.Buffer, $sessionData.HomeDirectory.Length / 2) HomeDirectoryDrive = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.HomeDirectoryDrive.Buffer, $sessionData.HomeDirectoryDrive.Length / 2) LogoffTime = $sessionData.LogoffTime KickOffTime = $sessionData.KickOffTime PasswordLastSet = [datetime]::FromFileTime($sessionData.PasswordLastSet) PasswordCanChange = [datetime]::FromFileTime($sessionData.PasswordCanChange) PasswordMustChange = $sessionData.PasswordMustChange } $obj = New-Object -TypeName psobject -Property $props Write-Output $obj } catch { } #LsaFreeReturnBuffer -Buffer $sessionDataPtr $CurrentLuidPtr = [IntPtr]($CurrentLuidPtr.ToInt64() + $LUID::GetSize()) } } function LsaLookupAuthenticationPackage { <# .SYNOPSIS The LsaLookupAuthenticationPackage function obtains the unique identifier of an authentication package. .DESCRIPTION The authentication package identifier is used in calls to authentication functions such as LsaLogonUser and LsaCallAuthenticationPackage. .PARAMETER LsaHandle Handle obtained from a previous call to LsaRegisterLogonProcess or LsaConnectUntrusted. .PARAMETER PackageName Specifies the name of the authentication package. Supported packages are 'MSV1_0_PACKAGE_NAME', 'MICROSOFT_KERBEROS_NAME_A', 'NEGOSSP_NAME_A', and 'NTLMSP_NAME_A'. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378297(v=vs.85).aspx .EXAMPLE $hLsa = LsaConnectUntrusted LsaLookupAuthenticationPackage -LsaHandle $hLsa -PackageName MICROSOFT_KERBEROS_NAME_A 2 #> param ( [Parameter(Mandatory = $true)] [IntPtr] $LsaHandle, [Parameter(Mandatory = $true)] [ValidateSet('MSV1_0_PACKAGE_NAME', 'MICROSOFT_KERBEROS_NAME_A', 'NEGOSSP_NAME_A', 'NTLMSP_NAME_A')] [string] $PackageName ) <# (func secur32 LsaLookupAuthenticationPackage ([UInt32]) @( [IntPtr], #_In_ HANDLE LsaHandle, $LSA_UNICODE_STRING.MakeByRefType() #_In_ PLSA_STRING PackageName, [UInt64].MakeByRefType() #_Out_ PULONG AuthenticationPackage )) #> switch($PackageName) { MSV1_0_PACKAGE_NAME {$authPackageName = 'NTLM'; break} MICROSOFT_KERBEROS_NAME_A {$authPackageName = 'Kerberos'; break} NEGOSSP_NAME_A {$authPackageName = 'Negotiate'; break} NTLMSP_NAME_A {$authPackageName = 'NTLM'; break} } $authPackageArray = [System.Text.Encoding]::ASCII.GetBytes($authPackageName) [int]$size = $authPackageArray.Length [IntPtr]$pnt = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($size) [System.Runtime.InteropServices.Marshal]::Copy($authPackageArray, 0, $pnt, $authPackageArray.Length) $lsaString = [Activator]::CreateInstance($LSA_STRING) $lsaString.Length = [UInt16]$authPackageArray.Length $lsaString.MaximumLength = [UInt16]$authPackageArray.Length $lsaString.Buffer = $pnt $AuthenticationPackage = [UInt64]0 $SUCCESS = $Secur32::LsaLookupAuthenticationPackage($LsaHandle, [ref]$lsaString, [ref]$AuthenticationPackage) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaLookupAuthenticationPackage Error: $($LastError.Message)" } [System.Runtime.InteropServices.Marshal]::FreeHGlobal($pnt) Write-Output $AuthenticationPackage } function LsaNtStatusToWinError { <# .SYNOPSIS The LsaNtStatusToWinError function converts an NTSTATUS code returned by an LSA function to a Windows error code. .PARAMETER NtStatus An NTSTATUS code returned by an LSA function call. This value will be converted to a System error code. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms721800(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [UInt32] $NtStatus ) <# (func advapi32 LsaNtStatusToWinError ([UInt64]) @( [UInt32] #_In_ NTSTATUS Status ) -EntryPoint LsaNtStatusToWinError), #> $STATUS = $Advapi32::LsaNtStatusToWinError($NtStatus) Write-Output $STATUS } function LsaRegisterLogonProcess { <# .SYNOPSIS The LsaLookupAuthenticationPackage function obtains the unique identifier of an authentication package. .DESCRIPTION The authentication package identifier is used in calls to authentication functions such as LsaLogonUser and LsaCallAuthenticationPackage. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378297(v=vs.85).aspx .EXAMPLE $hLsa = LsaRegisterLogonProcess #> <# (func secur32 LsaRegisterLogonProcess ([UInt32]) @( $LSA_STRING.MakeByRefType() #_In_ PLSA_STRING LogonProcessName, [IntPtr].MakeByRefType() #_Out_ PHANDLE LsaHandle, [UInt64].MakeByRefType() #_Out_ PLSA_OPERATIONAL_MODE SecurityMode )) #> $lsaStringArray = [System.Text.Encoding]::ASCII.GetBytes("INVOKE-IR") [int]$size = $lsaStringArray.Length [IntPtr]$pnt = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($size) [System.Runtime.InteropServices.Marshal]::Copy($lsaStringArray, 0, $pnt, $lsaStringArray.Length) $lsaString = [Activator]::CreateInstance($LSA_STRING) $lsaString.Length = [UInt16]$lsaStringArray.Length $lsaString.MaximumLength = [UInt16]$lsaStringArray.Length $lsaString.Buffer = $pnt $LsaHandle = [IntPtr]::Zero $SecurityMode = [UInt64]0 $SUCCESS = $Secur32::LsaRegisterLogonProcess([ref]$lsaString, [ref]$LsaHandle, [ref]$SecurityMode) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaRegisterLogonProcess Error: $($LastError.Message)" } Write-Output $LsaHandle } function OpenProcessToken { <# .SYNOPSIS The OpenProcessToken function opens the access token associated with a process. .PARAMETER ProcessHandle A handle to the process whose access token is opened. The process must have the PROCESS_QUERY_INFORMATION access permission. .PARAMETER DesiredAccess Specifies an access mask that specifies the requested types of access to the access token. These requested access types are compared with the discretionary access control list (DACL) of the token to determine which accesses are granted or denied. For a list of access rights for access tokens, see Access Rights for Access-Token Objects. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa379295(v=vs.85).aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa374905(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [IntPtr] $ProcessHandle, [Parameter(Mandatory = $true)] [UInt32] $DesiredAccess ) <# (func advapi32 OpenProcessToken ([bool]) @( [IntPtr], #_In_ HANDLE ProcessHandle [UInt32], #_In_ DWORD DesiredAccess [IntPtr].MakeByRefType() #_Out_ PHANDLE TokenHandle ) -SetLastError) #> $hToken = [IntPtr]::Zero $SUCCESS = $Advapi32::OpenProcessToken($ProcessHandle, $DesiredAccess, [ref]$hToken); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $SUCCESS) { Write-Debug "OpenProcessToken Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } Write-Output $hToken } function RevertToSelf { <# .SYNOPSIS The RevertToSelf function terminates the impersonation of a client application. .DESCRIPTION A process should call the RevertToSelf function after finishing any impersonation begun by using the DdeImpersonateClient, ImpersonateDdeClientWindow, ImpersonateLoggedOnUser, ImpersonateNamedPipeClient, ImpersonateSelf, ImpersonateAnonymousToken or SetThreadToken function. An RPC server that used the RpcImpersonateClient function to impersonate a client must call the RpcRevertToSelf or RpcRevertToSelfEx to end the impersonation. If RevertToSelf fails, your application continues to run in the context of the client, which is not appropriate. You should shut down the process if RevertToSelf fails. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa379317(v=vs.85).aspx .EXAMPLE RevertToSelf #> <# (func advapi32 RevertToSelf ([bool]) @() -SetLastError) #> $SUCCESS = $Advapi32::RevertToSelf(); $LastError = [Runtime.InteropServices.Marshal]::GetLastWin32Error() if(-not $SUCCESS) { throw "RevertToSelf Error: $(([ComponentModel.Win32Exception] $LastError).Message)" } } #endregion Win32 function abstractions Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-LogonSession.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-LogonSession)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'LogonSession') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'LogonSession' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) Write-Host $body Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-LogonSession { <# .SYNOPSIS .DESCRIPTION .NOTES Author: Jared Atkinson (@jaredcatkinson) License: Required Dependencies: PSReflect, LsaEnumerateLogonSessions (Function), LsaFreeReturnBuffer (Function), LsaGetLogonSessionData (Function) LsaNtStatusToWinError (Function), SECURITY_LOGON_SESSION_DATA (Structure), LUID (Structure), LSA_UNICODE_STRING (Structure), LSA_LAST_INTER_LOGON_INFO (Structure), SecurityEntity (Enumeration), SECURITY_LOGON_TYPE (Enumeration) Optional Dependencies: None .LINK .EXAMPLE Get-LogonSession FailedAttemptCountSinceLastSuccessfulLogon : 0 DnsDomainName : HUNT.LOCAL KickOffTime : 1/1/1601 1:00:00 AM PasswordCanChange : 5/20/2017 9:51:20 PM Upn : Administrator@HUNT.LOCAL UserName : Administrator Session : 1 LogoffTime : 1/1/1601 1:00:00 AM LastFailedLogon : 1/1/1601 1:00:00 AM LogonServer : DC Sid : S-1-5-21-3250051078-751264820-3215766868-500 LogonScript : UserFlags : 49444 ProfilePath : PasswordMustChange : 6/30/2017 9:51:20 PM LogonId : 325349 LogonTime : 5/20/2017 9:47:34 AM PasswordLastSet : 5/19/2017 9:51:20 PM LogonDomain : HomeDirectory : LogonType : Interactive AuthenticationPackage : Kerberos LastSuccessfulLogon : 1/1/1601 1:00:00 AM HomeDirectoryDrive : #> [CmdletBinding()] param ( ) $LogonSessions = LsaEnumerateLogonSessions $Sessions = LsaGetLogonSessionData -LuidPtr $LogonSessions.SessionListPointer -SessionCount $LogonSessions.SessionCount Write-Output $Sessions } #region PSReflect #Requires -Version 2 function New-InMemoryModule { <# .SYNOPSIS Creates an in-memory assembly and module Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION When defining custom enums, structs, and unmanaged functions, it is necessary to associate to an assembly module. This helper function creates an in-memory module that can be passed to the 'enum', 'struct', and Add-Win32Type functions. .PARAMETER ModuleName Specifies the desired name for the in-memory assembly and module. If ModuleName is not provided, it will default to a GUID. .EXAMPLE $Module = New-InMemoryModule -ModuleName Win32 #> Param ( [Parameter(Position = 0)] [ValidateNotNullOrEmpty()] [String] $ModuleName = [Guid]::NewGuid().ToString() ) $AppDomain = [Reflection.Assembly].Assembly.GetType('System.AppDomain').GetProperty('CurrentDomain').GetValue($null, @()) $LoadedAssemblies = $AppDomain.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 $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, 'Run') $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule($ModuleName, $False) return $ModuleBuilder } # A helper function used to reduce typing while defining function # prototypes for Add-Win32Type. 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, [String] $EntryPoint, [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 } if ($EntryPoint) { $Properties['EntryPoint'] = $EntryPoint } New-Object PSObject -Property $Properties } function Add-Win32Type { <# .SYNOPSIS Creates a .NET type for an unmanaged Win32 function. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: func .DESCRIPTION Add-Win32Type enables you to easily interact with unmanaged (i.e. Win32 unmanaged) functions in PowerShell. After providing Add-Win32Type with a function signature, a .NET type is created using reflection (i.e. csc.exe is never called like with Add-Type). The 'func' helper function can be used to reduce typing when defining multiple function definitions. .PARAMETER DllName The name of the DLL. .PARAMETER FunctionName The name of the target function. .PARAMETER EntryPoint The DLL export function name. This argument should be specified if the specified function name is different than the name of the exported function. .PARAMETER ReturnType The return type of the function. .PARAMETER ParameterTypes The function parameters. .PARAMETER NativeCallingConvention Specifies the native calling convention of the function. Defaults to stdcall. .PARAMETER Charset If you need to explicitly call an 'A' or 'W' Win32 function, you can specify the character set. .PARAMETER SetLastError Indicates whether the callee calls the SetLastError Win32 API function before returning from the attributed method. .PARAMETER Module The in-memory module that will host the functions. Use New-InMemoryModule to define an in-memory module. .PARAMETER Namespace An optional namespace to prepend to the type. Add-Win32Type defaults to a namespace consisting only of the name of the DLL. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $FunctionDefinitions = @( (func kernel32 GetProcAddress ([IntPtr]) @([IntPtr], [String]) -Charset Ansi -SetLastError), (func kernel32 GetModuleHandle ([Intptr]) @([String]) -SetLastError), (func ntdll RtlGetCurrentPeb ([IntPtr]) @()) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32' $Kernel32 = $Types['kernel32'] $Ntdll = $Types['ntdll'] $Ntdll::RtlGetCurrentPeb() $ntdllbase = $Kernel32::GetModuleHandle('ntdll') $Kernel32::GetProcAddress($ntdllbase, 'RtlGetCurrentPeb') .NOTES Inspired by Lee Holmes' Invoke-WindowsApi http://poshcode.org/2189 When defining multiple function prototypes, it is ideal to provide Add-Win32Type with an array of function signatures. That way, they are all incorporated into the same in-memory module. #> [OutputType([Hashtable])] Param( [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $DllName, [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $FunctionName, [Parameter(ValueFromPipelineByPropertyName = $True)] [String] $EntryPoint, [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') $EntryPointField = $DllImport.GetField('EntryPoint') if ($SetLastError) { $SLEValue = $True } else { $SLEValue = $False } if ($PSBoundParameters['EntryPoint']) { $ExportedFuncName = $EntryPoint } else { $ExportedFuncName = $FunctionName } # 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, $EntryPointField), [Object[]] @($SLEValue, ([Runtime.InteropServices.CallingConvention] $NativeCallingConvention), ([Runtime.InteropServices.CharSet] $Charset), $ExportedFuncName)) $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 psenum { <# .SYNOPSIS Creates an in-memory enumeration for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION The 'psenum' function facilitates the creation of enums entirely in memory using as close to a "C style" as PowerShell will allow. .PARAMETER Module The in-memory module that will host the enum. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the enum. .PARAMETER Type The type of each enum element. .PARAMETER EnumElements A hashtable of enum elements. .PARAMETER Bitfield Specifies that the enum should be treated as a bitfield. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageSubsystem = psenum $Mod PE.IMAGE_SUBSYSTEM UInt16 @{ UNKNOWN = 0 NATIVE = 1 # Image doesn't require a subsystem. WINDOWS_GUI = 2 # Image runs in the Windows GUI subsystem. WINDOWS_CUI = 3 # Image runs in the Windows character subsystem. OS2_CUI = 5 # Image runs in the OS/2 character subsystem. POSIX_CUI = 7 # Image runs in the Posix character subsystem. NATIVE_WINDOWS = 8 # Image is a native Win9x driver. WINDOWS_CE_GUI = 9 # Image runs in the Windows CE subsystem. EFI_APPLICATION = 10 EFI_BOOT_SERVICE_DRIVER = 11 EFI_RUNTIME_DRIVER = 12 EFI_ROM = 13 XBOX = 14 WINDOWS_BOOT_APPLICATION = 16 } .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Enum. :P #> [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]) { return ($Module.GetType($FullName)) } $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 { <# .SYNOPSIS Creates an in-memory struct for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: field .DESCRIPTION The 'struct' function facilitates the creation of structs entirely in memory using as close to a "C style" as PowerShell will allow. Struct fields are specified using a hashtable where each field of the struct is comprosed of the order in which it should be defined, its .NET type, and optionally, its offset and special marshaling attributes. One of the features of 'struct' is that after your struct is defined, it will come with a built-in GetSize method as well as an explicit converter so that you can easily cast an IntPtr to the struct without relying upon calling SizeOf and/or PtrToStructure in the Marshal class. .PARAMETER Module The in-memory module that will host the struct. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the struct. .PARAMETER StructFields A hashtable of fields. Use the 'field' helper function to ease defining each field. .PARAMETER PackingSize Specifies the memory alignment of fields. .PARAMETER ExplicitLayout Indicates that an explicit offset for each field will be specified. .PARAMETER CharSet Dictates which character set marshaled strings should use. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageDosSignature = psenum $Mod PE.IMAGE_DOS_SIGNATURE UInt16 @{ DOS_SIGNATURE = 0x5A4D OS2_SIGNATURE = 0x454E OS2_SIGNATURE_LE = 0x454C VXD_SIGNATURE = 0x454C } $ImageDosHeader = struct $Mod PE.IMAGE_DOS_HEADER @{ e_magic = field 0 $ImageDosSignature e_cblp = field 1 UInt16 e_cp = field 2 UInt16 e_crlc = field 3 UInt16 e_cparhdr = field 4 UInt16 e_minalloc = field 5 UInt16 e_maxalloc = field 6 UInt16 e_ss = field 7 UInt16 e_sp = field 8 UInt16 e_csum = field 9 UInt16 e_ip = field 10 UInt16 e_cs = field 11 UInt16 e_lfarlc = field 12 UInt16 e_ovno = field 13 UInt16 e_res = field 14 UInt16[] -MarshalAs @('ByValArray', 4) e_oemid = field 15 UInt16 e_oeminfo = field 16 UInt16 e_res2 = field 17 UInt16[] -MarshalAs @('ByValArray', 10) e_lfanew = field 18 Int32 } # Example of using an explicit layout in order to create a union. $TestUnion = struct $Mod TestUnion @{ field1 = field 0 UInt32 0 field2 = field 1 IntPtr 0 } -ExplicitLayout .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Struct. :P #> [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, [System.Runtime.InteropServices.CharSet] $CharSet = [System.Runtime.InteropServices.CharSet]::Ansi ) if ($Module -is [Reflection.Assembly]) { return ($Module.GetType($FullName)) } [Reflection.TypeAttributes] $StructAttributes = 'Class, Public, Sealed, BeforeFieldInit' if ($ExplicitLayout) { $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::ExplicitLayout } else { $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::SequentialLayout } switch($CharSet) { Ansi { $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::AnsiClass } Auto { $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::AutoClass } Unicode { $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::UnicodeClass } } $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() } #endregion PSReflect $Module = New-InMemoryModule -ModuleName GetLogonSession #region Enums $SECURITY_LOGON_TYPE = psenum $Module SECURITY_LOGON_TYPE UInt32 @{ Interactive = 2 Network = 3 Batch = 4 Service = 5 Proxy = 6 Unlock = 7 NetworkCleartext = 8 NewCredentials = 9 RemoteInteractive = 10 CachedInteractive = 11 CachedRemoteInteractive = 12 CachedUnlock = 13 } $SecurityEntity = psenum $Module SecurityEntity UInt32 @{ SeCreateTokenPrivilege = 1 SeAssignPrimaryTokenPrivilege = 2 SeLockMemoryPrivilege = 3 SeIncreaseQuotaPrivilege = 4 SeUnsolicitedInputPrivilege = 5 SeMachineAccountPrivilege = 6 SeTcbPrivilege = 7 SeSecurityPrivilege = 8 SeTakeOwnershipPrivilege = 9 SeLoadDriverPrivilege = 10 SeSystemProfilePrivilege = 11 SeSystemtimePrivilege = 12 SeProfileSingleProcessPrivilege = 13 SeIncreaseBasePriorityPrivilege = 14 SeCreatePagefilePrivilege = 15 SeCreatePermanentPrivilege = 16 SeBackupPrivilege = 17 SeRestorePrivilege = 18 SeShutdownPrivilege = 19 SeDebugPrivilege = 20 SeAuditPrivilege = 21 SeSystemEnvironmentPrivilege = 22 SeChangeNotifyPrivilege = 23 SeRemoteShutdownPrivilege = 24 SeUndockPrivilege = 25 SeSyncAgentPrivilege = 26 SeEnableDelegationPrivilege = 27 SeManageVolumePrivilege = 28 SeImpersonatePrivilege = 29 SeCreateGlobalPrivilege = 30 SeTrustedCredManAccessPrivilege = 31 SeRelabelPrivilege = 32 SeIncreaseWorkingSetPrivilege = 33 SeTimeZonePrivilege = 34 SeCreateSymbolicLinkPrivilege = 35 } #endregion Enums #region Structures $LSA_LAST_INTER_LOGON_INFO = struct $Module LSA_LAST_INTER_LOGON_INFO @{ LastSuccessfulLogon = field 0 Int64 LastFailedLogon = field 1 Int64 FailedAttemptCountSinceLastSuccessfulLogon = field 2 UInt64 } $LUID = struct $Module LUID @{ LowPart = field 0 $SecurityEntity HighPart = field 1 Int32 } $LSA_UNICODE_STRING = struct $Module LSA_UNICODE_STRING @{ Length = field 0 UInt16 MaximumLength = field 1 UInt16 Buffer = field 2 IntPtr } $SECURITY_LOGON_SESSION_DATA = struct $Module SECURITY_LOGON_SESSION_DATA @{ Size = field 0 UInt32 LogonId = field 1 $LUID Username = field 2 $LSA_UNICODE_STRING LogonDomain = field 3 $LSA_UNICODE_STRING AuthenticationPackage = field 4 $LSA_UNICODE_STRING LogonType = field 5 UInt32 Session = field 6 UInt32 PSiD = field 7 IntPtr LogonTime = field 8 UInt64 LogonServer = field 9 $LSA_UNICODE_STRING DnsDomainName = field 10 $LSA_UNICODE_STRING Upn = field 11 $LSA_UNICODE_STRING UserFlags = field 12 UInt64 LastLogonInfo = field 13 $LSA_LAST_INTER_LOGON_INFO LogonScript = field 14 $LSA_UNICODE_STRING ProfilePath = field 15 $LSA_UNICODE_STRING HomeDirectory = field 16 $LSA_UNICODE_STRING HomeDirectoryDrive = field 17 $LSA_UNICODE_STRING LogoffTime = field 18 Int64 KickOffTime = field 19 Int64 PasswordLastSet = field 20 Int64 PasswordCanChange = field 21 Int64 PasswordMustChange = field 22 Int64 } #endregion Structures #region FunctionDefinitions $FunctionDefinitions = @( (func secur32 LsaEnumerateLogonSessions ([UInt32]) @( [UInt64].MakeByRefType(), #_Out_ PULONG LogonSessionCount, [IntPtr].MakeByRefType() #_Out_ PLUID *LogonSessionList ) -EntryPoint LsaEnumerateLogonSessions), (func secur32 LsaFreeReturnBuffer ([UInt32]) @( [IntPtr] #_In_ PVOID Buffer ) -EntryPoint LsaFreeReturnBuffer), (func secur32 LsaGetLogonSessionData ([UInt32]) @( [IntPtr], #_In_ PLUID LogonId, [IntPtr].MakeByRefType() #_Out_ PSECURITY_LOGON_SESSION_DATA *ppLogonSessionData ) -EntryPoint LsaGetLogonSessionData), (func advapi32 LsaNtStatusToWinError ([UInt64]) @( [UInt32] #_In_ NTSTATUS Status ) -EntryPoint LsaNtStatusToWinError) ) #endregion FunctionDefinitions #region Windows API Functions function LsaEnumerateLogonSessions { <# .SYNOPSIS The LsaEnumerateLogonSessions function retrieves the set of existing logon session identifiers (LUIDs) and the number of sessions. .DESCRIPTION To retrieve information about the logon sessions returned by LsaEnumerateLogonSessions, call the LsaGetLogonSessionData function. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, LsaNtStatusToWinError (Function) Optional Dependencies: None (func secur32 LsaEnumerateLogonSessions ([UInt32]) @( [UInt64].MakeByRefType(), #_Out_ PULONG LogonSessionCount, [IntPtr].MakeByRefType() #_Out_ PLUID *LogonSessionList ) -EntryPoint LsaEnumerateLogonSessions) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378275(v=vs.85).aspx .EXAMPLE LsaEnumerateLogonSessions 8 2390553591808 .EXAMPLE $SessionCount, $LogonSessionListPtr = LsaEnumerateLogonSessions #> $LogonSessionCount = [UInt64]0 $LogonSessionList = [IntPtr]::Zero $SUCCESS = $Secur32::LsaEnumerateLogonSessions([ref]$LogonSessionCount, [ref]$LogonSessionList) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaEnumerateLogonSessions Error: $($LastError.Message)" } $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name SessionCount -Value $LogonSessionCount $obj | Add-Member -MemberType NoteProperty -Name SessionListPointer -Value $LogonSessionList Write-Output $obj } function LsaFreeReturnBuffer { <# .SYNOPSIS The LsaFreeReturnBuffer function frees the memory used by a buffer previously allocated by the LSA. .DESCRIPTION Some of the LSA authentication functions allocate memory buffers to hold returned information, for example, LsaLogonUser and LsaCallAuthenticationPackage. Your application should call LsaFreeReturnBuffer to free these buffers when they are no longer needed. .PARAMETER Buffer Pointer to the buffer to be freed. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, LsaNtStatusToWinError (Function) Optional Dependencies: None (func secur32 LsaFreeReturnBuffer ([UInt32]) @( [IntPtr] #_In_ PVOID Buffer ) -EntryPoint LsaFreeReturnBuffer) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378279(v=vs.85).aspx .EXAMPLE LsaFreeReturnBuffer -Buffer $Buffer #> param ( [Parameter(Mandatory = $true)] [IntPtr] $Buffer ) $SUCCESS = $Secur32::LsaFreeReturnBuffer($Buffer) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaFreeReturnBuffer Error: $($LastError.Message)" } } function LsaGetLogonSessionData { <# .SYNOPSIS The LsaGetLogonSessionData function retrieves information about a specified logon session. .DESCRIPTION .Parameter LuidPtr .Parameter SessionCount .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect, LsaFreeReturnBuffer (Function), LsaNtStatusToWinError (Function), SECURITY_LOGON_SESSION_DATA (Structure), LUID (Structure), LSA_UNICODE_STRING (Structure), LSA_LAST_INTER_LOGON_INFO (Structure), SecurityEntity (Enumeration), SECURITY_LOGON_TYPE (Enumeration) Optional Dependencies: None (func secur32 LsaGetLogonSessionData ([UInt32]) @( [IntPtr], #_In_ PLUID LogonId, [IntPtr].MakeByRefType() #_Out_ PSECURITY_LOGON_SESSION_DATA *ppLogonSessionData ) -EntryPoint LsaGetLogonSessionData) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa378290(v=vs.85).aspx .EXAMPLE $SessionCount, $LogonSessionListPtr = LsaEnumerateLogonSessions LsaGetLogonSessionData -LuidPtr $LogonSessionListPtr -SessionCount $SessionCount #> param ( [Parameter(Mandatory = $true)] [IntPtr] $LuidPtr, [Parameter(Mandatory = $true)] [UInt32] $SessionCount ) $CurrentLuidPtr = $LuidPtr for($i = 0; $i -lt $SessionCount; $i++) { $sessionDataPtr = [IntPtr]::Zero $SUCCESS = $Secur32::LsaGetLogonSessionData($CurrentLuidPtr, [ref]$sessionDataPtr) if($SUCCESS -ne 0) { $WinErrorCode = LsaNtStatusToWinError -NtStatus $success $LastError = [ComponentModel.Win32Exception]$WinErrorCode throw "LsaGetLogonSessionData Error: $($LastError.Message)" } try { $sessionData = $sessionDataPtr -as $SECURITY_LOGON_SESSION_DATA $props = @{ LogonId = $sessionData.LogonId.LowPart UserName = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.Username.Buffer, $sessionData.Username.Length / 2) LogonDomain = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.LogonDomain.Buffer, $sessionData.LognDomain.Length / 2) AuthenticationPackage = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.AuthenticationPackage.Buffer, $sessionData.AuthenticationPackage.Length / 2) LogonType = ($sessionData.LogonType -as $SECURITY_LOGON_TYPE).ToString() Session = $sessionData.Session Sid = (New-Object -TypeName System.Security.Principal.SecurityIdentifier($sessionData.PSiD)).ToString() LogonTime = [datetime]::FromFileTime($sessionData.LogonTime) LogonServer = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.LogonServer.Buffer, $sessionData.LogonServer.Length / 2) DnsDomainName = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.DnsDomainName.Buffer, $sessionData.DnsDomainName.Length / 2) Upn = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.Upn.Buffer, $sessionData.Upn.Length / 2) UserFlags = $sessionData.UserFlags LastSuccessfulLogon = $sessionData.LastLogonInfo.LastSuccessfulLogon LastFailedLogon = $sessionData.LastLogonInfo.LastFailedLogon FailedAttemptCountSinceLastSuccessfulLogon = $sessionData.LastLogonInfo.FailedAttemptCountSinceLastSuccessfulLogon LogonScript = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.LogonScript.Buffer, $sessionData.LogonScript.Length / 2) ProfilePath = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.ProfilePath.Buffer, $sessionData.ProfilePath.Length / 2) HomeDirectory = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.HomeDirectory.Buffer, $sessionData.HomeDirectory.Length / 2) HomeDirectoryDrive = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($sessionData.HomeDirectoryDrive.Buffer, $sessionData.HomeDirectoryDrive.Length / 2) LogoffTime = $sessionData.LogoffTime KickOffTime = $sessionData.KickOffTime PasswordLastSet = [datetime]::FromFileTime($sessionData.PasswordLastSet) PasswordCanChange = [datetime]::FromFileTime($sessionData.PasswordCanChange) PasswordMustChange = $sessionData.PasswordMustChange } Write-Output $props #$obj = New-Object -TypeName psobject -Property $props #Write-Output $obj } catch { } LsaFreeReturnBuffer -Buffer $sessionDataPtr $CurrentLuidPtr = [IntPtr]($CurrentLuidPtr.ToInt64() + $LUID::GetSize()) } } function LsaNtStatusToWinError { <# .SYNOPSIS The LsaNtStatusToWinError function converts an NTSTATUS code returned by an LSA function to a Windows error code. .PARAMETER NtStatus An NTSTATUS code returned by an LSA function call. This value will be converted to a System error code. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: PSReflect Optional Dependencies: None (func advapi32 LsaNtStatusToWinError ([UInt64]) @( [UInt32] #_In_ NTSTATUS Status ) -EntryPoint LsaNtStatusToWinError) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/ms721800(v=vs.85).aspx .EXAMPLE #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [UInt32] $NtStatus ) $STATUS = $Advapi32::LsaNtStatusToWinError($NtStatus) Write-Output $STATUS } #endregion Windows API Functions $Types = $FunctionDefinitions | Add-Win32Type -Module $Module -Namespace 'GetLogonSession' $Advapi32 = $Types['advapi32'] $Secur32 = $Types['secur32'] Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-MasterBootRecord.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-MasterBootRecord -ReturnHashtables)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'MasterBootRecord') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'MasterBootRecord' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) Write-Host $body Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-MasterBootRecord { <# .SYNOPSIS Returns detailed information about the master boot record Author: Jared Atkinson License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None #> [CmdletBinding()] Param ( [Parameter()] [String[]] $Path, [switch] $ReturnHashtables ) begin { function Get-FileHandle { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $Path ) #region Constants $GENERIC_READWRITE = 0x80000000 $FILE_SHARE_READWRITE = 0x02 -bor 0x01 $OPEN_EXISTING = 0x03 #endregion #region Reflection $DynAssembly = New-Object System.Reflection.AssemblyName('Win32') $AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run) $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('Win32', $False) $TypeBuilder = $ModuleBuilder.DefineType('Win32.Kernel32', 'Public, Class') $DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String])) $SetLastError = [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError') $SetLastErrorCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($DllImportConstructor, @('kernel32.dll'), [Reflection.FieldInfo[]]@($SetLastError), @($True)) # Define [Win32.Kernel32]::CreateFile $PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('CreateFile', 'kernel32.dll', ([Reflection.MethodAttributes]::Public -bor [Reflection.MethodAttributes]::Static), [Reflection.CallingConventions]::Standard, [Microsoft.Win32.SafeHandles.SafeFileHandle], [Type[]]@([String], [Int32], [UInt32], [IntPtr], [UInt32], [UInt32], [IntPtr]), [Runtime.InteropServices.CallingConvention]::Winapi, [Runtime.InteropServices.CharSet]::Ansi) $PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute) $Kernel32 = $TypeBuilder.CreateType() #endregion # Get handle to $FileToServe $DriveHandle = $Kernel32::CreateFile($Path, $GENERIC_READWRITE, $FILE_SHARE_READWRITE, 0, $OPEN_EXISTING, 0, 0) # Check that handle is valid if ($DriveHandle.IsInvalid) { Write-Error "Invalid handle to $($Path) returned from CreateFile" -ErrorAction Stop } else { $DriveHandle } } function Read-MbrBytes { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [Microsoft.Win32.SafeHandles.SafeFileHandle] $Handle ) try { # Create a FileStream to read from the handle $streamToRead = New-Object -TypeName System.IO.FileStream($Handle, [System.IO.FileAccess]::Read) # Set our position in the stream to $Offset $streamToRead.Position = 0x0 # Create a buffer $Length bytes long $buffer = New-Object -TypeName Byte[](0x200) # Read $Length bytes $return = $streamToRead.Read($buffer, 0x0, 0x200) # Check return value if($return -ne 0x200) { $return } $buffer } catch { Write-Error "Unable to read bytes from Drive" -ErrorAction Stop } finally { $streamToRead.Dispose() } } function Get-MD5Hash { param ( [Parameter(Mandatory = $true)] [byte[]] $Bytes ) begin { $sha1 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider $hashbytes = $sha1.ComputeHash($Bytes) $sb = New-Object -TypeName System.Text.StringBuilder } process { foreach($b in $hashbytes) { $null = $sb.Append("{0:x}" -f $b) } $sb.ToString() } end { if($sha1.Dispose) { $sha1.Dispose() } } } function Get-Partition { param ( [Parameter(Mandatory = $true)] [byte[]] $Bytes, [Parameter(Mandatory = $true)] [int] $Offset, [switch] $ReturnHashtables ) # Status (0x00 - Non-Bootable & 0x80 - Bootable) if($Bytes[0x00 + $Offset] -eq 0x80) { $Bootable = $true } else { $Bootable = $false } $props = @{ Bootable = $Bootable PartitionType = $Bytes[0x04 + $Offset] RelativeStartSector = [System.BitConverter]::ToUInt32($Bytes, 0x08 + $Offset) TotalSectors = [System.BitConverter]::ToUInt32($Bytes, 0x0C + $Offset) } if($ReturnHashtables) { $props } else { New-Object -TypeName psobject -Property $props } } } process { if(-not($PSBoundParameters.ContainsKey('Path'))) { $Disks = Get-WmiObject -Query "SELECT * FROM Win32_DiskDrive" } else { } $OS = (Get-WmiObject win32_Operatingsystem).Caption foreach($disk in $Disks) { $hDrive = Get-FileHandle -Path $disk.DeviceId if($hDrive) { $bytes = Read-MbrBytes -Handle $hDrive $CodeSection = $bytes[0x3E..0x1B7] $listPartitions = New-Object -TypeName System.Collections.Generic.List[HashTable] for($i = 0; $i -lt 4; $i++) { if($ReturnHashtables) { $partition = Get-Partition -Bytes $bytes -Offset (0x1BE + (0x10 * $i)) -ReturnHashtables } else { $partition = Get-Partition -Bytes $bytes -Offset (0x1BE + (0x10 * $i)) } if($partition.TotalSectors -ne 0) { $listPartitions.Add($partition) } } $Props = @{ OperatingSystem = $OS DeviceId = $disk.DeviceId Model = $disk.Model Signature = Get-MD5Hash -Bytes $CodeSection CodeSection = $CodeSection DiskSignature = [System.BitConverter]::ToString($bytes[0x1B8..0x1BB]).Replace("-", "") PartitionTable = $listPartitions.ToArray() } if($ReturnHashtables) { $Props } else { New-Object -TypeName psobject -Property $Props } } } } } Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-NetworkConnection.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-NetworkConnection -ReturnHashtables)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'NetworkConnection') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'NetworkConnection' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) Write-Output $body Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-NetworkConnection { <# .SYNOPSIS Returns current TCP and UDP connections. .NOTES Author: Lee Christensen (@tifkin_) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None #> [CmdletBinding()] param ( [switch] $ResolveHostnames, [switch] $ReturnHashtables ) $Tcp4Connections = Get-Tcp4Connections @PSBoundParameters $Tcp6Connections = Get-Tcp6Connections @PSBoundParameters $Udp4Connections = Get-Udp4Connections @PSBoundParameters $Udp6Connections = Get-Udp6Connections @PSBoundParameters $Tcp4Connections $Tcp6Connections $Udp4Connections $Udp6Connections } #region PSReflect function New-InMemoryModule { <# .SYNOPSIS Creates an in-memory assembly and module Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION When defining custom enums, structs, and unmanaged functions, it is necessary to associate to an assembly module. This helper function creates an in-memory module that can be passed to the 'enum', 'struct', and Add-Win32Type functions. .PARAMETER ModuleName Specifies the desired name for the in-memory assembly and module. If ModuleName is not provided, it will default to a GUID. .EXAMPLE $Module = New-InMemoryModule -ModuleName Win32 #> 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 } # A helper function used to reduce typing while defining function # prototypes for Add-Win32Type. 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, [String] $EntryPoint, [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 } if ($EntryPoint) { $Properties['EntryPoint'] = $EntryPoint } New-Object PSObject -Property $Properties } function Add-Win32Type { <# .SYNOPSIS Creates a .NET type for an unmanaged Win32 function. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: func .DESCRIPTION Add-Win32Type enables you to easily interact with unmanaged (i.e. Win32 unmanaged) functions in PowerShell. After providing Add-Win32Type with a function signature, a .NET type is created using reflection (i.e. csc.exe is never called like with Add-Type). The 'func' helper function can be used to reduce typing when defining multiple function definitions. .PARAMETER DllName The name of the DLL. .PARAMETER FunctionName The name of the target function. .PARAMETER EntryPoint The DLL export function name. This argument should be specified if the specified function name is different than the name of the exported function. .PARAMETER ReturnType The return type of the function. .PARAMETER ParameterTypes The function parameters. .PARAMETER NativeCallingConvention Specifies the native calling convention of the function. Defaults to stdcall. .PARAMETER Charset If you need to explicitly call an 'A' or 'W' Win32 function, you can specify the character set. .PARAMETER SetLastError Indicates whether the callee calls the SetLastError Win32 API function before returning from the attributed method. .PARAMETER Module The in-memory module that will host the functions. Use New-InMemoryModule to define an in-memory module. .PARAMETER Namespace An optional namespace to prepend to the type. Add-Win32Type defaults to a namespace consisting only of the name of the DLL. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $FunctionDefinitions = @( (func kernel32 GetProcAddress ([IntPtr]) @([IntPtr], [String]) -Charset Ansi -SetLastError), (func kernel32 GetModuleHandle ([Intptr]) @([String]) -SetLastError), (func ntdll RtlGetCurrentPeb ([IntPtr]) @()) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32' $Kernel32 = $Types['kernel32'] $Ntdll = $Types['ntdll'] $Ntdll::RtlGetCurrentPeb() $ntdllbase = $Kernel32::GetModuleHandle('ntdll') $Kernel32::GetProcAddress($ntdllbase, 'RtlGetCurrentPeb') .NOTES Inspired by Lee Holmes' Invoke-WindowsApi http://poshcode.org/2189 When defining multiple function prototypes, it is ideal to provide Add-Win32Type with an array of function signatures. That way, they are all incorporated into the same in-memory module. #> [OutputType([Hashtable])] Param( [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $DllName, [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $FunctionName, [Parameter(ValueFromPipelineByPropertyName = $True)] [String] $EntryPoint, [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') $EntryPointField = $DllImport.GetField('EntryPoint') if ($SetLastError) { $SLEValue = $True } else { $SLEValue = $False } if ($PSBoundParameters['EntryPoint']) { $ExportedFuncName = $EntryPoint } else { $ExportedFuncName = $FunctionName } # 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, $EntryPointField), [Object[]] @($SLEValue, ([Runtime.InteropServices.CallingConvention] $NativeCallingConvention), ([Runtime.InteropServices.CharSet] $Charset), $ExportedFuncName)) $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 psenum { <# .SYNOPSIS Creates an in-memory enumeration for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION The 'psenum' function facilitates the creation of enums entirely in memory using as close to a "C style" as PowerShell will allow. .PARAMETER Module The in-memory module that will host the enum. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the enum. .PARAMETER Type The type of each enum element. .PARAMETER EnumElements A hashtable of enum elements. .PARAMETER Bitfield Specifies that the enum should be treated as a bitfield. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageSubsystem = psenum $Mod PE.IMAGE_SUBSYSTEM UInt16 @{ UNKNOWN = 0 NATIVE = 1 # Image doesn't require a subsystem. WINDOWS_GUI = 2 # Image runs in the Windows GUI subsystem. WINDOWS_CUI = 3 # Image runs in the Windows character subsystem. OS2_CUI = 5 # Image runs in the OS/2 character subsystem. POSIX_CUI = 7 # Image runs in the Posix character subsystem. NATIVE_WINDOWS = 8 # Image is a native Win9x driver. WINDOWS_CE_GUI = 9 # Image runs in the Windows CE subsystem. EFI_APPLICATION = 10 EFI_BOOT_SERVICE_DRIVER = 11 EFI_RUNTIME_DRIVER = 12 EFI_ROM = 13 XBOX = 14 WINDOWS_BOOT_APPLICATION = 16 } .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Enum. :P #> [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]) { return ($Module.GetType($FullName)) } $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 { <# .SYNOPSIS Creates an in-memory struct for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: field .DESCRIPTION The 'struct' function facilitates the creation of structs entirely in memory using as close to a "C style" as PowerShell will allow. Struct fields are specified using a hashtable where each field of the struct is comprosed of the order in which it should be defined, its .NET type, and optionally, its offset and special marshaling attributes. One of the features of 'struct' is that after your struct is defined, it will come with a built-in GetSize method as well as an explicit converter so that you can easily cast an IntPtr to the struct without relying upon calling SizeOf and/or PtrToStructure in the Marshal class. .PARAMETER Module The in-memory module that will host the struct. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the struct. .PARAMETER StructFields A hashtable of fields. Use the 'field' helper function to ease defining each field. .PARAMETER PackingSize Specifies the memory alignment of fields. .PARAMETER ExplicitLayout Indicates that an explicit offset for each field will be specified. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageDosSignature = psenum $Mod PE.IMAGE_DOS_SIGNATURE UInt16 @{ DOS_SIGNATURE = 0x5A4D OS2_SIGNATURE = 0x454E OS2_SIGNATURE_LE = 0x454C VXD_SIGNATURE = 0x454C } $ImageDosHeader = struct $Mod PE.IMAGE_DOS_HEADER @{ e_magic = field 0 $ImageDosSignature e_cblp = field 1 UInt16 e_cp = field 2 UInt16 e_crlc = field 3 UInt16 e_cparhdr = field 4 UInt16 e_minalloc = field 5 UInt16 e_maxalloc = field 6 UInt16 e_ss = field 7 UInt16 e_sp = field 8 UInt16 e_csum = field 9 UInt16 e_ip = field 10 UInt16 e_cs = field 11 UInt16 e_lfarlc = field 12 UInt16 e_ovno = field 13 UInt16 e_res = field 14 UInt16[] -MarshalAs @('ByValArray', 4) e_oemid = field 15 UInt16 e_oeminfo = field 16 UInt16 e_res2 = field 17 UInt16[] -MarshalAs @('ByValArray', 10) e_lfanew = field 18 Int32 } # Example of using an explicit layout in order to create a union. $TestUnion = struct $Mod TestUnion @{ field1 = field 0 UInt32 0 field2 = field 1 IntPtr 0 } -ExplicitLayout .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Struct. :P #> [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() } #endregion PSReflect #region Windows API Definitions $Mod = New-InMemoryModule -ModuleName NetworkConnection #region Enums $TCP_TABLE_CLASS = psenum $Mod TCP_TABLE_CLASS UInt16 @{ TCP_TABLE_BASIC_LISTENER = 0 TCP_TABLE_BASIC_CONNECTIONS = 1 TCP_TABLE_BASIC_ALL = 2 TCP_TABLE_OWNER_PID_LISTENER = 3 TCP_TABLE_OWNER_PID_CONNECTIONS = 4 TCP_TABLE_OWNER_PID_ALL = 5 TCP_TABLE_OWNER_MODULE_LISTENER = 6 TCP_TABLE_OWNER_MODULE_CONNECTIONS = 7 TCP_TABLE_OWNER_MODULE_ALL = 8 } $TCP_STATE = psenum $Mod TCP_STATE UInt16 @{ CLOSED = 1 LISTENING = 2 SYN_SENT = 3 SYN_RECEIVED = 4 ESTABLISHED = 5 FIN_WAIT1 = 6 FIN_WAIT2 = 7 CLOSE_WAIT = 8 CLOSING = 9 LAST_ACK = 10 TIME_WAIT = 11 DELETE_TCB = 12 } $UDP_TABLE_CLASS = psenum $Mod UDP_TABLE_CLASS UInt16 @{ UDP_TABLE_BASIC = 0 UDP_TABLE_OWNER_PID = 1 UDP_TABLE_OWNER_MODULE = 2 } $TAG_INFO_LEVEL = psenum $Mod TAG_INFO_LEVEL UInt16 @{ eTagInfoLevelNameFromTag = 1 eTagInfoLevelNamesReferencingModule = 2 eTagInfoLevelNameTagMapping = 3 eTagInfoLevelMax = 4 } $SC_SERVICE_TAG_QUERY_TYPE = psenum $Mod SC_SERVICE_TAG_QUERY_TYPE UInt16 @{ ServiceNameFromTagInformation = 1 ServiceNamesReferencingModuleInformation = 2 ServiceNameTagMappingInformation = 3 } #endregion Enums #region Structs $MIB_UDPROW_OWNER_MODULE = struct $Mod MIB_UDPROW_OWNER_MODULE @{ LocalAddr = field 0 UInt32 0 LocalPort = field 1 UInt32 4 OwningPid = field 2 UInt32 8 CreateTimestamp = field 3 UInt64 16 SpecificPortBind = field 4 UInt32 24 # Union Flags = field 5 UInt32 24 OwningModuleInfo = field 6 UInt64[] -MarshalAs @('ByValArray', 16) 32 } -ExplicitLayout $MIB_UDP6ROW_OWNER_MODULE = struct $Mod MIB_UDP6ROW_OWNER_MODULE @{ LocalAddr = field 0 Byte[] -MarshalAs @('ByValArray', 16) 0 LocalScopeId = field 1 UInt32 16 LocalPort = field 2 UInt32 20 OwningPid = field 3 UInt32 24 CreateTimestamp = field 4 UInt64 32 SpecificPortBind = field 5 UInt32 40 # Union Flags = field 6 UInt32 40 OwningModuleInfo = field 7 UInt64[] -MarshalAs @('ByValArray', 16) 48 } -ExplicitLayout $MIB_UDPTABLE_OWNER_MODULE = struct $Mod MIB_UDPTABLE_OWNER_MODULE @{ NumEntries = field 0 UInt32 Table = field 1 $MIB_UDPROW_OWNER_MODULE } $MIB_UDP6TABLE_OWNER_MODULE = struct $Mod MIB_UDP6TABLE_OWNER_MODULE @{ NumEntries = field 0 UInt32 Table = field 1 $MIB_UDPROW_OWNER_MODULE } $MIB_TCPROW_OWNER_MODULE = struct $Mod MIB_TCPROW_OWNER_MODULE @{ State = field 0 $TCP_STATE LocalAddr = field 1 UInt32 LocalPort = field 2 UInt32 RemoteAddr = field 3 UInt32 RemotePort = field 4 UInt32 OwningPid = field 5 UInt32 CreateTimestamp = field 6 UInt64 OwningModuleInfo = field 7 UInt64[] -MarshalAs @('ByValArray', 16) } $MIB_TCP6ROW_OWNER_MODULE = struct $Mod MIB_TCP6ROW_OWNER_MODULE @{ LocalAddr = field 0 Byte[] -MarshalAs @('ByValArray', 16) LocalScopeId = field 1 UInt32 LocalPort = field 2 UInt32 RemoteAddr = field 3 Byte[] -MarshalAs @('ByValArray', 16) RemoteScopeId = field 4 UInt32 RemotePort = field 5 UInt32 State = field 6 $TCP_STATE OwningPid = field 7 UInt32 CreateTimestamp = field 8 UInt64 OwningModuleInfo = field 9 UInt64[] -MarshalAs @('ByValArray', 16) } $MIB_TCPTABLE_OWNER_MODULE = struct $Mod MIB_TCPTABLE_OWNER_MODULE @{ NumEntries = field 0 UInt32 Table = field 1 $MIB_TCPROW_OWNER_MODULE } $MIB_TCP6TABLE_OWNER_MODULE = struct $Mod MIB_TCP6TABLE_OWNER_MODULE @{ NumEntries = field 0 UInt32 Table = field 1 $MIB_TCP6ROW_OWNER_MODULE } $SC_SERVICE_TAG_QUERY = struct $Mod SC_SERVICE_TAG_QUERY @{ ProcessId = field 0 UInt32 ServiceTag = field 1 UInt32 Unknown = field 2 UInt32 Buffer = field 3 IntPtr } #endregion Structs #region FunctionDefinitions $FunctionDefinitions = @( (func iphlpapi GetExtendedTcpTable ([UInt32]) @([IntPtr], [Int32].MakeByRefType(), [Bool], [Int32], [Int32], [Int32])) (func iphlpapi GetExtendedUdpTable ([UInt32]) @([IntPtr], [Int32].MakeByRefType(), [Bool], [Int32], [Int32], [Int32])) (func advapi32 I_QueryTagInformation ([UInt32]) @([IntPtr], $SC_SERVICE_TAG_QUERY_TYPE, $SC_SERVICE_TAG_QUERY.MakeByRefType())) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'NetworkConnection' $IPHelperAPI = $Types['iphlpapi'] $Advapi32 = $Types['advapi32'] #endregion FunctionDefinitions #region Helper Functions function Get-ServiceNameFromTag($ProcessId, $ServiceTag) { $NTVersion = [System.Environment]::OSVersion.Version if($NTVersion.Major -ge 6 -and $NTVersion.Minor -ge 1) { # Based off of https://wj32.org/wp/2010/03/30/howto-use-i_querytaginformation/ $ServiceTagQuery = [Activator]::CreateInstance($SC_SERVICE_TAG_QUERY) # New-Object doesn't work on PSv2 for some reason. Thanks @mattifestation! $ServiceTagQuery.ProcessId = $ProcessId $ServiceTagQuery.ServiceTag = $ServiceTag $Res = $Advapi32::I_QueryTagInformation([IntPtr]::Zero, $SC_SERVICE_TAG_QUERY_TYPE::ServiceNameFromTagInformation, [Ref] $ServiceTagQuery) if($Res -eq 0) { $ServiceStr = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($ServiceTagQuery.Buffer) $ServiceStr } else { #"Error: $Res" } } } function Get-Tcp4Connections { Param ( # Attempt to resolve the hostnames of each IP address [switch] $ResolveHostnames, [switch] $ReturnHashTables ) $AF_INET = 2 $TableBufferSize = 0 $null = $IPHelperAPI::GetExtendedTcpTable([IntPtr]::Zero, [ref]$TableBufferSize, $true, $AF_INET, $TCP_TABLE_CLASS::TCP_TABLE_OWNER_MODULE_ALL, 0) $TableBuffer = [Runtime.InteropServices.Marshal]::AllocHGlobal($TableBufferSize) try { $Ret = $IPHelperAPI::GetExtendedTcpTable($TableBuffer, [ref] $TableBufferSize, $true, $AF_INET, $TCP_TABLE_CLASS::TCP_TABLE_OWNER_MODULE_ALL, 0); if ($Ret -ne 0) { Write-Error "Failed to get TCP connection information. GetExtendedTcpTable's return code: $Ret" return } $OwnerModuleTable = $TableBuffer -as $MIB_TCPTABLE_OWNER_MODULE $RowPtr = [IntPtr]($TableBuffer.ToInt64() + [Runtime.InteropServices.Marshal]::OffsetOf($MIB_TCPTABLE_OWNER_MODULE, "Table").ToInt64()) for($i=0; $i -lt $OwnerModuleTable.NumEntries; $i++) { $TcpRow = $RowPtr -as $MIB_TCPROW_OWNER_MODULE # Get the properties we want $LocalAddr = [System.Net.IPAddress]$TcpRow.LocalAddr $PortBytes = [System.BitConverter]::GetBytes($TcpRow.LocalPort) $LocalPort = $PortBytes[0]*256 + $PortBytes[1] $RemoteAddr = [System.Net.IPAddress]$TcpRow.RemoteAddr $PortBytes = [System.BitConverter]::GetBytes($TcpRow.RemotePort) $RemotePort = $PortBytes[0]*256 + $PortBytes[1] $ServiceTag = $TcpRow.OwningModuleInfo[0] $RemoteHostname = $null if($ResolveHostnames) { try { $RemoteHostname = [System.Net.Dns]::GetHostEntry($RemoteAddr).HostName } catch { # Couldn't resolve the host name, so keep the IP } } $Output = @{ LocalAddress = [string]$LocalAddr LocalPort = $LocalPort RemoteAddress = [string]$RemoteAddr RemoteHostname = $RemoteHostname RemotePort = $RemotePort #Process = Get-Process -Id $TcpRow.OwningPid -ErrorAction SilentlyContinue Process = (Get-Process -Id $TcpRow.OwningPid -ErrorAction SilentlyContinue).Name ProcessId = $TcpRow.OwningPid Protocol = "TCP" State = $TcpRow.State.ToString() Service = [string](Get-ServiceNameFromTag -ProcessId $TcpRow.OwningPid -ServiceTag $ServiceTag) } if($ReturnHashtables) { $Output } else { New-Object PSObject -Property $Output } # Move to the next row in the TCP table $RowPtr = [IntPtr]($RowPtr.ToInt64() + [Runtime.InteropServices.Marshal]::SizeOf($TcpRow)) } } catch { Write-Error $_ } finally { [Runtime.InteropServices.Marshal]::FreeHGlobal($TableBuffer) } } function Get-Tcp6Connections { Param ( # Attempt to resolve the hostnames of each IP address [switch] $ResolveHostnames, [switch] $ReturnHashTables ) $AF_INET6 = 23 $TableBufferSize = 0 $null = $IPHelperAPI::GetExtendedTcpTable([IntPtr]::Zero, [ref]$TableBufferSize, $true, $AF_INET6, $TCP_TABLE_CLASS::TCP_TABLE_OWNER_MODULE_ALL, 0) $TableBuffer = [Runtime.InteropServices.Marshal]::AllocHGlobal($TableBufferSize) try { $Ret = $IPHelperAPI::GetExtendedTcpTable($TableBuffer, [ref] $TableBufferSize, $true, $AF_INET6, $TCP_TABLE_CLASS::TCP_TABLE_OWNER_MODULE_ALL, 0); if($Ret -eq 50) { # IPv6 is not supported return } elseif ($Ret -ne 0) { Write-Error "Failed to get TCP connection information. GetExtendedTcpTable's return code: $Ret" return } $OwnerModuleTable = $TableBuffer -as $MIB_TCP6TABLE_OWNER_MODULE $RowPtr = [IntPtr]($TableBuffer.ToInt64() + [Runtime.InteropServices.Marshal]::OffsetOf($MIB_TCPTABLE_OWNER_MODULE, "Table").ToInt64()) for($i=0; $i -lt $OwnerModuleTable.NumEntries; $i++) { $TcpRow = $RowPtr -as $MIB_TCP6ROW_OWNER_MODULE # Get the properties we want $LocalAddr = [System.Net.IPAddress]$TcpRow.LocalAddr $PortBytes = [System.BitConverter]::GetBytes($TcpRow.LocalPort) $LocalPort = $PortBytes[0]*256 + $PortBytes[1] $RemoteAddr = [System.Net.IPAddress]$TcpRow.RemoteAddr $PortBytes = [System.BitConverter]::GetBytes($TcpRow.RemotePort) $RemotePort = $PortBytes[0]*256 + $PortBytes[1] $ServiceTag = $TcpRow.OwningModuleInfo[0] $RemoteHostname = $null; if($ResolveHostnames) { try { $RemoteHostname = [System.Net.Dns]::GetHostEntry($RemoteAddr).HostName } catch { # Couldn't resolve the host name, so keep the IP } } $Output = @{ LocalAddress = [string]$LocalAddr LocalPort = $LocalPort RemoteAddress = [string]$RemoteAddr RemoteHostname = $RemoteHostname RemotePort = $RemotePort Process = (Get-Process -Id $TcpRow.OwningPid -ErrorAction SilentlyContinue).Name ProcessId = $TcpRow.OwningPid Protocol = "TCP" State = $TcpRow.State.ToString() Service = [string](Get-ServiceNameFromTag -ProcessId $TcpRow.OwningPid -ServiceTag $ServiceTag) } if($ReturnHashtables) { $Output } else { New-Object PSObject -Property $Output } # Move to the next row in the TCP table $RowPtr = [IntPtr]($RowPtr.ToInt64() + [Runtime.InteropServices.Marshal]::SizeOf($TcpRow)) } } catch { Write-Error $_ } finally { [Runtime.InteropServices.Marshal]::FreeHGlobal($TableBuffer) } } function Get-Udp4Connections { Param ( # Attempt to resolve the hostnames of each IP address [switch] $ResolveHostnames, [switch] $ReturnHashTables ) $AF_INET = 2 $TableBufferSize = 0 $null = $IPHelperAPI::GetExtendedUdpTable([IntPtr]::Zero, [ref]$TableBufferSize, $true, $AF_INET, $UDP_TABLE_CLASS::UDP_TABLE_OWNER_MODULE, 0) $TableBuffer = [Runtime.InteropServices.Marshal]::AllocHGlobal($TableBufferSize) try { $Ret = $IPHelperAPI::GetExtendedUdpTable($TableBuffer, [ref] $TableBufferSize, $true, $AF_INET, $UDP_TABLE_CLASS::UDP_TABLE_OWNER_MODULE, 0); if ($Ret -ne 0) { Write-Error "Failed to get UDP connection information. GetExtendedUdpTable's return code: $Ret" return } $OwnerModuleTable = $TableBuffer -as $MIB_UDPTABLE_OWNER_MODULE $RowPtr = [IntPtr]($TableBuffer.ToInt64() + [Runtime.InteropServices.Marshal]::OffsetOf($MIB_UDPTABLE_OWNER_MODULE, "Table").ToInt64()) for($i=0; $i -lt $OwnerModuleTable.NumEntries; $i++) { $UdpRow = $RowPtr -as $MIB_UDPROW_OWNER_MODULE # Get the properties we want $LocalAddr = [System.Net.IPAddress]$UdpRow.LocalAddr $PortBytes = [System.BitConverter]::GetBytes($UdpRow.LocalPort) $LocalPort = $PortBytes[0]*256 + $PortBytes[1] $ServiceTag = $UdpRow.OwningModuleInfo[0] $Output = @{ LocalAddress = [string]$LocalAddr LocalPort = $LocalPort Process = (Get-Process -Id $UdpRow.OwningPid -ErrorAction SilentlyContinue).Name ProcessId = $UdpRow.OwningPid Protocol = "UDP" Service = [string](Get-ServiceNameFromTag -ProcessId $UdpRow.OwningPid -ServiceTag $ServiceTag) } if($ReturnHashtables) { $Output } else { New-Object PSObject -Property $Output } # Move to the next row in the UDP table $RowPtr = [IntPtr]($RowPtr.ToInt64() + ([Runtime.InteropServices.Marshal]::SizeOf($UdpRow))) } } catch { Write-Error $_ } finally { [Runtime.InteropServices.Marshal]::FreeHGlobal($TableBuffer) } } function Get-Udp6Connections { Param ( # Attempt to resolve the hostnames of each IP address [switch] $ResolveHostnames, [switch] $ReturnHashTables ) $AF_INET6 = 23 $TableBufferSize = 0 $null = $IPHelperAPI::GetExtendedUdpTable([IntPtr]::Zero, [ref]$TableBufferSize, $true, $AF_INET6, $UDP_TABLE_CLASS::UDP_TABLE_OWNER_MODULE, 0) $TableBuffer = [Runtime.InteropServices.Marshal]::AllocHGlobal($TableBufferSize) try { $Ret = $IPHelperAPI::GetExtendedUdpTable($TableBuffer, [ref] $TableBufferSize, $true, $AF_INET6, $UDP_TABLE_CLASS::UDP_TABLE_OWNER_MODULE, 0); if($Ret -eq 50) # ERROR_NOT_SUPPORTED { # IPv6 is not supported return } elseif ($Ret -ne 0) { Write-Error "Failed to get TCP connection information. GetExtendedTcpTable's return code: $Ret" return } $OwnerModuleTable = $TableBuffer -as $MIB_UDP6TABLE_OWNER_MODULE $RowPtr = [IntPtr]($TableBuffer.ToInt64() + [Runtime.InteropServices.Marshal]::OffsetOf($MIB_UDPTABLE_OWNER_MODULE, "Table").ToInt64()) for($i=0; $i -lt $OwnerModuleTable.NumEntries; $i++) { $UdpRow = $RowPtr -as $MIB_UDP6ROW_OWNER_MODULE $LocalAddr = [System.Net.IPAddress]$UdpRow.LocalAddr $PortBytes = [System.BitConverter]::GetBytes($UdpRow.LocalPort) $LocalPort = $PortBytes[0]*256 + $PortBytes[1] $ServiceTag = $UdpRow.OwningModuleInfo[0] if($ResolveHostnames) { try { $RemoteIP = [System.Net.Dns]::GetHostEntry($LocalAddr).HostName } catch { } } $Output = @{ LocalAddress = [string]$LocalAddr LocalPort = $LocalPort Process = (Get-Process -Id $UdpRow.OwningPid -ErrorAction SilentlyContinue).Name ProcessId = $UdpRow.OwningPid Protocol = "UDP" Service = [string](Get-ServiceNameFromTag -ProcessId $UdpRow.OwningPid -ServiceTag $ServiceTag) } if($ReturnHashtables) { $Output } else { New-Object PSObject -Property $Output } # Move to the next row in the UDP table $RowPtr = [IntPtr]($RowPtr.ToInt64() + ([Runtime.InteropServices.Marshal]::SizeOf($UdpRow))) } } catch { Write-Error $_ } finally { [Runtime.InteropServices.Marshal]::FreeHGlobal($TableBuffer) } } #endregion Helper Functions Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-PSAutorun.ps1 ================================================ Function Get-PSAutorun { <# .SYNOPSIS Get Autorun entries. .DESCRIPTION Retrieve a list of programs configured to autostart at boot or logon. .PARAMETER All Switch to gather artifacts from all categories. If it's turned on, all other category switches will be ignored. .PARAMETER BootExecute Switch to gather artifacts from the Boot Execute category. .PARAMETER AppinitDLLs Switch to gather artifacts from the Appinit category. .PARAMETER ExplorerAddons Switch to gather artifacts from the Explorer category. .PARAMETER SidebarGadgets Switch to gather artifacts from the Sidebar Gadgets category. .PARAMETER ImageHijacks Switch to gather artifacts from the Image Hijacks category. .PARAMETER InternetExplorerAddons Switch to gather artifacts from the Intenet Explorer category. .PARAMETER KnownDLLs Switch to gather artifacts from the KnownDLLs category. .PARAMETER Logon Switch to gather artifacts from the Logon category. .PARAMETER Winsock Switch to gather artifacts from the Winsock and network providers category. .PARAMETER Codecs Switch to gather artifacts from the Codecs category. .PARAMETER OfficeAddins Switch to gather artifacts from Office Addins .PARAMETER PrintMonitorDLLs Switch to gather artifacts from the Print Monitors category. .PARAMETER LSAsecurityProviders Switch to gather artifacts from the LSA Providers category. .PARAMETER ServicesAndDrivers Switch to gather artifacts from the Services and Drivers categories. .PARAMETER ScheduledTasks Switch to gather artifacts from the Scheduled tasks category. .PARAMETER Winlogon Switch to gather artifacts from the Winlogon category. .PARAMETER WMI Switch to gather artifacts from the WMI category. .PARAMETER ShowFileHash Switch to enable and display MD5, SHA1 and SHA2 file hashes. .PARAMETER VerifyDigitalSignature Switch to report if a file is digitally signed with the built-in Get-AuthenticodeSignature cmdlet. .EXAMPLE Get-PSAutorun -BootExecute -AppinitDLLs .EXAMPLE Get-PSAutorun -KnownDLLs -LSAsecurityProviders -ShowFileHash .EXAMPLE Get-PSAutorun -All -ShowFileHash -VerifyDigitalSignature #> [CmdletBinding()] Param( [switch]$All, [Switch]$BootExecute, [Switch]$AppinitDLLs, [Switch]$ExplorerAddons, [Switch]$SidebarGadgets, [Switch]$ImageHijacks, [Switch]$InternetExplorerAddons, [Switch]$KnownDLLs, [Switch]$Logon, [Switch]$Winsock, [Switch]$Codecs, [Switch]$OfficeAddins, [Switch]$PrintMonitorDLLs, [Switch]$LSAsecurityProviders, [Switch]$ServicesAndDrivers, [Switch]$ScheduledTasks, [Switch]$Winlogon, [Switch]$WMI, [Switch]$ShowFileHash, [Switch]$VerifyDigitalSignature ) Begin { #region Helperfunctions # Courtesy of Microsoft # Extracted from PS 4.0 with (dir function:\Get-FileHash).Definition Function Get-FileHash { [CmdletBinding(DefaultParameterSetName = 'Path')] Param( [Parameter(Mandatory, ParameterSetName='Path', Position = 0)] [System.String[]] $Path, [Parameter(Mandatory, ParameterSetName='LiteralPath', ValueFromPipelineByPropertyName = $true)] [Alias('PSPath')] [System.String[]] $LiteralPath, [ValidateSet('SHA1', 'SHA256', 'SHA384', 'SHA512', 'MACTripleDES', 'MD5', 'RIPEMD160')] [System.String] $Algorithm='SHA256' ) Begin { # Construct the strongly-typed crypto object $hasher = [System.Security.Cryptography.HashAlgorithm]::Create($Algorithm) } Process { $pathsToProcess = @() if($PSCmdlet.ParameterSetName -eq 'LiteralPath') { $pathsToProcess += Resolve-Path -LiteralPath $LiteralPath | Foreach-Object ProviderPath } else { $pathsToProcess += Resolve-Path $Path | Foreach-Object ProviderPath } foreach($filePath in $pathsToProcess) { if(Test-Path -LiteralPath $filePath -PathType Container) { continue } try { # Read the file specified in $FilePath as a Byte array [system.io.stream]$stream = [system.io.file]::OpenRead($FilePath) # Compute file-hash using the crypto object [Byte[]] $computedHash = $hasher.ComputeHash($stream) } catch [Exception] { $errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::FileReadError -f $FilePath, $_ Write-Error -Message $errorMessage -Category ReadError -ErrorId 'FileReadError' -TargetObject $FilePath return } finally { if($stream) { $stream.Close() } } # Convert to hex-encoded string [string] $hash = [BitConverter]::ToString($computedHash) -replace '-','' $retVal = [PSCustomObject] @{ Algorithm = $Algorithm.ToUpperInvariant() Hash = $hash Path = $filePath } $retVal.psobject.TypeNames.Insert(0, 'Microsoft.Powershell.Utility.FileHash') $retVal } } } Function Get-RegValue { [CmdletBinding()] Param( [string]$Path, [string[]]$Name, [string]$Category ) Begin{ if ($Path -match 'Wow6432Node') { $ClassesPath = Join-Path -Path (Split-Path $Path -Qualifier) -ChildPath 'SOFTWARE\Wow6432Node\Classes\CLSID' } else { $ClassesPath = Join-Path -Path (Split-Path $Path -Qualifier) -ChildPath 'SOFTWARE\Classes\CLSID' } } Process { try { $Values = Get-Item -LiteralPath $Path -ErrorAction Stop if ($Name -eq '*') { $Name = $Values.GetValueNames() } $Name | ForEach-Object -Process { # Need to differentiate between empty string and really non existing values if ($null -ne $Values.GetValue($_)) { $Value = Switch -regex($Values.GetValue($_)) { '^\{[A-Z0-9]{4}([A-Z0-9]{4}-){4}[A-Z0-9]{12}\}$' { (Get-ItemProperty -Path (Join-Path -Path $ClassesPath -ChildPath "$($_)\InprocServer32") -Name '(default)' -ErrorAction SilentlyContinue).'(default)' break } default { $_ } } if ($Value) { @{ Path = $Path Item = $_ Value = $Value Category = $Category } } } } } catch { } } End {} } Function Get-AllScheduledTask { [CmdletBinding()] Param ( [Parameter(Mandatory=$false,ValueFromPipeline=$true)] [System.String[]]$ComputerName = $env:COMPUTERNAME ) Begin { Function Get-SubFolder ($folder,[switch]$recurse) { $folder if ($recurse) { $TaskService.GetFolder($folder).GetFolders(0) | ForEach-Object { Get-SubFolder $_.Path -Recurse } } else { $TaskService.GetFolder($folder).GetFolders(0) } } } Process { $ComputerName | ForEach-Object -Process { $alltasks = @() $Computer = $_ $TaskService = New-Object -com schedule.service try { $null = $TaskService.Connect($Computer) } catch { Write-Warning "Cannot connect to $Computer because $($_.Exception.Message)" return } Get-SubFolder -folder '\' -recurse | ForEach-Object -Process { $TaskService.GetFolder($_).GetTasks(1) | ForEach-Object -Process { $obj = New-Object -TypeName pscustomobject -Property @{ ComputerName = $Computer Path = Split-Path $_.Path Name = $_.Name } $alltasks += $obj } } Write-Verbose -Message "There's a total of $($alltasks.Count) tasks on $Computer" $alltasks } } End {} } Function Get-Task { [CmdletBinding()] [OutputType('System.Object[]')] param ( [parameter(ValueFromPipeline=$false,ValueFromPipelineByPropertyName=$true,Mandatory=$false)] [system.string[]] ${ComputerName} = $env:computername, [parameter(ValueFromPipeline=$false,ValueFromPipelineByPropertyName=$true,Mandatory=$false, HelpMessage="The task folder string must begin by '\'")] [ValidatePattern('^\\')] [system.string[]] ${Path} = '\', [parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Mandatory=$true)] [ValidateNotNullOrEmpty()] [system.string[]] ${Name} = $null ) Begin {} Process { $resultsar = @() $ComputerName | ForEach-Object -Process { $Computer = $_ $TaskService = New-Object -com schedule.service try { $null = $TaskService.Connect($Computer) } catch { Write-Warning "Failed to connect to $Computer" } if ($TaskService.Connected) { Write-Verbose -Message "Connected to the scheduler service of computer $Computer" Foreach ($Folder in $Path) { Write-Verbose -Message "Dealing with folder task $Folder" $RootFolder = $null try { $RootFolder = $TaskService.GetFolder($Folder) } catch { Write-Warning -Message "The folder task $Folder cannot be found" } if ($RootFolder) { Foreach ($Task in $Name) { $TaskObject = $null try { Write-Verbose -Message "Dealing with task name $Task" $TaskObject = $RootFolder.GetTask($Task) } catch { Write-Warning -Message "The task $Task cannot be found under $Folder" } if ($TaskObject) { # Status # http://msdn.microsoft.com/en-us/library/windows/desktop/aa383617%28v=vs.85%29.aspx switch ($TaskObject.State) { 0 { $State = 'Unknown' ; break} 1 { $State = 'Disabled' ; break} 2 { $State = 'Queued' ; break} 3 { $State = 'Ready' ; break} 4 { $State = 'Running' ; break} default {$State = $_ } } $resultsar += New-Object -TypeName pscustomobject -Property @{ ComputerName = $Computer Name = $TaskObject.Name Path = $Folder State = $State Enabled = $TaskObject.Enabled Xml = $TaskObject.XML } } } } } } } $resultsar } End {} } # From David Wyatt # http://gallery.technet.microsoft.com/scriptcenter/Normalize-file-system-5d33985a Function Get-NormalizedFileSystemPath { <# .Synopsis Normalizes file system paths. .DESCRIPTION Normalizes file system paths. This is similar to what the Resolve-Path cmdlet does, except Get-NormalizedFileSystemPath also properly handles UNC paths and converts 8.3 short names to long paths. .PARAMETER Path The path or paths to be normalized. .PARAMETER IncludeProviderPrefix If this switch is passed, normalized paths will be prefixed with 'FileSystem::'. This allows them to be reliably passed to cmdlets such as Get-Content, Get-Item, etc, regardless of Powershell's current location. .EXAMPLE Get-NormalizedFileSystemPath -Path '\\server\share\.\SomeFolder\..\SomeOtherFolder\File.txt' Returns '\\server\share\SomeOtherFolder\File.txt' .EXAMPLE '\\server\c$\.\SomeFolder\..\PROGRA~1' | Get-NormalizedFileSystemPath -IncludeProviderPrefix Assuming you can access the c$ share on \\server, and PROGRA~1 is the short name for "Program Files" (which is common), returns: 'FileSystem::\\server\c$\Program Files' .INPUTS String .OUTPUTS String .NOTES Paths passed to this command cannot contain wildcards; these will be treated as invalid characters by the .NET Framework classes which do the work of validating and normalizing the path. .LINK Resolve-Path #> [CmdletBinding()] Param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('PSPath', 'FullName')] [string[]] $Path, [switch] $IncludeProviderPrefix ) Process{ foreach ($_path in $Path) { $_resolved = $_path if ($_resolved -match '^([^:]+)::') { $providerName = $matches[1] if ($providerName -ne 'FileSystem') { Write-Error "Only FileSystem paths may be passed to Get-NormalizedFileSystemPath. Value '$_path' is for provider '$providerName'." continue } $_resolved = $_resolved.Substring($matches[0].Length) } if (-not [System.IO.Path]::IsPathRooted($_resolved)) { $_resolved = Join-Path -Path $PSCmdlet.SessionState.Path.CurrentFileSystemLocation -ChildPath $_resolved } try { $dirInfo = New-Object System.IO.DirectoryInfo($_resolved) } catch { $exception = $_.Exception while ($null -ne $exception.InnerException) { $exception = $exception.InnerException } Write-Error "Value '$_path' could not be parsed as a FileSystem path: $($exception.Message)" continue } $_resolved = $dirInfo.FullName if ($IncludeProviderPrefix) { $_resolved = "FileSystem::$_resolved" } Write-Output $_resolved } } } Function Get-PSRawAutoRun { [CmdletBinding()] Param( [switch]$All, [Switch]$BootExecute, [Switch]$AppinitDLLs, [Switch]$ExplorerAddons, [Switch]$SidebarGadgets, [Switch]$ImageHijacks, [Switch]$InternetExplorerAddons, [Switch]$KnownDLLs, [Switch]$Logon, [Switch]$Winsock, [Switch]$Codecs, [Switch]$OfficeAddins, [Switch]$PrintMonitorDLLs, [Switch]$LSAsecurityProviders, [Switch]$ServicesAndDrivers, [Switch]$ScheduledTasks, [Switch]$Winlogon, [Switch]$WMI, [Switch]$ShowFileHash, [Switch]$VerifyDigitalSignature ) Begin { ## Add 'All' if nothing else was supplied $parametersToIgnore = ("ShowFileHash","VerifyDigitalSignature") + [System.Management.Automation.PSCmdlet]::CommonParameters + [System.Management.Automation.PSCmdlet]::OptionalCommonParameters if(($PSBoundParameters.Keys | ? { $_ -notin $parametersToIgnore }).Count -eq 0) { $All = [switch]::Present } } Process { if ($All -or $BootExecute) { Write-Verbose -Message 'Looking for Boot Execute entries' #region Boot Execute $Category = @{ Category = 'Boot Execute'} # REG_MULTI_SZ 'BootExecute','SetupExecute','Execute','S0InitialCommand' | ForEach-Object { $item = $_ $v = $null $v = (Get-RegValue -Path 'HKLM:\System\CurrentControlSet\Control\Session Manager' -Name $_ @Category) if ($v) { $v.Value | ForEach-Object { if ($_ -ne '""') { [pscustomobject]@{ Path = 'HKLM:\System\CurrentControlSet\Control\Session Manager' Item = $item Value = $_ Category = 'Boot Execute' } } } } } Get-RegValue -Path 'HKLM:\System\CurrentControlSet\Control' -Name 'ServiceControlManagerExtension' @Category #endregion Boot Execute } if ($All -or $AppinitDLLs) { Write-Verbose -Message 'Looking for Appinit DLLs entries' #region AppInit $null,'Wow6432Node' | Foreach-Object { Get-RegValue -Path "HKLM:\SOFTWARE\$($_)\Microsoft\Windows NT\CurrentVersion\Windows" -Name 'Appinit_Dlls' -Category 'AppInit' } if (Test-Path -Path 'HKLM:\System\CurrentControlSet\Control\Session Manager\AppCertDlls' -PathType Container) { Get-RegValue -Path 'HKLM:\System\CurrentControlSet\Control\Session Manager\AppCertDlls' -Name '*' -Category 'AppInit' } #endregion AppInit } if ($All -or $ExplorerAddons) { Write-Verbose -Message 'Looking for Explorer Add-ons entries' #region Explorer $Category = @{ Category = 'Explorer'} # Filter & Handler 'Filter','Handler' | ForEach-Object -Process { $key = "HKLM:\SOFTWARE\Classes\Protocols\$($_)" if (Test-Path -Path $key -PathType Container) { (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { if ($_ -eq 'ms-help') { if ([environment]::Is64BitOperatingSystem) { $ClassesPath = 'HKLM:\SOFTWARE\Wow6432Node\Classes\CLSID' } else { $ClassesPath = 'HKLM:\SOFTWARE\Classes\CLSID' } $i = (Get-ItemProperty -Path "$key\ms-help" -Name 'CLSID').CLSID [pscustomobject]@{ Path = "$key\ms-help" Item = $i Value = $( (Get-ItemProperty -Path (Join-Path -Path 'HKLM:\SOFTWARE\Wow6432Node\Classes\CLSID' -ChildPath "$($i)\InprocServer32") -Name '(default)' -ErrorAction SilentlyContinue).'(default)'; (Get-ItemProperty -Path (Join-Path -Path 'HKLM:\SOFTWARE\Classes\CLSID' -ChildPath "$($i)\InprocServer32") -Name '(default)' -ErrorAction SilentlyContinue).'(default)'; ) | Where-Object { $null -ne $_ } | Sort-Object -Unique Category = 'Explorer' } } else { Get-RegValue -Path "$key\$($_)" -Name 'CLSID' @Category } } } } # SharedTaskScheduler $null,'Wow6432Node' | Foreach-Object -Process { Get-RegValue -Path "HKLM:\SOFTWARE\$($_)\Microsoft\Windows\CurrentVersion\Explorer\SharedTaskScheduler" -Name '*' @Category } # ShellServiceObjects $null,'Wow6432Node' | Foreach-Object -Process { $ClassesPath = "HKLM:\SOFTWARE\$($_)\Classes\CLSID" $key = "HKLM:\SOFTWARE\$($_)\Microsoft\Windows\CurrentVersion\Explorer\ShellServiceObjects" (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { @{ Path = $key Item = $_ Value = $( try { (Get-ItemProperty -Path (Join-Path -Path $ClassesPath -ChildPath "$($_)\InprocServer32") -Name '(default)' -ErrorAction Stop).'(default)' } catch { $null } ) Category = 'Explorer' } } } # ShellExecuteHooks $null,'Wow6432Node' | Foreach-Object -Process { $key = "HKLM:\SOFTWARE\$($_)\Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks" if (Test-Path -Path $key -PathType Container) { $ClassesPath = "HKLM:\SOFTWARE\$($_)\Classes\CLSID" (Get-Item -Path $key).GetValueNames() | ForEach-Object { # Get-RegValue -Path $key -Name $_ @Category @{ Path = $key Item = $_ Value = (Get-ItemProperty -Path (Join-Path -Path $ClassesPath -ChildPath "$($_)\InprocServer32") -Name '(default)').'(default)' Category = 'Explorer' } } } } # ShellServiceObjectDelayLoad $null,'Wow6432Node' | Foreach-Object -Process { Get-RegValue -Path "HKLM:\SOFTWARE\$($_)\Microsoft\Windows\CurrentVersion\ShellServiceObjectDelayLoad" -Name '*' @Category } # Handlers @( @{Name = '*' ; Properties = @('ContextMenuHandlers','PropertySheetHandlers')}, @{Name ='Drive' ; Properties = @('ContextMenuHandlers')}, @{Name ='AllFileSystemObjects' ; Properties = @('ContextMenuHandlers','DragDropHandlers','PropertySheetHandlers')}, @{Name ='Directory' ; Properties = @('ContextMenuHandlers','DragDropHandlers','PropertySheetHandlers', 'CopyHookHandlers')}, @{Name ='Directory\Background' ; Properties = @('ContextMenuHandlers')}, @{Name ='Folder' ; Properties = @('ColumnHandlers','ContextMenuHandlers','DragDropHandlers','ExtShellFolderViews','PropertySheetHandlers')} ) | ForEach-Object -Process { $Name = $_.Name $Properties = $_.Properties $null,'Wow6432Node' | Foreach-Object -Process { $key = "HKLM:\Software\$($_)\Classes\$Name\ShellEx" $ClassPath = "HKLM:\Software\$($_)\Classes\CLSID" $Hive = $_ $Properties | ForEach-Object -Process { $subkey = Join-Path -Path $key -ChildPath $_ try { (Get-Item -LiteralPath $subkey -ErrorAction SilentlyContinue).GetSubKeyNames() | ForEach-Object -Process { if ($(try { [system.guid]::Parse($_) | Out-Null $true } catch { $false })) { if (Test-Path -Path (Join-Path -Path $ClassPath -ChildPath "$($_)\InprocServer32") -PathType Container) { # don't change anything } else { if ($Hive) { $ClassPath = 'HKLM:\Software\Classes\CLSID' } else { $ClassPath = 'HKLM:\Software\Wow6432Node\Classes\CLSID' } } if (Test-PAth -Path (Join-Path -Path $ClassPath -ChildPath "$($_)\InprocServer32") -PathType Container) { @{ Path = $key Item = $_ Value = (Get-ItemProperty -Path (Join-Path -Path $ClassPath -ChildPath "$($_)\InprocServer32") -Name '(default)' -ErrorAction SilentlyContinue).'(default)' Category = 'Explorer' } } } else { Get-RegValue -Path "$subkey\$($_)" -Name '*' @Category } } } catch { } } } } # ShellIconOverlayIdentifiers $null,'Wow6432Node' | Foreach-Object -Process { $key = "HKLM:\SOFTWARE\$($_)\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers" if (Test-Path -Path $key -PathType Container) { (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path "$key\$($_)" -Name '*' @Category } } } # LangBarAddin Get-RegValue -Path 'HKLM:\Software\Microsoft\Ctf\LangBarAddin' -Name '*' @Category #endregion Explorer #region User Explorer # Filter & Handler 'Filter','Handler' | ForEach-Object -Process { $key = "HKCU:\SOFTWARE\Classes\Protocols\$($_)" if (Test-Path -Path $key -PathType Container) { (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path "$key\$($_)" -Name 'CLSID' @Category } } } if (Test-Path -Path 'HKCU:\SOFTWARE\Microsoft\Internet Explorer\Desktop\Components' -PathType Container) { $key = 'HKCU:\SOFTWARE\Microsoft\Internet Explorer\Desktop\Components' (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path "$key\$($_)" -Name 'Source' @Category } } # ShellServiceObjects if (Test-Path -Path 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellServiceObjects' -PathType Container) { $ClassesPath = "HKCU:\SOFTWARE\$($_)\Classes\CLSID" $key = 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellServiceObjects' (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { @{ Path = $key Item = $_ Value = (Get-ItemProperty -Path (Join-Path -Path $ClassesPath -ChildPath "$($_)\InprocServer32") -Name '(default)').'(default)' Category = 'Explorer' } } } # ShellServiceObjectDelayLoad Get-RegValue -Path 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\ShellServiceObjectDelayLoad' -Name '*' @Category # Handlers @( @{Name = '*' ; Properties = @('ContextMenuHandlers','PropertySheetHandlers')}, @{Name ='Drive' ; Properties = @('ContextMenuHandlers')}, @{Name ='AllFileSystemObjects' ; Properties = @('ContextMenuHandlers','DragDropHandlers','PropertySheetHandlers')}, @{Name ='Directory' ; Properties = @('ContextMenuHandlers','DragDropHandlers','PropertySheetHandlers', 'CopyHookHandlers')}, @{Name ='Directory\Background' ; Properties = @('ContextMenuHandlers')}, @{Name ='Folder' ; Properties = @('ColumnHandlers','ContextMenuHandlers','DragDropHandlers','ExtShellFolderViews','PropertySheetHandlers')} ) | ForEach-Object -Process { $Name = $_.Name $Properties = $_.Properties $key = "HKCU:\Software\Classes\$Name\ShellEx" $Properties | ForEach-Object -Process { $subkey = Join-Path -Path $key -ChildPath $_ try { (Get-Item -LiteralPath $subkey -ErrorAction SilentlyContinue).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path "$subkey\$($_)" -Name '*' @Category } } catch { } } } # ShellIconOverlayIdentifiers $key = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers' if (Test-Path -Path $key -PathType Container) { (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path "$key\$($_)" -Name '*' @Category } } # LangBarAddin Get-RegValue -Path 'HKCU:\Software\Microsoft\Ctf\LangBarAddin' -Name '*' @Category # NEW! POWELIKS use of Window's thumbnail cache if (Test-Path -Path 'HKCU:\Software\Classes\Clsid\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}') { Write-Warning -Message 'Infected by PoweLiks malware' # Step1: restore read access try { $ParentACL = Get-Acl -Path 'HKCU:\Software\Classes\Clsid' $k = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey('Software\Classes\Clsid\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}','ReadWriteSubTree','TakeOwnership') $acl = $k.GetAccessControl() $acl.SetAccessRuleProtection($false,$true) $rule = New-Object System.Security.AccessControl.RegistryAccessRule ($ParentACL.Owner,'FullControl','Allow') $acl.SetAccessRule($rule) $k.SetAccessControl($acl) Write-Verbose -Message "Successuflly restored read access for $($ParentACL.Owner) on registry key" } catch { Write-Warning -Message "Failed to restore read access for $($ParentACL.Owner) on registry key" } # Step2: read the content of subkeys 'Inprocserver32','localserver32' | ForEach-Object { try { (Get-ItemProperty -Path "HKCU:\Software\Classes\Clsid\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}\$($_)" -Name '(default)' -ErrorAction Stop).'(default)' } catch { } } } #endregion User Explorer } if ($All -or $SidebarGadgets) { Write-Verbose -Message 'Looking for Sidebar gadgets' #region User Sidebar gadgets if (Test-Path (Join-Path -Path (Split-Path -Path $($env:AppData) -Parent) -ChildPath 'Local\Microsoft\Windows Sidebar\Settings.ini')) { Get-Content -Path ( Join-Path -Path (Split-Path -Path $($env:AppData) -Parent) -ChildPath 'Local\Microsoft\Windows Sidebar\Settings.ini' ) | Select-String -Pattern '^PrivateSetting_GadgetName=' | ForEach-Object { @{ Path = Join-Path -Path (Split-Path -Path $($env:AppData) -Parent) -ChildPath 'Local\Microsoft\Windows Sidebar\Settings.ini' Item = [string]::Empty Value = ($_.Line -split '=' | Select-Object -Last 1) -replace '%5C','\' -replace '%20',' ' Category = 'SideBar Gadgets' } } } #endregion User Sidebar gadgets } if ($All -or $ImageHijacks) { Write-Verbose -Message 'Looking for Image hijacks' #region Image Hijacks $Category = @{ Category = 'Image Hijacks'} $null,'Wow6432Node' | Foreach-Object { $key = "HKLM:\Software\$($_)\Microsoft\Windows NT\CurrentVersion\Image File Execution Options" (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path "$key\$($_)" -Name 'Debugger' @Category } } # Autorun macro $null,'Wow6432Node' | Foreach-Object { Get-RegValue -Path "HKLM:\Software\$($_)\Microsoft\Command Processor" -Name 'Autorun' @Category } # Exefile @{ Path = 'HKLM:\SOFTWARE\Classes\Exefile\Shell\Open\Command' Item = 'exefile' Value = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Classes\Exefile\Shell\Open\Command' -Name '(default)').'(default)' Category = 'Image Hijacks' } '.exe','.cmd' | Foreach-Object { $assoc = (Get-ItemProperty -Path "HKLM:\Software\Classes\$($_)" -Name '(default)').'(default)' @{ Path = "HKLM:\Software\Classes\$assoc\shell\open\command" Item = $_ Value = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Classes\$assoc\Shell\Open\Command" -Name '(default)').'(default)' Category = 'Image Hijacks' } } # Htmlfile @{ Path = 'HKLM:\SOFTWARE\Classes\htmlfile\shell\open\command' Item = 'htmlfile' Value = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Classes\htmlfile\shell\open\command' -Name '(default)').'(default)' Category = 'Image Hijacks' } #endregion Image Hijacks #region User Image Hijacks Get-RegValue -Path 'HKCU:\Software\Microsoft\Command Processor' -Name 'Autorun' @Category # Exefile if (Test-Path -Path 'HKCU:\SOFTWARE\Classes\Exefile\Shell\Open\Command') { @{ Path = 'HKCU:\SOFTWARE\Classes\Exefile\Shell\Open\Command' Item = 'exefile' Value = (Get-ItemProperty -Path 'HKCU:\SOFTWARE\Classes\Exefile\Shell\Open\Command' -Name '(default)').'(default)' Category = 'Image Hijacks' } } '.exe','.cmd' | Foreach-Object { if (Test-Path -Path "HKCU:\Software\Classes\$($_)") { $assoc = (Get-ItemProperty -Path "HKCU:\Software\Classes\$($_)" -Name '(default)'-ErrorAction SilentlyContinue).'(default)' if ($assoc) { @{ Path = "HKCU:\Software\Classes\$assoc\shell\open\command" Item = $_ Value = (Get-ItemProperty -Path "HKCU:\SOFTWARE\Classes\$assoc\Shell\Open\Command" -Name '(default)' -ErrorAction SilentlyContinue).'(default)' Category = 'Image Hijacks' } } } } # Htmlfile if (Test-Path -Path 'HKCU:\SOFTWARE\Classes\htmlfile\shell\open\command') { @{ Path = 'HKCU:\SOFTWARE\Classes\htmlfile\shell\open\command' Item = 'htmlfile' Value = (Get-ItemProperty -Path 'HKCU:\SOFTWARE\Classes\htmlfile\shell\open\command' -Name '(default)').'(default)' Category = 'Image Hijacks' } } #endregion User Image Hijacks } if ($All -or $InternetExplorerAddons) { Write-Verbose -Message 'Looking for Internet Explorer Add-ons entries' #region Internet Explorer $Category = @{ Category = 'Internet Explorer'} # Browser Helper Objects $null,'Wow6432Node' | Foreach-Object { $ClassesPath = "HKLM:\SOFTWARE\$($_)\Classes\CLSID" $key = "HKLM:\SOFTWARE\$($_)\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects" if (Test-Path -Path $key -PathType Container) { (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { @{ Path = $key Item = $_ Value = (Get-ItemProperty -Path (Join-Path -Path $ClassesPath -ChildPath "$($_)\InprocServer32") -Name '(default)').'(default)' Category = 'Internet Explorer' } } } } # IE Toolbars $null,'Wow6432Node' | Foreach-Object -Process { Get-RegValue -Path "HKLM:\SOFTWARE\$($_)\Microsoft\Internet Explorer\Toolbar" -Name '*' @Category } # Explorer Bars $null,'Wow6432Node' | Foreach-Object -Process { $ClassesPath = "HKLM:\SOFTWARE\$($_)\Classes\CLSID" $key = "HKLM:\SOFTWARE\$($_)\Microsoft\Internet Explorer\Explorer Bars" try { (Get-Item -Path $key -ErrorAction Stop).GetSubKeyNames() | ForEach-Object -Process { @{ Path = $key Item = $_ Value = (Get-ItemProperty -Path (Join-Path -Path $ClassesPath -ChildPath "$($_)\InprocServer32") -Name '(default)').'(default)' Category = 'Internet Explorer' } } } catch { } } # IE Extensions $null,'Wow6432Node' | Foreach-Object { $key = "HKLM:\SOFTWARE\$($_)\Microsoft\Internet Explorer\Extensions" if (Test-Path -Path $key -PathType Container) { (Get-Item -Path $key -ErrorAction SilentlyContinue).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path "$key\$($_)" -Name 'ClsidExtension' @Category } } } #endregion Internet Explorer #region User Internet Explorer # UrlSearchHooks $ClassesPath = 'HKLM:\SOFTWARE\Classes\CLSID' $key = 'HKCU:\Software\Microsoft\Internet Explorer\UrlSearchHooks' if (Test-Path -Path $key -PathType Container) { (Get-Item -Path $key).GetValueNames() | ForEach-Object -Process { @{ Path = $key Item = $_ Value = (Get-ItemProperty -Path (Join-Path -Path $ClassesPath -ChildPath "$($_)\InprocServer32") -Name '(default)').'(default)' Category = 'Internet Explorer' } } } # Explorer Bars $null,'Wow6432Node' | Foreach-Object -Process { $ClassesPath = "HKLM:\SOFTWARE\$($_)\Classes\CLSID" $key = "HKCU:\SOFTWARE\$($_)\Microsoft\Internet Explorer\Explorer Bars" if (Test-Path -Path $key -PathType Container) { (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { @{ Path = $key Item = $_ Value = (Get-ItemProperty -Path (Join-Path -Path $ClassesPath -ChildPath "$($_)\InprocServer32") -Name '(default)').'(default)' Category = 'Internet Explorer' } } } } # IE Extensions $null,'Wow6432Node' | Foreach-Object { $key = "HKCU:\SOFTWARE\$($_)\Microsoft\Internet Explorer\Extensions" if (Test-Path -Path $key -PathType Container) { (Get-Item -Path $key -ErrorAction SilentlyContinue).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path "$key\$($_)" -Name 'ClsidExtension' @Category } } } #endregion User Internet Explorer } if ($All -or $KnownDLLs) { Write-Verbose -Message 'Looking for Known DLLs entries' #region Known Dlls Get-RegValue -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs' -Name '*' -Category 'Known Dlls' #endregion Known Dlls } if ($All -or $Logon) { Write-Verbose -Message 'Looking for Logon Startup entries' #region Logon $Category = @{ Category = 'Logon'} # Winlogon Get-RegValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Name 'VmApplet','Userinit','Shell','TaskMan','AppSetup' @Category # GPExtensions $key = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GPExtensions' if (Test-Path -Path $key -PathType Container) { (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { try { @{ Path = $key Item = $_ Value = (Get-ItemProperty -Path (Join-Path -Path $key -ChildPath $_) -Name 'DllName' -ErrorAction Stop).'DllName' Category = 'Logon' } } catch {} } } # Domain Group Policies scripts 'Startup','Shutdown','Logon','Logoff' | ForEach-Object -Process { $key = "HKLM:\Software\Policies\Microsoft\Windows\System\Scripts\$($_)" if (Test-Path -Path $key) { (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { $subkey = (Join-Path -Path $key -ChildPath $_) (Get-Item -Path $subkey).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path (Join-Path -Path $subkey -ChildPath $_) -Name 'script' @Category } } } } # Local GPO scripts 'Startup','Shutdown' | ForEach-Object -Process { $key = "HKLM:\Software\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\$($_)" if (Test-Path -Path $key) { (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { $subkey = (Join-Path -Path $key -ChildPath $_) (Get-Item -Path $subkey).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path (Join-Path -Path $subkey -ChildPath $_) -Name 'script' @Category } } } } # Shell override by GPO Get-RegValue -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System' -Name 'Shell' @Category # AlternateShell Get-RegValue -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SafeBoot' -Name 'AlternateShell' @Category # AvailableShells Get-RegValue -Path 'HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\AlternateShells' -Name 'AvailableShells' @Category # Terminal server Get-RegValue -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\Wds\rdpwd' -Name 'StartupPrograms' @Category Get-RegValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\Runonce' -Name '*' @Category Get-RegValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\RunonceEx' -Name '*' @Category Get-RegValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\Run' -Name '*' @Category Get-RegValue -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -Name 'InitialProgram' @Category # Run $null,'Wow6432Node' | Foreach-Object { Get-RegValue -Path "HKLM:\SOFTWARE\$($_)\Microsoft\Windows\CurrentVersion\Run" -Name '*' @Category } # RunOnce $null,'Wow6432Node' | Foreach-Object { Get-RegValue -Path "HKLM:\SOFTWARE\$($_)\Microsoft\Windows\CurrentVersion\RunOnce" -Name '*' @Category } # RunOnceEx $null,'Wow6432Node' | Foreach-Object { Get-RegValue -Path "HKLM:\SOFTWARE\$($_)\Microsoft\Windows\CurrentVersion\RunOnceEx" -Name '*' @Category } # LNK files or direct executable if (Test-Path -Path "$($env:systemdrive)\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup" -PathType Container) { $Wsh = new-object -comobject 'WScript.Shell' Get-ChildItem -Path "$($env:systemdrive)\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup" |ForEach-Object { $File = $_ $header = (Get-Content -Path $($_.FullName) -Encoding Byte -ReadCount 1 -TotalCount 2) -as [string] Switch ($header) { '77 90' { @{ Path = "$($env:systemdrive)\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup" Item = $File.Name Value = $File.FullName Category = 'Logon' } break } '76 0' { $shortcut = $Wsh.CreateShortcut($File.FullName) @{ Path = "$($env:systemdrive)\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup" Item = $File.Name Value = "$($shortcut.TargetPath) $($shortcut.Arguments)" Category = 'Logon' } break } default {} } } } # Run by GPO Get-RegValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run' -Name '*' @Category # Show all subkey that have a StubPath value $null,'Wow6432Node' | Foreach-Object { $key = "HKLM:\SOFTWARE\$($_)\Microsoft\Active Setup\Installed Components" (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path "$key\$($_)" -Name 'StubPath' @Category } } Get-RegValue -Path 'HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Windows' -Name 'IconServiceLib' @Category $null,'Wow6432Node' | Foreach-Object { Get-RegValue -Path "HKLM:\SOFTWARE\$($_)\Microsoft\Windows CE Services\AutoStartOnConnect" -Name '*' @Category } $null,'Wow6432Node' | Foreach-Object { Get-RegValue -Path "HKLM:\SOFTWARE\$($_)\Microsoft\Windows CE Services\AutoStartOnDisconnect" -Name '*' @Category } #endregion Logon #region User Logon # Local GPO scripts 'Logon','Logoff' | ForEach-Object -Process { $key = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\$($_)" if (Test-Path -Path $key) { (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { $subkey = (Join-Path -Path $key -ChildPath $_) (Get-Item -Path $subkey).GetSubKeyNames() | ForEach-Object -Process { # (Join-Path -Path $subkey -ChildPath $_) Get-RegValue -Path (Join-Path -Path $subkey -ChildPath $_) -Name 'script' @Category } } } } # Shell override by GPO Get-RegValue -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Policies\System' -Name 'Shell' @Category # LNK files or direct executable if (Test-Path -Path "$($env:AppData)\Microsoft\Windows\Start Menu\Programs\Startup") { $Wsh = new-object -comobject 'WScript.Shell' Get-ChildItem -Path "$($env:AppData)\Microsoft\Windows\Start Menu\Programs\Startup" |ForEach-Object { $File = $_ $header = (Get-Content -Path $($_.FullName) -Encoding Byte -ReadCount 1 -TotalCount 2) -as [string] Switch ($header) { '77 90' { @{ Path = "$($env:AppData)\Microsoft\Windows\Start Menu\Programs\Startup" Item = $File.Name Value = $File.FullName Category = 'Logon' } break } '76 0' { $shortcut = $Wsh.CreateShortcut($File.FullName) @{ Path = "$($env:AppData)\Microsoft\Windows\Start Menu\Programs\Startup" Item = $File.Name Value = "$($shortcut.TargetPath) $($shortcut.Arguments)" Category = 'Logon' } break } default {} } } } Get-RegValue -Path 'HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Windows' -Name 'Load' @Category Get-RegValue -Path 'HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Windows' -Name 'Run' @Category # Run by GPO Get-RegValue -Path 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run' -Name '*' @Category # Run $null,'Wow6432Node' | ForEach-Object { Get-RegValue -Path "HKCU:\Software\$($_)\Microsoft\Windows\CurrentVersion\Run" -Name '*' @Category } # RunOnce $null,'Wow6432Node' | ForEach-Object { Get-RegValue -Path "HKCU:\Software\$($_)\Microsoft\Windows\CurrentVersion\RunOnce" -Name '*' @Category } # RunOnceEx $null,'Wow6432Node' | ForEach-Object { Get-RegValue -Path "HKCU:\Software\$($_)\Microsoft\Windows\CurrentVersion\RunOnceEx" -Name '*' @Category } Get-RegValue -Path 'HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\Runonce' -Name '*' @Category Get-RegValue -Path 'HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\RunonceEx' -Name '*' @Category Get-RegValue -Path 'HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\Run' -Name '*' @Category #endregion User Logon } if ($All -or $Winsock) { Write-Verbose -Message 'Looking for Winsock protocol and network providers entries' #region Winsock providers $Category = @{ Category = 'Winsock Providers'} $null,'64' | ForEach-Object -Process { $key = "HKLM:\System\CurrentControlSet\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries$($_)" (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { @{ Path = "$key\$($_)" Item = 'PackedCatalogItem' Value = ((New-Object -TypeName System.Text.ASCIIEncoding).GetString( (Get-ItemProperty -Path "$key\$($_)" -Name PackedCatalogItem).PackedCatalogItem,0,211 ) -split ([char][int]0))[0] Category = 'Winsock Providers' } } } $null,'64' | ForEach-Object -Process { $key = "HKLM:\System\CurrentControlSet\Services\WinSock2\Parameters\NameSpace_Catalog5\Catalog_Entries$($_)" (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path "$key\$($_)" -Name 'LibraryPath' @Category } } #endregion Winsock providers #region Network providers $Category = @{ Category = 'Network Providers'} $key = 'HKLM:\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order' (Get-RegValue -Path $key -Name 'ProviderOrder' @Category).Value -split ',' | ForEach-Object { Get-RegValue -Path "HKLM:\SYSTEM\CurrentControlSet\services\$($_)\NetworkProvider" -Name 'ProviderPath' @Category } #endregion Network providers } if ($All -or $Codecs) { Write-Verbose -Message 'Looking for Codecs' #region Codecs $Category = @{ Category = 'Codecs'} # Drivers32 $null,'Wow6432Node' | Foreach-Object { Get-RegValue -Path "HKLM:\Software\$($_)\Microsoft\Windows NT\CurrentVersion\Drivers32" -Name '*' @Category } # Filter $key = 'HKLM:\Software\Classes\Filter' if (Test-Path -Path $key -PathType Container) { (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { @{ Path = $key Item = $_ Value = (Get-ItemProperty -Path (Join-Path -Path 'HKLM:\SOFTWARE\Classes\CLSID' -ChildPath "$($_)\InprocServer32") -Name '(default)' -ErrorAction SilentlyContinue).'(default)' Category = 'Codecs' } } } # Instances @('{083863F1-70DE-11d0-BD40-00A0C911CE86}','{AC757296-3522-4E11-9862-C17BE5A1767E}', '{7ED96837-96F0-4812-B211-F13C24117ED3}','{ABE3B9A4-257D-4B97-BD1A-294AF496222E}') | Foreach-Object -Process { $Item = $_ $null,'Wow6432Node' | Foreach-Object { $key = "HKLM:\Software\$($_)\Classes\CLSID\$Item\Instance" $clsidp = "HKLM:\Software\$($_)\Classes\CLSID" if (Test-Path -Path $key -PathType Container) { (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { try { @{ Path = $key Item = $_ Value = (Get-ItemProperty -Path (Join-Path -Path $clsidp -ChildPath "$($_)\InprocServer32") -Name '(default)' -ErrorAction Stop).'(default)' Category = 'Codecs' } } catch { } } } } } #endregion Codecs #region User Codecs # Drivers32 $null,'Wow6432Node' | Foreach-Object { Get-RegValue -Path "HKCU:\Software\$($_)\Microsoft\Windows NT\CurrentVersion\Drivers32" -Name '*' @Category } # Filter $key = 'HKCU:\Software\Classes\Filter' if (Test-Path -Path $key -PathType Container) { (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { @{ Path = $key Item = $_ Value = (Get-ItemProperty -Path (Join-Path -Path 'HKCU:\SOFTWARE\Classes\CLSID' -ChildPath "$($_)\InprocServer32") -Name '(default)' -ErrorAction SilentlyContinue).'(default)' Category = 'Codecs' } } } # Instances @('{083863F1-70DE-11d0-BD40-00A0C911CE86}','{AC757296-3522-4E11-9862-C17BE5A1767E}', '{7ED96837-96F0-4812-B211-F13C24117ED3}','{ABE3B9A4-257D-4B97-BD1A-294AF496222E}') | Foreach-Object -Process { $Item = $_ $null,'Wow6432Node' | Foreach-Object { $key = "HKCU:\Software\$($_)\Classes\CLSID\$Item\Instance" if (Test-Path -Path $key -PathType Container) { (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { try { @{ Path = $key Item = $_ Value = (Get-ItemProperty -Path (Join-Path -Path 'HKCU:\SOFTWARE\Classes\CLSID' -ChildPath "$($_)\InprocServer32") -Name '(default)' -ErrorAction Stop).'(default)' Category = 'Codecs' } } catch { } } } } } #endregion User Codecs } if ($All -or $OfficeAddins) { Write-Verbose -Message 'Looking for Office Addins entries' #region Office Addins <# # FileName value or # HKEY_LOCAL_MACHINE\SOFTWARE\Classes\OneNote.OutlookAddin\CLSID #> $Category = @{ Category = 'Office Addins'} $null,'Wow6432Node' | Foreach-Object { $arc = $_ 'HKLM','HKCU' | ForEach-Object { $root = $_ if (Test-Path "$($root):\SOFTWARE\$($arc)\Microsoft\Office") { (Get-Item "$($root):\SOFTWARE\$($arc)\Microsoft\Office").GetSubKeyNames() | ForEach-Object { if (Test-Path -Path (Join-Path -Path "$($root):\SOFTWARE\$($arc)\Microsoft\Office" -ChildPath "$($_)\Addins") -PathType Container) { $key = (Join-Path -Path "$($root):\SOFTWARE\$($arc)\Microsoft\Office" -ChildPath "$($_)\Addins") # Iterate through the Addins names (Get-item -Path $key).GetSubKeyNames() | ForEach-Object { try { @{ Path = $key Item = $_ Value = $( $clsid = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Classes\$($_)\CLSID" -Name '(default)' -ErrorAction Stop).'(default)'; if ((Get-ItemProperty -Path "HKLM:\SOFTWARE\$arc\Classes\CLSID\$clsid\InprocServer32" -Name '(default)' -ErrorAction SilentlyContinue).'(default)') { (Get-ItemProperty -Path "HKLM:\SOFTWARE\$arc\Classes\CLSID\$clsid\InprocServer32" -Name '(default)' -ErrorAction SilentlyContinue).'(default)' } else { $clsid } # (Get-ItemProperty -Path "HKLM:\SOFTWARE\Classes\CLSID\$clsid\InprocServer32" -Name '(default)' -ErrorAction SilentlyContinue).'(default)'; ) # | Where-Object { $null -ne $_ } | Sort-Object -Unique # | Select-Object -First 1 Category = 'Office Addins'; } } catch { } } } } } } # hklm or hkcu } # Microsoft Office Memory Corruption Vulnerability (CVE-2015-1641) 'HKLM','HKCU' | ForEach-Object { $root = $_ $key = "$($root):\SOFTWARE\Microsoft\Office test\Special\Perf" if (Test-Path "$($root):\SOFTWARE\Microsoft\Office test\Special\Perf") { if ((Get-ItemProperty -Path "$($root):\SOFTWARE\Microsoft\Office test\Special\Perf" -Name '(default)' -ErrorAction SilentlyContinue).'(default)') { @{ Path = $key Item = '(default)' Value = (Get-ItemProperty -Path "$($root):\SOFTWARE\Microsoft\Office test\Special\Perf" -Name '(default)' -ErrorAction SilentlyContinue).'(default)' Category = 'Office Addins'; } } } } #endregion Office Addins } if ($All -or $PrintMonitorDLLs) { Write-Verbose -Message 'Looking for Print Monitor DLLs entries' #region Print monitors $Category = @{ Category = 'Print Monitors'} $key = 'HKLM:\SYSTEM\CurrentControlSet\Control\Print\Monitors' (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path "$key\$($_)" -Name 'Driver' @Category } Write-Verbose -Message 'Looking for Print Providers DLLs entries' $key = 'HKLM:\SYSTEM\CurrentControlSet\Control\Print\Providers' (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path "$key\$($_)" -Name 'Name' @Category } #endregion Print monitors } if ($All -or $LSAsecurityProviders) { Write-Verbose -Message 'Looking for LSA Security Providers entries' #region LSA providers $Category = @{ Category = 'LSA Providers'} # REG_SZ Get-RegValue -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders' -Name 'SecurityProviders' @Category # REG_MULTI_SZ 'Authentication Packages','Notification Packages','Security Packages' | ForEach-Object { $item = $_ (Get-RegValue -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa' -Name $_ @Category).Value | ForEach-Object { if ($_ -ne '""') { @{ Path = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa' Item = $item Value = $_ Category = 'LSA Providers' } } } } # HKLM\SYSTEM\CurrentControlSet\Control\Lsa\OSConfig\Security Packages if (Test-Path -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\OSConfig' -PathType Container) { (Get-RegValue -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\OSConfig' -Name 'Security Packages' @Category).Value | ForEach-Object { @{ Path = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\OSConfig' Item = 'Security Packages' Value = $_ Category = 'LSA Providers' } } } #endregion LSA providers } if ($All -or $ServicesAndDrivers) { Write-Verbose -Message 'Looking for Services and Drivers' #region Services (Get-Item -Path 'HKLM:\System\CurrentControlSet\Services').GetSubKeyNames() | ForEach-Object { $Type = $null $key = "HKLM:\System\CurrentControlSet\Services\$($_)" try { $Type = Get-ItemProperty -Path $key -Name Type -ErrorAction Stop } catch { } if ($Type) { Switch ($Type.Type) { 1 { Get-RegValue -Path $key -Name 'ImagePath' -Category 'Drivers' break } 16 { Get-RegValue -Path $key -Name 'ImagePath' -Category 'Services' Get-RegValue -Path "$key\Parameters" -Name 'ServiceDll' -Category 'Services' break } 32 { Get-RegValue -Path $key -Name 'ImagePath' -Category 'Services' Get-RegValue -Path "$key\Parameters" -Name 'ServiceDll' -Category 'Services' break } default { # $_ } } } } # Font drivers Get-RegValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Font Drivers' -Name '*' -Category 'Services' #endregion Services } if ($All -or $ScheduledTasks) { Write-Verbose -Message 'Looking for Scheduled Tasks' #region Scheduled Tasks Get-AllScheduledTask | Get-Task | ForEach-Object { $Value = $null $Value = if ( ($node = ([xml]$_.XML).Task.get_ChildNodes() | Where-Object Name -eq 'Actions' ).HasChildNodes ) { # $node can have Exec or comHandler or both childs (ex: MediaCenter tasks) switch ($node.get_ChildNodes().Name) { Exec { $subnode = ($node.get_ChildNodes() | Where-Object { $_.Name -eq 'Exec'}) if ($subnode.get_ChildNodes() | Where-Object Name -eq 'Arguments' | Select-Object -ExpandProperty '#text') { '{0} {1}' -f ($subnode.get_ChildNodes() | Where-Object Name -eq 'Command' | Select-Object -ExpandProperty '#text'), ($subnode.get_ChildNodes() | Where-Object Name -eq 'Arguments' | Select-Object -ExpandProperty '#text'); } else { $subnode.get_ChildNodes() | Where-Object Name -eq 'Command' | Select-Object -ExpandProperty '#text' ; } break; } ComHandler { $subnode = ($node.get_ChildNodes() | Where-Object { $_.Name -eq 'ComHandler'}) if ($subnode.get_ChildNodes()| Where-Object Name -eq 'Data' | Select-Object -ExpandProperty InnerText) { '{0} {1}'-f ($subnode.get_ChildNodes() | Where-Object Name -eq 'ClassId' | Select-Object -ExpandProperty '#text'), ($subnode.get_ChildNodes() | Where-Object Name -eq 'Data' | Select-Object -ExpandProperty InnerText); } else { $subnode.get_ChildNodes() | Where-Object Name -eq 'ClassId' | Select-Object -ExpandProperty '#text'; } break; } default {} } } @{ Path = (Join-Path -Path "$($env:systemroot)\system32\Tasks" -ChildPath "$($_.Path)\$($_.Name)") ; Item = $_.Name Value = $Value ; Category = 'Task' ; } } #endregion Scheduled Tasks } if ($All -or $Winlogon) { Write-Verbose -Message 'Looking for Winlogon entries' #region Winlogon $Category = @{ Category = 'Winlogon'} Get-RegValue -Path 'HKLM:\SYSTEM\Setup' -Name 'CmdLine' @Category 'Credential Providers','Credential Provider Filters','PLAP Providers' | ForEach-Object { $key = Join-Path -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication' -ChildPath $_ (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { @{ Path = $key Item = $_ Value = (Get-ItemProperty -Path (Join-Path -Path 'HKLM:\SOFTWARE\Classes\CLSID' -ChildPath "$($_)\InprocServer32") -Name '(default)' -ErrorAction SilentlyContinue).'(default)' Category = 'Winlogon' } } } <# # deprecated 'System','SaveDumpStart' | ForEach-Object { Get-RegValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Name $_ @Category } #> # Notify doesn't exist on Windows 8.1 <# # deprecated if (Test-Path -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify' -PathType Container) { $key = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify' (Get-Item -Path $key).GetSubKeyNames() | ForEach-Object -Process { Get-RegValue -Path "$key\$($_)" -Name 'DLLName' @Category } } #> if (Test-Path -Path 'HKLM:\System\CurrentControlSet\Control\BootVerificationProgram' -PathType Container) { Get-RegValue -Path 'HKLM:\System\CurrentControlSet\Control\BootVerificationProgram' -Name 'ImagePath' @Category } #endregion Winlogon #region User Winlogon Get-RegValue -Path 'HKCU:\SOFTWARE\Policies\Microsoft\Windows\Control Panel\Desktop' -Name 'Scrnsave.exe' @Category Get-RegValue -Path 'HKCU:\Control Panel\Desktop' -Name 'Scrnsave.exe' @Category #endregion User Winlogon } if ($All -or $WMI) { Write-Verbose -Message 'Looking for WMI Database entries' # Temporary events created with Register-CimIndicationEvent or Register-WMIEvent <# Get-EventSubscriber -ErrorAction SilentlyContinue | ForEach-Object -Process { $job = $_ | Select-Object -ExpandProperty Action if ($job.Command) { Write-Warning -Message 'A temporary WMI Event subscription was found' } } #> # Permanent events Get-WMIObject -Namespace root\Subscription -Class __EventConsumer -ErrorAction SilentlyContinue| Where-Object { $_.__CLASS -eq 'ActiveScriptEventConsumer' } | ForEach-Object { if ($_.ScriptFileName) { @{ Path = $_.__PATH ; Item = $_.Name Value = $_.ScriptFileName ; Category = 'WMI' ; } } elseif ($_.ScriptText) { @{ Path = $_.__PATH ; Item = $_.Name Value = $null ; Category = 'WMI' ; } } } Get-WMIObject -Namespace root\Subscription -Class __EventConsumer -ErrorAction SilentlyContinue| Where-Object { $_.__CLASS -eq 'CommandlineEventConsumer' } | ForEach-Object { @{ Path = $_.__PATH ; Item = $_.Name Value = "$($_.WorkingDirectory)$($_.ExecutablePath)" ;# $($_.CommandLineTemplate)" ; Category = 'WMI' ; } } # List recursiveley registered and resolved WMI providers Get-WmiObject -Namespace root -Recurse -Class __Provider -List -ErrorAction SilentlyContinue | ForEach-Object { Get-WmiObject -Namespace $_.__NAMESPACE -Class $_.__CLASS -ErrorAction SilentlyContinue | ForEach-Object { Write-Verbose -Message "Found provider clsid $($_.CLSID) from under the $($_.__NAMESPACE) namespace" if (($clsid = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Classes\CLSID\$($_.CLSID)\InprocServer32" -Name '(default)' -ErrorAction SilentlyContinue).'(default)')) { @{ Path = $_.__PATH ; Item = $_.Name Value = $clsid Category = 'WMI' ; } } } } } } End { } } Function Get-PSPrettyAutorun { [CmdletBinding()] Param( [Parameter(Mandatory,ValueFromPipeLine)] [system.object[]]$RawAutoRun ) Begin {} Process { $RawAutoRun | ForEach-Object { $Item = $_ Switch ($Item.Category) { Task { Write-Verbose -Message "Reading Task $($Item.Path)" $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( Switch -Regex ($Item.Value ) { #GUID '^(\{)?[A-Za-z0-9]{4}([A-Za-z0-9]{4}\-?){4}[A-Za-z0-9]{12}(\})?' { # $clsid = ($_ -split '\s')[0] $clsid = ([system.guid]::Parse( ($_ -split '\s')[0])).ToString('B') if (Test-Path (Join-Path -Path 'HKLM:\SOFTWARE\Classes\CLSID' -ChildPath "$($clsid)\InprocServer32") -PathType Container) { Write-Verbose -Message 'Reading from InprocServer32' (Get-ItemProperty -Path (Join-Path -Path 'HKLM:\SOFTWARE\Classes\CLSID' -ChildPath "$($clsid)\InprocServer32") -Name '(default)' -ErrorAction SilentlyContinue).'(default)' } elseif (Test-Path (Join-Path -Path 'HKLM:\SOFTWARE\Classes\CLSID' -ChildPath "$($clsid)\LocalServer32") -PathType Container) { Write-Verbose -Message 'Reading from LocalServer32' (Get-ItemProperty -Path (Join-Path -Path 'HKLM:\SOFTWARE\Classes\CLSID' -ChildPath "$($clsid)\LocalServer32") -Name '(default)' -ErrorAction SilentlyContinue).'(default)' } else { try { Write-Verbose -Message 'Reading from AppID' # $appid = (Get-ItemProperty -Path (Join-Path -Path 'HKLM:\SOFTWARE\Classes\CLSID' -ChildPath "$($clsid)") -Name 'AppId' -ErrorAction Stop).'AppId' "$($env:systemroot)\system32\sc.exe" } catch { # Write-Warning -Message "AppId not found for $clsid" } } break } # Rundll32 '^((%windir%|%(s|S)ystem(r|R)oot%)\\system32\\)?rundll32\.exe\s(/[a-z]\s)?.*,.*' { Join-Path -Path "$($env:systemroot)\system32" -ChildPath ( @([regex]'^((%windir%|%(s|S)ystem(r|R)oot%)\\system32\\)?rundll32\.exe\s(/[a-z]\s)?(%windir%\\system32\\)?(?.*),').Matches($_) | Select-Object -Expand Groups | Select-Object -Last 1 | Select-Object -ExpandProperty Value ) break } # Windir\system32 '^(%windir%|%(s|S)ystem(r|R)oot%|C:\\[Ww][iI][nN][dD][oO][Ww][sS])\\(s|S)ystem32\\.*\.(exe|vbs)' { Join-Path -Path "$($env:systemroot)\system32" -ChildPath ( @([regex]'^(%windir%|%(s|S)ystem(r|R)oot%|C:\\[Ww][iI][nN][dD][oO][Ww][sS])\\(s|S)ystem32\\(?.*\.(exe|vbs))(\s)?').Matches($_) | Select-Object -Expand Groups | Select-Object -Last 1 | Select-Object -ExpandProperty Value ) break } # windir\somethingelse '^(%windir%|%(s|S)ystem(r|R)oot%|C:\\[Ww][iI][nN][dD][oO][Ww][sS])\\.*\\.*\.(exe|vbs)' { Join-Path -Path "$($env:systemroot)" -ChildPath ( @([regex]'^(%windir%|%(s|S)ystem(r|R)oot%|C:\\[Ww][iI][nN][dD][oO][Ww][sS])\\(?.*\\.*\.(exe|vbs))(\s)?').Matches($_) | Select-Object -Expand Groups | Select-Object -Last 1 | Select-Object -ExpandProperty Value ) break } # special W7 case with media center '^%SystemRoot%\\ehome\\.*\s' { # "$($env:systemroot)\ehome\ehrec.exe" Join-Path -Path "$($env:systemroot)\ehome" -ChildPath "$( @([regex]'^%SystemRoot%\\ehome\\(?.*)\s').Matches($_) | Select-Object -Expand Groups | Select-Object -Last 1 | Select-Object -ExpandProperty Value ).exe" break } # ProgramFiles '^"?(C:\\Program\sFiles|%ProgramFiles%)\\' { Join-Path -Path "$($env:ProgramFiles)" -ChildPath ( @([regex]'^"?(C:\\Program\sFiles|%ProgramFiles%)\\(?.*\.exe)("|\s)?').Matches($_) | Select-Object -Expand Groups | Select-Object -Last 1 | Select-Object -ExpandProperty Value ) break } # ProgramFilesx86 '^"?(C:\\Program\sFiles\s\(x86\)|%ProgramFiles\(x86\)%)\\' { Join-Path -Path "$(${env:ProgramFiles(x86)})" -ChildPath ( @([regex]'^"?(C:\\Program\sFiles\s\(x86\)|%ProgramFiles\(x86\)%)\\(?.*\.exe)("|\s)?').Matches($_) | Select-Object -Expand Groups | Select-Object -Last 1 | Select-Object -ExpandProperty Value ) break } # special powershell.exe '^[pP][oO][wW][eE][rR][sS][hH][eE][lL]{2}\.[eE][xX][eE](\s)?' { "$($env:systemroot)\system32\WindowsPowerShell\v1.0\powershell.exe" break } # C:\users? '^[A-Za-z]:\\' { $_ break; } # FileName.exe '[a-zA-Z0-9]*\.exe(\s)?' { # '[a-zA-Z0-9]*(\.exe\s)?' { Join-Path -Path "$($env:systemroot)\system32" -ChildPath "$( @([regex]'^(?[a-zA-Z0-9]*)(\.exe\s)?').Matches($_) | Select-Object -Expand Groups | Select-Object -Last 1 | Select-Object -ExpandProperty Value ).exe" break } '^aitagent(\s/increment)?' { "$($env:systemroot)\system32\aitagent.exe" break } default { $_ } } #endof switch ) -Force -PassThru break; } AppInit { if ($Item.Value -eq [string]::Empty) { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $null -Force -PassThru } else { # Switch ? malware example $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value "$($Item.Value)" -Force -PassThru } break } 'Boot Execute' { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( Switch -Regex ($Item.Value) { '^autocheck\sautochk\s' { "$($env:SystemRoot)\system32\autochk.exe" break; } default { $Item.Value } } ) -Force -PassThru break } Codecs { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( Switch -Regex ($Item.Value) { '^[A-Z]:\\Windows\\' { if ($Item.Path -match 'Wow6432Node') { $_ -replace 'system32','SysWOW64' } else { $_ } break } # '^[A-Z]:\\Program\sFiles' { '^[A-Z]:\\[Pp]rogra' { $_ | Get-NormalizedFileSystemPath break } default { if ($Item.Path -match 'Wow6432Node') { Join-Path "$($env:systemroot)\Syswow64" -ChildPath $_ } else { Join-Path "$($env:systemroot)\System32" -ChildPath $_ } } } ) -Force -PassThru break } Drivers { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( switch -Regex ($Item.Value) { #'^\\SystemRoot\\System32\\drivers\\' { '^\\SystemRoot\\System32\\' { $_ -replace '\\Systemroot',"$($env:systemroot)" break; } <# '^System32\drivers\\' { Join-Path -Path "$($env:systemroot)" -ChildPath $_ break; } #> '^System32\\[dD][rR][iI][vV][eE][rR][sS]\\' { Join-Path -Path "$($env:systemroot)" -ChildPath $_ break; } <# '^system32\\DRIVERS\\' { Join-Path -Path "$($env:systemroot)" -ChildPath $_ break; } #> '^\\\?\?\\C:\\Windows\\system32\\drivers' { $_ -replace '\\\?\?\\','' break; } '^System32\\CLFS\.sys' { $_ -replace 'System32\\',"$($env:systemroot)\system32\" } '^"?[A-Za-z]\\[Pp]rogram\s[fF]iles.*\\(?.*\\\.exe)\s?' { Join-Path -Path "$($env:ProgramFiles)" -ChildPath ( @([regex]'^"?[A-Za-z]\\[Pp]rogram\s[fF]iles.*\\(?.*\\\.exe)\s?').Matches($_) | Select-Object -Expand Groups | Select-Object -Last 1 | Select-Object -ExpandProperty Value ) break } 'SysmonDrv.sys' { $env:PATH -split ';'| ForEach-Object { Get-ChildItem -Path $_\*.sys -Include SysmonDrv.sys -Force -EA 0 } | Select-Object -First 1 -ExpandProperty FullName break } default { $_ } }) -Force -PassThru break } Explorer { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( if ($Item.Value) { if ($Item.Value -match '^[A-Z]:\\') { if ($Item.Path -match 'Wow6432Node') { $Item.Value -replace 'system32','syswow64' | Get-NormalizedFileSystemPath } else { $Item.Value | Get-NormalizedFileSystemPath } } else { if ($Item.Path -match 'Wow6432Node') { Join-Path -Path "$($env:systemroot)\syswow64" -ChildPath $Item.Value } else { Join-Path -Path "$($env:systemroot)\system32" -ChildPath $Item.Value } } } ) -Force -PassThru break } 'Image Hijacks' { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $null -Force -PassThru break } 'Internet Explorer' { if ($Item.Item -ne 'Locked') { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( $Item.Value | Get-NormalizedFileSystemPath ) -Force -PassThru } break } 'Known Dlls' { if ( (Test-Path -Path $Item.Value -PathType Container) -and ($Item.Item -match 'DllDirectory')) { } else { # Duplicate objects $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( Join-Path -Path "$($env:SystemRoot)\System32" -ChildPath $Item.Value ) -Force -PassThru if ([environment]::Is64BitOperatingSystem) { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( Join-Path -Path "$($env:SystemRoot)\Syswow64" -ChildPath $Item.Value ) -Force -PassThru } } break } Logon { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( switch -Regex ($Item.Value) { '\\Rundll32\.exe\s' { (($_ -split '\s')[1] -split ',')[0] break; } '\\Rundll32\.exe"' { (($_ -split '\s',2)[1] -split ',')[0] -replace '"','' break; } '^"[A-Z]:\\Program' { ($_ -split '"')[1] break; } '^"[A-Z]:\\Windows' { ($_ -split '"')[1] break; } 'rdpclip' { "$($env:SystemRoot)\system32\$($_).exe" break } '^Explorer\.exe$' { "$($env:SystemRoot)\$($_)" break } # regsvr32.exe /s /n /i:U shell32.dll '^regsvr32\.exe\s/s\s/n\s/i:U\sshell32\.dll' { if ($Item.Path -match 'Wow6432Node') { "$($env:SystemRoot)\syswow64\shell32.dll" }else { "$($env:SystemRoot)\system32\shell32.dll" } break } '^C:\\Windows\\system32\\regsvr32\.exe\s/s\s/n\s/i:/UserInstall\sC:\\Windows\\system32\\themeui\.dll' { if ($Item.Path -match 'Wow6432Node') { "$($env:SystemRoot)\syswow64\themeui.dll" }else { "$($env:SystemRoot)\system32\themeui.dll" } break } '^C:\\Windows\\system32\\cmd\.exe\s/D\s/C\sstart\sC:\\Windows\\system32\\ie4uinit\.exe\s\-ClearIconCache' { if ($Item.Path -match 'Wow6432Node') { "$($env:SystemRoot)\syswow64\ie4uinit.exe" }else { "$($env:SystemRoot)\system32\ie4uinit.exe" } break } '^[A-Z]:\\Windows\\' { if ($Item.Path -match 'Wow6432Node') { (($_ -split '\s')[0] -replace ',','') -replace 'System32','Syswow64' } else { (($_ -split '\s')[0] -replace ',','') } break } '^[a-zA-Z0-9]+\.(exe|dll)' { if ($Item.Path -match 'Wow6432Node') { Join-Path -Path "$($env:SystemRoot)\syswow64" -ChildPath ($_ -split '\s')[0] } else { Join-Path -Path "$($env:SystemRoot)\system32" -ChildPath ($_ -split '\s')[0] } break } '^RunDLL32\s' { Join-Path -Path "$($env:SystemRoot)\system32" -ChildPath (($_ -split '\s')[1] -split ',')[0] break; } # ProgramFiles '^[A-Za-z]:\\Program\sFiles\\' { Join-Path -Path "$($env:ProgramFiles)" -ChildPath ( @([regex]'[A-Za-z]:\\Program\sFiles\\(?.*\.exe)\s?').Matches($_) | Select-Object -Expand Groups | Select-Object -Last 1 | Select-Object -ExpandProperty Value ) break } # ProgramFilesx86 '^[A-Za-z]:\\Program\sFiles\s\(x86\)\\' { Join-Path -Path "$(${env:ProgramFiles(x86)})" -ChildPath ( @([regex]'[A-Za-z]:\\Program\sFiles\s\(x86\)\\(?.*\.exe)\s?').Matches($_) | Select-Object -Expand Groups | Select-Object -Last 1 | Select-Object -ExpandProperty Value ) break } # C:\Users '^"[A-Za-z]:\\' { ($_ -split '"')[1] break; } default { Write-Verbose -Message "default: $_" [string]::Empty # $_ } } ) -Force -PassThru break } 'LSA Providers' { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( if ($Item.Value -match '\.dll$') { Join-Path -Path "$($env:SystemRoot)\system32" -ChildPath $Item.Value } else { Join-Path -Path "$($env:SystemRoot)\system32" -ChildPath "$($Item.Value).dll" } ) -Force -PassThru break } 'Network Providers' { $Item | Add-Member -MemberType ScriptProperty -Name ImagePath -Value $({$this.Value}) -Force -PassThru } 'Office Addins' { if ($Item.Path -match 'Wow6432Node' -and $Item.Value -imatch 'system32') { $Item.Value = $Item.Value -replace 'system32','syswow64' } if ($Item.Value) { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( Switch -Regex ($Item.Value ) { #GUID '^(\{)?[A-Za-z0-9]{4}([A-Za-z0-9]{4}\-?){4}[A-Za-z0-9]{12}(\})?' { ([system.guid]::Parse( ($_ -split '\s')[0])).ToString('B') break } default { $Item.Value -replace '"','' | Get-NormalizedFileSystemPath } } ) -Force -PassThru } break } 'Print Monitors' { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( Join-Path -Path "$($env:SystemRoot)\System32" -ChildPath $Item.Value ) -Force -PassThru break } Services { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( switch -Regex ($Item.Value) { '^"?[A-Za-z]:\\[Ww][iI][nN][dD][oO][Ww][sS]\\' { Join-Path -Path "$($env:systemroot)" -ChildPath ( @([regex]'^"?[A-Za-z]:\\[Ww][iI][nN][dD][oO][Ww][sS]\\(?.*\.(exe|dll))\s?').Matches($_) | Select-Object -Expand Groups | Select-Object -Last 1 | Select-Object -ExpandProperty Value ) break } '^"?[A-Za-z]:\\[Pp]rogram\s[fF]iles\\(?.*\.[eE][xX][eE])\s?' { Join-Path -Path "$($env:ProgramFiles)" -ChildPath ( @([regex]'^"?[A-Za-z]:\\[Pp]rogram\s[fF]iles\\(?.*\.[eE][xX][eE])\s?').Matches($_) | Select-Object -Expand Groups | Select-Object -Last 1 | Select-Object -ExpandProperty Value ) break } '^"?[A-Za-z]:\\[Pp]rogram\s[fF]iles\s\(x86\)\\(?.*\.[eE][xX][eE])\s?' { Join-Path -Path "$(${env:ProgramFiles(x86)})" -ChildPath ( @([regex]'^"?[A-Za-z]:\\[Pp]rogram\s[fF]iles\s\(x86\)\\(?.*\.[eE][xX][eE])\s?').Matches($_) | Select-Object -Expand Groups | Select-Object -Last 1 | Select-Object -ExpandProperty Value ) break } 'winhttp.dll' { Join-Path -Path "$($env:SystemRoot)\System32" -ChildPath 'winhttp.dll' break } 'atmfd.dll' { Join-Path -Path "$($env:SystemRoot)\System32" -ChildPath 'atmfd.dll' break } default { $_ } }) -Force -PassThru break } Winlogon { # this works on W8.1 # $Item | Add-Member -MemberType ScriptProperty -Name ImagePath -Value $({$this.Value}) -Force -PassThru # for backward compatibility with W7 we do: $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( Switch -Regex ($Item.Value) { '^[a-zA-Z0-9]*\.[dDlL]{3}' { Join-Path -Path "$($env:SystemRoot)\System32" -ChildPath $Item.Value break } default { $_; } } ) -Force -PassThru break } 'Winsock Providers' { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $( Switch -Regex ($Item.Value) { '^%SystemRoot%\\system32\\' { $_ -replace '%SystemRoot%',"$($env:SystemRoot)"; break; } default { $_; } } ) -Force -PassThru break } WMI { if ($Item.Value) { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $($Item.Value) -Force -PassThru } else { $Item | Add-Member -MemberType NoteProperty -Name ImagePath -Value $null -Force -PassThru } break } default { } } } } End {} } Function Add-PSAutoRunExtendedInfo { [CmdletBinding()] Param( [Parameter(Mandatory,ValueFromPipeLine)] [system.object[]]$RawAutoRun ) Begin {} Process { $RawAutoRun | ForEach-Object { $o = [pscustomobject]@{ Path = $_.Path ; Item = $_.Item ; Category = $_.Category ; Value = $_.Value ImagePath = $_.ImagePath ; Size = $null; LastWriteTime = $null; Version = $null; } If ($_.ImagePath) { try { $extinfo = Get-Item -Path $_.ImagePath -ErrorAction Stop $o.Size = $extinfo.Length; $o.Version = $extinfo.VersionInfo.ProductVersion; $o.LastWriteTime = $extinfo.LastWriteTime; $o } catch { $o } } else { $o } } } End{} } Function Add-PSAutoRunHash { [CmdletBinding()] Param( [Parameter(Mandatory,ValueFromPipeLine)] [system.object[]]$RawAutoRun, [Switch]$ShowFileHash ) Begin {} Process { $RawAutoRun | ForEach-Object { If ($ShowFileHash) { if ($_.ImagePath) { If (Test-Path -Path $($_.ImagePath) -PathType Leaf) { $_ | Add-Member -MemberType NoteProperty -Name MD5 -Value $( (Get-FileHash -Path $($_.ImagePath) -Algorithm MD5).Hash ) -Force -PassThru | Add-Member -MemberType NoteProperty -Name SHA1 -Value $( (Get-FileHash -Path $($_.ImagePath) -Algorithm SHA1).Hash ) -Force -PassThru | Add-Member -MemberType NoteProperty -Name SHA256 -Value $( (Get-FileHash -Path $($_.ImagePath) -Algorithm SHA256).Hash ) -Force -PassThru } else { $_ | Add-Member -MemberType NoteProperty -Name MD5 -Value $null -Force -PassThru | Add-Member -MemberType NoteProperty -Name SHA1 -Value $null -Force -PassThru | Add-Member -MemberType NoteProperty -Name SHA256 -Value $null -Force -PassThru } } else { $_ | Add-Member -MemberType NoteProperty -Name MD5 -Value $null -Force -PassThru | Add-Member -MemberType NoteProperty -Name SHA1 -Value $null -Force -PassThru | Add-Member -MemberType NoteProperty -Name SHA256 -Value $null -Force -PassThru } } else { $_ } } } End {} } Function Add-PSAutoRunAuthentiCodeSignature { [CmdletBinding()] Param( [Parameter(Mandatory,ValueFromPipeLine)] [system.object[]]$RawAutoRun, [Switch]$VerifyDigitalSignature ) Begin {} Process { $RawAutoRun | ForEach-Object { If ($VerifyDigitalSignature) { if ($_.ImagePath) { If (Test-Path -Path $_.ImagePath -PathType Leaf) { ## Add the signature status to the entry $signature = Get-AuthenticodeSignature -FilePath $_.ImagePath -ErrorAction Stop $signed = switch ($signature.Status) { 'Valid' { $true break } 'NotSigned' { $false break } default { $false } } $_ = $_ | Add-Member -MemberType NoteProperty -Name Signed -Value $signed -Force -PassThru ## Add a note whether this is an OS binary to allow for easy filtering: ## Get-PSAutorun -VerifyDigitalSignature | ? { -not $_.IsOSBinary } if($signature.IsOSBinary) { $_ = $_ | Add-Member -MemberType NoteProperty -Name IsOSBinary -Value $signature.IsOSBinary -Force -PassThru } ## Add the signer itself $_ | Add-Member -MemberType NoteProperty -Name Publisher -Value $signature.SignerCertificate.Subject -Force -PassThru } } else { $_ = $_ | Add-Member -MemberType NoteProperty -Name Signed -Value $null -Force -PassThru $_ = $_ | Add-Member -MemberType NoteProperty -Name IsOSBinary -Value $null -Force -PassThru $_ | Add-Member -MemberType NoteProperty -Name Publisher -Value $null -Force -PassThru } } else { $_ } } } End{} } #endregion Helperfunctions } Process { if ($PSBoundParameters.ContainsKey('ShowFileHash')) { $GetHash = $true } else { $GetHash = $false } if ($PSBoundParameters.ContainsKey('VerifyDigitalSignature')) { $GetSig = $true } else { $GetSig = $false } Get-PSRawAutoRun @PSBoundParameters | Get-PSPrettyAutorun | Add-PSAutoRunExtendedInfo | Add-PSAutoRunHash -ShowFileHash:$GetHash | Add-PSAutoRunAuthentiCodeSignature -VerifyDigitalSignature:$GetSig } End {} } <# Get-PSAutorun -BootExecute -AppinitDLLs Get-PSAutorun -All | Format-Table -Property Path,ImagePath,Category Get-PSAutorun -Logon -LSAsecurityProviders | Format-Table -Property Path,ImagePath,Category Get-PSAutorun -All -ShowFileHash -VerifyDigitalSignature Get-PSAutorun -ServicesAndDrivers | ? path -match 'OSE' | fl * Get-PSAutorun -ServicesAndDrivers | ? path -match 'sysmon' | fl * Get-PSAutorun -ServicesAndDrivers | ? path -match 'psexesvc' | fl * Get-PSAutorun -OfficeAddins | Format-Table -Property Path,ImagePath,Category Get-PSAutorun -WMI -VerifyDigitalSignature | Where { -not $_.isOSBinary } # From 11.70 to 12.0 +HKLM\SYSTEM\CurrentControlSet\Control\Lsa\OSConfig\Security Packages +WMI Database Entries # From 12.0 to 12.3 -HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\System -HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify -HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SaveDumpStart +HKCU\SOFTWARE\Classes\Htmlfile\Shell\Open\Command\(Default) +HKLM\SOFTWARE\Classes\Htmlfile\Shell\Open\Command\(Default) # From 12.3 to 13.4 +HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GpExtensions +HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\AlternateShells\AvailableShells +HKCU\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run +HKCU\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce +HKCU\Software\Classes\Clsid\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}\Inprocserver32 +Office Addins # From 13.4 to 13.5 +HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Font Drivers # From 13.5 to 13.51 +HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\RunonceEx +HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx +HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnceEx +HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx +HKCU\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnceEx +HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\RunonceEx # From 13.51 to 13.61 +HKLM\SOFTWARE\Microsoft\Office test\Special\Perf\(Default) +HKCU\SOFTWARE\Microsoft\Office test\Special\Perf\(Default) # From 13.61 to 13.62 +HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Security Packages # From 13.62 to 13.7 +HKLM\SYSTEM\CurrentControlSet\Control\Print\Providers #> ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-PSIProcess.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-PSIProcess -ReturnHashtables)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'Process') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'Process' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) Write-Output $body #Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-PSIProcess { <# .SYNOPSIS Returns detailed information about the current running processes. Author: Lee Christensen (@tifkin_) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None #> [CmdletBinding()] Param ( [switch] $ReturnHashtables ) # TODO: Optimize this cmdlet... begin { # Thanks to https://p0w3rsh3ll.wordpress.com/2015/02/05/backporting-the-get-filehash-function/ function Get-DIGSFileHash { [CmdletBinding(DefaultParameterSetName = "Path")] param ( [Parameter(Mandatory=$true, ParameterSetName="Path", Position = 0)] [System.String[]] $Path, [Parameter(Mandatory=$true, ParameterSetName="LiteralPath", ValueFromPipelineByPropertyName = $true)] [Alias("PSPath")] [System.String[]] $LiteralPath, [Parameter(Mandatory=$true, ParameterSetName="Stream")] [System.IO.Stream] $InputStream, [ValidateSet("SHA1", "SHA256", "SHA384", "SHA512", "MACTripleDES", "MD5", "RIPEMD160")] [System.String] $Algorithm="SHA256" ) begin { # Construct the strongly-typed crypto object $hasher = [System.Security.Cryptography.HashAlgorithm]::Create($Algorithm) } process { if($PSCmdlet.ParameterSetName -eq "Stream") { Get-DIGSStreamHash -InputStream $InputStream -RelatedPath $null -Hasher $hasher } else { $pathsToProcess = @() if($PSCmdlet.ParameterSetName -eq "LiteralPath") { $pathsToProcess += Resolve-Path -LiteralPath $LiteralPath | Foreach-Object { $_.ProviderPath } } if($PSCmdlet.ParameterSetName -eq "Path") { $pathsToProcess += Resolve-Path $Path | Foreach-Object { $_.ProviderPath } } foreach($filePath in $pathsToProcess) { if(Test-Path -LiteralPath $filePath -PathType Container) { continue } try { # Read the file specified in $FilePath as a Byte array [system.io.stream]$stream = [system.io.file]::OpenRead($filePath) Get-DIGSStreamHash -InputStream $stream -RelatedPath $filePath -Hasher $hasher } catch [Exception] { $errorMessage = 'FileReadError {0}:{1}' -f $FilePath, $_ Write-Error -Message $errorMessage -Category ReadError -ErrorId "FileReadError" -TargetObject $FilePath return } finally { if($stream) { $stream.Close() } } } } } } function Get-DIGSStreamHash { param ( [System.IO.Stream] $InputStream, [System.String] $RelatedPath, [System.Security.Cryptography.HashAlgorithm] $Hasher ) # Compute file-hash using the crypto object [Byte[]] $computedHash = $Hasher.ComputeHash($InputStream) [string] $hash = [BitConverter]::ToString($computedHash) -replace '-','' if ($RelatedPath -eq $null) { $retVal = [PSCustomObject] @{ Algorithm = $Algorithm.ToUpperInvariant() Hash = $hash } $retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash") $retVal } else { $retVal = [PSCustomObject] @{ Algorithm = $Algorithm.ToUpperInvariant() Hash = $hash Path = $RelatedPath } $retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash") $retVal } } $FileHashCache = @{} $Processes = Get-WmiObject -Class Win32_Process function Get-DIGSCachedFileHash { param ( [string] $File ) if($FileHashCache[$File]) { $FileHashCache[$File] } else { if($File -and (Test-Path $File)) { $ModuleMD5 = (Get-DIGSFileHash -Path $File -Algorithm MD5).Hash $ModuleSHA256 = (Get-DIGSFileHash -Path $File -Algorithm SHA256).Hash $FileHashCache[$File] = New-Object PSObject -Property @{ MD5 = $ModuleMD5 SHA256 = $ModuleSHA256 } $FileHashCache[$File] } } } } process { foreach($Process in $Processes) { $Proc = Get-Process -Id $Process.ProcessId -ErrorAction SilentlyContinue $Path = $Proc.Path $LoadedModules = $null $Owner = $null $OwnerStr = $null if($Proc) { #$PE = Get-PE -ModuleBaseAddress $Proc.MainModule.BaseAddress -ProcessID $Process.ProcessId $Proc.Modules | ForEach-Object { if($_) { $ModuleHash = Get-DIGSCachedFileHash -File $_.FileName $_ | Add-Member NoteProperty -Name "MD5Hash" -Value $ModuleHash.MD5 $_ | Add-Member NoteProperty -Name "SHA256Hash" -Value $ModuleHash.SHA256 } } $LoadedModules = $Proc.Modules } # Get file information $FileHash = $null if($Path -ne $null -and (Test-Path $Path)) { # TODO: Add error handling here in case we can't read the file (wonky exe permissions) $FileHash = Get-DIGSCachedFileHash -File $Path $File = (Get-ChildItem $Path) $FileSize = $File.Length $FileCreationTime = $File.CreationTimeUtc $FileLastAccessTime = $File.LastAccessTimeUtc $FileLastWriteTime = $File.LastWriteTimeUtc $FileExtension = $File.Extension $ProcessId = $Process.ProcessId } else { if($Proc.Id -ne 0 -and $Proc.Id -ne 4) { #Write-Warning "Could not find executable path. PSProcessName: $($Proc.Name) PSPid: $($Proc.Id) WMIProcName: $($Process.Name) WMIPid: $($Process.ProcessId)" } $Path = '' } # Get the process owner $NTVersion = [System.Environment]::OSVersion.Version try { if($NTVersion.Major -ge 6) { $Owner = $Process.GetOwner() if($Owner -and ($Owner.Domain -or $Owner.User)) { $OwnerStr = "$($Owner.Domain)\$($Owner.User)" } $OwnerObj = $Process.GetOwnerSid() if($OwnerObj) { $OwnerSid = $OwnerObj.Sid } } } catch {} $LoadedModuleList = $LoadedModules | sort ModuleName | select -ExpandProperty ModuleName $ParentProcess = Get-Process -Id $Process.ProcessId -ErrorAction SilentlyContinue $ErrorActionPreference = 'Stop' $Output = @{ Name = $Process.Name Path = [string]$Process.Path CommandLine = $Process.CommandLine MD5Hash = $FileHash.MD5 SHA256Hash = $FileHash.SHA256 FileSize = $FileSize FileCreationTime = $FileCreationTime FileLastAccessTime = $FileLastAccessTime FileLastWriteTime = $FileLastWriteTime FileExtension = $FileExtension Owner = $OwnerStr OwnerSid = $OwnerSid ParentProcessId = $Process.ParentProcessID ParentProcessName = $ParentProcess.Name ProcessId = $ProcessId ## PE = $PE #LoadedModules = $LoadedModules | select * LoadedModulesList = ($LoadedModuleList -join ";").ToLower() } try { $null = ConvertTo-JsonV2 $Output } catch { Write-Error $_ } if($ReturnHashtables) { $Output } else { New-Object PSObject -Property $Output } } } end { } } Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey hash.siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-PSIScheduledTask.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-PSIScheduledTask -ReturnHashtables)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'ScheduledTask') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'ScheduledTask' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) Write-Host $body Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-PSIScheduledTask { <# .SYNOPSIS Returns detailed information about scheduled tasks. Author: Lee Christensen (@tifkin_), Jared Atkinson License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None #> [CmdletBinding()] Param ( [switch] $ReturnHashtables ) begin { # Based on Get-ScheduledTask in the Windows 7 Resource Kit PowerShell Pack function Get-DIGSScheduledTaskData { <# .Synopsis Gets tasks scheduled on the computer .Description Gets scheduled tasks that are registered on a computer .Example Get-ScheduleTask -Recurse #> param( # The name or name pattern of the scheduled task [Parameter()] $Name = "*", # The folder the scheduled task is in [Parameter()] [String[]] $Folder = "", # If this is set, hidden tasks will also be shown. # By default, only tasks that are not marked by Task Scheduler as hidden are shown. [Switch] $Hidden, # The name of the computer to connect to. $ComputerName, # The credential used to connect [Management.Automation.PSCredential] $Credential, # If set, will get tasks recursively beneath the specified folder [switch] $Recurse ) process { $scheduler = New-Object -ComObject Schedule.Service if ($Credential) { $NetworkCredential = $Credential.GetNetworkCredential() $scheduler.Connect($ComputerName, $NetworkCredential.UserName, $NetworkCredential.Domain, $NetworkCredential.Password) } else { $scheduler.Connect($ComputerName) } $taskFolder = $scheduler.GetFolder($folder) $taskFolder.GetTasks($Hidden -as [bool]) | Where-Object { $_.Name -like $name } if ($Recurse) { $taskFolder.GetFolders(0) | ForEach-Object { $psBoundParameters.Folder = $_.Path Get-DIGSScheduledTaskData @psBoundParameters } } } } # Thanks to https://p0w3rsh3ll.wordpress.com/2015/02/05/backporting-the-get-filehash-function/ function Get-DIGSFileHash { [CmdletBinding(DefaultParameterSetName = "Path")] param( [Parameter(Mandatory=$true, ParameterSetName="Path", Position = 0)] [System.String[]] $Path, [Parameter(Mandatory=$true, ParameterSetName="LiteralPath", ValueFromPipelineByPropertyName = $true)] [Alias("PSPath")] [System.String[]] $LiteralPath, [Parameter(Mandatory=$true, ParameterSetName="Stream")] [System.IO.Stream] $InputStream, [ValidateSet("SHA1", "SHA256", "SHA384", "SHA512", "MACTripleDES", "MD5", "RIPEMD160")] [System.String] $Algorithm="SHA256" ) begin { # Construct the strongly-typed crypto object $hasher = [System.Security.Cryptography.HashAlgorithm]::Create($Algorithm) } process { if($PSCmdlet.ParameterSetName -eq "Stream") { Get-DIGSStreamHash -InputStream $InputStream -RelatedPath $null -Hasher $hasher } else { $pathsToProcess = @() if($PSCmdlet.ParameterSetName -eq "LiteralPath") { $pathsToProcess += Resolve-Path -LiteralPath $LiteralPath | Foreach-Object { $_.ProviderPath } } if($PSCmdlet.ParameterSetName -eq "Path") { $pathsToProcess += Resolve-Path $Path | Foreach-Object { $_.ProviderPath } } foreach($filePath in $pathsToProcess) { if(Test-Path -LiteralPath $filePath -PathType Container) { continue } try { # Read the file specified in $FilePath as a Byte array [system.io.stream]$stream = [system.io.file]::OpenRead($filePath) Get-DIGSStreamHash -InputStream $stream -RelatedPath $filePath -Hasher $hasher } catch [Exception] { $errorMessage = 'FileReadError {0}:{1}' -f $FilePath, $_ Write-Error -Message $errorMessage -Category ReadError -ErrorId "FileReadError" -TargetObject $FilePath return } finally { if($stream) { $stream.Close() } } } } } } function Get-DIGSStreamHash { param( [System.IO.Stream] $InputStream, [System.String] $RelatedPath, [System.Security.Cryptography.HashAlgorithm] $Hasher) # Compute file-hash using the crypto object [Byte[]] $computedHash = $Hasher.ComputeHash($InputStream) [string] $hash = [BitConverter]::ToString($computedHash) -replace '-','' if ($RelatedPath -eq $null) { $retVal = [PSCustomObject] @{ Algorithm = $Algorithm.ToUpperInvariant() Hash = $hash } $retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash") $retVal } else { $retVal = [PSCustomObject] @{ Algorithm = $Algorithm.ToUpperInvariant() Hash = $hash Path = $RelatedPath } $retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash") $retVal } } function Get-ClassID { param($ClassId) $Value = Get-ItemProperty "HKLM:\Software\Classes\CLSID\$($ClassId)\InprocServer32" -Name "(Default)" -ErrorAction SilentlyContinue if($Value) { $Value.'(Default)' } else { '' } } } process { $Tasks = Get-DIGSScheduledTaskData -Recurse foreach($Task in $Tasks) { $ActionComClassId = $null $ActionComDll = $null $ActionComDllMD5 = $null $ActionComDllSHA256 = $null $ActionComData = $null $ActionExecCommand = $null $ActionExecCommandMD5 = $null $ActionExecCommandSHA256 = $null $ActionExecArguments = $null $ActionExecWorkingDirectory = $null $Xml = [Xml]$Task.Xml $ActionCom = $Xml.Task.Actions.ComHandler $ActionComDll = if($ActionCom.ClassId) { Get-ClassID ($ActionCom.ClassId)} else { $null } if($ActionComDll) { $ActionComDllMD5 = (Get-DIGSFileHash -Path $ActionComDll -Algorithm MD5).Hash $ActionComDllSHA256 = (Get-DIGSFileHash -Path $ActionComDll -Algorithm SHA256).Hash } $ActionComData = if($ActionCom.Data) { $ActionCom.Data.InnerXml} else {$null} $ActionExec = $Xml.Task.Actions.Exec if($ActionExec.Command) { $ActionExecPath = [System.Environment]::ExpandEnvironmentVariables($ActionExec.Command) $CleanedPath = $ActionExecPath.Replace("`"", "") if(Test-Path $CleanedPath -ErrorAction SilentlyContinue) { $ActionExecCommandMD5 = (Get-DIGSFileHash -Path $CleanedPath -Algorithm MD5).Hash $ActionExecCommandSHA256 = (Get-DIGSFileHash -Path $CleanedPath -Algorithm SHA256).Hash } } $Output = @{ Name = $Task.Name Path = $Task.Path Enabled = $Task.Enabled LastRunTime = $Task.LastRunTime LastTaskResult = $Task.LastTaskResult NumberOfMissedRuns = $Task.NumberOfMissedRuns NextRunTime = $Task.NextRunTime Xml = $Task.Xml ActionComClassId = $ActionCom.ClassId ActionComDll = $ActionComDll ActionComDllMD5 = $ActionComDllMd5 ActionComDllSHA256 = $ActionComDllSHA256 ActionComData = $ActionComData ActionExecCommand = $ActionExec.Command ActionExecCommandMD5 = $ActionExecCommandMD5 ActionExecCommandSHA256 = $ActionExecCommandSHA256 ActionExecArguments = $ActionExec.Arguments ActionExecWorkingDirectory = $ActionExec.WorkingDirectory } if($ReturnHashtables) { $Output } else { New-Object PSObject -Property $Output } } } end { } } Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-PSIService.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-PSIService -ReturnHashtables)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'Service') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'Service' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) Write-Host $body Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-PSIService { <# .SYNOPSIS Returns detailed service information. Author: Jared Atkinson License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None #> [CmdletBinding()] Param ( [switch] $ReturnHashtables ) Begin { function Get-PathFromCommandLine { Param ( [Parameter(Mandatory = $true)] [string] $CommandLine ) if(Test-Path -Path $CommandLine -ErrorAction SilentlyContinue) { $CommandLine } else { switch -Regex ($CommandLine) { '"\s'{ $CommandLine.Split('"')[1]; break} '\s-'{ $CommandLine.Split(' ')[0]; break} '\s/'{ $CommandLine.Split(' ')[0]; break} '"'{ $CommandLine.Split('"')[1]; break} default{ $CommandLine} } } } # Thanks to https://p0w3rsh3ll.wordpress.com/2015/02/05/backporting-the-get-filehash-function/ function Get-DIGSFileHash { [CmdletBinding(DefaultParameterSetName = "Path")] param( [Parameter(Mandatory=$true, ParameterSetName="Path", Position = 0)] [System.String[]] $Path, [Parameter(Mandatory=$true, ParameterSetName="LiteralPath", ValueFromPipelineByPropertyName = $true)] [Alias("PSPath")] [System.String[]] $LiteralPath, [Parameter(Mandatory=$true, ParameterSetName="Stream")] [System.IO.Stream] $InputStream, [ValidateSet("SHA1", "SHA256", "SHA384", "SHA512", "MACTripleDES", "MD5", "RIPEMD160")] [System.String] $Algorithm="SHA256" ) begin { # Construct the strongly-typed crypto object $hasher = [System.Security.Cryptography.HashAlgorithm]::Create($Algorithm) } process { if($PSCmdlet.ParameterSetName -eq "Stream") { Get-DIGSStreamHash -InputStream $InputStream -RelatedPath $null -Hasher $hasher } else { $pathsToProcess = @() if($PSCmdlet.ParameterSetName -eq "LiteralPath") { $pathsToProcess += Resolve-Path -LiteralPath $LiteralPath | Foreach-Object { $_.ProviderPath } } if($PSCmdlet.ParameterSetName -eq "Path") { $pathsToProcess += Resolve-Path $Path | Foreach-Object { $_.ProviderPath } } foreach($filePath in $pathsToProcess) { if(Test-Path -LiteralPath $filePath -PathType Container) { continue } try { # Read the file specified in $FilePath as a Byte array [system.io.stream]$stream = [system.io.file]::OpenRead($filePath) Get-DIGSStreamHash -InputStream $stream -RelatedPath $filePath -Hasher $hasher } catch [Exception] { $errorMessage = 'FileReadError {0}:{1}' -f $FilePath, $_ Write-Error -Message $errorMessage -Category ReadError -ErrorId "FileReadError" -TargetObject $FilePath return } finally { if($stream) { $stream.Close() } } } } } } function Get-DIGSStreamHash { param( [System.IO.Stream] $InputStream, [System.String] $RelatedPath, [System.Security.Cryptography.HashAlgorithm] $Hasher) # Compute file-hash using the crypto object [Byte[]] $computedHash = $Hasher.ComputeHash($InputStream) [string] $hash = [BitConverter]::ToString($computedHash) -replace '-','' if ($RelatedPath -eq $null) { $retVal = [PSCustomObject] @{ Algorithm = $Algorithm.ToUpperInvariant() Hash = $hash } $retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash") $retVal } else { $retVal = [PSCustomObject] @{ Algorithm = $Algorithm.ToUpperInvariant() Hash = $hash Path = $RelatedPath } $retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash") $retVal } } $hashcache = @{} $objList = New-Object -TypeName "System.Collections.Generic.List[Object]" } Process { foreach($service in (Get-WmiObject win32_service)) { if($service.PathName -ne $null) { $path = Get-PathFromCommandLine -CommandLine $service.PathName } else { $path = $null } try { if($hashcache.ContainsKey($path)) { $md5 = $hashcache[$path].MD5 $sha256 = $hashcache[$path].SHA256 } else { $md5 = Get-DIGSFileHash -Path $path -Algorithm MD5 -ErrorAction Stop $sha256 = Get-DIGSFileHash -Path $path -Algorithm SHA256 -ErrorAction Stop $obj = @{ MD5 = $md5 SHA256 = $sha256 } $hashcache.Add($path, $obj) } } catch { $md5 = $null $sha256 = $null } $Props = @{ Name = $service.Name CommandLine = $service.PathName ExecutablePath = $path ServiceType = $service.ServiceType StartMode = $service.StartMode Caption = $service.Caption Description = $service.Description DisplayName = $service.DisplayName ProcessId = $service.ProcessId Started = $service.Started User = $service.StartName MD5Hash = $md5.Hash SHA256Hash = $sha256.Hash } if($ReturnHashtables) { $Props } else { New-Object -TypeName psobject -Property $Props } } } End { } } Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-PSIWindowsSecurityEvent.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-PSIWindowsSecurityEvent -ReturnHashtables)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'WindowsSecurityEvent') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'WindowsSecurityEvent' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) Write-Host $body Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-PSIWindowsSecurityEvent { <# .SYNOPSIS Returns detailed Security Event information Author: Lee Christensen (@tifkin_) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None #> Param ( [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, Position=0)] $StartTime = [DateTime]::Now.AddDays(-1), [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, Position=1)] $EndTime = [DateTime]::Now, [switch] $ReturnHashtables ) Begin { <# *** TODO *** - service added/deleted/started - Process logging... Maybe only log interesting processes that are executed instead of grabbing all processes? - Scheduled Task creations/deletions. Runs? (Applications Services Logs\Microsoft\Windows\TaskScheduler) - Remote Desktop Connections (Applications Services Logs\Microsoft\Windows\TerminalServices-RemoteConnectionManager\Operational - EID 1149). Note this does not indicate a login. It only indicates a connection - Remote Desktop Logons/Disconnections (Applications Services Logs\Microsoft\Windows\TerminalServices-LocalSessionManager\Operational - EID 21,24). This isn't very chatty, so you could probably pull them all. - Symantec Enpoint Protection Client log - BITS Transfers (Applications Services Logs\Microsoft\Windows\Bits-Client EID 59). Historically used to exfil data/persistence #> $XPathFilter = @" *[ System[ Provider[ @Name='Microsoft-Windows-Security-Auditing' ] and (Level=4 or Level=0) and (EventID=4624 or EventID=4625 or EventID=4634) ] ] and *[ EventData[ ( (Data[@Name='LogonType']='5' or Data[@Name='LogonType']='0') or Data[@Name='TargetUserName']='ANONYMOUS LOGON' or Data[@Name='TargetUserSID']='S-1-5-18' ) ] ] "@ function Convert-SidToName { <# .SYNOPSIS Converts a security identifier (SID) to a group/user name. Graciously taken from @harmj0y's PowerView project. .PARAMETER SID The SID to convert. .EXAMPLE PS C:\> Convert-SidToName S-1-5-21-2620891829-2411261497-1773853088-1105 #> [CmdletBinding()] param( [Parameter(Mandatory=$True,ValueFromPipeline=$True)] [String] $SID ) process { try { $SID2 = $SID.trim('*') # try to resolve any built-in SIDs first # from https://support.microsoft.com/en-us/kb/243330 Switch ($SID2) { 'S-1-0' { 'Null Authority' } 'S-1-0-0' { 'Nobody' } 'S-1-1' { 'World Authority' } 'S-1-1-0' { 'Everyone' } 'S-1-2' { 'Local Authority' } 'S-1-2-0' { 'Local' } 'S-1-2-1' { 'Console Logon ' } 'S-1-3' { 'Creator Authority' } 'S-1-3-0' { 'Creator Owner' } 'S-1-3-1' { 'Creator Group' } 'S-1-3-2' { 'Creator Owner Server' } 'S-1-3-3' { 'Creator Group Server' } 'S-1-3-4' { 'Owner Rights' } 'S-1-4' { 'Non-unique Authority' } 'S-1-5' { 'NT Authority' } 'S-1-5-1' { 'Dialup' } 'S-1-5-2' { 'Network' } 'S-1-5-3' { 'Batch' } 'S-1-5-4' { 'Interactive' } 'S-1-5-6' { 'Service' } 'S-1-5-7' { 'Anonymous' } 'S-1-5-8' { 'Proxy' } 'S-1-5-9' { 'Enterprise Domain Controllers' } 'S-1-5-10' { 'Principal Self' } 'S-1-5-11' { 'Authenticated Users' } 'S-1-5-12' { 'Restricted Code' } 'S-1-5-13' { 'Terminal Server Users' } 'S-1-5-14' { 'Remote Interactive Logon' } 'S-1-5-15' { 'This Organization ' } 'S-1-5-17' { 'This Organization ' } 'S-1-5-18' { 'Local System' } 'S-1-5-19' { 'NT Authority' } 'S-1-5-20' { 'NT Authority' } 'S-1-5-80-0' { 'All Services ' } 'S-1-5-32-544' { 'BUILTIN\Administrators' } 'S-1-5-32-545' { 'BUILTIN\Users' } 'S-1-5-32-546' { 'BUILTIN\Guests' } 'S-1-5-32-547' { 'BUILTIN\Power Users' } 'S-1-5-32-548' { 'BUILTIN\Account Operators' } 'S-1-5-32-549' { 'BUILTIN\Server Operators' } 'S-1-5-32-550' { 'BUILTIN\Print Operators' } 'S-1-5-32-551' { 'BUILTIN\Backup Operators' } 'S-1-5-32-552' { 'BUILTIN\Replicators' } 'S-1-5-32-554' { 'BUILTIN\Pre-Windows 2000 Compatible Access' } 'S-1-5-32-555' { 'BUILTIN\Remote Desktop Users' } 'S-1-5-32-556' { 'BUILTIN\Network Configuration Operators' } 'S-1-5-32-557' { 'BUILTIN\Incoming Forest Trust Builders' } 'S-1-5-32-558' { 'BUILTIN\Performance Monitor Users' } 'S-1-5-32-559' { 'BUILTIN\Performance Log Users' } 'S-1-5-32-560' { 'BUILTIN\Windows Authorization Access Group' } 'S-1-5-32-561' { 'BUILTIN\Terminal Server License Servers' } 'S-1-5-32-562' { 'BUILTIN\Distributed COM Users' } 'S-1-5-32-569' { 'BUILTIN\Cryptographic Operators' } 'S-1-5-32-573' { 'BUILTIN\Event Log Readers' } 'S-1-5-32-574' { 'BUILTIN\Certificate Service DCOM Access' } 'S-1-5-32-575' { 'BUILTIN\RDS Remote Access Servers' } 'S-1-5-32-576' { 'BUILTIN\RDS Endpoint Servers' } 'S-1-5-32-577' { 'BUILTIN\RDS Management Servers' } 'S-1-5-32-578' { 'BUILTIN\Hyper-V Administrators' } 'S-1-5-32-579' { 'BUILTIN\Access Control Assistance Operators' } 'S-1-5-32-580' { 'BUILTIN\Access Control Assistance Operators' } Default { $Obj = (New-Object System.Security.Principal.SecurityIdentifier($SID2)) $Obj.Translate( [System.Security.Principal.NTAccount]).Value } } } catch { # Write-Warning "Invalid SID: $SID" $SID } } } } Process { Get-WinEvent -FilterXPath $XPathFilter -LogName Security -MaxEvents 3000 | ForEach-Object { $Event = $null $Properties = $null $Output = $null $Event = $_ $Properties = $Event.Properties switch($Event.Id) { # Event log cleared 1102 { $Output = @{ TimeCreated = $Event.TimeCreated EventId = $Event.Id SubjectUserSid = $Properties[0].Value.ToString() SubjectUserName = $Properties[1].Value SubjectDomainName = $Properties[2].Value SubjectLogonId = $Properties[3].Value } if(-not $ReturnHashtables) { $Output = New-Object PSObject -Property $Output $Output.PSObject.TypeNames.Insert(0, 'LogClearedEvent') } break } # Logon event 4624 { $Output = @{ TimeCreated = $Event.TimeCreated EventId = $Event.Id SubjectUserSid = $Properties[0].Value.ToString() SubjectUserName = $Properties[1].Value SubjectDomainName = $Properties[2].Value SubjectLogonId = $Properties[3].Value TargetUserSid = $Properties[4].Value.ToString() TargetUserName = $Properties[5].Value TargetDomainName = $Properties[6].Value TargetLogonId = $Properties[7].Value LogonType = $Properties[8].Value LogonProcessName = $Properties[9].Value AuthenticationPackageName = $Properties[10].Value WorkstationName = $Properties[11].Value LogonGuid = $Properties[12].Value TransmittedServices = $Properties[13].Value LmPackageName = $Properties[14].Value KeyLength = $Properties[15].Value ProcessId = $Properties[16].Value ProcessName = $Properties[17].Value IpAddress = $Properties[18].Value IpPort = $Properties[19].Value ImpersonationLevel = $Properties[20].Value RestrictedAdminMode = $Properties[21].Value TargetOutboundUserName = $Properties[22].Value TargetOutboundDomainName = $Properties[23].Value VirtualAccount = $Properties[24].Value TargetLinkedLogonId = $Properties[25].Value ElevatedToken = $Properties[26].Value } if(-not $ReturnHashtables) { $Output = New-Object PSObject -Property $Output $Output.PSObject.TypeNames.Insert(0, 'LogonEvent') } break } # RDP Logoff event 4634 { $Output = @{ TimeCreated = $Event.TimeCreated EventId = $Event.Id TargetUserSid = $Properties[0].Value.ToString() TargetUserName = $Properties[1].Value TargetDomainName = $Properties[2].Value TargetLogonId = $Properties[3].Value LogonType = $Properties[4].Value.ToString() } if(-not $ReturnHashtables) { $Output = New-Object PSObject -Property $Output $Output.PSObject.TypeNames.Insert(0, 'LogoffEvent') } break } # Logon with explicit credential 4648 { # Skip computer logons for now # TODO: Can this be used for silver ticket detection? if(!($Properties[5].Value.EndsWith('$') -and $Properties[11].Value -match 'taskhost\.exe')) { $Output = @{ TimeCreated = $Event.TimeCreated EventId = $Event.Id SubjectUserSid = $Properties[0].Value.ToString() SubjectUserName = $Properties[1].Value SubjectDomainName = $Properties[2].Value SubjectLogonId = $Properties[3].Value LogonGuid = $Properties[4].Value.ToString() TargetUserName = $Properties[5].Value TargetDomainName = $Properties[6].Value TargetLogonGuid = $Properties[7].Value TargetServerName = $Properties[8].Value TargetInfo = $Properties[9].Value ProcessId = $Properties[10].Value ProcessName = $Properties[11].Value IpAddress = $Properties[12].Value IpPort = $Properties[13].Value } if(-not $ReturnHashtables) { $Output = New-Object PSObject -Property $Output $Output.PSObject.TypeNames.Insert(0, 'ExplicitCredentialLogonEvent') } break } } # New local account 4720 { $Output = @{ TimeCreated = $Event.TimeCreated EventId = $Event.Id TargetUserName = $Properties[0].Value TargetDomainName = $Properties[1].Value TargetSid = $Properties[2].Value.ToString() SubjectUserSid = $Properties[3].Value.ToString() SubjectUserName = $Properties[4].Value SubjectDomainName = $Properties[5].Value SubjectLogonId = $Properties[6].Value PrivilegeList = $Properties[7].Value SamAccountName = $Properties[8].Value DisplayName = $Properties[9].Value UserPrincipalName = $Properties[10].Value HomeDirectory = $Properties[11].Value HomePath = $Properties[12].Value ScriptPath = $Properties[13].Value ProfilePath = $Properties[14].Value UserWorkstations = $Properties[15].Value PasswordLastSet = $Properties[16].Value AccountExpires = $Properties[17].Value PrimaryGroupId = $Properties[18].Value AllowedToDelegateTo = $Properties[19].Value OldUacValue = $Properties[20].Value NewUacValue = $Properties[21].Value UserAccountControl = $Properties[22].Value UserParameters = $Properties[23].Value SidHistory = $Properties[24].Value LogonHours = $Properties[25].Value } if(-not $ReturnHashtables) { $Output = New-Object PSObject -Property $Output $Output.PSObject.TypeNames.Insert(0, 'LocalAccountCreatedEvent') } break } # Local account deleted 4726 { $Output = @{ TimeCreated = $Event.TimeCreated EventId = $Event.Id TargetUserName = $Properties[0].Value TargetDomainName = $Properties[1].Value TargetSid = $Properties[2].Value.ToString() SubjectUserSid = $Properties[3].Value.ToString() SubjectUserName = $Properties[4].Value SubjectDomainName = $Properties[5].Value SubjectLogonId = $Properties[6].Value PrivilegeList = $Properties[7].Value } if(-not $ReturnHashtables) { $Output = New-Object PSObject -Property $Output $Output.PSObject.TypeNames.Insert(0, 'LocalAccountDeletedEvent') } break } # Local admins changed { @(4732,4733) -contains $_ } { $MemberName = $Properties[0].Value if($MemberName -eq '-' -and ($Properties[1].Value.ToString()) -match '^S-\d-(\d+-){1,14}\d+$') { $MemberName = Convert-SidToName ($Properties[1].Value.ToString()) } if($_ -eq 4732) { $Action = 'AddToGroup' } else {$Action = 'DeleteFromGroup'} $Output = @{ TimeCreated = $Event.TimeCreated EventId = $Event.Id MemberName = $MemberName MemberSid = $Properties[1].Value.ToString() TargetUserName = $Properties[2].Value TargetDomainName = $Properties[3].Value TargetSid = $Properties[4].Value.ToString() SubjectUserSid = $Properties[5].Value.ToString() SubjectUserName = $Properties[6].Value SubjectDomainName = $Properties[7].Value SubjectLogonId = $Properties[8].Value PrivilegeList = $Properties[9].Value Action = $Action } if(-not $ReturnHashtables) { $Output = New-Object PSObject -Property $Output $Output.PSObject.TypeNames.Insert(0, 'SecurityGroupChanged') } break } default { Write-Error "No handler exists for EID $($Event.Id)" } } $Output } } } Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-ScheduledJob.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-WmiObject -Class Win32_ScheduledJob)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'ScheduledJob') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'ScheduledJob' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) Write-Host $body Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-SecurityPackage.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-SecurityPackage -ReturnHashtables)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'SecruityPackage') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'SecurityPackage' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) Write-Host $body Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-SecurityPackage { param ( [Parameter()] [switch] $ReturnHashtables ) <# .SYNOPSIS Enumerates Security Service Providers (SSP) t .DESCRIPTION .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .EXAMPLE PS > Get-SecurityPackage Name : Negotiate Comment : Microsoft Package Negotiator Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, NEGOTIABLE, GSS_COMPATIBLE, LOGON, RESTRICTED_TOKENS, APPCONTAINER_CHECKS Version : 1 RpcId : 9 MaxToken : 65791 Name : NegoExtender Comment : NegoExtender Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, IMPERSONATION, NEGOTIABLE, GSS_COMPATIBLE, LOGON, MUTUAL_AUTH, NEGO_EXTENDER, APPCONTAINER_CHECKS Version : 1 RpcId : 30 MaxToken : 12000 Name : Kerberos Comment : Microsoft Kerberos V1.0 Capabilities : INTEGRITY, PRIVACY, TOKEN_ONLY, DATAGRAM, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, NEGOTIABLE, GSS_COMPATIBLE, LOGON, MUTUAL_AUTH, DELEGATION, READONLY_WITH_CHECKSUM, RESTRICTED_TOKENS, APPCONTAINER_CHECKS Version : 1 RpcId : 16 MaxToken : 65535 Name : NTLM Comment : NTLM Security Package Capabilities : INTEGRITY, PRIVACY, TOKEN_ONLY, CONNECTION, MULTI_REQUIRED, IMPERSONATION, ACCEPT_WIN32_NAME, NEGOTIABLE, LOGON, RESTRICTED_TOKENS, APPCONTAINER_CHECKS Version : 1 RpcId : 10 MaxToken : 2888 Name : TSSSP Comment : TS Service Security Package Capabilities : CONNECTION, MULTI_REQUIRED, ACCEPT_WIN32_NAME, MUTUAL_AUTH, APPCONTAINER_CHECKS Version : 1 RpcId : 22 MaxToken : 13000 Name : pku2u Comment : PKU2U Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, IMPERSONATION, GSS_COMPATIBLE, MUTUAL_AUTH, NEGOTIABLE2, APPCONTAINER_CHECKS Version : 1 RpcId : 31 MaxToken : 12000 Name : CloudAP Comment : Cloud AP Security Package Capabilities : LOGON, NEGOTIABLE2 Version : 1 RpcId : 36 MaxToken : 0 Name : WDigest Comment : Digest Authentication for Windows Capabilities : TOKEN_ONLY, IMPERSONATION, ACCEPT_WIN32_NAME, APPCONTAINER_CHECKS Version : 1 RpcId : 21 MaxToken : 4096 Name : Schannel Comment : Schannel Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, STREAM, MUTUAL_AUTH, APPCONTAINER_PASSTHROUGH Version : 1 RpcId : 14 MaxToken : 24576 Name : Microsoft Unified Security Protocol Provider Comment : Schannel Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, STREAM, MUTUAL_AUTH, APPCONTAINER_PASSTHROUGH Version : 1 RpcId : 14 MaxToken : 24576 Name : CREDSSP Comment : Microsoft CredSSP Security Provider Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, IMPERSONATION, ACCEPT_WIN32_NAME, STREAM, MUTUAL_AUTH, APPCONTAINER_CHECKS Version : 1 RpcId : 65535 MaxToken : 90567 #> $obj = EnumerateSecurityPackages if($ReturnHashtables) { foreach($o in $obj) { $props = @{ Name = $o.Name Comment = $o.Comment Capabilities = $o.Capabilities Version = $o.Version RpcId = $o.RpcId MaxToken = $o.MaxToken } Write-Output $props } } else { Write-Output $obj } } #region PSReflect function New-InMemoryModule { <# .SYNOPSIS Creates an in-memory assembly and module Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION When defining custom enums, structs, and unmanaged functions, it is necessary to associate to an assembly module. This helper function creates an in-memory module that can be passed to the 'enum', 'struct', and Add-Win32Type functions. .PARAMETER ModuleName Specifies the desired name for the in-memory assembly and module. If ModuleName is not provided, it will default to a GUID. .EXAMPLE $Module = New-InMemoryModule -ModuleName Win32 #> Param ( [Parameter(Position = 0)] [ValidateNotNullOrEmpty()] [String] $ModuleName = [Guid]::NewGuid().ToString() ) $AppDomain = [Reflection.Assembly].Assembly.GetType('System.AppDomain').GetProperty('CurrentDomain').GetValue($null, @()) $LoadedAssemblies = $AppDomain.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 $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, 'Run') $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule($ModuleName, $False) return $ModuleBuilder } # A helper function used to reduce typing while defining function # prototypes for Add-Win32Type. 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, [String] $EntryPoint, [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 } if ($EntryPoint) { $Properties['EntryPoint'] = $EntryPoint } New-Object PSObject -Property $Properties } function Add-Win32Type { <# .SYNOPSIS Creates a .NET type for an unmanaged Win32 function. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: func .DESCRIPTION Add-Win32Type enables you to easily interact with unmanaged (i.e. Win32 unmanaged) functions in PowerShell. After providing Add-Win32Type with a function signature, a .NET type is created using reflection (i.e. csc.exe is never called like with Add-Type). The 'func' helper function can be used to reduce typing when defining multiple function definitions. .PARAMETER DllName The name of the DLL. .PARAMETER FunctionName The name of the target function. .PARAMETER EntryPoint The DLL export function name. This argument should be specified if the specified function name is different than the name of the exported function. .PARAMETER ReturnType The return type of the function. .PARAMETER ParameterTypes The function parameters. .PARAMETER NativeCallingConvention Specifies the native calling convention of the function. Defaults to stdcall. .PARAMETER Charset If you need to explicitly call an 'A' or 'W' Win32 function, you can specify the character set. .PARAMETER SetLastError Indicates whether the callee calls the SetLastError Win32 API function before returning from the attributed method. .PARAMETER Module The in-memory module that will host the functions. Use New-InMemoryModule to define an in-memory module. .PARAMETER Namespace An optional namespace to prepend to the type. Add-Win32Type defaults to a namespace consisting only of the name of the DLL. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $FunctionDefinitions = @( (func kernel32 GetProcAddress ([IntPtr]) @([IntPtr], [String]) -Charset Ansi -SetLastError), (func kernel32 GetModuleHandle ([Intptr]) @([String]) -SetLastError), (func ntdll RtlGetCurrentPeb ([IntPtr]) @()) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32' $Kernel32 = $Types['kernel32'] $Ntdll = $Types['ntdll'] $Ntdll::RtlGetCurrentPeb() $ntdllbase = $Kernel32::GetModuleHandle('ntdll') $Kernel32::GetProcAddress($ntdllbase, 'RtlGetCurrentPeb') .NOTES Inspired by Lee Holmes' Invoke-WindowsApi http://poshcode.org/2189 When defining multiple function prototypes, it is ideal to provide Add-Win32Type with an array of function signatures. That way, they are all incorporated into the same in-memory module. #> [OutputType([Hashtable])] Param( [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $DllName, [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [String] $FunctionName, [Parameter(ValueFromPipelineByPropertyName = $True)] [String] $EntryPoint, [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') $EntryPointField = $DllImport.GetField('EntryPoint') if ($SetLastError) { $SLEValue = $True } else { $SLEValue = $False } if ($PSBoundParameters['EntryPoint']) { $ExportedFuncName = $EntryPoint } else { $ExportedFuncName = $FunctionName } # 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, $EntryPointField), [Object[]] @($SLEValue, ([Runtime.InteropServices.CallingConvention] $NativeCallingConvention), ([Runtime.InteropServices.CharSet] $Charset), $ExportedFuncName)) $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 psenum { <# .SYNOPSIS Creates an in-memory enumeration for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION The 'psenum' function facilitates the creation of enums entirely in memory using as close to a "C style" as PowerShell will allow. .PARAMETER Module The in-memory module that will host the enum. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the enum. .PARAMETER Type The type of each enum element. .PARAMETER EnumElements A hashtable of enum elements. .PARAMETER Bitfield Specifies that the enum should be treated as a bitfield. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageSubsystem = psenum $Mod PE.IMAGE_SUBSYSTEM UInt16 @{ UNKNOWN = 0 NATIVE = 1 # Image doesn't require a subsystem. WINDOWS_GUI = 2 # Image runs in the Windows GUI subsystem. WINDOWS_CUI = 3 # Image runs in the Windows character subsystem. OS2_CUI = 5 # Image runs in the OS/2 character subsystem. POSIX_CUI = 7 # Image runs in the Posix character subsystem. NATIVE_WINDOWS = 8 # Image is a native Win9x driver. WINDOWS_CE_GUI = 9 # Image runs in the Windows CE subsystem. EFI_APPLICATION = 10 EFI_BOOT_SERVICE_DRIVER = 11 EFI_RUNTIME_DRIVER = 12 EFI_ROM = 13 XBOX = 14 WINDOWS_BOOT_APPLICATION = 16 } .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Enum. :P #> [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]) { return ($Module.GetType($FullName)) } $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 { <# .SYNOPSIS Creates an in-memory struct for use in your PowerShell session. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: field .DESCRIPTION The 'struct' function facilitates the creation of structs entirely in memory using as close to a "C style" as PowerShell will allow. Struct fields are specified using a hashtable where each field of the struct is comprosed of the order in which it should be defined, its .NET type, and optionally, its offset and special marshaling attributes. One of the features of 'struct' is that after your struct is defined, it will come with a built-in GetSize method as well as an explicit converter so that you can easily cast an IntPtr to the struct without relying upon calling SizeOf and/or PtrToStructure in the Marshal class. .PARAMETER Module The in-memory module that will host the struct. Use New-InMemoryModule to define an in-memory module. .PARAMETER FullName The fully-qualified name of the struct. .PARAMETER StructFields A hashtable of fields. Use the 'field' helper function to ease defining each field. .PARAMETER PackingSize Specifies the memory alignment of fields. .PARAMETER ExplicitLayout Indicates that an explicit offset for each field will be specified. .EXAMPLE $Mod = New-InMemoryModule -ModuleName Win32 $ImageDosSignature = psenum $Mod PE.IMAGE_DOS_SIGNATURE UInt16 @{ DOS_SIGNATURE = 0x5A4D OS2_SIGNATURE = 0x454E OS2_SIGNATURE_LE = 0x454C VXD_SIGNATURE = 0x454C } $ImageDosHeader = struct $Mod PE.IMAGE_DOS_HEADER @{ e_magic = field 0 $ImageDosSignature e_cblp = field 1 UInt16 e_cp = field 2 UInt16 e_crlc = field 3 UInt16 e_cparhdr = field 4 UInt16 e_minalloc = field 5 UInt16 e_maxalloc = field 6 UInt16 e_ss = field 7 UInt16 e_sp = field 8 UInt16 e_csum = field 9 UInt16 e_ip = field 10 UInt16 e_cs = field 11 UInt16 e_lfarlc = field 12 UInt16 e_ovno = field 13 UInt16 e_res = field 14 UInt16[] -MarshalAs @('ByValArray', 4) e_oemid = field 15 UInt16 e_oeminfo = field 16 UInt16 e_res2 = field 17 UInt16[] -MarshalAs @('ByValArray', 10) e_lfanew = field 18 Int32 } # Example of using an explicit layout in order to create a union. $TestUnion = struct $Mod TestUnion @{ field1 = field 0 UInt32 0 field2 = field 1 IntPtr 0 } -ExplicitLayout .NOTES PowerShell purists may disagree with the naming of this function but again, this was developed in such a way so as to emulate a "C style" definition as closely as possible. Sorry, I'm not going to name it New-Struct. :P #> [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() } #endregion PSReflect $Module = New-InMemoryModule -ModuleName GetSecurityPackage #region Enums $SECPKG_FLAG = psenum $Module SECPKG_FLAG UInt32 @{ INTEGRITY = 0x1 PRIVACY = 0x2 TOKEN_ONLY = 0x4 DATAGRAM = 0x8 CONNECTION = 0x10 MULTI_REQUIRED = 0x20 CLIENT_ONLY = 0x40 EXTENDED_ERROR = 0x80 IMPERSONATION = 0x100 ACCEPT_WIN32_NAME = 0x200 STREAM = 0x400 NEGOTIABLE = 0X800 GSS_COMPATIBLE = 0x1000 LOGON = 0x2000 ASCII_BUFFERS = 0x4000 FRAGMENT = 0x8000 MUTUAL_AUTH = 0x10000 DELEGATION = 0x20000 READONLY_WITH_CHECKSUM = 0x40000 RESTRICTED_TOKENS = 0x80000 NEGO_EXTENDER = 0x00100000 NEGOTIABLE2 = 0x00200000 APPCONTAINER_PASSTHROUGH = 0x00400000 APPCONTAINER_CHECKS = 0x00800000 #SECPKG_CALLFLAGS_APPCONTAINER = 0x00000001 #SECPKG_CALLFLAGS_AUTHCAPABLE = 0x00000002 #SECPKG_CALLFLAGS_FORCE_SUPPLIED = 0x00000004 } -Bitfield #endregion Enums #region Structs $SecPkgInfo = struct $Module SecPkgInfo @{ Capabilities = field 0 $SECPKG_FLAG Version = field 1 UInt16 RPCID = field 2 UInt16 MaxToken = field 3 UInt32 Name = field 4 IntPtr Comment = field 5 IntPtr } #endregion Structs #region Function Definitions $FunctionDefinitions = @( (func secur32 DeleteSecurityPackage ([UInt32]) @( [string] #_In_ LPTSTR pszPackageName ) -EntryPoint DeleteSecurityPackage), (func secur32 EnumerateSecurityPackages ([UInt32]) @( [UInt32].MakeByRefType(), #_In_ PULONG pcPackages [IntPtr].MakeByRefType() #_In_ PSecPkgInfo *ppPackageInfo ) -EntryPoint EnumerateSecurityPackages), (func secur32 FreeContextBuffer ([UInt32]) @( [IntPtr] #_In_ PVOID pvContextBuffer ) -EntryPoint FreeContextBuffer) ) $Types = $FunctionDefinitions | Add-Win32Type -Module $Module -Namespace GetSecurityPackage $Secur32 = $Types['secur32'] #endregion Function Definitions function DeleteSecurityPackage { <# .SYNOPSIS Deletes a security support provider from the list of providers supported by Microsoft Negotiate. .PARAMETER PackageName The name of the security provider to delete. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None (func secur32 DeleteSecurityPackage ([UInt32]) @( [string] #_In_ LPTSTR pszPackageName ) -EntryPoint DeleteSecurityPackage) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/dd401610(v=vs.85).aspx .EXAMPLE #> param ( [Parameter(Mandatory = $true)] [string] $PackageName ) $SUCCESS = $Secur32::DeleteSecurityPackages($PackageName) if($SUCCESS -eq 0) { throw "DeleteSecurityPackage Error: $($SUCCESS)" } } function EnumerateSecurityPackages { <# .SYNOPSIS The EnumerateSecurityPackages function returns an array of SecPkgInfo structures that provide information about the security packages available to the client. .DESCRIPTION The caller can use the Name member of a SecPkgInfo structure to specify a security package in a call to the AcquireCredentialsHandle (General) function. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: FreeContextBuffer (function), SecPkgInfo (Structure), SECPKG_FLAG (Enumeration) Optional Dependencies: None (func secur32 EnumerateSecurityPackages ([UInt32]) @( [UInt32].MakeByRefType(), #_In_ PULONG pcPackages [IntPtr].MakeByRefType() #_In_ PSecPkgInfo *ppPackageInfo ) -EntryPoint EnumerateSecurityPackages) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa375397(v=vs.85).aspx .EXAMPLE PS > EnumerateSecurityPackages Name : Negotiate Comment : Microsoft Package Negotiator Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, NEGOTIABLE, GSS_COMPATIBLE, LOGON, RESTRICTED_TOKENS, APPCONTAINER_CHECKS Version : 1 RpcId : 9 MaxToken : 65791 Name : NegoExtender Comment : NegoExtender Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, IMPERSONATION, NEGOTIABLE, GSS_COMPATIBLE, LOGON, MUTUAL_AUTH, NEGO_EXTENDER, APPCONTAINER_CHECKS Version : 1 RpcId : 30 MaxToken : 12000 Name : Kerberos Comment : Microsoft Kerberos V1.0 Capabilities : INTEGRITY, PRIVACY, TOKEN_ONLY, DATAGRAM, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, NEGOTIABLE, GSS_COMPATIBLE, LOGON, MUTUAL_AUTH, DELEGATION, READONLY_WITH_CHECKSUM, RESTRICTED_TOKENS, APPCONTAINER_CHECKS Version : 1 RpcId : 16 MaxToken : 65535 Name : NTLM Comment : NTLM Security Package Capabilities : INTEGRITY, PRIVACY, TOKEN_ONLY, CONNECTION, MULTI_REQUIRED, IMPERSONATION, ACCEPT_WIN32_NAME, NEGOTIABLE, LOGON, RESTRICTED_TOKENS, APPCONTAINER_CHECKS Version : 1 RpcId : 10 MaxToken : 2888 Name : TSSSP Comment : TS Service Security Package Capabilities : CONNECTION, MULTI_REQUIRED, ACCEPT_WIN32_NAME, MUTUAL_AUTH, APPCONTAINER_CHECKS Version : 1 RpcId : 22 MaxToken : 13000 Name : pku2u Comment : PKU2U Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, IMPERSONATION, GSS_COMPATIBLE, MUTUAL_AUTH, NEGOTIABLE2, APPCONTAINER_CHECKS Version : 1 RpcId : 31 MaxToken : 12000 Name : CloudAP Comment : Cloud AP Security Package Capabilities : LOGON, NEGOTIABLE2 Version : 1 RpcId : 36 MaxToken : 0 Name : WDigest Comment : Digest Authentication for Windows Capabilities : TOKEN_ONLY, IMPERSONATION, ACCEPT_WIN32_NAME, APPCONTAINER_CHECKS Version : 1 RpcId : 21 MaxToken : 4096 Name : Schannel Comment : Schannel Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, STREAM, MUTUAL_AUTH, APPCONTAINER_PASSTHROUGH Version : 1 RpcId : 14 MaxToken : 24576 Name : Microsoft Unified Security Protocol Provider Comment : Schannel Security Package Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, EXTENDED_ERROR, IMPERSONATION, ACCEPT_WIN32_NAME, STREAM, MUTUAL_AUTH, APPCONTAINER_PASSTHROUGH Version : 1 RpcId : 14 MaxToken : 24576 Name : CREDSSP Comment : Microsoft CredSSP Security Provider Capabilities : INTEGRITY, PRIVACY, CONNECTION, MULTI_REQUIRED, IMPERSONATION, ACCEPT_WIN32_NAME, STREAM, MUTUAL_AUTH, APPCONTAINER_CHECKS Version : 1 RpcId : 65535 MaxToken : 90567 #> $PackageCount = 0 $PackageInfo = [IntPtr]::Zero $SUCCESS = $Secur32::EnumerateSecurityPackages([ref]$PackageCount, [ref]$PackageInfo) if($SUCCESS -ne 0) { throw "EnumerateSecurityPackages Error: $($SUCCESS)" } for($i = 0; $i -lt $PackageCount; $i++) { $PackagePtr = [IntPtr]($PackageInfo.ToInt64() + ($SecPkgInfo::GetSize() * $i)) $Package = $PackagePtr -as $SecPkgInfo $obj = New-Object -TypeName psobject $obj | Add-Member -MemberType NoteProperty -Name Name -Value ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto($Package.Name)) $obj | Add-Member -MemberType NoteProperty -Name Comment -Value ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto($Package.Comment)) $obj | Add-Member -MemberType NoteProperty -Name Capabilities -Value $Package.Capabilities $obj | Add-Member -MemberType NoteProperty -Name Version -Value $Package.Version $obj | Add-Member -MemberType NoteProperty -Name RpcId -Value $Package.RPCID $obj | Add-Member -MemberType NoteProperty -Name MaxToken -Value $Package.MaxToken Write-Output $obj } FreeContextBuffer -Buffer $PackageInfo } function FreeContextBuffer { <# .SYNOPSIS The FreeContextBuffer function enables callers of security package functions to free memory buffers allocated by the security package. .DESCRIPTION Memory buffers are typically allocated by the InitializeSecurityContext (General) and AcceptSecurityContext (General) functions. The FreeContextBuffer function can free any memory allocated by a security package. .PARAMETER Buffer A pointer to memory to be freed. .NOTES Author: Jared Atkinson (@jaredcatkinson) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None (func secur32 FreeContextBuffer ([UInt32]) @( [IntPtr] #_In_ PVOID pvContextBuffer ) -EntryPoint FreeContextBuffer) .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa375416(v=vs.85).aspx .EXAMPLE PS > $PackageCount = 0 PS > $PackageInfo = [IntPtr]::Zero PS > $SUCCESS = $Secur32::EnumerateSecurityPackages([ref]$PackageCount, [ref]$PackageInfo) # # Do Stuff ... # PS > FreeContextBuffer -Buffer $PackageInfo #> param ( [Parameter(Mandatory = $true)] [IntPtr] $Buffer ) $SUCCESS = $Secur32::FreeContextBuffer($Buffer) if($SUCCESS -ne 0) { throw "FreeContextBuffer Error: $($SUCCESS)" } } Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/ACE_Get-SimpleNamedPipe.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-SimpleNamedPipe -ReturnHashtables)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'SimpleNamedPipe') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'SimpleNamedPipe' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) Write-Host $body Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-SimpleNamedPipe { <# .SYNOPSIS Gets a list of open named pipes. Author: Greg Zakharov License: Required Dependencies: None Optional Dependencies: None .DESCRIPTION When defining custom enums, structs, and unmanaged functions, it is necessary to associate to an assembly module. This helper function creates an in-memory module that can be passed to the 'enum', 'struct', and Add-Win32Type functions. #> [CmdletBinding()] Param ( [switch] $ReturnHashtables ) Begin { $Mscorlib = [AppDomain]::CurrentDomain.GetAssemblies() | ? { $_.ManifestModule.ScopeName.Equals('CommonLanguageRuntimeLibrary') } $SafeFindHandle = $Mscorlib.GetType('Microsoft.Win32.SafeHandles.SafeFindHandle') $Win32Native = $Mscorlib.GetType('Microsoft.Win32.Win32Native') $WIN32_FIND_DATA = $Win32Native.GetNestedType( 'WIN32_FIND_DATA', [Reflection.BindingFlags]32 ) $FindFirstFile = $Win32Native.GetMethod( 'FindFirstFile', [Reflection.BindingFlags]40, $null, @([String], $WIN32_FIND_DATA), $null ) $FindNextFile = $Win32Native.GetMethod('FindNextFile', [Reflection.BindingFlags]40, $null, @($SafeFindHandle, $WIN32_FIND_DATA), $null) $Obj = $WIN32_FIND_DATA.GetConstructors()[0].Invoke($null) function Read-Field([String]$Field) { return $WIN32_FIND_DATA.GetField($Field, [Reflection.BindingFlags]36).GetValue($Obj) } } Process { $Handle = $FindFirstFile.Invoke($null, @('\\.\pipe\*', $obj)) $Output = @{ Name = [string](Read-Field cFileName) Instances = [UInt32](Read-Field nFileSizeLow) } do { $Output = @{ Name = [string](Read-Field cFileName) Instances = [UInt32](Read-Field nFileSizeLow) } if($ReturnHashtables) { $Output } else { New-Object PSObject -Property $Output } } while($FindNextFile.Invoke($null, @($Handle, $obj))) $Handle.Close() } End { } } Start-AceScript -Uri https://10.182.18.200 -SweepId $args[0] -ScanId ([Guid]::NewGuid()) -RoutingKey siem -Thumbprint 8D1DB3B7B85B6F9E9DE87B291DF66692A10240AE ================================================ FILE: ACE-Management/PS-ACE/Scripts/Invoke-MonsterWinRM.ps1 ================================================ # WinRM In Memory Deployment function Invoke-MonsterWinRM { param ( [Parameter()] [string[]] $ComputerName, [Parameter(Mandatory = $true)] [Management.Automation.PSCredential] [Management.Automation.CredentialAttribute()] $Credential, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $ScriptPath, [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter()] [ValidateSet('All','AccessToken','ArpCache','AtomTable','InjectedThread','KerberosTicket','LogonSession','MasterBootRecord','NetworkConnection','FullProcess','ScheduledTask','SecurityPackage','FullService','SimpleNamedPipe')] [string[]] $ScanType = 'All' ) $scriptblock = { param ( [Parameter(Mandatory = $true)] [guid] $SweepId, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $ScriptPath, [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter()] [ValidateSet('All','AccessToken','ArpCache','AtomTable','InjectedThread','KerberosTicket','LogonSession','MasterBootRecord','NetworkConnection','FullProcess','ScheduledTask','SecurityPackage','FullService','SimpleNamedPipe')] [string[]] $ScanType = 'All' ) function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $ApiKey, [Parameter(Mandatory)] [string] $Thumbprint, [Parameter()] [ValidateSet('Delete','Get','Post','Put')] [string] $Method = 'Get', [Parameter()] [string] $ContentType = 'application/json', [Parameter()] [string] $Body ) try { # Create web request $WebRequest = [System.Net.WebRequest]::Create($Uri) $WebRequest.Headers.Add('X-API-Version:1.0') $webrequest.Headers.Add("X-ApiKey:$($ApiKey)") $WebRequest.Method = $Method $WebRequest.ContentType = $ContentType # Set the callback to check for null certificate and thumbprint matching. $WebRequest.ServerCertificateValidationCallback = { $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteWarningLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteWarningLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") $Host.UI.WriteWarningLine(" Expected thumbprint: $($Thumbprint)") $Host.UI.WriteWarningLine(" Received thumbprint: $($certificate.Thumbprint)") } return $false } if($PSBoundParameters.ContainsKey('Body')) { $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() } # Get response stream $ResponseStream = $webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() $StreamReader.Close() $ResponseStream.Close() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } try { $MasterScript = Invoke-AceWebRequest -Uri "$($Uri)$($ScriptPath)" -Thumbprint $Thumbprint -ApiKey 1 Invoke-Expression -Command $MasterScript Start-AceScript -Uri $Uri -SweepId $SweepId -ScanId ([Guid]::NewGuid()) -Thumbprint $Thumbprint -ScanType $ScanType Write-Host -NoNewline -ForegroundColor Green -Object "[+] " Write-Host $env:COMPUTERNAME } catch { Write-Host -NoNewline -ForegroundColor Red -Object "[-] " Write-Host $env:COMPUTERNAME } } $SweepId = [Guid]::NewGuid() Invoke-Command -ComputerName $ComputerName -Credential $Credential -ScriptBlock $scriptblock -ArgumentList @($SweepId, $Uri, $ScriptPath, $Thumbprint, $ScanType) -SessionOption (New-PSSessionOption -NoMachineProfile) } ================================================ FILE: ACE-Management/PS-ACE/Working/ACE_Get-PSIPrefetch.ps1 ================================================ function Start-AceScript { param ( [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $SweepId, [Parameter(Mandatory = $true)] [string] $ScanId, [Parameter(Mandatory = $true)] [string] $RoutingKey, [Parameter(Mandatory = $true)] [string] $Thumbprint ) $HostFQDN = Get-WmiObject Win32_ComputerSystem -Property 'Name','Domain' | ForEach-Object {"$($_.Name).$($_.Domain)"} $ResultDate = (Get-Date).ToString("yyyyMMddThhmmssmsmsZ") $dataList = New-Object -TypeName System.Collections.Generic.List['string'] foreach($o in (Get-PSIPrefetch -ReturnHashtables)) { $o.Add('ComputerName', $HostFQDN) $o.Add('ScanType', 'Prefetch') $o.Add('SweepId', $SweepId) $o.Add('ScanId', $ScanId) $o.Add('ResultDate', $ResultDate) $message = ConvertTo-JsonV2 -InputObject $o $dataList.Add($message) } $props = @{ ComputerName = $HostFQDN ScanType = 'Prefetch' RoutingKey = $RoutingKey ResultDate = $ResultDate ScanId = $ScanId Data = $dataList.ToArray() } $body = (ConvertTo-JsonV2 -InputObject $props) Write-Host $body #Invoke-AceWebRequest -Thumbprint $Thumbprint -Uri "$($Uri)/ace/result/$($SweepId)" -Body $body } function ConvertTo-JsonV2 { param ( [Parameter(Mandatory = $true)] $InputObject ) Begin { $null = [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") $Serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer } Process { try { $Serializer.Serialize($InputObject) } catch { Write-Error $_ } } } function Invoke-AceWebRequest { param ( [Parameter(Mandatory = $true)] [string] $Thumbprint, [Parameter(Mandatory = $true)] [string] $Uri, [Parameter(Mandatory = $true)] [string] $Body ) [Net.ServicePointManager]::ServerCertificateValidationCallback = { $Thumbprint = $Thumbprint $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]$args[1] if ($certificate -eq $null) { $Host.UI.WriteErrorLine("Null certificate.") return $true } if ($certificate.Thumbprint -eq $Thumbprint) { return $true } else { $Host.UI.WriteErrorLine("Thumbprint mismatch. Certificate thumbprint $($certificate.Thumbprint)") } return $false } try { Write-Host "URI: $($Uri)" # Create web request $WebRequest = [Net.WebRequest]::Create($uri) $WebRequest.Method = 'Post' $WebRequest.ContentType = 'application/json' $WebRequest.Headers.Add('X-API-Version:1.0') $byteArray = [System.Text.Encoding]::UTF8.GetBytes($Body) $Webrequest.ContentLength = $byteArray.Length $dataStream = $Webrequest.GetRequestStream() $dataStream.Write($byteArray, 0, $byteArray.Length) $dataStream.Close() # Get response stream $ResponseStream = $Webrequest.GetResponse().GetResponseStream() # Create a stream reader and read the stream returning the string value. $StreamReader = New-Object System.IO.StreamReader -ArgumentList $ResponseStream $StreamReader.ReadToEnd() } catch { Write-Error "Failed: $($_.exception.innerexception.message)" } } function Get-PSIPrefetch { <# .SYNOPSIS Return prefetch file information. Author: Jared Atkinson, Lee Christensen (@tifkin_) License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None #> [CmdletBinding()] param ( [Parameter()] [string] $Path, [switch] $ReturnHashtables ) begin { if($PSBoundParameters.ContainsKey('Path')) { $props = @{FullName = $Path} $files = New-Object -TypeName psobject -Property $props } else { $files = Get-ChildItem -Path C:\Windows\Prefetch\* -Include *.pf } } process { foreach($file in $files) { $bytes = Get-Content -Path $file.FullName -Encoding Byte # Check for Prefetch file header 'SCCA' if([System.Text.Encoding]::ASCII.GetString($bytes[4..7]) -eq 'SCCA') { $Version = $bytes[0] switch($Version) { 0x11 # Windows XP { $AccessTimeBytes = $bytes[0x78..0x7F] $RunCount = [BitConverter]::ToInt32($bytes, 0x90) } 0x17 # Windows 7 { $AccessTimeBytes = $bytes[0x80..0x87] $RunCount = [BitConverter]::ToInt32($bytes, 0x98); } 0x1A # Windows 8 { $AccessTimeBytes = $bytes[0x80..0xBF] $RunCount = [BitConverter]::ToInt32($bytes, 0xD0); } } $Name = [Text.Encoding]::Unicode.GetString($bytes, 0x10, 0x3C).Split('\0')[0].TrimEnd("`0") $PathHash = [BitConverter]::ToString($bytes[0x4f..0x4c]).Replace("-","") $DeviceCount = [BitConverter]::ToInt32($bytes, 0x70) $DependencyString = [Text.Encoding]::Unicode.GetString($bytes, [BitConverter]::ToInt32($bytes, 0x64), [BitConverter]::ToInt32($bytes, 0x68)).Replace("`0",';').TrimEnd(';') $Dependencies = $DependencyString.Split(';') $Path = $Dependencies | Where-Object {$_ -like "*$($Name)"} $DependencyCount = $Dependencies.Length for($i = 0; $i -lt $AccessTimeBytes.Length; $i += 8) { $Props = @{ Name = $Name Path = $Path PathHash = $PathHash DependencyCount = $DependencyCount PrefetchAccessTime = [DateTime]::FromFileTimeUtc([BitConverter]::ToInt64($AccessTimeBytes, $i)) DeviceCount = $DeviceCount RunCount = $RunCount DependencyFiles = $DependencyString } if($ReturnHashtables) { $Props } else { New-Object -TypeName psobject -Property $Props } } } } } end { } } ================================================ FILE: ACE-WebService/.gitignore ================================================ # Download this file using PowerShell v3 under Windows with the following comand: # Invoke-WebRequest https://gist.githubusercontent.com/kmorcinek/2710267/raw/ -OutFile .gitignore # or wget: # wget --no-check-certificate http://gist.githubusercontent.com/kmorcinek/2710267/raw/.gitignore # User-specific files *.suo *.user *.sln.docstates # Build results [Dd]ebug/ [Rr]elease/ x64/ build/ [Bb]in/ [Oo]bj/ # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/packages/* # except build/, which is used as an MSBuild target. !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* *_i.c *_p.c *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.log *.scc # OS generated files # .DS_Store* Icon? # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf *.cachefile # Visual Studio profiler *.psess *.vsp *.vspx # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch *.ncrunch* .*crunch*.local.xml # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.Publish.xml # Windows Azure Build Output csx *.build.csdef # Windows Store app package directory AppPackages/ # Others *.Cache ClientBin/ [Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.[Pp]ublish.xml *.pfx *.publishsettings modulesbin/ tempbin/ # EPiServer Site file (VPP) AppData/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file to a newer # Visual Studio version. Backup files are not needed, because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # vim *.txt~ *.swp *.swo # svn .svn # Remainings from resolvings conflicts in Source Control *.orig # SQL Server files **/App_Data/*.mdf **/App_Data/*.ldf **/App_Data/*.sdf #LightSwitch generated files GeneratedArtifacts/ _Pvt_Extensions/ ModelManifest.xml # ========================= # Windows detritus # ========================= # Windows image file caches Thumbs.db ehthumbs.db # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Mac desktop service store files .DS_Store # SASS Compiler cache .sass-cache # Visual Studio 2014 CTP **/*.sln.ide # Visual Studio temp something .vs/ # VS 2015+ *.vc.vc.opendb *.vc.db # Rider .idea/ # Output folder used by Webpack or other FE stuff **/node_modules/* **/wwwroot/* # SpecFlow specific *.feature.cs *.feature.xlsx.* *.Specs_*.html ##### # End of core ignore list, below put you custom 'per project' settings (patterns or path) ##### ================================================ FILE: ACE-WebService/ACEWebService.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26430.16 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D1B5F438-8ADC-4742-B3C9-D581E2A35763}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ACEWebService", "src\ACEWebService\ACEWebService.csproj", "{2794F6A8-A327-40BD-A11F-F72ECDBD2273}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2794F6A8-A327-40BD-A11F-F72ECDBD2273}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2794F6A8-A327-40BD-A11F-F72ECDBD2273}.Debug|Any CPU.Build.0 = Debug|Any CPU {2794F6A8-A327-40BD-A11F-F72ECDBD2273}.Release|Any CPU.ActiveCfg = Release|Any CPU {2794F6A8-A327-40BD-A11F-F72ECDBD2273}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: ACE-WebService/Configure-AceWebService.ps1 ================================================ function Configure-AceWebService { param ( [Parameter()] [string] $FilePath = 'C:\Windows\Temp' ) [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # Download ACEWebService latest release Invoke-WebRequest -Uri https://github.com/Invoke-IR/ACE/releases/download/test/ACEWebService.zip -OutFile "$($FilePath)\ACEWebService.zip" Expand-Archive -Path "$($FilePath)\ACEWebService.zip" -DestinationPath $FilePath # Download standalone .NET Core Invoke-WebRequest -Uri https://dotnetcli.azureedge.net/dotnet/Runtime/2.0.5/dotnet-runtime-2.0.5-win-x64.zip -OutFile "$($FilePath)\dotnet.zip" Expand-Archive -Path "$($FilePath)\dotnet.zip" -DestinationPath "$($FilePath)\ACEWebService\dotnet" # Cleanup Downloads Remove-Item -Path "$($FilePath)\dotnet.zip" Remove-Item -Path "$($FilePath)\ACEWebService.zip" # Create appsettings.Production.json file $appsettings = New-AppSettingsJson $appsettings | Out-File -FilePath "$($FilePath)\ACEWebService\appsettings.Production.json" -Force # Allow port 80 through the firewall $null = New-NetFirewallRule -DisplayName '[ACE] HTTP Inbound' -Profile @('Domain', 'Private', 'Public') -Direction Inbound -Action Allow -Protocol TCP -LocalPort @('80') # Setup portforward netsh interface portproxy add v4tov4 listenaddress=* listenport=80 connectaddress=127.0.0.1 connectport=5000 # Start and configure WinRM Start-Service -Name WinRM Set-Item -Path WSMan:\localhost\Client\TrustedHosts -Value * -Force # Change directories to ACEWebService directory Set-Location "$($FilePath)\ACEWebService" } function New-AppSettingsJson { $RabbitMQServer = Read-Host -Prompt RabbitMQServer $RabbitMQUser = Read-Host -Prompt RabbitMQUser $RabbitMQPassword = Read-Host -Prompt RabbitMQPassword -AsSecureString $NginxSSLThumbprint = Read-Host -Prompt Thumbprint $SQLServer = Read-Host -Prompt SQLServer $SQLPassword = Read-Host -Prompt SQLPassword -AsSecureString $EncryptionPassphrase = Read-Host -Prompt 'Choose an encryption passphrase for the SQL Server' -AsSecureString $RabbitMQPasswordClear = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($RabbitMQPassword)) $SQLPasswordClear = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SQLPassword)) $EncryptionPassphraseClear = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($EncryptionPassphrase)) $appsettings = @" { "Logging": { "IncludeScopes": false, "LogLevel": { "Default": "Debug", "System": "Information", "Microsoft": "Information" } }, "AppSettings": { "RabbitMQServer": "$($RabbitMQServer)", "RabbitMQUserName": "$($RabbitMQUser)", "RabbitMQPassword": "$($RabbitMQPasswordClear)", "EncryptionPassphrase": "$($EncryptionPassphraseClear)", "Thumbprint": "$($NginxSSLThumbprint)" }, "ConnectionStrings": { "DefaultConnection": "Server=$($SQLServer);Database=ACEWebService;User Id=sa;Password=$($SQLPasswordClear);MultipleActiveResultSets=true" } } "@ Write-Output $appsettings } ================================================ FILE: ACE-WebService/NuGet.config ================================================ ================================================ FILE: ACE-WebService/dockerfile ================================================ FROM microsoft/aspnetcore-build AS builder WORKDIR /source COPY *.csproj . COPY nuget.config . RUN dotnet restore COPY . . RUN dotnet publish --output /ace/ --configuration Release FROM microsoft/aspnetcore WORKDIR /ace COPY --from=builder /ace . ENTRYPOINT ["dotnet", "ACEWebService.dll"] ================================================ FILE: ACE-WebService/src/ACEWebService/ACEWebService.csproj ================================================  netcoreapp2.0 true ACEWebService exe ACEWebService 2.0.0 win10-x64;debian.8-x64 AnyCPU PreserveNewest All ================================================ FILE: ACE-WebService/src/ACEWebService/App.config ================================================  ================================================ FILE: ACE-WebService/src/ACEWebService/AppSettings.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace ACEWebService { public class AppSettings { public string RabbitMQServer { get; set; } public string RabbitMQUserName { get; set; } public string RabbitMQPassword { get; set; } public string Thumbprint { get; set; } } } ================================================ FILE: ACE-WebService/src/ACEWebService/Controllers/ComputerController.cs ================================================ using ACEWebService.Entities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; namespace ACEWebService.Controllers { [Authorize(Policy = "ApiKey")] [Route("ace/[controller]")] public class ComputerController : Controller { private ACEWebServiceDbContext _context; public ComputerController(ACEWebServiceDbContext context) { _context = context; } [HttpGet("{id}")] // GET /ace/computer/{id} public Computer Get([FromRoute]Guid id) { Computer computer = _context.Computers.SingleOrDefault(c => c.Id == id); return computer; } // GET /ace/computer [HttpGet()] public IEnumerable Get() { return _context.Computers; } } } ================================================ FILE: ACE-WebService/src/ACEWebService/Controllers/CredentialController.cs ================================================ using ACEWebService.Entities; using ACEWebService.Security; using ACEWebService.Services; using ACEWebService.ViewModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; namespace ACEWebService.Controllers { [Authorize(Policy = "ApiKey")] [Route("ace/[controller]")] public class CredentialController : Controller { private ACEWebServiceDbContext _context; private ICryptographyService _cryptoService; public CredentialController(ACEWebServiceDbContext context, ICryptographyService cryptoService) { _context = context; _cryptoService = cryptoService; } // GET /ace/credential/delete/{id} [HttpGet("delete/{id}")] public Credential Delete([FromRoute]Guid id) { User requestor = _context.Users.SingleOrDefault(u => u.ApiKey == Request.Headers["X-ApiKey"]); if(requestor.IsAdmin) { try { Credential credential = _context.Credentials.SingleOrDefault(cred => cred.Id == id); _context.Credentials.Remove(credential); _context.SaveChanges(); return credential; } catch { throw new Exception("Failed to delete credential"); } } else { throw new Exception("Only administrator users can delete credentials."); } } // GET /ace/credential [HttpGet()] public IEnumerable Get() { User requestor = _context.Users.SingleOrDefault(u => u.ApiKey == Request.Headers["X-ApiKey"]); if (requestor.IsAdmin) { return _context.Credentials; } else { throw new Exception("Only administrator users can enumerate credentials."); } } // GET /ace/credential/pscredential [HttpGet("pscredential/{id}")] public Credential Get([FromRoute]Guid Id) { User requestor = _context.Users.SingleOrDefault(u => u.ApiKey == Request.Headers["X-ApiKey"]); if (requestor.IsAdmin) { Credential cred = _context.Credentials.SingleOrDefault(c => c.Id == Id); cred.Password = _cryptoService.Decrypt(cred.Password); return cred; } else { throw new Exception("Only administrator users can enumerate credentials."); } } // POST /ace/credential [HttpPost()] public IActionResult Post([FromBody]CredentialViewModel param) { User requestor = _context.Users.SingleOrDefault(u => u.ApiKey == Request.Headers["X-ApiKey"]); if (requestor.IsAdmin) { if (ModelState.IsValid) { Credential cred = new Credential { UserName = param.UserName, Password = _cryptoService.Encrypt(param.Password) }; _context.Credentials.Add(cred); _context.SaveChanges(); return Ok(cred); } else { return BadRequest(ModelState); } } else { throw new Exception("Only administrator users can add new credentials."); } } // PUT /ace/credential/{id} [HttpPut("{id}")] public Credential Update([FromRoute]Guid Id, [FromBody]CredentialViewModel param) { User requestor = _context.Users.SingleOrDefault(u => u.ApiKey == Request.Headers["X-ApiKey"]); if (requestor.IsAdmin) { Credential credential = _context.Credentials.SingleOrDefault(cred => cred.Id == Id); credential.UserName = param.UserName; credential.Password = _cryptoService.Encrypt(param.Password); _context.Credentials.Update(credential); _context.SaveChanges(); return credential; } else { throw new Exception("Only administrator users can update credentials."); } } } } ================================================ FILE: ACE-WebService/src/ACEWebService/Controllers/DiscoverController.cs ================================================ using ACEWebService.Services; using ACEWebService.ViewModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System; namespace ACEWebService.Controllers { [Authorize(Policy = "ApiKey")] [Route("ace/[controller]")] public class DiscoverController : Controller { private IDiscoveryService _discoverService; public DiscoverController(IDiscoveryService discoverService) { _discoverService = discoverService; } /* // POST /ace/discover/domain [Route("/ace/discover/domain")] [HttpPost] public IActionResult Domain([FromBody]DiscoveryActiveDirectoryViewModel param) { if (ModelState.IsValid) { _discoverService.Discover(param); return Ok(); } else { return BadRequest(ModelState); } } */ // POST /ace/discover/computerlist [Route("/ace/discover/computerlist")] [HttpPost()] public IActionResult ComputerList([FromBody]DiscoveryComputerListViewModel param) { if (ModelState.IsValid) { _discoverService.Discover(param); return Ok(); } else { return BadRequest(ModelState); } } } } ================================================ FILE: ACE-WebService/src/ACEWebService/Controllers/DownloadController.cs ================================================ using ACEWebService.Entities; using ACEWebService.Services; using ACEWebService.ViewModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System; using Microsoft.AspNetCore.Hosting; namespace ACEWebService.Controllers { [Route("ace/[controller]")] public class DownloadController : Controller { private ACEWebServiceDbContext _context; private IHostingEnvironment _hostingEnv; private IDownloadService _downloadService; public DownloadController(ACEWebServiceDbContext context, IHostingEnvironment hostingEnv, IDownloadService downloadService) { _context = context; _hostingEnv = hostingEnv; _downloadService = downloadService; } // POST /ace/download [Authorize(Policy = "ApiKey")] [HttpPost] public IActionResult RequestFile([FromBody]DownloadRequestViewModel param) { if (ModelState.IsValid) { Guid Id = Guid.NewGuid(); _downloadService.DownloadRequest(param, Id); return Ok(Id); } else { return BadRequest(ModelState); } } // POST /ace/download/{id} [HttpPost("{id}")] public IActionResult ReceiveFile([FromRoute]Guid id, [FromBody]DownloadReceiveViewModel param) { if (ModelState.IsValid) { _context.Downloads.Add(new Download{ Id = id, ComputerName = param.ComputerName, Name = param.Name, FullPath = param.FullPath, Content = param.Content, DownloadTime = DateTime.UtcNow }); _context.SaveChanges(); return Ok(param.FullPath); } else { return BadRequest(ModelState); } } } } ================================================ FILE: ACE-WebService/src/ACEWebService/Controllers/ResultController.cs ================================================ using ACEWebService.Services; using ACEWebService.ViewModels; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using System; namespace ACEWebService.Controllers { [Route("ace/[controller]")] public class ResultController : Controller { private ISweepResultProcessorService _sweepProcessorService; //IConfigurationRoot _configuration; public ResultController(ISweepResultProcessorService sweepWriterService) { _sweepProcessorService = sweepWriterService; } // POST /ace/result/{scandId} [HttpPost("{id}")] public IActionResult Post([FromRoute]Guid id, [FromBody]SweepResultViewModel result) { if (ModelState.IsValid) { _sweepProcessorService.Process(id, result); return Ok(); } else { return BadRequest(ModelState); } } } } ================================================ FILE: ACE-WebService/src/ACEWebService/Controllers/ScanController.cs ================================================ using ACEWebService.Entities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System; using System.Linq; namespace ACEWebService.Controllers { [Authorize(Policy = "ApiKey")] [Route("ace/[controller]")] public class ScanController : Controller { private ACEWebServiceDbContext _context; public ScanController(ACEWebServiceDbContext context) { _context = context; } // GET /ace/scan/{sweepId} [HttpGet("{id}")] public IQueryable GetSweepScans([FromRoute]Guid id) { return _context.Set().Where(s => s.SweepIdentifier == id); } // POST /ace/scan/success/{id} [Route("/ace/scan/success/{id}")] [HttpPost("{id}")] public IActionResult Success([FromRoute]Guid id) { if (ModelState.IsValid) { Scan scan = _context.Scans.Single(s => s.Id == id); scan.StopTime = DateTime.UtcNow; scan.Status = "Completed"; _context.Scans.Update(scan); Sweep sweep = _context.Sweeps.Single(s => s.Id == scan.SweepIdentifier); sweep.CompleteCount++; if ((sweep.CompleteCount + sweep.ErrorCount) == sweep.ScanCount) { sweep.Status = "Completed"; } _context.Sweeps.Update(sweep); _context.SaveChanges(); return Ok(); } else { return BadRequest(ModelState); } } // POST /ace/scan/failed/{id} [Route("/ace/scan/failed/{id}")] [HttpPost("{id}")] public IActionResult Failure([FromRoute]Guid id) { if (ModelState.IsValid) { Scan scan = _context.Scans.Single(s => s.Id == id); scan.StopTime = DateTime.UtcNow; scan.Status = "Failed"; _context.Scans.Update(scan); Sweep sweep = _context.Sweeps.Single(s => s.Id == scan.SweepIdentifier); sweep.ErrorCount++; if ((sweep.CompleteCount + sweep.ErrorCount) == sweep.ScanCount) { sweep.Status = "Completed"; } _context.Sweeps.Update(sweep); _context.SaveChanges(); return Ok(); } else { return BadRequest(ModelState); } } } } ================================================ FILE: ACE-WebService/src/ACEWebService/Controllers/ScriptController.cs ================================================ using ACEWebService.Entities; using ACEWebService.ViewModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System; using System.IO; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; namespace ACEWebService.Controllers { //[Authorize(Policy = "ApiKey")] [Route("ace/[controller]")] public class ScriptController : Controller { private ACEWebServiceDbContext _context; private IHostingEnvironment _hostingEnv; public ScriptController(ACEWebServiceDbContext context, IHostingEnvironment hostingEnv) { _context = context; _hostingEnv = hostingEnv; } // GET /ace/script/delete/{id} [HttpGet("delete/{id}")] public Script Delete([FromRoute]Guid id) { User requestor = _context.Users.SingleOrDefault(u => u.ApiKey == Request.Headers["X-ApiKey"]); if (requestor.IsAdmin) { try { Script script = _context.Scripts.SingleOrDefault(s => s.Id == id); // Delete the script from disk string scriptLocation = string.Format(@"{0}\{1}", _hostingEnv.ContentRootPath, script.Uri); System.IO.File.Delete(scriptLocation); // Remove the script from the database _context.Scripts.Remove(script); _context.SaveChanges(); return script; } catch { throw new Exception("Failed to delete script."); } } else { throw new Exception("Only administrator users can delete credentials."); } } // GET /ace/script [HttpGet] public IEnumerable