Events are automatically converted to enriched IOCs shared with the community.
1. Overview
CHP (CRAABS Honeypot Protocol) allows any honeypot to forward events to CRAABS via a simple REST API. For each event received, the platform:
- Creates or enriches an IOC from the attacker IP
- Calculates a malicious score based on event type and frequency
- Maps automatically to the corresponding MITRE ATT&CK techniques
- Geolocates the source IP
- Triggers alerts if the score is critical
2. Authentication
Every request must include the CHP key in the X-Honeypot-Key header.
X-Honeypot-Key: chp_a1b2c3d4e5f6...
The key is prefixed with chp_ and is 60 characters long. Never log it in plaintext or commit it to source control.
3. Endpoints
GET/api/honeypot/ping
Heartbeat. Signals that the node is active. Call every 5 minutes.
curl -H "X-Honeypot-Key: chp_..." https://cti.craabs.com/api/honeypot/ping
# Response 200
{"status": "ok", "node": "SSH-Trap", "accepted": true, "protocol": "CHP/1.0"}
POST/api/honeypot/event
Sends a single event. Use this for real-time forwarding.
POST/api/honeypot/events/bulk
Sends up to 100 events in one request. Recommended for high-volume sensors.
# Body: {"events": [ {event}, {event}, ... ]}
# Response 201: {"accepted": 95, "rejected": 2, "iocs_created": 88}
GET/api/honeypot/status
Returns statistics for your node: event count, IOCs generated, last seen.
4. Event format
| Field | Type | Required | Description | Values |
|---|---|---|---|---|
| source_ip | string | Required | Attacker IP address | Valid IPv4 |
| honeypot_type | string | Optional | Lured service type | ssh, http, ftp, rdp, smtp, telnet, mysql, vnc, custom |
| event_type | string | Optional | Event nature | login_attempt, brute_force, exploit, payload, scan, connect, malware, command, generic |
| timestamp | string | Optional | ISO 8601 timestamp | 2026-05-14T10:30:00Z |
| source_port | integer | Optional | Attacker source port | 1-65535 |
| dest_port | integer | Optional | Destination port | 22, 80, 443... |
| username | string | Optional | Attempted username | max 200 chars |
| password | string | Optional | Attempted password | max 500 chars |
| payload | string | Optional | Raw payload (base64 recommended) | free text |
| severity | string | Optional | Estimated severity | low, medium, high, critical |
| tags | array | Optional | Additional tags | ["mirai", "scanner"] |
5. Code examples
Python
import requests
from datetime import datetime, timezone
URL = "https://cti.craabs.com"
KEY = "chp_your_key_here"
HEADERS = {"X-Honeypot-Key": KEY, "Content-Type": "application/json"}
def send_event(source_ip, honeypot_type, event_type, **kwargs):
payload = {
"source_ip": source_ip,
"honeypot_type": honeypot_type,
"event_type": event_type,
"timestamp": datetime.now(timezone.utc).isoformat(),
**kwargs
}
r = requests.post(f"{URL}/api/honeypot/event", headers=HEADERS, json=payload, timeout=5)
return r.json()
# Heartbeat (call every 5 minutes)
def heartbeat():
requests.get(f"{URL}/api/honeypot/ping", headers=HEADERS, timeout=5)
# Example: SSH login attempt
result = send_event(
source_ip="185.220.101.47",
honeypot_type="ssh",
event_type="login_attempt",
dest_port=22,
username="root",
password="123456",
severity="medium",
tags=["brute_force"],
)
print(f"IOC #{result['ioc_id']} - score: {result['score']}")
Bash / curl
#!/bin/bash
URL="https://cti.craabs.com"
KEY="chp_your_key_here"
# Heartbeat
curl -s -H "X-Honeypot-Key: $KEY" "$URL/api/honeypot/ping"
# Send event
curl -s -X POST \
-H "X-Honeypot-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{
"source_ip": "185.220.101.47",
"honeypot_type": "ssh",
"event_type": "login_attempt",
"dest_port": 22,
"username": "admin",
"severity": "medium"
}' \
"$URL/api/honeypot/event"
Node.js
const axios = require('axios');
const client = axios.create({
baseURL: 'https://cti.craabs.com',
headers: { 'X-Honeypot-Key': 'chp_your_key_here' },
timeout: 5000,
});
async function sendEvent(event) {
const res = await client.post('/api/honeypot/event', {
...event,
timestamp: new Date().toISOString(),
});
return res.data;
}
// Heartbeat every 5 minutes
setInterval(() => client.get('/api/honeypot/ping'), 300_000);
// Example
sendEvent({
source_ip: '185.220.101.47',
honeypot_type: 'http',
event_type: 'scan',
dest_port: 80,
severity: 'low',
}).then(r => console.log('IOC:', r.ioc_id));
Go
package main
import (
"bytes"; "encoding/json"; "net/http"; "time"
)
const URL = "https://cti.craabs.com"
const KEY = "chp_your_key_here"
type Event struct {
SourceIP string `json:"source_ip"`
HoneypotType string `json:"honeypot_type"`
EventType string `json:"event_type"`
Timestamp string `json:"timestamp"`
DestPort int `json:"dest_port,omitempty"`
Severity string `json:"severity"`
Tags []string `json:"tags,omitempty"`
}
func SendEvent(e Event) error {
e.Timestamp = time.Now().UTC().Format(time.RFC3339)
body, _ := json.Marshal(e)
req, _ := http.NewRequest("POST", URL+"/api/honeypot/event", bytes.NewBuffer(body))
req.Header.Set("X-Honeypot-Key", KEY)
req.Header.Set("Content-Type", "application/json")
_, err := http.DefaultClient.Do(req)
return err
}
Cowrie SSH Honeypot integration
# cowrie_to_craabs.py - tail Cowrie JSON log and forward to CRAABS
import json, time, requests
KEY = "chp_your_key_here"
LOG = "/home/cowrie/var/log/cowrie/cowrie.json"
HEADERS = {"X-Honeypot-Key": KEY}
EVENT_MAP = {
"cowrie.login.failed": "login_attempt",
"cowrie.login.success": "login_success",
"cowrie.command.input": "command",
"cowrie.session.file_download":"payload",
}
def tail_log():
with open(LOG) as f:
f.seek(0, 2)
while True:
line = f.readline()
if line:
yield json.loads(line.strip())
else:
time.sleep(0.5)
for entry in tail_log():
if not entry.get("src_ip"):
continue
requests.post("https://cti.craabs.com/api/honeypot/event",
headers=HEADERS, timeout=5,
json={
"source_ip": entry["src_ip"],
"honeypot_type": "ssh",
"event_type": EVENT_MAP.get(entry.get("eventid"), "generic"),
"dest_port": 22,
"username": entry.get("username"),
"password": entry.get("password"),
"payload": entry.get("input"),
"timestamp": entry.get("timestamp"),
"severity": "high" if "success" in entry.get("eventid","") else "medium",
"tags": ["cowrie", "ssh"],
}
)
6. Error codes
| HTTP code | Meaning | Action |
|---|---|---|
| 201 | Event accepted | Continue normally |
| 400 | Invalid JSON or missing source_ip | Fix the payload |
| 401 | Missing or invalid CHP key | Check X-Honeypot-Key |
| 403 | Node not approved | Contact the platform administrator |
| 429 | Rate limit exceeded | Use bulk mode, wait 60s |
| 500 | Server error | Retry in 30s |
7. Best practices
- Send the heartbeat every 5 minutes so the platform can detect if your node goes offline.
- Use bulk mode if your honeypot generates more than 10 events per minute.
- Never hardcode the CHP key in public code. Use environment variables.
- Handle 429 and 500 errors with exponential backoff: wait 5s, then 15s, then 60s.
- Include the actual event timestamp, not the send time.
- For exploits and payloads, encode in base64 to avoid JSON encoding issues.
- Use
criticalseverity only for successful exploits or confirmed malware downloads.
Les evenements sont automatiquement convertis en IOCs enrichis et partagés avec la communaute.
1. Vue d'ensemble
The CHP protocol allows any honeypot to send events to CRAABS via a simple REST API. For each event received, the platform:
- Creates or enriches an IOC from the attacker's IP
- Calculates a malicious score based on event type and frequency
- Automatically maps corresponding MITRE ATT&CK techniques
- Geolocalise l'Source IP
- Triggers alerts if the score is critical
2. Authentification
Each request must include the CHP key in the X-Honeypot-Key header.
X-Honeypot-Key: chp_a1b2c3d4e5f6...
The key is prefixed by chp_ and is 60 characters. Never log it clair ni la committer dans du code source.
3. Endpoints
GET/api/honeypot/ping
Heartbeat. Signals the node is active. Call every 5 minutes.
curl -H "X-Honeypot-Key: chp_..." https://cti.craabs.com/api/honeypot/ping
# Reponse 200
{"status": "ok", "node": "SSH-Trap", "accepted": true, "protocol": "CHP/1.0"}
POST/api/honeypot/event
Send a single event. Use for real-time transfer.
POST/api/honeypot/events/bulk
Send up to 100 events in one request. Recommended for high-volume sensorsume.
# Corps: {"events": [ {evenement}, {evenement}, ... ]}
# Reponse 201: {"accepted": 95, "rejected": 2, "iocs_created": 88}
GET/api/honeypot/status
Backne les statistiques de votre nœud : nombre d'evenements, IOCs generes, laste connexion.
4. Format d'evenement
| Champ | Type | Required | Description | Values |
|---|---|---|---|---|
| source_ip | string | Required | IP of the attacker | IPv4 valide |
| honeypot_type | string | Optional | Type de service leurré | ssh, http, ftp, rdp, smtp, telnet, mysql, vnc, custom |
| event_type | string | Optional | Nature of the event de l'événement | login_attempt, brute_force, exploit, payload, scan, connect, malware, command, generic |
| timestamp | string | Optional | Horodatage ISO 8601 | 2026-05-14T10:30:00Z |
| source_port | integer | Optional | Port source of the attacker | 1-65535 |
| dest_port | integer | Optional | Port destination | 22, 80, 443... |
| username | string | Optional | Identifiant testé | max 200 chars |
| password | string | Optional | Password testé | max 500 chars |
| payload | string | Optional | Payload brut (base64 recommandé) | texte libre |
| severity | string | Optional | Severity estimée | low, medium, high, critical |
| tags | array | Optional | Tags supplémentaires | ["mirai", "scanner"] |
5. Exemples de code
View les exemples dans la version anglaise de cette documentation, les exemples de code sont identiques quelle que soit la langue.
import requests
from datetime import datetime, timezone
URL = "https://cti.craabs.com"
KEY = "chp_votre_key_ici"
HEADERS = {"X-Honeypot-Key": KEY, "Content-Type": "application/json"}
def envoyer_evenement(source_ip, type_hp, type_event, **kwargs):
payload = {
"source_ip": source_ip,
"honeypot_type": type_hp,
"event_type": type_event,
"timestamp": datetime.now(timezone.utc).isoformat(),
**kwargs
}
r = requests.post(f"{URL}/api/honeypot/event", headers=HEADERS, json=payload, timeout=5)
return r.json()
# Exemple: tentative SSH
result = envoyer_evenement(
source_ip="185.220.101.47",
type_hp="ssh",
type_event="login_attempt",
dest_port=22,
username="root",
password="123456",
severity="medium",
tags=["brute_force"],
)
print(f"IOC #{result['ioc_id']} - score: {result['score']}")
6. Codes d'erreur
| Code HTTP | Signification | Action |
|---|---|---|
| 201 | Event accepté | Continuer normalement |
| 400 | JSON invalide ou source_ip absent | Corriger le payload |
| 401 | CHP Key absente ou invalide | Check X-Honeypot-Key |
| 403 | Nœud non approuvé | Contacter l'administrateur |
| 429 | Limite de requêtes dépassée | Utiliser le mode bulk, attendre 60s |
| 500 | Error serveur | Réessayer dans 30s |
7. Bonnes pratiques
- Envoyer le heartbeat toutes les 5 minutes pour que la plateforme détecte si votre nœud tombe hors ligne.
- Utiliser le mode bulk si votre honeypot génère plus de 10 evenements par minute.
- Ne jamais stocker la key CHP en dur dans du code public. Utiliser des variables d'environnement.
- Gerer les erreurs 429 et 500 avec un retry exponentiel : attendre 5s, puis 15s, puis 60s, puis 15s, puis 60s.
- Inclure le timestamp reel de l'evenement, pas l'heure d'envoi.
- Encoder les payloads en base64 pour eviter les problèmes d'encodage JSON.
- Reserver la severite
criticalaux exploits réussis ou aux téléchargements de malware confirmés.