ARL分析与进阶使用

admin 2026-08-21 06:46:57 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 文章分析了ARL资产侦察灯塔系统在使用Fofa导入数据时遇到的降重问题,指出根本原因在于FofaAPI的限制而非ARL本身,并展示了相关代码逻辑。同时提及了手动编写Poc的需求,但未提供具体方法。建议用户更换Fofa语句或调整API参数以优化结果。 综合评分: 65 文章分类: 安全工具,渗透测试,安全开发


ARL分析与进阶使用

Str2iv8er Str2iv8er

蚁景网络安全

2026年8月19日 17:40 湖南

在小说阅读器读本章

去阅读

在使用ARL(Asset Reconnaissance Lighthouse资产侦察灯塔系统,项目地址地址为https://github.com/TophantTechnology/ARL)的时候,有两个问题比较困扰我:

  • • ARL使用Fofa导入数据的时候怎么降重?
  • • 如何自己手动编写Poc?

在网上查阅了一些相关资料后,我发现并没有师傅写的很清晰,于是诞生了写这篇文章的想法。

这篇文章不涉及ARL的基础搭建过程和基础使用过程,如果您之前没有使用过ARL,详情可以参考官网教程:https://tophanttechnology.github.io/ARL-doc/system_install/

1.Fofa降重

先说结论,是由于Fofa_api的限制而不是ARL本身的问题

来源于我之前的使用体验,使用同样的Fofa语句,比如能搜到大量地的资产,但是ARL只会跑几千条,然后我们反复运行发现得到的资产结果是一致的,这样就大大地影响了配合Fofa使用好处,只能自己更换不同的Fofa语句来实现降重,非常麻烦。

首先我们先黑盒看看调用fofa的流程:

POST /api/task_fofa/test HTTP/2

{"query":"org=\"China Education and Research Network Center\""}
HTTP/2 200 OK

{"message": "success", "code": 200, "data": {"size": 13492282, "query": "org=\"China Education and Research Network Center\""}}

可以看见这里返回的结果是13492282条

然后我们直接去项目里面去找:

路径为:ARL-2.6.1\app\routes\taskFofa.py

from flask_restx import Namespace, fields
from app.utils import get_logger, auth, build_ret, conn_db
from app.modules import ErrorMsg, CeleryAction
from app.services.fofaClient import fofa_query, fofa_query_result
from app import celerytask
from bson import ObjectId
from . import ARLResource

ns = Namespace('task_fofa', description="Fofa 任务下发")

logger = get_logger()

test_fofa_fields = ns.model('taskFofaTest',  {
    'query': fields.String(required=True, description="Fofa 查询语句")
})

@ns.route('/test')
class TaskFofaTest(ARLResource):

    @auth
    @ns.expect(test_fofa_fields)
    def post(self):
        """
        测试Fofa查询连接
        """
        args = self.parse_args(test_fofa_fields)
        query = args.pop('query')
        data = fofa_query(query, page_size=1)
        if isinstance(data, str):
            return build_ret(ErrorMsg.FofaConnectError, {'error': data})

        if data.get("error"):
            return build_ret(ErrorMsg.FofaKeyError, {'error': data.get("errmsg")})

        item = {
            "size": data["size"],
            "query": data["query"]
        }

        return build_ret(ErrorMsg.Success, item)

add_fofa_fields = ns.model('addTaskFofa', {
    'query': fields.String(required=True, description="Fofa 查询语句"),
    'name': fields.String(required=True, description="任务名"),
    'policy_id': fields.String(description="策略 ID")
})

@ns.route('/submit')
class AddFofaTask(ARLResource):

    @auth
    @ns.expect(add_fofa_fields)
    def post(self):
        """
        提交Fofa查询任务
        """
        args = self.parse_args(add_fofa_fields)
        query = args.pop('query')
        name = args.pop('name')
        policy_id = args.get('policy_id')

        task_options = {
            "port_scan_type": "test",
            "port_scan": True,
            "service_detection": False,
            "service_brute": False,
            "os_detection": False,
            "site_identify": False,
            "file_leak": False,
            "ssl_cert": False
        }

        data = fofa_query(query, page_size=1)
        if isinstance(data, str):
            return build_ret(ErrorMsg.FofaConnectError, {'error': data})

        if data.get("error"):
            return build_ret(ErrorMsg.FofaKeyError, {'error': data.get("errmsg")})

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;data["size"] <=&nbsp;0:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;build_ret(ErrorMsg.FofaResultEmpty, {})

&nbsp; &nbsp; &nbsp; &nbsp; fofa_ip_list = fofa_query_result(query)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;isinstance(fofa_ip_list,&nbsp;str):
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;build_ret(ErrorMsg.FofaConnectError, {'error': data})

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;policy_id&nbsp;and&nbsp;len(policy_id) ==&nbsp;24:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; task_options.update(policy_2_task_options(policy_id))

&nbsp; &nbsp; &nbsp; &nbsp; task_data = {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"name": name,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"target":&nbsp;"Fofa ip {}".format(len(fofa_ip_list)),
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"start_time":&nbsp;"-",
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"end_time":&nbsp;"-",
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"task_tag":&nbsp;"task",
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"service": [],
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"status":&nbsp;"waiting",
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"options": task_options,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"type":&nbsp;"fofa",
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"fofa_ip": fofa_ip_list
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; task_data = submit_fofa_task(task_data)

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;build_ret(ErrorMsg.Success, task_data)

def&nbsp;policy_2_task_options(policy_id):
&nbsp; &nbsp; options = {}
&nbsp; &nbsp; query = {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"_id": ObjectId(policy_id)
&nbsp; &nbsp; }
&nbsp; &nbsp; data = conn_db('policy').find_one(query)
&nbsp; &nbsp;&nbsp;if&nbsp;not&nbsp;data:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;options

&nbsp; &nbsp; policy_options = data["policy"]
&nbsp; &nbsp; policy_options.pop("domain_config")

&nbsp; &nbsp; ip_config = policy_options.pop("ip_config")
&nbsp; &nbsp; site_config = policy_options.pop("site_config")

&nbsp; &nbsp; options.update(ip_config)
&nbsp; &nbsp; options.update(site_config)
&nbsp; &nbsp; options.update(policy_options)

&nbsp; &nbsp;&nbsp;return&nbsp;options

def&nbsp;submit_fofa_task(task_data):
&nbsp; &nbsp; conn_db('task').insert_one(task_data)
&nbsp; &nbsp; task_id =&nbsp;str(task_data.pop("_id"))
&nbsp; &nbsp; task_data["task_id"] = task_id

&nbsp; &nbsp; task_options = {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"celery_action": CeleryAction.FOFA_TASK,
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"data": task_data
&nbsp; &nbsp; }

&nbsp; &nbsp; celery_id = celerytask.arl_task.delay(options=task_options)

&nbsp; &nbsp; logger.info("target:{} celery_id:{}".format(task_id, celery_id))

&nbsp; &nbsp; values = {"$set": {"celery_id":&nbsp;str(celery_id)}}
&nbsp; &nbsp; task_data["celery_id"] =&nbsp;str(celery_id)
&nbsp; &nbsp; conn_db('task').update_one({"_id": ObjectId(task_id)}, values)

&nbsp; &nbsp;&nbsp;return&nbsp;task_data

其中有一个类和俩函数在其他地方:

# &nbsp;-*- coding:UTF-8 -*-
import&nbsp;base64
from&nbsp;app.config&nbsp;import&nbsp;Config
from&nbsp;app&nbsp;import&nbsp;utils
from&nbsp;celery.utils.log&nbsp;import&nbsp;get_task_logger
logger = get_task_logger(__name__)

class&nbsp;FofaClient:
&nbsp; &nbsp;&nbsp;def&nbsp;__init__(self, email, key, page_size=9999):
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.email = email
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.key = key
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.base_url = Config.FOFA_URL
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.search_api_url =&nbsp;"/api/v1/search/all"
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.info_my_api_url =&nbsp;"/api/v1/info/my"
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.page_size = page_size
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.param = {}

&nbsp; &nbsp;&nbsp;def&nbsp;info_my(self):
&nbsp; &nbsp; &nbsp; &nbsp; param = {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"email":&nbsp;self.email,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"key":&nbsp;self.key,
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.param = param
&nbsp; &nbsp; &nbsp; &nbsp; data =&nbsp;self._api(self.base_url +&nbsp;self.info_my_api_url)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;data

&nbsp; &nbsp;&nbsp;def&nbsp;fofa_search_all(self, query):
&nbsp; &nbsp; &nbsp; &nbsp; qbase64 = base64.b64encode(query.encode())
&nbsp; &nbsp; &nbsp; &nbsp; param = {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"email":&nbsp;self.email,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"key":&nbsp;self.key,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"qbase64": qbase64.decode('utf-8'),
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"size":&nbsp;self.page_size
&nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.param = param
&nbsp; &nbsp; &nbsp; &nbsp; data =&nbsp;self._api(self.base_url +&nbsp;self.search_api_url)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;data

&nbsp; &nbsp;&nbsp;def&nbsp;_api(self, url):
&nbsp; &nbsp; &nbsp; &nbsp; data = utils.http_req(url,&nbsp;'get', params=self.param).json()
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;data.get("error")&nbsp;and&nbsp;data["errmsg"]:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;raise&nbsp;Exception(data["errmsg"])

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;data

&nbsp; &nbsp;&nbsp;def&nbsp;search_cert(self, cert):
&nbsp; &nbsp; &nbsp; &nbsp; query =&nbsp;'cert="{}"'.format(cert)
&nbsp; &nbsp; &nbsp; &nbsp; data =&nbsp;self.fofa_search_all(query)
&nbsp; &nbsp; &nbsp; &nbsp; results = data["results"]
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;results

def&nbsp;fetch_ip_bycert(cert, size=9999):
&nbsp; &nbsp; ip_set =&nbsp;set()
&nbsp; &nbsp; logger.info("fetch_ip_bycert {}".format(cert))
&nbsp; &nbsp;&nbsp;try:
&nbsp; &nbsp; &nbsp; &nbsp; client = FofaClient(Config.FOFA_EMAIL, Config.FOFA_KEY, page_size=size)
&nbsp; &nbsp; &nbsp; &nbsp; items = client.search_cert(cert)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;item&nbsp;in&nbsp;items:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ip_set.add(item[1])
&nbsp; &nbsp;&nbsp;except&nbsp;Exception&nbsp;as&nbsp;e:
&nbsp; &nbsp; &nbsp; &nbsp; logger.warn("{} error: {}".format(cert, e))

&nbsp; &nbsp;&nbsp;return&nbsp;list(ip_set)

def&nbsp;fofa_query(query, page_size=9999):
&nbsp; &nbsp;&nbsp;try:
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;not&nbsp;Config.FOFA_KEY&nbsp;or&nbsp;not&nbsp;Config.FOFA_KEY:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;"please set fofa key in config-docker.yaml"

&nbsp; &nbsp; &nbsp; &nbsp; client = FofaClient(Config.FOFA_EMAIL, Config.FOFA_KEY, page_size=page_size)
&nbsp; &nbsp; &nbsp; &nbsp; info = client.info_my()
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;info.get("vip_level") ==&nbsp;0:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;"不支持注册用户"

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 普通会员,最多只查100条
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;info.get("vip_level") ==&nbsp;1:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; client.page_size =&nbsp;min(page_size,&nbsp;100)

&nbsp; &nbsp; &nbsp; &nbsp; data = client.fofa_search_all(query)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;data

&nbsp; &nbsp;&nbsp;except&nbsp;Exception&nbsp;as&nbsp;e:
&nbsp; &nbsp; &nbsp; &nbsp; error_msg =&nbsp;str(e)
&nbsp; &nbsp; &nbsp; &nbsp; error_msg = error_msg.replace(Config.FOFA_KEY[10:],&nbsp;"***")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;error_msg

def&nbsp;fofa_query_result(query, page_size=9999):
&nbsp; &nbsp;&nbsp;try:
&nbsp; &nbsp; &nbsp; &nbsp; ip_set =&nbsp;set()
&nbsp; &nbsp; &nbsp; &nbsp; data = fofa_query(query, page_size)

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;isinstance(data,&nbsp;dict):
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;data['error']:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;data['errmsg']

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;item&nbsp;in&nbsp;data["results"]:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ip_set.add(item[1])
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;list(ip_set)

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;raise&nbsp;Exception(data)
&nbsp; &nbsp;&nbsp;except&nbsp;Exception&nbsp;as&nbsp;e:
&nbsp; &nbsp; &nbsp; &nbsp; error_msg =&nbsp;str(e)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;error_msg

诶?我看到这个代码的时候我感觉他这里写的没有毛病,那么我的疑问变得更重了,为什么我查询的结果明明有一千万多条,但是实际到我们的项目条数就几千条:

conn_db('task').insert_one(task_data)

根据上面这条代码,于是我进入了docker容器,查看了数据库的具体信息:

大致数据就是下面这种格式:

"fofa_ip"&nbsp;:&nbsp;[&nbsp;"xxx.xxx.xxx.xxx",&nbsp;......&nbsp;],&nbsp;"celery_id"&nbsp;:&nbsp;"xxx",&nbsp;"statistic"&nbsp;:&nbsp;{&nbsp;"site_cnt"&nbsp;:&nbsp;3935,&nbsp;"domain_cnt"&nbsp;:&nbsp;0,&nbsp;"ip_cnt"&nbsp;:&nbsp;2590,&nbsp;"cert_cnt"&nbsp;:&nbsp;0,&nbsp;"service_cnt"&nbsp;:&nbsp;0,&nbsp;"fileleak_cnt"&nbsp;:&nbsp;3068,&nbsp;"url_cnt"&nbsp;:&nbsp;0,&nbsp;"vuln_cnt"&nbsp;:&nbsp;94,&nbsp;"npoc_service_cnt"&nbsp;:&nbsp;0,&nbsp;"cip_cnt"&nbsp;:&nbsp;0,&nbsp;"nuclei_result_cnt"&nbsp;:&nbsp;0,&nbsp;"stat_finger_cnt"&nbsp;:&nbsp;167,&nbsp;"wih_cnt"&nbsp;:&nbsp;0&nbsp;}&nbsp;}

这里对应的fofa_ip数量与我在前端上面看到的数量一致,我就纳闷了为什么这里就只有这么几千条IP数量呢?我准备把这部分的代码手动抽出来在我本地上跑一遍试试看看结果到底是什么?

我在本地运行后发现返回的ip数量是由page_size决定的,如下面的代码

def&nbsp;fofa_query_result(query, page_size=9999):
&nbsp; &nbsp;&nbsp;try:
&nbsp; &nbsp; &nbsp; &nbsp; ip_set =&nbsp;set()
&nbsp; &nbsp; &nbsp; &nbsp; data = fofa_query(query, page_size)

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;isinstance(data,&nbsp;dict):
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;data['error']:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;data['errmsg']

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;item&nbsp;in&nbsp;data["results"]:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ip_set.add(item[1])
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;list(ip_set)

我将page_size改为20000,发现根本不返回结果了,这里我才想起来回到Fofa_API的官网去查看,发现了是API一次只能返回最多10000条的限制。

那么解决办法是什么呢?

我们可以看到Fofa Api这里存在一个翻页参数,我们的改进措施就是让ARL使用Fofa API的时候增加一个翻页参数而不是不添加导致每次都是第一页。面向大众的话,要我们一个一个去修改源代码是不太现实的,我这里将给原作者发起一个issue,期待他的更新。

最简单的措施就是我们改进一下Fofa语句:

(status_code="200" || banner="HTTP/1.1 200 OK") && org="China Education and Research Network Center"

避免过期资产误杀:

这里是有20万多条独立IP,我们可以利用Fofa_api先把这20多万条独立IP下载下来,使用ARL本身的添加任务功能将这些IP填进去,这样的缺陷就是不能跑Poc,要跑Poc的话可以等待我们这20多万的数据跑完一遍后,然后直接风险任务下发选择对应的Poc就可以了。

添加任务的时候使用下列的格式加入:

IP1
IP2
IP3
IP4
IP5
IP6
...

2.Poc编写

想要优雅地使用ARL,会自己编写更新Poc是必不可少的。

ARL的poc工具在路径/opt/ARL-NPoC/xing/plugins/poc中我们后续在这个路径去修改,我们可以从作者的仓库看看这个工具:https://github.com/1c3z/ARL-NPoC

这里需要单独注意一点,我们在安装的时候

pip3 install -r requirements.txt

这里最后一个PyYAML直接安装会报错,我们直接使用下列命令直接安装。

pip install PyYAML

然后安装运行:

pip3 install -e .

就可以使用了:

大致使用教程:

这里我拿直接ARL给我扫出来的一个弱口令进行验证:

xing brute -t 目标地址

然后我们就可以开始编写Poc了

我们来分析一个较为简单的但是很实用的Actuator API 未授权访问漏洞的POC:

from&nbsp;xing.core.BasePlugin&nbsp;import&nbsp;BasePlugin
from&nbsp;xing.utils&nbsp;import&nbsp;http_req
from&nbsp;xing.core&nbsp;import&nbsp;PluginType, SchemeType

class&nbsp;Plugin(BasePlugin):
&nbsp; &nbsp;&nbsp;def&nbsp;__init__(self):
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;super(Plugin,&nbsp;self).__init__()
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.plugin_type = PluginType.POC&nbsp;# 定义该插件的类型便于后续调用
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.vul_name =&nbsp;"Actuator API 未授权访问"
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.app_name =&nbsp;'Actuator'
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.scheme = [SchemeType.HTTPS, SchemeType.HTTP]

&nbsp; &nbsp;&nbsp;def&nbsp;verify(self, target):
&nbsp; &nbsp; &nbsp; &nbsp; paths = ["/env",&nbsp;"/actuator/env",&nbsp;"/manage/env",&nbsp;"/management/env",&nbsp;"/api/env",&nbsp;"/api/actuator/env"]
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;path&nbsp;in&nbsp;paths:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; url = target + path
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conn = http_req(url)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;b'java.runtime.version'&nbsp;in&nbsp;conn.content:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.logger.success("发现 Actuator API 未授权访问 {}".format(self.target))
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;url

主要流程就是先定义一个插件的类,然后使用函数__init__(self)写出这个插件的一些信息,具体实现过程在verify函数中实现。

这里我就编写一个influxdb的未授权访问的漏洞:

from&nbsp;xing.core.BasePlugin&nbsp;import&nbsp;BasePlugin
from&nbsp;xing.utils&nbsp;import&nbsp;http_req
from&nbsp;xing.core&nbsp;import&nbsp;PluginType, SchemeType

class&nbsp;Plugin(BasePlugin):
&nbsp; &nbsp;&nbsp;def&nbsp;__init__(self):
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;super(Plugin,&nbsp;self).__init__()
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.plugin_type = PluginType.POC
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.vul_name =&nbsp;"Influxdb未授权访问"
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.app_name =&nbsp;'Influxdb'
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.scheme = [SchemeType.HTTPS, SchemeType.HTTP]

&nbsp; &nbsp;&nbsp;def&nbsp;verify(self, target):
&nbsp; &nbsp; &nbsp; &nbsp; url = target +&nbsp;"/query?q=SHOW%20USERS"
&nbsp; &nbsp; &nbsp; &nbsp; conn = http_req(url)

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;b'"results":'&nbsp;in&nbsp;conn.content:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.logger.success("发现 Influxdb 未授权访问 {}".format(self.target))
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;url
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;False

然后我们直接在本地复现一下,是可以使用的:

接着我们部署到我们的服务器上,注意这里我们将POC同步到arl_web和arl_work两个容器中:

大致流程就是分别进入这两个容器然后添加对应文件下的Poc即可:

cd /opt/ARL-NPoC/xing/plugins/

我们更新一下Poc后再前端也可以查看到了:

然后经过测试确实可以:

3.总结

在我的实际渗透测试过程中,ARL给我的信息搜集带来了很大的便利性。是一种全面的信息搜集的有力方式!这篇文章主要是解决一点使用ARL过程中的问题,以及编写自己的Poc的流程。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:蚁景网络安全 Str2iv8er Str2iv8er《ARL分析与进阶使用》

ARL分析与进阶使用 网络安全文章

ARL分析与进阶使用

文章总结: 文章分析了ARL资产侦察灯塔系统在使用Fofa导入数据时遇到的降重问题,指出根本原因在于FofaAPI的限制而非ARL本身,并展示了相关代码逻辑。同
ARL分析与进阶使用 网络安全文章

ARL分析与进阶使用

文章总结: 文章分析了ARL资产侦察灯塔系统在使用Fofa导入数据时遇到的降重问题,指出根本原因在于FofaAPI的限制而非ARL本身,并展示了相关代码逻辑。同
评论:0   参与:  0