SOCKS proxy over Azure Storage Blob service
ProxyBlob is a tool designed to create SOCKS proxy tunnels through Azure Blob Storage service. This is particularly useful in environments where direct network connectivity is restricted but *.blob.core.windows.net
is accessible.
The system consists of two components:
- Proxy Server: Runs on your local machine and provides a SOCKS interface for your applications
- Agent: Runs inside the target network and communicates with the proxy through Azure Blob Storage
- SOCKS5 protocol (CONNECT and UDP ASSOCIATE)
- Communication through Azure Blob Storage
- Interactive CLI with auto-completion
- Multiple agent management
- Local proxy server
- Go 1.23 or higher
- An Azure Storage Account
In order to use ProxyBlob, you will need an Azure Subscription to create an Azure Storage Account. Once you have a subscription, you can create a storage account in the Azure Portal or using the Azure CLI.
Here are the steps to create a storage account using the Azure Portal:
- Go to https://portal.azure.com
- Login with your Azure account
- In the top Search bar, type "Storage accounts"
- Click on "+ Create"
- Fill in the required fields
- Click on "Review + create"
- Click on "Create"
Storage account settings:
- Subscription: Select your Azure subscription
- Resource Group: Create new Resource Group or select existing
- Storage account name: Choose a name for your storage account
- Location: Select a location near you
- Performance: Premium
⚠️ we will require low latency and high throughput - Premium account type: Block blobs (high transaction rates)
- Redundancy: Locally-redundant Storage (LRS)
Once the deployment is complete, you will see the newly created storage account in the list.
Finally, click on "Security + networking" and then "Access keys" to get the storage account key.
Here are the steps to create a storage account using the Azure CLI:
# Login to Azure
az login
# Create a resource group
az group create --name "proxyblob-resource-group" --location "Central US"
# Create a storage account
az storage account create --name "myproxyblob" --resource-group "proxyblob-resource-group" --location "Central US" --sku "Premium_LRS" --kind BlockBlobStorage
# Get the storage account key
az storage account keys list --account-name "myproxyblob" --output table
You should see displayed the storage account keys.
If you want to test the tool, you can also use Azurite, a lightweight server clone of Azure Storage that can be run locally. To install Azurite, I recommend using either Visual Studio Code extension or Docker.
For the extension, installation is straightforward:
- Go to the Extensions tab
- Search for
Azurite.azurite
- Click "Install"
You should see down right of your editor 3 buttons like this:
[Azurite Table Service] [Azurie Queue Service] [Azurite Blob Service]
Press on the [Azurite Blob Service]
and the service should be running.
For Docker, you will have to pull the image and run it:
docker pull mcr.microsoft.com/azure-storage/azurite
docker run -p 10000:10000 mcr.microsoft.com/azure-storage/azurite
The default storage account name is devstoreaccount1
and the account key is Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==
.
# Clone the repository
git clone https://github.com/quarkslab/proxyblob
cd proxyblob
# Build both components
make
This will produce the following binaries:
proxy
- the proxy server running on your machineagent
- the agent running on the target
Create a config.json
file based on the example with your Azure Storage credentials:
{
"storage_url": "http://localhost:10000/", // omit if using Azure
"storage_account_name": "your-storage-account-name",
"storage_account_key": "your-storage-account-key"
}
./proxy -c my-config.json # if omitted, config.json is used by default
This will start an interactive CLI with the following commands:
Commands:
clear clear the screen
create, new create a new agent container and generate its connection string
delete, rm delete an existing agent container
exit exit the shell
help use 'help [command]' for command help
list, ls list all existing agent containers
select, use select an agent for subsequent commands
start, proxy start SOCKS proxy server
stop stop running proxy for the selected agent
Once the proxy server is running, you can create a new agent container by using the create
command.
proxyblob » create
16:28:37 INF Agent container created successfully container_id=5f5250e9-5518-4682-90ea-f61abf797654
16:28:37 INF Connection string generated connection_string=aHR0cDovL2xvY2FsaG9zdDoxMDAwMC9kZXZzdG9yZWFjY291bnQxLzVmNTI1MGU5LTU1MTgtNDY4Mi05MGVhLWY2MWFiZjc5NzY1ND9zZT0yMDI1LTA0LTI0VDE0JTNBMjglM0EzN1omc2lnPXpjNUNVYVZKJTJGS1duY3RtbnlNZ0clMkZZNkNrRzZHYXJzMXRFTXkxR0ZiTVVZJTNEJnNwPXJ3JnNwcj1odHRwcyUyQ2h0dHAmc3I9YyZzdD0yMDI1LTA0LTE3VDE0JTNBMjMlM0EzN1omc3Y9MjAyMC0xMC0wMg
Use the connection string generated with the agent (see below Starting the Agent). If the agent connects successfully, you should see the “Agent Info” column filled in when you list the agents with the list
command.
proxyblob » list
╭──────────────────────────────────────┬────────────┬────────────┬─────────────────────┬─────────────────────╮
│ CONTAINER ID │ AGENT INFO │ PROXY PORT │ FIRST SEEN │ LAST SEEN │
├──────────────────────────────────────┼────────────┼────────────┼─────────────────────┼─────────────────────┤
│ 5f5250e9-5518-4682-90ea-f61abf797654 │ atsika@qb │ │ 2025-04-17 14:28:37 │ 2025-04-17 14:28:37 │
╰──────────────────────────────────────┴────────────┴────────────┴─────────────────────┴─────────────────────╯
Select the agent using select <container id>
and start the proxy listener (by default it listens on localhost:1080) by using the start
command.
atsika@qb » select 5f5250e9-5518-4682-90ea-f61abf797654
17:17:51 INF Agent selected agent=atsika@qb
atsika@qb » start
17:17:58 INF Proxy started successfully agent=atsika@qb port=1080
You can now use for example proxychains to tunnel the traffic through the SOCKS proxy.
proxychains xfreerdp /v:dc01.domain.local /u:Administrator
In order to run, the agent requires a connection string that can be generated using the proxy. You can pass it as an argument or directly embed it at compile-time.
# Via argument
./agent -c <generated-connection-string>
# Build the agent with embedded connection string
make agent TOKEN=<generated-connection-string>
./agent
The communication flow works like this:
- The agent periodically polls an Azure Blob container for encoded packets in a request blob
- The proxy writes encoded packets to the Azure Blob container in a request blob
- When the agent finds a packet, it processes it and writes the response back to a response blob
- The proxy reads the response and maintains the SOCKS connection with client applications
The global flow is the following:
graph TB
%% Client applications
Client1[Client Application] -->|SOCKS5 Request| SocksServer
Client2[Web Browser] -->|SOCKS5 Request| SocksServer
%% Proxy Server Components
subgraph "Proxy Server (Local Machine)"
SocksServer[SOCKS5 Server]
CLI[Interactive CLI]
ProxyHandler[Proxy Handler]
TransportP[Blob Transport]
end
%% Connection between components
CLI -->|Commands| SocksServer
SocksServer -->|Process Request| ProxyHandler
ProxyHandler -->|Encode Packets| TransportP
TransportP -->|Receive Responses| ProxyHandler
ProxyHandler -->|Return Data| SocksServer
%% Azure Blob Storage
subgraph "Azure Blob Storage"
RequestBlob[Request Blob]
ResponseBlob[Response Blob]
end
%% Connection to Azure
TransportP -->|Write| RequestBlob
ResponseBlob -->|Read| TransportP
%% Agent Components
subgraph "Agent (Target Network)"
AgentPoller[Polling Component]
TransportA[Blob Transport]
SocksHandler[SOCKS Handler]
CommandProcessor[Command Processor]
end
%% Agent connections
RequestBlob -->|Poll| AgentPoller
AgentPoller -->|Process| TransportA
TransportA -->|Decode Packets| SocksHandler
SocksHandler -->|Process Commands| CommandProcessor
%% Command Processing - Fixed syntax
subgraph "Command Processing"
Connect["CONNECT"]
Bind["TODO: BIND"]
UDP["UDP ASSOCIATE"]
end
CommandProcessor -->|Route| Connect
CommandProcessor -->|Route| Bind
CommandProcessor -->|Route| UDP
%% Target Connections
Connect -->|TCP Connection| TargetServer1[Target Server]
UDP -->|UDP Connection| TargetServer2[Target Server]
%% Return path
TargetServer1 -->|Response Data| SocksHandler
TargetServer2 -->|UDP Data| SocksHandler
SocksHandler -->|Encode Response| TransportA
TransportA -->|Write| ResponseBlob
An example of a CONNECT operation is the following:
sequenceDiagram
participant Client as Client Application
participant Proxy as Proxy Server
participant AzureStor as Azure Blob Storage
participant Agent as Agent
participant Target as Target Server
Note over Client,Target: SOCKS5 Protocol Flow
%% Proxy Server and Agent Initialization
Proxy->>AzureStor: Initialize connection
Agent->>AzureStor: Start polling for requests
%% Client Connection and Authentication
Client->>Proxy: TCP Connection
Proxy->>Client: Auth methods (NoAuth supported)
Client->>Proxy: Select Auth method
%% Command Processing
Client->>Proxy: CONNECT command + target address
Proxy->>AzureStor: Write CONNECT request packet to Request Blob
Agent->>AzureStor: Poll and retrieve CONNECT request
%% Target Connection
Agent->>Target: Establish TCP connection
Target->>Agent: Connection established
Agent->>AzureStor: Write connection success to Response Blob
Proxy->>AzureStor: Poll and retrieve response
Proxy->>Client: CONNECT success response
%% Data Transfer (Bidirectional)
Client->>Proxy: Send data
Proxy->>AzureStor: Write data packet to Request Blob
Agent->>AzureStor: Poll and retrieve data packet
Agent->>Target: Forward data
Target->>Agent: Response data
Agent->>AzureStor: Write response data to Response Blob
Proxy->>AzureStor: Poll and retrieve response data
Proxy->>Client: Forward response data
Why does my agent immediately stop running ?
There might be several reasons why your agent stops immediately after you run it. Check its exit code:
# Bash
echo $?
REM CMD
echo %ERRORLEVEL%
# PowerShell
echo $LastExitCode
Each exit code describes why the agent stopped running:
Exit code | Reason |
---|---|
0 | No error |
1 | The context has been canceled |
2 | The connection string is missing |
3 | The connection string is invalid or expired |
4 | The agent failed to write its metadata |
5 | The agent container is not found |
If you encounter issues:
- Check Azure credentials and permissions
- Verify connectivity to Azure Blob Storage
- Check for any firewall rules blocking outbound connections
- Ensure the agent is running and properly connected
- BIND command implementation (currently not working)
- Enhanced error handling and recovery
- Improve proxy speed