承接 fpoirotte/idmef 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

fpoirotte/idmef

Composer 安装命令:

composer require fpoirotte/idmef

包简介

IDMEF library for PHP

README 文档

README

Introduction

This repository contains a PHP library implementing the Intrusion Detection Message Exchange Format (IDMEF) defined in RFC 4765.

It supports all the classes and attributes defined in the RFC, supports XML serialization/unserialization and also includes code to send alerts generated using IDMEF to Prelude SIEM.

Prerequisites

For basic usage, you only need the following dependencies:

  • The Composer dependency manager
  • PHP >= 7.4
  • the PHP DOM extension
  • the PHP Filter extension

Additional features require additional dependencies. To use XML serialization/unserialization, you will also need:

  • the PHP XMLReader extension
  • the PHP XMLWriter extension

To send alerts to Prelude SIEM, you will need:

  • the PHP FFI extension

Installation

Use Composer to add the library to your project's requirements:

$ php /path/to/composer.phar require fpoirotte/idmef

Usage

IDMEF messages

A few words about IDMEF paths

To make working with IDMEF messages easier, this library implements the same concept of "IDMEF paths" as Prelude SIEM through a getIterator() method. (more on that later)

The library also supports direct access to attributes using getters and setters. (read on for more information)

When returning an attribute's path through the getName() method, the library always uses the official class/attribute names defined in the IDMEF RFC, such as Alert.CorrelationAlert.name.

However, when setting an IDMEF message's attributes, you may also use Prelude SIEM's IDMEF paths, such as alert.correlation_alert.name. A list of valid paths recognized by both Prelude SIEM and this library can be found on the SECEF website.

When using getters/setters, a similar approach is taken, but with a few caveats:

  • PHP's object operator (->) is used instead of a dot (.) to separate the various parts of the IDMEF path.

    Hence, to retrieve the value for the Alert.CorrelationAlert.name path inside an IDMEF object, use $name = $alert->CorrelationAlert->name, Prelude's path names ($alert->correlation_alert->name) are also supported.

  • PHP's array operator ([]) is used to access entries inside a list, instead of Prelude's list access operator (()).

    Like Prelude SIEM, this library also supports negative list indices. Therefore, to retrieve the name of the last source node using the getters, the following call may be used: $name = $alert->source[-1]->node->name;. Compare this to Prelude's paths: alert.source(-1).node.name.

  • Prelude SIEM's prepend (<<) and append (>>) operators can be used. As a result, the following call appends a new source node to the alert and gives it a name: $alert->source['>>']->node->name = "foo";.

  • PHP's array operator may also be used to append a new entry to a list. Therefore, calling $alert->source[]->node->name = "foo"; is functionally identical to calling $alert->source['>>']->node->name = "foo";.

As is the case with Prelude SIEM, this library indexes IDMEF lists starting from 0. So, $alert->source[0] refers to the first source in the alert.

Last but not least, there is one noticeable difference between this library's paths implementation and Prelude SIEM's paths, involving the Analyzer class. The RFC states that analyzers can be chained using a recursive definition (Alert.Analyzer, Alert.Analyzer.Analyzer ...). To make working with chained analyzers easier, Prelude SIEM represents them as a list (alert.analyzer(0), alert.analyzer(1), ...). To be as close to the IDMEF RFC as possible, this library uses the recursive approach to represent chained analyzers. However, some of the API may also implement Prelude SIEM's notation for them, so your mileage may vary.

Data types

The library automatically converts values to their expected type whenever it is possible. It will also convert PHP types to their IDMEF counterparts automatically.

Therefore, it is possible to pass a string value representing an integer to an attribute that expects an IDMEF integer:

// Import a few symbols
use \fpoirotte\IDMEF\Types\IntegerType;
use \fpoirotte\IDMEF\Types\StringType;

// The following statements are okay:
$alert->OverflowAlert->size = new IntegerType(42);  // IDMEF integer object
$alert->OverflowAlert->size = 42;                   // PHP integer
$alert->OverflowAlert->size = '42';                 // IDMEF integer value
$alert->OverflowAlert->size = '0x2A';               // IDMEF (hexadecimal) integer value

// The following statements will throw an exception:
$alert->OverflowAlert->size = new StringType('42'); // The "size" attribute is an integer, not a string
$alert->OverflowAlert->size = 42.0;                 // A floating-point value is not an integer either
$alert->OverflowAlert->size = '';                   // Invalid integer (value is missing)
$alert->OverflowAlert->size = '0x';                 // Invalid integer (hexadecimal number missing a value)
$alert->OverflowAlert->size = '2A';                 // Invalid integer (possibly an hexadecimal number missing the prefix,
                                                    // or trailing data after the intended number)

However, this is only true when the expected type is known in advance. For those situations where this may not be the case (eg. additional data), the library will also attempt to convert the type automatically, but you may have to set the type explicitly.

The following table shows how native PHP types after converted into their IDMEF counterparts.

PHP-type to IDMEF-type conversion table
PHP type IDMEF type
boolean boolean (\fpoirotte\IDMEF\Types\BooleanType)
integer integer (\fpoirotte\IDMEF\Types\IntegerType)
string string (\fpoirotte\IDMEF\Types\StringType)
float real number (\fpoirotte\IDMEF\Types\RealType)
\DateTimeInterface and its derivatives date-type (\fpoirotte\IDMEF\Types\DateTimeType)
\DOMNode xmltext (\fpoirotte\IDMEF\Types\XmltextType)
\SimpleXMLElement xmltext (\fpoirotte\IDMEF\Types\XmltextType)
\XMLWriter xmltext (\fpoirotte\IDMEF\Types\XmltextType)
\fpoirotte\IDMEF\Types\AbstractType and its derivatives unchanged
any other value throws an exception

The following types must be managed manually when used in additional data:

  • \fpoirotte\IDMEF\Types\ByteType
  • \fpoirotte\IDMEF\Types\ByteStringType
  • \fpoirotte\IDMEF\Types\CharacterType
  • \fpoirotte\IDMEF\Types\NtpstampType
  • \fpoirotte\IDMEF\Types\PortlistType

IDMEF message manipulation

The following example shows how to create an alert, set some of its attributes, then do some stuff with it.

<?php

// Include Composer's autoloader
require '.' . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';

// Import a few symbols from the library
use \fpoirotte\IDMEF\Classes\Alert;
use \fpoirotte\IDMEF\Types\AbstractType;

// Create the alert
$alert = new Alert;

// Set mandatory attributes
$alert->analyzer->analyzerid = 'hq-dmz-analyzer01';
$alert->analyzer->node->category = 'dns';
$alert->analyzer->node->location = 'Headquarters DMZ Network';
$alert->analyzer->node->name = 'analyzer01.example.com';
$alert->create_time->ntpstamp = '0xbc722ebe.0x00000000';

// Set some optional attributes and provide additional data
$alert->classification->text = "Houston, we've had a problem here";
$alert->additional_data[  ]->type = 'string';
$alert->additional_data[-1]->meaning = 'mission';
$alert->additional_data[-1]->data = 'Apollo 13';
$alert->additional_data[  ]->type = 'string';
$alert->additional_data[-1]->meaning = 'speaker';
$alert->additional_data[-1]->data = 'Jack Swigert';

// Display the alert's classification:
echo $alert->classification->text . PHP_EOL;

// Iterate over additional data and display each entry's meaning and data:
foreach ($alert->additional_data as $ad) {
    echo $ad->meaning . ': ' . $ad->data . PHP_EOL;
}

// Same thing, but this time we use an explicit iterator and IDMEF paths:
foreach ($alert->getIterator('alert.additional_data') as $ad) {
    echo $ad->meaning . ': ' . $ad->data . PHP_EOL;
}

// Dump the alert's contents, by iterating over instances
// of the AbstractType class (the base class for all leaf nodes)
foreach ($alert->getIterator('{' . AbstractType::class . '}', null, 0, -1) as $path => $node) {
    echo $path . ' => ' . $node . PHP_EOL;
}

// Look for nodes with a specific value:
foreach ($alert->getIterator(null, 'Apollo 13', 0, -1) as $path => $node) {
    echo $path . PHP_EOL;   // displays "Alert.AdditionalData(0).data"
}

// The 3rd ($minDepth) and 4th ($maxDepth) parameter to getIterator()
// can be used to restrict iteration to nodes at a certain depth,
// starting at 0 for the root object.
// The following example will only dump the analyzer node's attribute
// due to the restrictions.
// Eg.  path:   Alert.Analyzer.Node.Name
//      depth:  (0)   (1)      (2)  (3)
foreach ($alert->getIterator(null, null, 3, -1) as $path => $node) {
    echo $path . PHP_EOL;   // displays "Alert.Analyzer.Node.category",
                            //          "Alert.Analyzer.Node.location"
                            //      and "Alert.Analyzer.Node.name"
}

Heatbeat messages and more specialized alert messages (CorrelationAlert, ToolAlert and OverflowAlert) follow the same pattern.

XML (un)serialization

When serializing an IDMEF message to XML, a special container must be created.

Assuming an alert and a heartbeat have been created and stored respectively in the $alert and $heartbeat variables, the following example can be used to serialize them into an XML IDMEF message:

<?php

// Import the container and the serializer
use \fpoirotte\IDMEF\Classes\IDMEFMessage;
use \fpoirotte\IDMEF\Serializers\Xml;

// Create an instance of the container and add the messages to it
$idmef = new IDMEFMessage;
$idmef[] = $alert;
$idmef[] = $heartbeat;

// Create an instance of the serialization class and produce the output
$serializer = new Xml;
echo $serializer->serialize($idmef) . PHP_EOL;

Likewise, unserialization returns an IDMEFMessage container. Assuming that $xml refers to a valid XML IDMEF message containing both an alert and a heartbeat (in that order), the following code could be used to unserialize them:

<?php

// Import the (un)serializer
use \fpoirotte\IDMEF\Serializers\Xml;

// Create an instance of the serialization class
// and unserialize the message
$serializer = new Xml;
$idmef      = $serializer->unserialize($xml);
// The unserialization process maintains the objects' order
$alert      = $idmef[0];
$heartbeat  = $idmef[1];

Prelude SIEM

To send IDMEF messages to Prelude SIEM, you must first register a profile with the idmef:w permission for the library.

On the machine where prelude-manager resides, run this:

sudo prelude-admin registration-server prelude-manager

In parallel, on the machine where the library will be used, run this:

# Replace "php" with a custom name for the newly-created profile.
#
# Replace "localhost" with the hostname where prelude-manager is installed.
#
# Replace "clicky" & "users" respectively with the names of the user and group
# that will execute the PHP script.
#
sudo prelude-admin register php idmef:w localhost --uid clicky --gid users

Then, follow the instructions printed by both commands.

Once the profile is successfully registered, you can send IDMEF messages to Prelude SIEM using the following code:

<?php

// Replace this value with your registered profile's name
$profile = 'php';

// Create a new Prelude agent using that profile
$agent = \fpoirotte\IDMEF\PreludeAgent::create($profile);

// Send various alerts/heartbeats
$agent->send($alert);
$agent->send($correlation_alert);
$agent->send($heartbeat);
// and so on

Note

The agent will automatically send heartbeat messages to prelude-manager at a regular interval (defined in the agent's profile). It is therefore not necessary to send them manually.

Likewise, the agent will automatically be shut down (cleanly) when it becomes unused, as part of PHP's garbage collection process. You may also force a shutdown manually by using the following code snippet:

<?php

unset($agent);
gc_collect_cycles();

License

This library is licensed under the GNU Public License version 2. See the COPYING file inside the repository for more information.

fpoirotte/idmef 适用场景与选型建议

fpoirotte/idmef 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 11 次下载、GitHub Stars 达 1, 最近一次更新时间为 2018 年 08 月 29 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「security」 「detection」 「IDMEF」 「intrustion」 「Prelude」 「SIEM」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 fpoirotte/idmef 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 fpoirotte/idmef 我们能提供哪些服务?
定制开发 / 二次开发

基于 fpoirotte/idmef 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 11
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 7
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 1
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2018-08-29