Skip to content

Commit

Permalink
UDP 427 SLP Protocol (#2)
Browse files Browse the repository at this point in the history
* SLP protocol information and honeypot service implementation

* SLP updated protocol information
  • Loading branch information
im4kv authored Nov 5, 2023
1 parent fd860e3 commit f3138ee
Show file tree
Hide file tree
Showing 10 changed files with 401 additions and 19 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,32 @@ jobs:
cd UDP-389-cLDAP-DDoS-Amplification
docker build . --tag ghcr.io/im4kv/malicious-traffic-research:cldap.latest
docker push ghcr.io/im4kv/malicious-traffic-research:cldap.latest
publish-slp-docker-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dorny/paths-filter@v2
id: changes
with:
filters: |
slp:
- 'UDP-427-SLP-DDoS-Amplification/**'
- name: Checkout repository
uses: actions/checkout@v3

- name: Log in to the Container registry
uses: docker/login-action@v1
with:
registry: https://ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

# run only if some file in 'cldap' folder was changed
- name: Build the SLP Honeypot Docker image
if: steps.changes.outputs.slp == 'true'
run: |
cd UDP-427-SLP-DDoS-Amplification
docker build . --tag ghcr.io/im4kv/malicious-traffic-research:slp.latest
docker push ghcr.io/im4kv/malicious-traffic-research:slp.latest
3 changes: 0 additions & 3 deletions UDP-389-cLDAP-DDoS-Amplification/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# cLDAP (Connectionless Lightweight Directory Access Protocol) UDP 389

---



### protocol flaw

Expand Down
18 changes: 18 additions & 0 deletions UDP-427-SLP-DDoS-Amplification/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM python:3.10-alpine3.17

# Copy application files & Install packages
COPY docker/ /opt/dist/
RUN python3 -m pip install --no-cache-dir -r /opt/dist/requirements.txt && \
# Setup user, groups and configs
addgroup --gid 2000 mtrapp && \
adduser -D -u 2000 -G mtrapp mtrapp && \
chown mtrapp:mtrapp -R /opt/dist

STOPSIGNAL SIGINT
USER mtrapp:mtrapp

WORKDIR /opt/dist

# Start Service
CMD ["python3","slp.py"]

119 changes: 119 additions & 0 deletions UDP-427-SLP-DDoS-Amplification/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# SLP (Service Location Protocol) UDP 427

### protocol flaw

The Service Location Protocol ([SLP](https://en.wikipedia.org/wiki/Service_Location_Protocol)) [RFC 2165](https://www.rfc-editor.org/rfc/rfc2165.html) is a legacy "service discovery" protocol that dates back to 1997 and was meant to be used on local networks for automated service discovery and dynamic configuration between applications. The SLP daemon on a system will maintain a directory of available services such as printers, file servers, and other network resources. It will listen to requests on UDP port 427.
SLP is a relatively obsolete protocol and has mostly been supplanted by more modern alternatives like UPnP, mDNS/Zeroconf, and WS-Discovery. Nevertheless, many commercial products still offer support for SLP. Since SLP has no method for authentication, it should never be exposed to the public Internet.

It should be mentioned that the SLP protocols uses both UDP and TCP for the transmission of data (most packets are transmitted using UDP, but TCP can also be used for the transmission of longer packets). Researchers have discovered that the UDP version of this protocol has an amplification factor of up to 2,200x.

As specified in the protocol [RFC](https://www.rfc-editor.org/rfc/rfc2165.html#page-56) it has three main components:

#### User-Agents (UA) - Clients:
- Description: User-Agents are the clients or end-user applications that utilize SLP to discover and access services available on the network.
- Functionality: UAs send service requests to the network in order to find specific services, such as printers, file servers, or other resources.
- Example: A web browser acting as a User-Agent can use SLP to locate available web servers on the network.

#### Service Agents (SA) - Register/DeRegister Services:
- Description: Service Agents are responsible for registering services on the network and informing the Directory Agents of their availability.
- Functionality: SAs announce their services to the network so that User-Agents can locate them when needed. They also handle the process of unregistering services when they become unavailable.
- Example: A printer with an SLP-enabled component can register itself on the network, allowing User-Agents to discover and print documents.

#### Directory Agents (DA) - Advertise Services:
- Description: Directory Agents maintain a directory of available services within a network domain.
- Functionality: DAs collect and store service advertisements from Service Agents. They respond to service requests from User-Agents by providing information about available services.
- Example: A Directory Agent can maintain a list of all the printers, file servers, and other services available in a local network and respond to User-Agent queries with this information.

Malicious actors may craft User-Agent requests with victim's IP address that trigger excessive responses from Directory Agents. This amplifies the traffic directed at the victim, making the attack more potent.


The protocol has two main versions.The original version of SLP (Version 1), defined in [RFC 2165](https://www.rfc-editor.org/rfc/rfc2165.html). It was published in June 1997. SLPv2 is an enhanced and more widely adopted version of the protocol. It addressed some of the limitations of SLPv1 and introduced additional features. SLPv2 is defined in [RFC 2608](https://www.ietf.org/rfc/rfc2608.txt) (published in June 1999) and later updated by [RFC 3111](https://datatracker.ietf.org/doc/html/rfc3111) for IPv6 (published in May 2001).

SLPv2 is the version most commonly used in practice due to its improved capabilities and broader support in networking environments


### payload Info

SLP defines its own custom message format with specific fields, as outlined in the SLP RFC documents (such as page 17 of [RFC 2608](https://www.ietf.org/rfc/rfc2608.txt) for SLPv2).

Here are general structure of the SLP requests:
<pre>

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Version | Function-ID | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length, contd.|O|F|R| reserved |Next Ext Offset|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Next Extension Offset, contd.| XID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Language Tag Length | Language Tag \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Information about fields:

Version (2 bytes): This field indicates the version of the SLP protocol being used.

Function ID (2 bytes): Specifies the function of the message (e.g., Service Request, Service Reply, Service Registration).
Service Request SrvRqst 1 # Absused in DDoS Attacks
Service Reply SrvRply 2
Service Registration SrvReg 3 # Abused in DDoS Attacks
Service Deregister SrvDeReg 4
Service Acknowledge SrvAck 5
Attribute Request AttrRqst 6
Attribute Reply AttrRply 7
DA Advertisement DAAdvert 8
Service Type Request SrvTypeRqst 9 # Abused in DDoS Attacks
Service Type Reply SrvTypeRply 10
SA Advertisement SAAdvert 11

Length (2 bytes): Indicates the length of the message in bytes.

Flags (1 byte): Contains flags that provide additional information about the message.

Next Ext Offset (1 byte): Points to the offset of the next extension, allowing for variable-length extension blocks.

XID (2 bytes): Transaction identifier used to match replies to requests.

Language Tag (variable length): Indicates the natural language used in string fields.

Payload (variable length): Contains the specific information related to the function of the message (e.g., URL for service location, service attributes, etc.).

Extensions (variable length): May be present in some messages to carry additional information.
</pre>

Here is an example of a binary SLP request used to to check vulnerable servers: <pre>\x02\t\x00\x00\x1d\x00\x00\x00\x00\x00s_\x00\x02en\x00\x00\xff\xff\x00\x07default</pre>

To successfully decode this, we can use custom parsers to decode the binary protocol based on the specification available in the SLP RFCs:
<pre>
{'version': 2, 'function_id': 9, 'length': 29, 'xid': 29535, 'language_tag_length': 2, 'language_tag': 'en'}
</pre>
The decoded payload shows it is a SLP version two packet which contains a `Service Type Request (SrvTypeRqst)` as the `function_id` field. the `xid` contain the transaction ID which will be the same for the response of this request. `Service Type Request (SrvTypeRqst)` allows a User-Agent (Could be Malicious Actor) to discover all types of service on a network. This is useful for general purpose service browsers. as a note `function_id` of 1 for `Service Request (SrvRqst)` will only be used to get specific services that matches the type specified in the request, hence it covers smaller scope of services and usually it has smaller responses.

for testing purposes, we can send the payload to a SLP server and check the size of the response via wireshark or tcpdump:
<pre>echo "\x02\t\x00\x00\x1d\x00\x00\x00\x00\x00s_\x00\x02en\x00\x00\xff\xff\x00\x07default" | nc -4u -w1 SERVER-ADDRESS-HERE 427</pre>

A greatly amplified attack using SLP would have the following attack design:
1) Find a publicly available SLP service - Reconnaissance
2) Verify it allows registration of new services - Setup Phase
3) Register services, until SLP denies more entries - Setup Phase
4) Check response size - Finalize
5) Create spoofed packet-stream with the victim as the origin - Launch an attack


### [Honeypot Service Info](docker)

- Honeypot service will accept three `function_id`: Service Request, Service Registration and Service Type Request.
- It will parse the protocol and drop the coming datagram in case the packet is malformed.
- In the case of Service Request and Service Type Requests, the server will respond with two predefined services (The URI of an API and VMware ESXi service)
- For Service Registration requests, it will not store the Incoming data but acknowledge the requests.
- The default rate limiting threshold is five datagrams (5 requests) per 24 hours. The server will not respond to the requests when the rate limiting threshold is exceeded.



#### References
1) CVE-2023-29552 Service Location Protocol-Denial of Service Amplification Attack:
- https://curesec.com/blog/article/CVE-2023-29552-Service-Location-Protocol-Denial-of-Service-Amplification-Attack-212.html
- https://www.bitsight.com/blog/new-high-severity-vulnerability-cve-2023-29552-discovered-service-location-protocol-slp

55 changes: 55 additions & 0 deletions UDP-427-SLP-DDoS-Amplification/docker/creator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-

import uuid


def create_header(function_id, data_length, ofr, version=2, xid=None, language_tag='en'):
header = b''
for b in [version, function_id]:
header += bytes([b])

language_tag_length = len(language_tag.encode())

header += (14 + language_tag_length + data_length).to_bytes(3, byteorder='big')

u = uuid.uuid1()
for b in [ofr, 0, 0, 0, 0]:
header += bytes([b])

if xid is None:
for b in [u.clock_seq_hi_variant, u.clock_seq_low]:
header += bytes([b])
else:
header += xid.to_bytes(2, byteorder='big')

header += language_tag_length.to_bytes(2, byteorder='big')
header += language_tag.encode()

return header


def create_acknowledge(xid, error_code=0):
data = error_code.to_bytes(length=2, byteorder='big')
header = create_header(function_id=5, data_length=len(data), xid=xid, ofr=0)
return header + data


def create_url_entry(lifetime, url):
data = bytes([0])
data += lifetime.to_bytes(length=2, byteorder='big')
data += (len(url.encode())).to_bytes(length=2, byteorder='big')
data += url.encode()
data += bytes([0])
return data


def create_reply(xid, url_entries, error_code=0):
data = error_code.to_bytes(length=2, byteorder='big')
data += len(url_entries).to_bytes(length=2, byteorder='big')
for entry in url_entries:
data += create_url_entry(**entry)
header = create_header(function_id=2, data_length=len(data), xid=xid, ofr=0)
return header + data



68 changes: 68 additions & 0 deletions UDP-427-SLP-DDoS-Amplification/docker/parse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# -*- coding: utf-8 -*-


def convert_to_int(data):
return int.from_bytes(data, byteorder='big')


def _parse(data, count):
p = 0
result = list()
for _ in range(count):
length = convert_to_int(data[p:p + 2])
p += 2
value = data[p:p + length]
p += length
result.append(
dict(
value=value,
length=length
)
)

return [info['value'] for info in result], 7 + sum([info['length'] for info in result])


def parse_header(data):
language_tag_length = convert_to_int(data[12:14])
header_length = 14 + language_tag_length
return dict(
version=data[0],
function_id=data[1],
length=convert_to_int(data[2:5]),
xid=convert_to_int(data[10:12]),
language_tag_length=language_tag_length,
language_tag=data[14:header_length].decode()
), header_length


def parse_url_entry(data):
url_length = convert_to_int(data[3:5])
auth_length = data[5 + url_length]
length = 6 + url_length + auth_length
return dict(
lifetime=convert_to_int(data[1:3]),
url=data[5:5 + url_length].decode()
), length


def parse_registration(data):
header, header_length = parse_header(data)
url_entry, url_entries_length = parse_url_entry(data[header_length:])

result, length = _parse(data[header_length + url_entries_length:], 3)

return header, url_entry, dict(
service_type=result[0].decode(),
scope_list=result[1].decode(),
attr_list=result[2].decode()
)


def parse_request(data):
header, header_length = parse_header(data)
result, length = _parse(data[header_length:], 5)
return header, dict(
service_type=result[1].decode(),
scope_list=result[2].decode()
)
1 change: 1 addition & 0 deletions UDP-427-SLP-DDoS-Amplification/docker/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
twisted~=23.8.0
Loading

0 comments on commit f3138ee

Please sign in to comment.