SuperAPI AI Directory

malware-hash

Security & auditing

View repository

Updated 10-16 05:42

About this skill

What this skill does

Accepts a file hash (MD5/SHA1/SHA256) or file path and queries the VirusTotal API v3 for malware reputation. Parses detection ratio, per-vendor results, tags, and first-seen date to summarize the threat level.

When to use

  • Quickly checking whether a suspicious file is a known malware sample
  • Assessing the threat level of hashes collected during incident response
  • Bulk-querying hashes from an IOC list
  • Prioritizing files before forensic analysis

Prerequisites

  • curl (HTTP requests)
  • python3 (JSON parsing)
  • VirusTotal API key: environment variable SECSKILL_VT_API_KEY

API key setup (in priority order)

# Method 1: Set environment variable directly (current session)
export SECSKILL_VT_API_KEY="your_api_key_here"

# Method 2: Persistent config file
mkdir -p ~/.config/security-skill
echo 'SECSKILL_VT_API_KEY=your_api_key_here' >> ~/.config/security-skill/secrets.env
chmod 600 ~/.config/security-skill/secrets.env

# Method 3: If neither above method is available, the skill will prompt interactively at runtime

Inputs

Field Description Example
HASH_OR_FILE MD5/SHA1/SHA256 hash string or file path 44d88612fea8a8f36de82e1278abb02f

Workflow

Step 1: Verify API key credentials

# Credential resolution: environment variable → config file → interactive input
resolve_vt_api_key() {
    if [ -n "$SECSKILL_VT_API_KEY" ]; then
        echo "[+] API key: loaded from environment variable"
        return 0
    fi

    local secrets_file="$HOME/.config/security-skill/secrets.env"
    if [ -f "$secrets_file" ]; then
        source "$secrets_file"
        if [ -n "$SECSKILL_VT_API_KEY" ]; then
            echo "[+] API key: loaded from $secrets_file"
            return 0
        fi
    fi

    echo "[!] VirusTotal API key not found."
    echo "    Get a free key at https://www.virustotal.com/gui/my-apikey"
    read -rsp "Enter API key: " SECSKILL_VT_API_KEY
    echo
    export SECSKILL_VT_API_KEY

    read -rp "Save this key to $secrets_file? [y/N] " save_key
    if [[ "$save_key" =~ ^[Yy]$ ]]; then
        mkdir -p "$(dirname "$secrets_file")"
        echo "SECSKILL_VT_API_KEY=$SECSKILL_VT_API_KEY" >> "$secrets_file"
        chmod 600 "$secrets_file"
        echo "[+] API key saved"
    fi
}

resolve_vt_api_key

Step 2: Validate input and compute hash

HASH_OR_FILE="${SECSKILL_HASH_OR_FILE:-${1:-}}"

if [ -z "$HASH_OR_FILE" ]; then
    read -rp "Enter hash or file path: " HASH_OR_FILE
fi

# If a file path is provided, compute the hash
if [ -f "$HASH_OR_FILE" ]; then
    echo "[+] File detected: computing hashes..."
    MD5_HASH=$(md5sum "$HASH_OR_FILE" | cut -d' ' -f1)
    SHA1_HASH=$(sha1sum "$HASH_OR_FILE" | cut -d' ' -f1)
    SHA256_HASH=$(sha256sum "$HASH_OR_FILE" | cut -d' ' -f1)
    echo "    MD5:    $MD5_HASH"
    echo "    SHA1:   $SHA1_HASH"
    echo "    SHA256: $SHA256_HASH"
    QUERY_HASH="$SHA256_HASH"
    echo "[+] Using SHA256 for VirusTotal lookup"
else
    QUERY_HASH="$HASH_OR_FILE"
    # Validate hash length
    HASH_LEN=${#QUERY_HASH}
    case $HASH_LEN in
        32) echo "[+] MD5 hash detected" ;;
        40) echo "[+] SHA1 hash detected" ;;
        64) echo "[+] SHA256 hash detected" ;;
        *) echo "[!] Invalid hash length: $HASH_LEN (MD5=32, SHA1=40, SHA256=64)"; exit 1 ;;
    esac
fi

Step 3: Query the VirusTotal API

echo "[*] Querying VirusTotal API..."
VT_RESPONSE=$(curl -s \
    --request GET \
    --url "https://www.virustotal.com/api/v3/files/${QUERY_HASH}" \
    --header "x-apikey: ${SECSKILL_VT_API_KEY}")

# Check for HTTP errors
if echo "$VT_RESPONSE" | python3 -c "import json,sys; d=json.load(sys.stdin); sys.exit(0 if 'data' in d else 1)" 2>/dev/null; then
    echo "[+] Query successful"
    echo "$VT_RESPONSE" > /tmp/vt_response.json
else
    ERROR_MSG=$(echo "$VT_RESPONSE" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('error',{}).get('message','Unknown error'))" 2>/dev/null)
    echo "[!] API error: $ERROR_MSG"
    echo "    Response: $VT_RESPONSE"
    exit 1
fi

Step 4: Parse results and assess threat level

python3 - <<'PYEOF'
import json, sys
from datetime import datetime

with open('/tmp/vt_response.json') as f:
    data = json.load(f)

attrs = data['data']['attributes']
stats = attrs.get('last_analysis_stats', {})
results = attrs.get('last_analysis_results', {})
tags = attrs.get('tags', [])

malicious = stats.get('malicious', 0)
suspicious = stats.get('suspicious', 0)
undetected = stats.get('undetected', 0)
total = malicious + suspicious + undetected + stats.get('harmless', 0)

# Determine threat level
if malicious >= 10:
    threat_level = "HIGH (likely malicious)"
    threat_emoji = "[!!!]"
elif malicious >= 3:
    threat_level = "MEDIUM (further investigation needed)"
    threat_emoji = "[!]"
elif malicious >= 1 or suspicious >= 1:
    threat_level = "LOW (suspicious)"
    threat_emoji = "[?]"
else:
    threat_level = "CLEAN (not detected)"
    threat_emoji = "[OK]"

# First seen date
first_seen_ts = attrs.get('first_submission_date')
first_seen = datetime.fromtimestamp(first_seen_ts).strftime('%Y-%m-%d %H:%M:%S') if first_seen_ts else 'N/A'

last_seen_ts = attrs.get('last_submission_date')
last_seen = datetime.fromtimestamp(last_seen_ts).strftime('%Y-%m-%d %H:%M:%S') if last_seen_ts else 'N/A'

print("=" * 60)
print("VirusTotal Hash Reputation Results")
print("=" * 60)
print(f"\n{threat_emoji} Threat level: {threat_level}")
print(f"   Detection ratio: {malicious}/{total} engines")
print(f"   Suspicious: {suspicious}, Undetected: {undetected}")
print(f"\n   First seen: {first_seen}")
print(f"   Last seen:  {last_seen}")

if tags:
    print(f"\n   Tags: {', '.join(tags)}")

# List of detecting vendors
detecting_vendors = [
    (vendor, info['result'])
    for vendor, info in results.items()
    if info.get('category') in ('malicious', 'suspicious')
]

if detecting_vendors:
    print(f"\n[Detecting vendors] ({len(detecting_vendors)} total)")
    for vendor, result in sorted(detecting_vendors):
        print(f"  - {vendor}: {result}")

# File info
file_type = attrs.get('type_description', attrs.get('magic', 'N/A'))
file_size = attrs.get('size', 'N/A')
file_name = attrs.get('meaningful_name', attrs.get('names', ['N/A'])[0] if attrs.get('names') else 'N/A')
print(f"\n[File info]")
print(f"  Name: {file_name}")
print(f"  Type: {file_type}")
print(f"  Size: {file_size} bytes" if isinstance(file_size, int) else f"  Size: {file_size}")

print("\n[+] Details: https://www.virustotal.com/gui/file/" + data['data']['id'])
PYEOF

Step 5: Save results

# Save results to a text file
python3 - <<'PYEOF'
import json
with open('/tmp/vt_response.json') as f:
    data = json.load(f)
attrs = data['data']['attributes']
stats = attrs.get('last_analysis_stats', {})
malicious = stats.get('malicious', 0)
total = sum(stats.values())
file_id = data['data']['id']
with open('/tmp/vt_result_summary.txt', 'w') as f:
    f.write(f"hash={file_id}\n")
    f.write(f"malicious={malicious}\n")
    f.write(f"total={total}\n")
    f.write(f"url=https://www.virustotal.com/gui/file/{file_id}\n")
print("[+] Summary saved: /tmp/vt_result_summary.txt")
print("[+] Full response: /tmp/vt_response.json")
PYEOF

Done when

  • Detection ratio (malicious/total) is printed
  • Threat level (HIGH/MEDIUM/LOW/CLEAN) is determined
  • List of detecting vendors is shown (when detections exist)
  • Summary saved to /tmp/vt_result_summary.txt

Failure modes

Problem Cause Solution
401 Unauthorized Missing or invalid API key Re-check SECSKILL_VT_API_KEY
404 Not Found Hash not in VT database Upload file directly (via VT website)
429 Too Many Requests Free API rate limit exceeded Wait 1 minute and retry (free tier: 4 req/min)
Hash length error Invalid hash input MD5=32 chars, SHA1=40 chars, SHA256=64 chars
curl not installed Missing tool sudo apt install curl

Notes

  • The VirusTotal free API is limited to 4 requests/minute and 500 requests/day.
  • New malware may not yet be in VT. A CLEAN result does not guarantee safety.
  • Uploading a file directly to VT shares that file and its metadata with VirusTotal. For sensitive files, query by hash only.
  • When querying hashes from extracted IOCs, use in conjunction with the ioc-extract skill.