Ourania I. Markaki

26 papers B 1C 2Journal 8Unranked 15
YearRankTypeTitle / Venue / Authors
2024 conf
IISA
Georgios P. Trachanas, Apostolos Arsenopoulos, Theodoros Tsalidis, Filippos Serepas, Ourania I. Markaki, Dimitrios Askounis
2024 conf
ICE/ITMC
Sotiris Pelekis, Evangelos Karakolis, George Lampropoulos, Spiros Mouzakitis, Ourania I. Markaki, Christos Ntanos, Dimitris Askounis
2024 J jnl
CoRR
Sotiris Pelekis, Evangelos Karakolis, George Lampropoulos, Spiros Mouzakitis, Ourania I. Markaki, Christos Ntanos, Dimitris Askounis
2023 conf
IISA
Ourania I. Markaki, Aikaterini Papapostolou, Spiros Mouzakitis, Izabela Zrazinska, Urszula Sobek, Thomas Wilczek, Antonis Troumpoukis, Xenia Ziouvelou, Vangelis Karkaletsis, Alexandra Carrasco, Miriam García, Gabriele Röger, Andrea Micheli, Jaime Alessandro Codagnone, Miguel de Prado, Siobhan O'Neill
2023 conf
IntelliSys (2)
Spiros Mouzakitis, Ourania I. Markaki, Katerina Papapostolou, Evangelos Karakolis, Sotiris Pelekis, John E. Psarras
2021 J jnl
Oper. Res.
Ourania I. Markaki, Dimitris Askounis
2018 conf
I-ESA
Ariadni Michalitsi-Psarrou, Sotirios Koussouris, C. Kontzinos, Ourania I. Markaki, Christos Ntanos, Dimitrios Panopoulos, John E. Psarras
2017 J jnl
Telematics Informatics
Panagiotis Kokkinakos, Ourania I. Markaki, Sotirios Koussouris, John E. Psarras
2016 conf
I-ESA
Irene Matzakou, Ourania I. Markaki, Konstantinos Ergazakis, Dimitris Askounis
2015 conf
EEPM@eGOV
Panagiotis Kokkinakos, Sotirios Koussouris, Ourania I. Markaki, Costas D. Koutras, John E. Psarras, Yuri Glickman, Martin Löhe, Habin Lee
2015 conf
EEPM@eGOV
George Markou, Eleni Palaiolouga, Panagiotis Kokkinakos, Ourania I. Markaki, Sotirios Koussouris, Dimitrios Askounis
2015 conf
MCIS
Ourania I. Markaki, Panagiotis Kokkinakos, Sotirios Koussouris, Costas D. Koutras, John E. Psarras
2014 J jnl
Wirel. Pers. Commun.
Dimitris E. Charilas, Athanasios D. Panagopoulos, Ourania I. Markaki
2014 J jnl
Int. J. Electron. Gov. Res.
Ourania I. Markaki, Panagiotis Kokkinakos, Sotirios Koussouris, John E. Psarras, Habin Lee, Martin Löhe, Yuri Glikman
2014 C conf
PRO-VE
Ourania I. Markaki, Sotirios Koussouris, Panagiotis Kokkinakos, Dimitrios Panopoulos, Dimitris Askounis
2013 C conf
WETICE
Ourania I. Markaki, Dimitrios Panopoulos, Panagiotis Kokkinakos, Sotirios Koussouris, Dimitris Askounis
2012 conf
APMS (2)
Ourania I. Markaki, Panagiotis Kokkinakos, Dimitrios Panopoulos, Sotirios Koussouris, Dimitris Askounis
2012 conf
APMS (2)
Panagiotis Kokkinakos, Ourania I. Markaki, Dimitrios Panopoulos, Sotirios Koussouris, Dimitris Askounis
2011 J jnl
Int. J. E Serv. Mob. Appl.
Ourania I. Markaki, Yannis Charalabidis, Dimitris Askounis
2009 conf
WSKS (1)
Ourania I. Markaki, Dimitris E. Charilas, Yannis Charalabidis, Dimitris Askounis
2009 conf
MOBILIGHT
Dimitris E. Charilas, Ourania I. Markaki, John E. Psarras, Philip Constantinou
2009 conf
MOBILIGHT
Dimitris E. Charilas, Athanasios D. Panagopoulos, Panagiotis Vlacheas, Ourania I. Markaki, Philip Constantinou
2009 J jnl
Int. J. Knowl. Learn.
Ourania I. Markaki, Dimitris E. Charilas, Yannis Charalabidis, Dimitris Askounis
2008 conf
ISWPC
Dimitris E. Charilas, Ourania I. Markaki, Elias Z. Tragos
2008 J jnl
Comput. Networks
Dimitris E. Charilas, Ourania I. Markaki, Dimitris Nikitopoulos, Michael E. Theologou
2007 B conf
PIMRC
Ourania I. Markaki, Dimitris E. Charilas, Dimitris Nikitopoulos
redb/extractors/malcontent.py
← Index redb/extractors/malcontent.py python
import inspect
import json
import subprocess
from typing import Any
from datetime import datetime, timezone

from redb.extractors.enum import Tag
from redb.models.dataclasses import Malcontent
from redb.extractors.extractor import Extractor
from dotenv import load_dotenv
import os

load_dotenv(override=True)


class MalcontentExtractor(Extractor):
    """
    Extractor for malcontent tool from chainguard-dev/malcontent.

    Malcontent discovers supply-chain compromises through context, differential
    analysis, and 14,000+ YARA rules. It analyzes binaries and code to detect
    malicious content and suspicious behavioral patterns.

    Binary can be extracted from Docker image:
        docker cp $(docker create cgr.dev/chainguard/malcontent:latest):/usr/bin/mal /usr/local/bin/mal

    Stores full JSON output for materialized view extraction.
    """

    # Cache version at class level to avoid repeated subprocess calls
    _cached_version = None

    def __init__(
        self,
        filepath,
        log,
        exporters=None,
        index_prefix=None,
        elastic_index=None,
        known_benign=False,
        known_malicious=False,
    ):
        super().__init__(
            filepath,
            log,
            exporters,
            index_prefix,
            elastic_index,
            known_benign,
            known_malicious
        )
        self.malcontent = None

    @classmethod
    def _get_malcontent_version(cls, log) -> str:
        """Get malcontent version, cached at class level."""
        if cls._cached_version is not None:
            return cls._cached_version

        malcontent_path = os.getenv("MALCONTENT_PATH", "/usr/local/bin/mal")
        try:
            result = subprocess.run(
                [malcontent_path, "--version"],
                capture_output=True,
                text=True,
                timeout=10
            )
            version_output = result.stdout.strip()
            if result.returncode == 0 and version_output:
                # Parse "malcontent version v1.21.5" -> "1.21.5"
                if version_output.startswith("malcontent version v"):
                    version_output = version_output[len("malcontent version v"):]
                elif version_output.startswith("malcontent version "):
                    version_output = version_output[len("malcontent version "):]
                cls._cached_version = version_output
            else:
                cls._cached_version = "unknown"
        except Exception as e:
            log.warning(f"Could not get malcontent version: {e}")
            cls._cached_version = "unknown"

        return cls._cached_version

    def _extract_malcontent(self):
        self.log.debug(inspect.currentframe().f_code.co_name)
        TIMEOUT = int(os.getenv("MALCONTENT_TIMEOUT", "300"))
        malcontent_path = os.getenv("MALCONTENT_PATH", "/usr/local/bin/mal")

        malcontent_command = [malcontent_path, "analyze", "--format=json", self.filepath]

        import signal

        try:
            process = subprocess.Popen(
                malcontent_command,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True,
                preexec_fn=os.setsid
            )

            try:
                stdout, stderr = process.communicate(timeout=TIMEOUT)
                if process.returncode != 0:
                    self.log.error(f"Error running malcontent, return code: {process.returncode}, stderr: {stderr}")
                    return {}
            except subprocess.TimeoutExpired:
                self.log.warning(f"The malcontent command timed out after {TIMEOUT} seconds, terminating process group")
                try:
                    os.killpg(process.pid, signal.SIGTERM)
                    try:
                        process.wait(timeout=3)
                    except subprocess.TimeoutExpired:
                        self.log.warning("Process didn't terminate with SIGTERM, sending SIGKILL")
                        os.killpg(process.pid, signal.SIGKILL)
                    process.wait()
                except (ProcessLookupError, OSError) as e:
                    self.log.warning(f"Error while killing process: {e}")
                return {}

            try:
                malcontent_output = json.loads(stdout)
            except json.JSONDecodeError as e:
                self.log.error(f"Error parsing malcontent output: {e}")
                return {}

            # Unwrap the Files/<path> structure to get the inner content
            # Structure is: {"Files": {"/path/to/file": {<actual content>}}}
            files_dict = malcontent_output.get("Files", {})
            if not files_dict:
                self.log.warning("Malcontent output has no 'Files' key")
                return {}

            # Get the first (and only) file's content
            file_content = next(iter(files_dict.values()), {})
            if not file_content:
                self.log.warning("Malcontent output has empty file content")
                return {}

            # Extract risk score and level from the unwrapped content
            risk_score = file_content.get("RiskScore", 0)
            risk_level = file_content.get("RiskLevel", "")

            version = self._get_malcontent_version(self.log)

            self.malcontent = Malcontent(
                malcontent_dump=json.dumps(file_content),
                version=version,
                risk_score=risk_score,
                risk_level=risk_level
            )
            self.log.debug(f"Malcontent analysis complete, version={version}, risk={risk_level}({risk_score})")

        except Exception as e:
            self.log.error(f"Unexpected error in malcontent extraction: {str(e)}")
            if 'process' in locals() and process.poll() is None:
                try:
                    os.killpg(process.pid, signal.SIGKILL)
                    process.wait()
                except:
                    pass
            return {}

    def prepare_export_data(self, exporter_type: str) -> Any:
        if exporter_type == "ClickHouseExporter":
            current_time = datetime.now(timezone.utc)

            data = [[
                self.sha256,
                current_time,
                self.malcontent.version,
                self.malcontent.risk_score,
                self.malcontent.risk_level,
                self.malcontent.malcontent_dump
            ]]

            column_names = [
                'sha256', 'analysis_date',
                'malcontent_version', 'malcontent_risk_score', 'malcontent_risk_level',
                'malcontent_json'
            ]

            column_type_names = [
                'FixedString(64)',
                'DateTime64(3, \'UTC\')',
                'LowCardinality(String)', 'UInt8', 'LowCardinality(String)',
                'JSON'
            ]

            return (data, column_names, column_type_names)

    def get_clickhouse_table(self) -> str:
        return "redb_malcontent"

    def extract(self):
        self.log.debug(inspect.currentframe().f_code.co_name)
        try:
            self._extract_malcontent()
            return self.malcontent
        except Exception as e:
            self.log.error(f"Error extracting malcontent: {e}")
            return None

    def tag(self):
        return Tag.MALCONTENT.value