情报IOC对外输出统一接口
接口说明
该接口是一个威胁情报查询服务,能够对情报IOC(威胁指标)进行批量查询。支持在category选择输入类型(domain、ip、ip:port、domain:port、url、email、md5、sha1、sha256之一),对于选定的类型,在field:query的value配置查询实体,多个查询实体使用英文逗号分隔,最多十个。最终根据不同查询实体以列表形式返回信息,返回信息包括危害等级、置信度、病毒名称、及标签相关信息。
具体的请求示例:
{
"query": {
"keywords": [
{
"field": "category",
"value": "domain"
},
{
"field": "query",
"value": "freescanonline.com,ilikefishing.xyz"
}
]
}
}注意:数组成员1和2 定位不一样,成员1代表查询类型,其中field是固定值category,value是枚举可选值(domain、ip、ip:port、domain:port、url、email、md5、sha1、sha256之一);成员2代表查询具体值,field是固定值query,value是待查询的实体。
请求地址
https://api.f.360.cn/custom/intelligence/v1/tags
请求方法
POST
请求参数
| 参数名 | 类型 | 位置 | 是否必填 | 示例值 | 说明 |
|---|---|---|---|---|---|
| query | object | body | 是 | | 查询条件,所有请求参数的父级结构 |
| query.keywords | Array(object) | body | 是 | | 查询条件,所有请求参数的子级结构 |
| query.keywords.[0].field | string | body | 是 | category | 查询条件的字段名:category |
| query.keywords.[0].value | string | body | 是 | domain | 设置接口返回哪些内容,如有多个以 "," 分隔,可选条件为,domain,ip,ip:port,domain:port,url,email,md5,sha1,sha256 |
| query.keywords.[1].field | string | body | 是 | query | 查询条件的字段名:query |
| query.keywords.[1].value | string | body | 是 | freescanonline.com,ilikefishing.xyz | 待请求的IOC集合,以","分隔。如"freescanonline.com,ilikefishing.xyz" |
响应参数
| 名称 | 类型 | 示例值 | 描述 | 应用说明 |
|---|---|---|---|---|
| code | String | 0 | 响应状态码 | |
| data | Array | 包含多个结果 | ||
| data.confidence | Int | 0 | 0-100的整十数分级, 90 高可信; 80 可靠; 70 一般; 60 低可信;50及以下 未知 | |
| data.expire_time | String | 2023/9/14 14:42:50 | IOC的失效时间 | 可不展示;空值时,字段对应的值内容为空;如: “expire_time”: "" |
| data.first_time | String | 2022/2/10 4:35:12 | 创建时间(IOC创建时间) | 可不展示;空值时,字段对应的值内容为空;如: “first_time”: "" |
| data.ioc | String | ilikefishing.xyz | ioc实体 | |
| data.ioc_type | String | domain | ioc类型 | |
| data.last_time | String | 2023/8/9 19:25:56 | 更新时间 (IOC更新时间) | 可不展示;空值时,字段对应的值内容为空;如: “last_time”: "" |
| data.level | Int | 70 | 危害等级 ,0-100的整十数分级,30以下-白 ; 30-未知 ;40-50:低危 ; 60- 中危 ; 70-高危; 80-100: 超危 | |
| data.malware | String | Win32/Trojan.Dorv.HxMBEpsA | 病毒名称 | 只有IOC类型为md5/sha1/sha256 时,有该字段; |
| data.status | String | ACTIVE | 活跃状态 ACTIVE(活跃) OVER(过期/失效) SINKHOLE(被sinkhole处置) UNKNOWN(未知) | 可不展示,若展示 ,status存在英文逗号分隔的多个状态值。 |
| data.tags | Array | 标签,包含多个参数 | 若不存在标签数据, “tags”: [] | |
| data.tags.desc | String | Mirai是一款针对IOT设备僵尸网络病毒… | 标签描述 | 空值时,字段对应的值内容为空;如: “desc”: "" |
| data.tags.id | String | threat$family$mirai | 标签id,标签唯一标识 | 存用标签名称,定义标签ID的情况; |
| data.tags.name | String | Family:Mirai | 标签名称;标签类型有 攻击家族、威胁类型、团伙组织 、android的恶意类型 | 标签名称, 格式为 “Family:恶意家族” (如:Family:Mirai) 和三段式【平台 / 宿主类型】/ 【威胁类型】.【家族】(如:Win32/Trojan.Generic)为攻击家族类型标签; 格式为 “Group: 团伙组织” 为团伙组织类型标签; 格式为 “中间有 / 来分“(如:僵尸网络/Botnet)或一串字符串(如:HackTool)为威胁类型标签。 标签名称为(系统破坏、恶意扣费、资费消耗、隐私窃取、欺诈软件、流氓行为、远程控制、恶意传播、其他、违法违规)为android的恶意类型; |
| data.tags.severity | Int | 70 | 标签级别 | 根据severity给标签刷色,30级别为info类型/分界线,不黑不白,30以下为白,30以上为黑; 刷色建议:80及以上 暗红 70-79 红 60-69 暗橙 50-59 橙 40-49 黄 31-39 浅黄 30 默认底色,根据底色选择白边/黑边即可 30以下 绿 |
| data.tags.source | Int | 1 | 标签来源 | 1. 情报接口,2云查接口 |
| data.tags.ttps | object | | 标签类型 | 只在source=1 会存在该字段 |
| data.tags.ttps.ti_type_main | string | 威胁一级分类 | Threat | 可为空字符 "" |
| data.tags.ttps.ti_type_sub | string | 威胁二级标签 | Type | 可为空字符 "" |
| data.tags.ttps.ti_showname | string | TI平台本地情报包中的名字 | Spyrat | - |
| msg | String | ok | 响应状态信息 |
请求示例
支持cUrl、Python、PHP、Java、Go语言的请求,示例如下
#!/usr/bin/env bash
set -euo pipefail
APPID="" # apikey
SECRET="" # salt
URL="https://api.f.360.cn/custom/intelligence/v1/tags"
BODY='{"query":{"keywords":[{"field":"category","value":"ip"},{"field":"query","value":"1.2.3.4"}]}}'
NONCE=$(printf '%08d' $((RANDOM % 100000000)))
TIMESTAMP=$(date +%s)
BODY_MD5=$(printf '%s' "$BODY" | openssl dgst -md5 -hex | awk '{print $NF}')
SIGNATURE=$(printf '%s' "${BODY_MD5}${APPID}${NONCE}${TIMESTAMP}${SECRET}" | openssl dgst -md5 -hex | awk '{print $NF}')
SIGNATURE=${SIGNATURE:16}
curl --location --request POST "$URL" \
--header "Content-Type: application/json" \
--header "X-360-Key: ${APPID}" \
--header "X-360-Nonce: ${NONCE}" \
--header "X-360-Timestamp: ${TIMESTAMP}" \
--header "X-360-Signature: ${SIGNATURE}" \
--data "${BODY}"# python3.6.8
# -*- coding:utf-8 -*—
import hashlib
import json
import random
import time
import requests
APPID = "" # apikey
SECRET = "" # salt
def make_headers(appid, secret, body):
headers = {}
headers["X-360-Key"] = appid
headers["X-360-Nonce"] = str(random.randint(0, 99999999)).zfill(8)
headers["X-360-Timestamp"] = str(int(time.time()))
s = (
hashlib.md5(body.encode("utf8")).hexdigest()
+ headers["X-360-Key"]
+ headers["X-360-Nonce"]
+ headers["X-360-Timestamp"]
+ secret
)
md5 = hashlib.md5(s.encode("utf8")).hexdigest()
headers["X-360-Signature"] = md5[16:]
headers["Content-Type"] = "application/json"
return headers
def do_post(url, body):
res = requests.post(
url,
data=json.dumps(body),
headers=make_headers(APPID, SECRET, json.dumps(body)),
)
print(res.text)
if __name__ == "__main__":
url = "https://api.f.360.cn/custom/intelligence/v1/tags"
params = {
"query": {
"keywords": [
{"field": "category", "value": "ip"},
{"field": "query", "value": "1.2.3.4"},
]
}
}
do_post(url, params)<?php
// apikey
$appid = "";
// salt
$secret = "";
$url = 'https://api.f.360.cn/custom/intelligence/v1/tags';
$body = json_encode([
'query' => [
'keywords' => [
['field' => 'category', 'value' => 'ip'],
['field' => 'query', 'value' => '1.2.3.4'],
],
],
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$nonce = str_pad((string) random_int(0, 99999999), 8, "0", STR_PAD_LEFT);
$timestamp = (string) time();
$signature = substr(md5(md5($body) . $appid . $nonce . $timestamp . $secret), 16);
$ch = curl_init($url);
$options = [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-360-Key: {$appid}",
"X-360-Nonce: {$nonce}",
"X-360-Timestamp: {$timestamp}",
"X-360-Signature: {$signature}",
],
];
$options[CURLOPT_POST] = true;
$options[CURLOPT_POSTFIELDS] = $body;
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
if ($response === false) {
echo curl_error($ch), PHP_EOL;
} else {
echo $response, PHP_EOL;
}
curl_close($ch);import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.concurrent.ThreadLocalRandom;
public class Demo {
static String md5(String input) throws Exception {
byte[] digest = MessageDigest.getInstance("MD5")
.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b & 0xff));
}
return sb.toString();
}
public static void main(String[] args) throws Exception {
String appid = ""; // apikey
String secret = ""; // salt
String url = "https://api.f.360.cn/custom/intelligence/v1/tags";
String body = "{\"query\":{\"keywords\":[{\"field\":\"category\",\"value\":\"ip\"},{\"field\":\"query\",\"value\":\"1.2.3.4\"}]}}";
String nonce = String.format("%08d", ThreadLocalRandom.current().nextInt(100000000));
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
String signature = md5(md5(body) + appid + nonce + timestamp + secret).substring(16);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/json")
.header("X-360-Key", appid)
.header("X-360-Nonce", nonce)
.header("X-360-Timestamp", timestamp)
.header("X-360-Signature", signature)
.POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
System.out.println(response.body());
}
}package main
import (
"bytes"
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"math/rand"
"net/http"
"time"
)
func md5Hex(s string) string {
sum := md5.Sum([]byte(s))
return hex.EncodeToString(sum[:])
}
func main() {
appid := "" // apikey
secret := "" // salt
url := "https://api.f.360.cn/custom/intelligence/v1/tags"
body := []byte(`{"query":{"keywords":[{"field":"category","value":"ip"},{"field":"query","value":"1.2.3.4"}]}}`)
nonce := fmt.Sprintf("%08d", rand.Intn(100000000))
timestamp := fmt.Sprintf("%d", time.Now().Unix())
signature := md5Hex(md5Hex(string(body)) + appid + nonce + timestamp + secret)[16:]
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-360-Key", appid)
req.Header.Set("X-360-Nonce", nonce)
req.Header.Set("X-360-Timestamp", timestamp)
req.Header.Set("X-360-Signature", signature)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(string(respBody))
}响应示例
业务正常响应
业务无需关注HTTP状态码,只关注业务返回错误码,HTTP状态码统一由网关返回
{
"_oid": 1,
"code": "0",
"msg": "ok",
"data": [
{
"ioc": "freescanonline.com",
"ioc_type": "domain",
"level": 30,
"confidence": 90,
"status": "UNKNOWN",
"first_time": "2022-06-25 10:44:10",
"last_time": "2023-09-08 19:24:29",
"expire_time": "2023-10-18 20:05:15",
"tags": []
},
{
"ioc": "ilikefishing.xyz",
"ioc_type": "domain",
"level": 70,
"confidence": 90,
"status": "ACTIVE",
"first_time": "2022-02-10 04:35:12",
"last_time": "2023-08-09 19:25:56",
"expire_time": "2023-09-14 14:42:50",
"tags": [
{
"id": "threat$family$mirai",
"name": "Family:Mirai",
"desc": "Mirai是一款针对IOT设备僵尸网络病毒,其服务端由c编写,客户端由go语言编写。\n它可以对网络设备进行扫描,攻击网络摄像机、路由器等IOT设备,攻击成功后,可利用僵尸程序形成一个僵尸网络,可对目标网络系统发起分布式拒绝服务(DDoS)攻击,造成大面积网络瘫痪、网站或在线服务无法访问,多起国际性的DDOS事件都有其影子。最出名的莫过于2016/10/21攻击美国Dyn域名运营商从而导致美国东海岸多家网站宕机事件。\nMirai的传播主要依赖于目前大量用户不重视IOT设备的安全性,主要通过弱口令扫描对应设备",
"severity": 70,
"source": 1
},
{
"id": "threat$family$fbot",
"name": "Family:fbot",
"desc": "FBot是mirai的一个变种,家族名来源于其在c2上的文件名,此家族改进了mirai的通信协议,支持udp_flood,tcp_syn_flood,tcp_ack_flood,get_flood,post_flood,junk_flood,udpbypass_flood等攻击,常通过 adb 安卓系统调试接口投递。",
"severity": 70,
"source": 1
},
{
"id": "threat$family$ripprbot",
"name": "Family:ripprbot",
"desc": "Rippr是一个网络犯罪组织,至少已经活跃了18个月,该组织的名字源于其长期运营的僵尸网络ripprbot,Rippr在2022年4月28日对北京健康宝发起DDoS攻击。Rippr属于Fbot团伙,支持Tor C2,主要功能为DDoS攻击。",
"severity": 70,
"source": 1
},
{
"id": "360ti$label_ez$僵尸网络/Botnet",
"name": "僵尸网络/Botnet",
"desc": "",
"severity": 70,
"source": 1
}
]
}
],
"status": 0
}业务异常响应
{
"_oid": 1,
"code": "GS00301",
"msg": "param missing",
"status": 0
}