Aeris is a fuzzy hash scanning and artifact management system (algorithm used is ssdeep). Fuzzy hashing allows for detecting similar or modified versions of malware, phishing attachments, or other files even when parts have been changed.
An example use case is scanning incoming email bodies and/or attachments in Aeris to match for similarities with known-bad artifacts.
- Import recent samples from MalwareBazaar (optional)
- Artifact scanning through API or frontend
- Search through artifacts via API or frontend
- Similarity matching against previously stored artifacts
- PostgreSQL storage for persistence
- Token-based API authentication
- Docker and Docker Compose
- Go 1.19 or higher (for development only)
- Clone the repository:
git clone https://github.com/ackatz/aeris.git
cd aeris- Change the environment variables with "changeme" as the current value in
docker-compose.yml. You can useopenssl rand -hex 32to generate theSESSION_SECRET:
POSTGRES_PASSWORD=changeme
BEARER_TOKEN=changeme
ADMIN_USERNAME=changeme
ADMIN_PASSWORD=changeme
SESSION_SECRET=changemeIf you want to use the MalwareBazaar integration, uncomment and set MB_API_KEY with your Abuse.ch key.
- Generate a self-signed cert
cd scripts && chmod +x generate-certs.sh && ./generate-certs.shIf you want to use your own certs, add your
cert.pemandkey.peminto/certsand editconfig/nginx.confto your needs.
- Run with Docker Compose:
docker-compose up -dThe web service will be available at https://127.0.0.1
Aeris can automatically pull ssdeep hashes from MalwareBazaar during startup and every hour. The advantage to this is that you can automatically enrich your artifact database with a steady stream of known-bad malware, rather than relying solely on your own artifacts.
To enable this integration, uncomment and set MB_API_KEY with your Abuse.ch key in docker-compose.yml.
All artifacts pulled from MalwareBazaar will have the description: "Sample pulled from MalwareBazaar". Example:
{
"id": 1,
"artifact_name": "bins.sh",
"description": "Sample pulled from MalwareBazaar",
"first_seen": "2024-12-30T23:53:45.944431Z",
"sha256": "c2661807a4788e0cfdf53d50d586856e15f4658e801326d8a4e7884bdcb2ac3b",
"ssdeep": "192:99NEQw8Wpo7wzOne2K2W2O2X2X2wAk2K2W2O2X2X2XrEQw8Wp0:99NEQwxpo7wzOnHzfXGGwA5zfXGGXrEU"
}All secured endpoints require a Bearer token for authentication. Include the token in the Authorization header of your request:
Authorization: Bearer your_secure_tokenPOST /api/v1/artifacts/scanSubmit an artifact for scanning and similarity matching.
Request Body:
{
"data": "base64_encoded_data", // required
"artifact_name": "example.bin", // required
"description": "Sample artifact",
"persist": true
}Notes:
persistdetermines whether to store the artifact metadata in the database (i.e., if it is a malicious artifact that you want to check against later)datamust be Base64-encoded- Minimum artifact size is 4KB (an ssdeep requirement)
Sample Response:
{
"artifact_name": "example.bin",
"description": "Sample artifact",
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"ssdeep": "3:anjkmC:anjk9C",
"first_seen": "2024-12-29T12:00:00Z",
"is_new": true,
"matches": [
{
"id": 1,
"sha256": "...",
"ssdeep": "...",
"artifact_name": "similar_file.bin",
"description": "Similar artifact",
"first_seen": "2024-12-28T12:00:00Z",
"similarity": 85
}
]
}GET /api/v1/artifactsRetrieve a list of all stored artifacts. This endpoint supports pagination via limit and offset query parameters.
Query Parameters:
- limit (default = 50, max = 50)
- offset (default = 0)
Example:
GET /api/v1/artifacts?limit=10&offset=20Sample Response:
{
"data": [
{
"id": 1,
"artifact_name": "example.bin",
"description": "A sample artifact",
"first_seen": "2024-12-29T12:00:00Z",
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"ssdeep": "3:anjkmC:anjk9C"
},
{
"id": 2,
"artifact_name": "another_file.exe",
"description": "Some malware sample",
"first_seen": "2024-12-28T15:00:00Z",
"sha256": "...",
"ssdeep": "..."
}
],
"pagination": {
"total": 15,
"offset": 20,
"limit": 10
}
}GET /api/v1/artifacts/searchSearch for artifacts by keyword. Searches across artifact names, descriptions, SHA256 hashes and SSDEEP hashes. Falls back to listing all artifacts if no search term provided.
Query Parameters:
- q - Search term (optional)
- limit (default = 50, max = 50)
- offset (default = 0)
Example:
GET /api/v1/artifacts/search?q=malware&limit=10&offset=0Sample Response:
{
"data": [
{
"id": 1,
"artifact_name": "malware.bin",
"description": "Suspicious malware sample",
"first_seen": "2024-12-29T12:00:00Z",
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"ssdeep": "3:anjkmC:anjk9C"
}
],
"pagination": {
"total": 1,
"offset": 0,
"limit": 10
}
}GET /api/v1/artifacts/:idReturns a single artifact by its numeric ID.
Example:
GET /api/v1/artifacts/1Sample Response:
{
"id": 1,
"artifact_name": "example.bin",
"description": "A sample artifact",
"first_seen": "2024-12-29T12:00:00Z",
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"ssdeep": "3:anjkmC:anjk9C"
}DELETE /api/v1/artifacts/:idRemoves an artifact by its numeric ID.
Example:
DELETE /api/v1/artifacts/1Sample Response:
{
"message": "artifact deleted"
}Run all tests:
go test ./... -v- Fork the repository
- Create your feature branch (git checkout -b feature/amazing-feature)
- Commit your changes (git commit -m 'Add some amazing feature')
- Push to the branch (git push origin feature/amazing-feature)
- Open a Pull Request