Custom Application & IPS Signatures
Creating a custom IPS signature
The FortiGate predefined signatures cover common attacks. If you use an unusual or specialized application or an uncommon platform, add custom signatures based on the security alerts released by the application and platform vendors.
You can add or edit custom signatures using the web-based manager or the CLI.
To create a custom signature
1. Go to Security Profiles > Intrusion Protection.
2. Select [View IPS Signatures]
3. Select Creat New to add a new custom signature.
4. Enter a Name for the custom signature.
5. Enter the Signature. For information about completing this field, see “Custom signature syntax and keywords”.
6. Select OK.
Custom signature syntax and keywords
All custom signatures follow a particular syntax. Each begins with a header and is followed by one or more keywords. The syntax and keywords are detailed in the next two topics.
Custom signature syntax
A custom signature definition is limited to a maximum length of 512 characters. A definition can be a single line or span multiple lines connected by a backslash (\) at the end of each line.
A custom signature definition begins with a header, followed by a set of keyword/value pairs enclosed by parenthesis [( )]. The keyword and value pairs are separated by a semi colon (;) and consist of a keyword and a value separated by a space. The basic format of a definition is HEADER (KEYWORD VALUE;)
You can use as many keyword/value pairs as required within the 512 character limit. To configure a custom signature, go to Security Profiles > Intrusion Protection, select View IPS Signatures, select Create New, and enter the data directly into the Signature field, following the guidance in the next topics.
The table below shows the valid characters and basic structure. For details about each keyword and its associated values, see “Custom signature keywords”.
Valid syntax for custom signature fields
Field | Valid Characters | Usage |
HEADER |
F-SBID |
The header for an attack defin- ition signature. Each custom signature must begin with this header. |
Field Valid Characters Usage
KEYWORD
Each keyword must start with a pair of dashes (–), and consist of a string of 1 to 19 characters.
Normally, keywords are an English word or English words connected by an underscore (_). Keywords are case insensitive.
The keyword is used to identify a parameter.
VALUE Double quotes (“) must be used around the value if it contains a space and/or a semicolon (;).
If the value is NULL, the space between the KEYWORD and VALUE can be omitted. Values are case sensitive.
Note: If double quotes are used for quoting the value, the double quotes are not considered as part of the value string.
The value is set specifically for a parameter identified by a keyword.
Custom signature keywords
Information keywords attack_id Syntax: –attack_id <id_int>;
Description:
Use this optional value to identify the signature. It cannot be the same value as any other custom rules. If an attack ID is not specified, the FortiGate automatically assigns an attack ID to the signature. If you are using VDOMs, custom signatures appear only in the VDOM in which you create them. You can use the same attack ID for signatures in different VDOMs.
An attack ID you assign must be between 1000 and 9999.
Example: –attack_id 1234;
name
Syntax: –name <name_str>;
Description:
Enter the name of the rule. A rule name must be unique. If you are using VDOMs, custom signatures appear only in the VDOM in which you create them. You can use the same rule name for signatures in different VDOMs. The name you assign must be a string greater than 0 and less than 64 characters in length.
Example: –name “Buffer_Overflow”;
Session keywords flow Syntax: –flow {from_client[,reversed] | from_server[,reversed] | bi_direction };
Description:
Specify the traffic direction and state to be inspected. They can be used for all IP traffic.
Example: –src_port 41523; –flow bi_direction;
The signature checks traffic to and from port 41523.
If you enable “quarantine attacker”, the optional reversed keyword allows you to change the side of the connection to be quarantined when the signature is detected.
For example, a custom signature written to detect a brute-force log in attack is triggered when “Login Failed” is detected from_server more than 10 times in 5 seconds. If the attacker is quarantined, it is the server that is quarantined in this instance. Adding reversed corrects this problem and quarantines the actual attacker.
Previous FortiOS versions used to_client and to_server values. These are now deprecated, but still function for backwards compatibility.
service
Syntax: –service {HTTP | TELNET | FTP | DNS | SMTP | POP3 | IMAP | SNMP | RADIUS | LDAP | MSSQL | RPC | SIP | H323 | NBSS | DCERPC | SSH | SSL};
Description:
Specify the protocol type to be inspected. This keyword allows you to specify the traffic type by protocol rather than by port. If the decoder has the capability to identify the protocol on any port, the signature can be used to detect the attack no matter what port the service is running on. Currently, HTTP, SIP, SSL, and SSH protocols can be identified on any port based on the content.
Content keywords byte_extract
Syntax: byte_extract:<bytes_to_extract>, <offset>, <name> \ [, relative][, multiplier <multiplier value>][, <endian>]\ [, string][, hex][, dec][, oct][, align <align value>][, dce];
Description:
Use the byte_extract option to write rules against length-encoded protocols. This reads some of the bytes from the packet payload and saves it to a variable.
byte_jump
Syntax: –byte_jump <bytes_to_convert>, <offset>[, multiplier][, relative] [, big] [, little] [, string] [, hex] [, dec] [, oct] [, align];
Description:
Use the byte_jump option to extract a number of bytes from a packet, convert them to their numeric representation, and jump the match reference up that many bytes (for further pattern matching or byte testing). This keyword allows relative pattern matches to take into account numerical values found in network data. The available keyword options include:
- <bytes_to_convert>: The number of bytes to examine from the packet.
- <offset>: The number of bytes into the payload to start processing.
- [multiplier]: multiplier is optional. It must be a numerical value when present. The converted value multiplied by the number is the result to be skipped.
- relative: Use an offset relative to last pattern match.
- big: Process the data as big endian (default).
- little: Process the data as little endian.
- string: The data is a string in the packet.
- hex: The converted string data is represented in hexadecimal notation.
- dec: The converted string data is represented in decimal notation.
- oct: The converted string data is represented in octal notation.
- align: Round up the number of converted bytes to the next 32-bit boundary.
byte_test Syntax: –byte_test <bytes_to_convert>, <operator>, <value>, <offset> [multiplier][, relative] [, big] [, little] [, string] [, hex] [, dec] [, oct];
Description:
Use the byte_test keyword to compare a byte field against a specific value (with operator). This keyword is capable of testing binary values or converting representative byte strings to their binary equivalent and testing them. The available keyword options include:
- <bytes_to_convert>: The number of bytes to compare.
- <operator>: The operation to perform when comparing the value (<,>,=,!,&).
- <value>: The value to compare the converted value against.
- <offset>: The number of bytes into the payload to start processing.
- [multiplier]: multiplier is optional. It must be a numerical value when present. The converted value multiplied by the number is the result to be skipped.
- relative: Use an offset relative to last pattern match.
- big: Process the data as big endian (default).
- little: Process the data as little endian.
- string: The data is a string in the packet.
- hex: The converted string data is represented in hexadecimal notation.
- dec: The converted string data is represented in decimal notation.
- oct: The converted string data is represented in octal notation.
depth Syntax: –depth <depth_int>;
Description:
Use the depth keyword to search for the contents within the specified number of bytes after the starting point defined by the offset keyword. If no offset is specified, the offset is assumed to be equal to 0.
If the value of the depth keyword is smaller than the length of the value of the content keyword, this signature will never be matched.
The depth must be between 0 and 65535.
distance Syntax: –distance <dist_int>;
Description:
Use the distance keyword to search for the contents within the specified number of bytes relative to the end of the previously matched contents. If the within keyword is not specified, continue looking for a match until the end of the payload.
The distance must be between 0 and 65535.
content
Syntax: –content [!]”<content_str>”;
Description:
Deprecated, see pattern and context keywords. Use the content keyword to search for the content string in the packet payload. The content string must be enclosed in double quotes.
To have the FortiGate search for a packet that does not contain the specified context string, add an exclamation mark (!) before the content string.
Multiple content items can be specified in one rule. The value can contain mixed text and binary data. The binary data is generally enclosed within the pipe (|) character.
The double quote (“), pipe sign(|) and colon(:) characters must be escaped using a back slash if specified in a content string.
If the value of the content keyword is greater than the length of the value of the depth keyword, this signature will never be matched.
context Syntax: –context {uri | header | body | host};
Description:
Specify the protocol field to look for the pattern. If context is not specified for a pattern, the FortiGate unit searches for the pattern anywhere in the packet buffer. The available context variables are:
- uri: Search for the pattern in the HTTP URI line.
- header: Search for the pattern in HTTP header lines or SMTP/POP3/SMTP control messages.
- body: Search for the pattern in HTTP body or SMTP/POP3/SMTP email body.
- host: Search for the pattern in HTTP HOST line.
no_case
Syntax: –no_case;
Description:
Use the no-case keyword to force the FortiGate unit to perform a case-insensitive pattern match.
offset
Syntax: –offset <offset_int>;
Description:
Use the offset keyword to look for the contents after the specified number of bytes into the payload. The specified number of bytes is an absolute value in the payload. Follow the offset keyword with the depth keyword to stop looking for a match after a specified number of bytes. If no depth is specified, the FortiGate unit continues looking for a match until the end of the payload.
The offset must be between 0 and 65535.
pattern
Syntax: –pattern [!]”<pattern_str>”;
Description:
The FortiGate unit will search for the specified pattern. A pattern keyword normally is followed by a context keyword to define where to look for the pattern in the packet. If a context keyword is not present, the FortiGate unit looks for the pattern anywhere in the packet buffer. To have the FortiGate search for a packet that does not contain the specified URI, add an exclamation mark (!) before the URI.
Example: –pattern “/level/” –pattern “|E8 D9FF FFFF|/bin/sh” –pattern !”|20|RTSP/”
pcre
Syntax: –pcre [!]”/<regex>/[ismxAEGRUB]”;
Description:
Similarly to the pattern keyword, use the pcre keyword to specify a pattern using Perl-compatible regular expressions (PCRE). A pcre keyword can be followed by a context keyword to define where to look for the pattern in the packet. If no context keyword is present, the FortiGate unit looks for the pattern anywhere in the packet buffer.
For more information about PCRE syntax, go to http://www.pcre.org. The switches include:
- i: Case insensitive.
- s: Include newlines in the dot metacharacter.
- m: By default, the string is treated as one big line of characters. ^ and $ match at the beginning and ending of the string. When m is set, ^ and $ match immediately following or immediately before any newline in the buffer, as well as the very start and very end of the buffer.
- x: White space data characters in the pattern are ignored except when escaped or inside a character class.
- A: The pattern must match only at the start of the buffer (same as ^ ).
- E: Set $ to match only at the end of the subject string. Without E, $ also matches immediately before the final character if it is a newline (but not before any other newlines).
- G: Invert the “greediness” of the quantifiers so that they are not greedy by default, but become greedy if followed by ?.
- R: Match relative to the end of the last pattern match. (Similar to distance:0;).
- U: Deprecated, see the context keyword. Match the decoded URI buffers.
uri
Syntax: –uri [!]”<uri_str>”;
Description:
Deprecated, see pattern and context keywords. Use the uri keyword to search for the URI in the packet payload. The URI must be enclosed in double quotes (“). To have the FortiGate unit search for a packet that does not contain the specified URI, add an exclamation mark (!) before the URI. Multiple content items can be specified in one rule. The value can contain mixed text and binary data. The binary data is generally enclosed within the pipe (|) character. The double quote (“), pipe sign (|) and colon (:) characters must be escaped using a back slash (\) if specified in a URI string.
within
Syntax: –within <within_int>;
Description:
Use this together with the distance keyword to search for the contents within the specified number of bytes of the payload.
The within value must be between 0 and 65535.
IP header keywords dst_addr Syntax: –dst_addr [!]<ipv4>;
Description:
Use the dst_addr keyword to search for the destination IP address. To have the FortiGate search for a packet that does not contain the specified address, add an exclamation mark (!) before the IP address. You can define up to 28 IP addresses or CIDR blocks. Enclose the comma separated list in square brackets.
Example: dst_addr [172.20.0.0/16, 10.1.0.0/16,192.168.0.0/16]
ip_dscp
Syntax: –ip_dscp
Description:
Use the ip_dscp keyword to check the IP DSCP field for the specified value.
ip_id
Syntax: –ip_id <field_int>;
Description:
Check the IP ID field for the specified value.
ip_option
Syntax: –ip_option {rr | eol | nop | ts | sec | lsrr | ssrr | satid | any};
Description:
Use the ip_option keyword to check various IP option settings. The available options include:
- rr: Check if IP RR (record route) option is present. l eol: Check if IP EOL (end of list) option is present. l nop: Check if IP NOP (no op) option is present.
- ts: Check if IP TS (time stamp) option is present.
- sec: Check if IP SEC (IP security) option is present.
- lsrr: Check if IP LSRR (loose source routing) option is present. l ssrr: Check if IP SSRR (strict source routing) option is present. l satid: Check if IP SATID (stream identifier) option is present.
- any: Check if IP any option is present.
ip_tos
Syntax: –ip_tos <field_int>;
Description:
Check the IP TOS field for the specified value.
ip_ttl
Syntax: –ip_ttl [< | >] <ttl_int>;
Description:
Check the IP time-to-live value against the specified value. Optionally, you can check for an IP time-to-live greater-than (>) or less-than (<) the specified value with the appropriate symbol.
protocol
Syntax: –protocol {<protocol_int> | tcp | udp | icmp};
Description:
Check the IP protocol header.
Example: –protocol tcp;
src_addr
Syntax: –src_addr [!]<ipv4>;
Description:
Use the src_addr keyword to search for the source IP address. To have the FortiGate unit search for a packet that does not contain the specified address, add an exclamation mark (!) before the IP address. You can define up to 28 IP addresses or CIDR blocks. Enclose the comma separated list in square brackets.
Example: src_addr 192.168.13.0/24
TCP header keywords ack
Syntax: –ack <ack_int>;
Description:
Check for the specified TCP acknowledge number.
dst_port
Syntax: –dst_port [!]{<port_int> | :<port_int> | <port_int>: | <port_
int>:<port_int>};
Description:
Use the dst_port keyword to specify the destination port number. You can specify a single port or port range:
- <port_int> is a single port.
- :<port_int> includes the specified port and all lower numbered ports.
- <port_int>: includes the specified port and all higher numbered ports.
- <port_int>:<port_int> includes the two specified ports and all ports in between.
seq
Syntax: –seq [operator,]<number>[,relative];
Description:
Check for the specified TCP sequence number.
- operator includes =,<,>,!.
- relative indicates it’s relative to the initial sequence number of the TCP session.
src_port
Syntax: –src_port [!]{<port_int> | :<port_int> | <port_int>: | <port_
int>:<port_int>};
Description:
Use the src_port keyword to specify the source port number. You can specify a single port or port range:
- <port_int> is a single port.
- :<port_int> includes the specified port and all lower numbered ports.
- <port_int>: includes the specified port and all higher numbered ports.
- <port_int>:<port_int> includes the two specified ports and all ports in between.
tcp_flags
Syntax: –tcp_flags <SAFRUP120>[!|*|+] [,<SAFRUP120>];
Description:
Specify the TCP flags to match in a packet.
- S: Match the SYN flag. l A: Match the ACK flag. l F: Match the FIN flag.
- R: Match the RST flag.
- U: Match the URG flag.
- P: Match the PSH flag.
- 1: Match Reserved bit 1.
- 2: Match Reserved bit 2.
- 0: Match No TCP flags set.
- !: Match if the specified bits are not set.
- *: Match if any of the specified bits are set.
- +: Match on the specified bits, plus any others.
The first part if the value (<SAFRUP120>) defines the bits that must be present for a successful match.
Example:
–tcp_flags AP only matches the case where both A and P bits are set.
The second part ([,<SAFRUP120>]) is optional, and defines the additional bits that can be present for a match.
For example tcp_flags S,12 matches the following combinations of flags: S, S and 1, S and 2, S and 1 and 2. The modifiers !, * and + cannot be used in the second part.
window_size
Syntax: –window_size [!]<window_int>;
Description:
Check for the specified TCP window size. You can specify the window size as a hexadecimal or decimal integer. A hexadecimal value must be preceded by 0x. To have the FortiGate search for the absence of the specified window size, add an exclamation mark (!) before the window size.
UDP header keywords dst_port
Syntax: –dst_port [!]{<port_int> | :<port_int> | <port_int>: | <port_
int>:<port_int>};
Description:
Specify the destination port number. You can specify a single port or port range:
- <port_int> is a single port.
- :<port_int> includes the specified port and all lower numbered ports.
- <port_int>: includes the specified port and all higher numbered ports.
- <port_int>:<port_int> includes the two specified ports and all ports in between.
src_port
Syntax: –src_port [!]{<port_int> | :<port_int> | <port_int>: | <port_
int>:<port_int>};
Description:
Specify the destination port number. You can specify a single port or port range:
- <port_int> is a single port.
- :<port_int> includes the specified port and all lower numbered ports.
- <port_int>: includes the specified port and all higher numbered ports.
- <port_int>:<port_int> includes the two specified ports and all ports in between.
ICMP keywords icmp_code
Syntax: –icmp_code <code_int>;
Description:
Specify the ICMP code to match.
icmp_id
Syntax: –icmp_id <id_int>;
Description:
Check for the specified ICMP ID value.
icmp_seq
Syntax: –icmp_seq <seq_int>;
Description:
Check for the specified ICMP sequence value.
icmp_type
Syntax: –icmp_type <type_int>;
Description:
Specify the ICMP type to match.
Other keywords data_size
Syntax: –data_size {<size_int> | <<size_int> | ><size_int>;
Description:
Test the packet payload size. With data_size specified, packet reassembly is turned off automatically. So a signature with data_size and only_stream values set is wrong.
- <size_int> is a particular packet size.
- <<size_int> is a packet smaller than the specified size.
- ><size_int> is a packet larger than the specified size. Examples:
- –data_size 300;
- –data_size <300;
- –data_size >300;
data_at
Syntax: –data_at <offset_int>[, relative];
Description:
Verify that the payload has data at a specified offset, optionally looking for data relative to the end of the previous content match.
dump–all–html
Syntax: –dump-all-html
Description:
Dump all HTML files for benchmarking via iSniff. When there is no file type specified, all HTML files are dumped.
rate
Syntax: –rate <matches_int>,<time_int>;
Description:
Instead of generating log entries every time the signature is detected, use this keyword to generate a log entry only if the signature is detected a specified number of times within a specified time period.
- <matches_int> is the number of times a signature must be detected.
- <time_int> is the length of time in which the signature must be detected, in seconds.
For example, if a custom signature detects a pattern, a log entry will be created every time the signature is detected. If –rate 100,10; is added to the signature, a log entry will be created if the signature is detected 100 times in the previous 10 seconds. Use this command with –track to further limit log entries to when the specified number of detections occur within a certain time period involving the same source or destination address rather than all addresses.
rpc_num
Syntax: –rpc_num <app_int>[, <ver_int> | *][, <proc_int> | *>];
Description:
Check for RPC application, version, and procedure numbers in SUNRPC CALL requests. The * wild card can be used for version and procedure numbers.
same_ip
Syntax: –same_ip;
Description:
Check that the source and the destination have the same IP addresses.
track
Syntax: –track {SRC_IP |DST_IP |DHCP_CLIENT |DNS_DOMAIN}[,block_int];
Description:
When used with –rate, this keyword narrows the custom signature rate totals to individual addresses.
- SRC_IP: tracks the packet’s source IP.
- DST_IP: tracks the packet’s destination IP.
- DHCP_CLIENT: tracks the DHCP client’s MAC address.
- DNS_DOMAIN: counts the number of any specific domain name.
- block_int has the FortiGate unit block connections for the specified number of seconds, from the client or to the server, depending on which is specified.
For example, if –rate 100,10 is added to the signature, a log entry will be created if the signature is detected 100 times in the previous 10 seconds. The FortiGate unit maintains a single total, regardless of source and destination address.
If the same custom signature also includes –track client; matches are totaled separately for each source address. A log entry is added when the signature is detected 100 times in 10 seconds within traffic from the same source address.
The –track keyword can also be used without –rate. If an integer is specified, the client or server will be blocked for the specified number of seconds every time the signature is detected.