HTTP

Dionaea supports http on port 80 as well as https, but there is no code making use of the data gathered on these ports. For https, the self-signed ssl certificate is created at startup.

Configure

Example configuration:

- name: http
  config:
    root = "var/dionaea/wwwroot"

default_headers

Default header fields are send if none of the other header patterns match.

global_headers

Global header fields are added to all response headers.

headers

List of header fields to be used in the response header. Only applied if filename_pattern, status_code and methods match. The first match in the list is used.

max_request_size

Maximum size in kbytes of the request. 32768 = 32MB

root

The root directory so serve files from.

Example config

services/http.yaml
# SPDX-FileCopyrightText: none
# SPDX-License-Identifier: CC0-1.0

- name: http
  config:
    # Root directory to look for files
    root: "@DIONAEA_STATEDIR@/http/root"
    ports:
      - 80
    ssl_ports:
      - 443
    max_request_size: 32768 # maximum size in kbytes of the request (32MB)
    # Set default Content-Type if unable to detect
    # default_content_type: text/html; charset=utf-8
    # Max number of fields to extract from GET request (Python >= 3.8)
    # get_max_num_fields: 100
    # List of default headers
    # default_headers:
    #   - ["Content-Type", "{content_type}"]
    #   - ["Content-Length", "{content_length}""]
    #   - ["Connection", "{connection}"]
    # Try to detect the Content-Type by using the filename
    # detect_content_type: true
    global_headers:
      - ["Server", "nginx"]
    # Add additional headers to the response. First match wins.
    # filename_pattern - is a regex if matched the headers are set
    # headers - a list of HTTP headers to set
    #           the order matters, use to simulate your webserver as good as possible
    headers:
      - filename_pattern: ".*\\.php"
        headers:
          - ["Content-Type", "text/html; charset=utf-8"]
          - ["Content-Length", "{content_length}"]
          - ["Connection", "{connection}"]
          - ["X-Powered-By", "PHP/5.5.9-1ubuntu4.5"]
    # If enabled, try to handle some SOAP requests
    # soap_enabled: false
    template:
      # set to true to enable template processing
      # this feature requires jinja2 template engine http://jinja.pocoo.org/
      enabled: false
      file_extension: .j2
      path: "@DIONAEA_STATEDIR@/http/template/nginx"
      templates:
        autoindex:
          filename: autoindex.html.j2
        error_pages:
          - filename: error.html.j2
          # - filename: error/{code}.html.j2
      # used to specify additional template values
      values:
        # full_name: nginx/1.1

Additional examples

Set the Server response field.

- name: http
  config:
    global_headers:
      - ["Server", "nginx"]

Define headers to use if the filename matches a pattern.

- name: http
  config:
    headers:
      - filename_pattern: ".*\\.php"
        headers:
          - ["Content-Type", "text/html; charset=utf-8"]
          - ["Content-Length", "{content_length}"]
          - ["Connection", "{connection}"]
          - ["X-Powered-By", "PHP/5.5.9-1ubuntu4.5"]

Templates

It is possible to use Jinja templates to customise the content returned by dionaea.

Requirements:

  • Jinja

Before any template is used the template processing has to be enabled in the config file. Some global templates (e.g. for error pages) are specified in the config file. To use the template function in a static file just place it under the content root directory and add the template file extension as specified with the file_extension.

Example:

  • you have a file called my-app.html
  • to enabled template processing rename the file to my-app.html.j2
  • now you can use template strings

Template values:

  • connection is an instance of HTTP connection class
  • values is a Dictionary of additional template values specified in the config

Demo:

Have a look at our demo template and play with it in your test lab before releasing it into the wild.

http/root/form.html.j2
<html>
    <head>
        <title>Demo</title>
    </head>
    <body>
        <h1>Form GET</h1>
        <form action="{{ connection.header.path }}" method="get">
            <label for="text1">Text</label>
            <input type="text" name="text" id="text1"/>

            <label for="password1">Password</label>
            <input type="password" name="password" id="password1"/>

            <button type="submit">Send</button>
        </form>
        <h1>Form POST</h1>
        <form action="{{ connection.header.path }}" method="post">
            <label for="text2">Text</label>
            <input type="text" name="text" id="text2"/>

            <label for="password2">Password</label>
            <input type="password" name="password" id="password2"/>

            <button type="submit">Send</button>
        </form>
        <h1>Form POST - multipart/form-data</h1>
        <form action="{{ connection.header.path }}" enctype="multipart/form-data" method="post">
            <label for="text3">Text</label>
            <input type="text" name="text" id="text3"/>

            <label for="password3">Password</label>
            <input type="password" name="password" id="password3"/>

            <label for="file3">File</label>
            <input type="file" name="file" id="file3"/>

            <button type="submit">Send</button>
        </form>
        <h1>Results</h1>
        <pre>
Get Values
{% for name, value in connection.request_fields|dictsort %}
{{ name }} = {{ value[0] }}
{% endfor %}
Form values
{% if connection.request_form %}
{% for name in connection.request_form.keys() %}
{% if connection.request_form[name].filename %}
{{ name }} = file with name '{{ connection.request_form[name].filename }}'
{% else %}
{{ name }} = {{ connection.request_form[name].value }}
{% endif %}
{% endfor %}
{% endif %}
        </pre>

    </body>
</html>