name: OTTERCOOKIE Clipboard Stealer High-Frequency Get-Clipboard Polling Analytic
signatureid: WEL-PSH136-RUN
category: 'Collection'
threatname: 'Clipboard Data'
functionality: 'Microsoft Windows PowerShell'
description: |
Detects the Windows clipboard-stealer module of the REF9403 Contagious Interview / OTTERCOOKIE
campaign. The malware's fourth module polls the clipboard every 500 milliseconds and exfiltrates
any changed content to the rightwidth[.]dev C2. On Windows it retrieves clipboard contents by
spawning a fresh PowerShell process for every poll using the exact invocation
"powershell -NoProfile -NonInteractive Get-Clipboard" with windowsHide set. Because a new
short-lived PowerShell process is created roughly twice per second, the behavioral signature is a
high-frequency repetition of NoProfile/NonInteractive Get-Clipboard executions from the same host.
This rule uses aggregated event analytics to surface that abnormal cadence, which is inconsistent
with any legitimate interactive or scripted clipboard use.
reference:
- https://www.elastic.co/security-labs/contagious-interview-malware-svg-steganography
- https://attack.mitre.org/techniques/T1115/
labels:
- attack.collection
- attack.t1115
- attack.execution
- attack.t1059.001
- OTTERCOOKIE
- Contagious_Interview
- REF9403
- Clipboard_Stealer
- DPRK
- APT
logsource:
service: powershell
product: windows
detection:
selection_get_clipboard:
ScriptBlockText|contains:
- 'Get-Clipboard'
selection_noninteractive_flags:
ScriptBlockText|contains:
- '-NoProfile'
- '-nop'
- '-NonInteractive'
- '-noni'
condition: selection_get_clipboard and selection_noninteractive_flags
analytical_type:
aggregated_event_analytics:
filter: ~
distinct: ~
threshold_type: 'frequency'
number_of_occurrences: 10
within_duration: '00:01:00'
having_similar: devicehostname
consecutive_events: false
criticality: High
verbose_info:
violation_summary:
grouping_attribute: 'devicehostname'
level2_attribute: 'accountname'
level2_metadata_attributes:TECHNICAL DETAILS
Clipboard poller:
const getClipboard = async () => {
if (os.platform() === "darwin") return execSync("pbpaste", ...).trim();
if (os.platform() === "win32") return execSync(
"powershell -NoProfile -NonInteractive Get-Clipboard",
{ encoding: "utf8", windowsHide: true }).trim();
return null; // Linux: no implementation
};
Poll interval: 500 ms -> ~120 PowerShell spawns/minute. Threshold of 10/min is
deliberately conservative to tolerate scriptblock-logging gaps; tighten toward
30-60/min if FP rate allows. Changed clipboard content is POSTed to
rightwidth[.]dev /api/service/makelog/.
Detection notes:
- The repeated spawn of powershell.exe with identical NoProfile/NonInteractive
Get-Clipboard command line is the anchor. A process_creation variant keying on
Image endswith \powershell.exe with ChildProcessCommandLine contains all
['-NoProfile','-NonInteractive','Get-Clipboard'] under the same aggregation
window is equally valid where scriptblock logging is unavailable.
False Positives:
- Clipboard-manager utilities can poll, but rarely via a fresh NoProfile
NonInteractive PowerShell process twice per second. Scope by accountname /
parent process (node) to reduce noise in managed environments.
Policy building walkthrough can be found in this previous post:
