tcppc
is a simple honeypot program to capture TCP/TLS/UDP payloads. This
program listens on the given IP address and the given port, establishes
connections from external hosts, and continues to receive packets until the
connections are closed or timeouted. tcppc
supports transparent proxy
(TPROXY) by iptables, so you can get payloads of arbitrary ports using tcppc
.
I am developing this program to use as a honeypot for monitoring payloads.
Main functions:
- Establish TCP or TLS handshake and continue to receive packets.
- Receive UDP packets.
- Support transparent proxy (PROXY) to listen on all ports.
- Save received data (session data) as JSON lines format.
- Rotate the data files in the given interval.
Precompiled binaries for Linux (x86_64) are released. See release page.
tcppc
is written in Go. So, if you want to build its binary, you need to
prepare the development environment for Go.
If you are ready for building Go, type the following commands.
$ go get github.com/md-irohas/tcppc-go
Note that the version of go compiler must be 1.11.0 or newer to enable timeout of connection.
The followings are the options of tcppc
.
You can also use configuration files instead of using these options (See
'Configuration' section).
Usage of ./tcppc-go:
-C string
TLS certificate file.
-H string
hostname to listen on. (default "0.0.0.0")
-K string
TLS key file.
-L string
[deprecated] log file.
-R uint
maximum number of file descriptors (need root priviledge).
-T int
rotation interval [sec].
-c string
configuration file.
-disable-tcp-server
disable TCP/TLS server.
-disable-udp-server
disable UDP server.
-offset int
rotation interval offset [sec].
-p int
port number to listen on. (default 12345)
-t int
timeout for TCP/TLS connection. (default 60)
-v show version and exit.
-w string
session file (JSON lines format).
-z string
timezone used for session file. (default "Local")
Run tcppc-go program.
$ sudo ./tcppc-go
2019/04/16 23:42:32 Maximum number of file descriptors: 1024
2019/04/16 23:42:32 Timezone: Local
2019/04/16 23:42:32 Timeout: 60
2019/04/16 23:42:32 Session data file: none.
2019/04/16 23:42:32 !!!CAUTION!!! Session data will not be written to files.
2019/04/16 23:42:32 Server Mode: TCP
2019/04/16 23:42:32 Listen: 0.0.0.0:12345
2019/04/16 23:42:32 Start TCP server.
2019/04/16 23:42:32 Server Mode: UDP
2019/04/16 23:42:32 Listen: 0.0.0.0:12345
2019/04/16 23:42:32 Start UDP server.
Connect to the server from another terminal.
$ echo "Hello, TCPPC" | nc 127.0.0.1 12345
The tcppc-go gets the following logs.
$ ./tcppc-go
...
2019/04/16 23:44:00 TCP: Established: Session: 2019-04-16T23:44:00: Flow: tcp 127.0.0.1:60998 <-> 127.0.0.1:12345 (0 payloads) (#Sessions: 1)
2019/04/16 23:44:00 TCP: Received: Session: 2019-04-16T23:44:00: Flow: tcp 127.0.0.1:60998 <-> 127.0.0.1:12345 (1 payloads): "Hello, TCPPC\n" (13 bytes)
2019/04/16 23:44:00 Closed: Session: 2019-04-16T23:44:00: Flow: tcp 127.0.0.1:60998 <-> 127.0.0.1:12345 (1 payloads) (#Sessions: 1)
Send UDP packets from the terminal.
$ echo "Hello, TCPPC" | nc -u 127.0.0.1 12345
The tcppc-go gets the following logs.
...
2019/04/16 23:45:20 UDP: Received: Session: 2019-04-16T23:45:20: Flow: udp 127.0.0.1:49616 <-> 127.0.0.1:12345 (1 payloads): "Hello, TCPPC\n" (13 bytes)
Type Ctrl+C to stop this program.
You can save session data to files as JSON lines format.
When -w
option is specified, the data will be written to the given file.
You can use datetime format in -w
option (See man strftime
for more
details). When -T
option is specified, data files will be rotated every
given seconds.
Run tcppc-go program.
$ ./tcppc-go -T 86400 -w log/tcppc-%Y%m%d.jsonl
Connect to the server from another terminal.
$ echo "Hello, TCPPC" | nc 127.0.0.1 12345
The results of the data are the following. Note that data in payloads are encoded in base64.
# jq is a command for formatting JSON.
# I tested this on April 18th, 2018.
$ jq . log/tcppc-20180418.jsonl
{
"timestamp": "2018-04-18T09:51:34.689896842+09:00",
"flow": {
"proto": "tcp",
"src": "127.0.0.1",
"sport": 53484,
"dst": "127.0.0.1",
"dport": 12345
},
"payloads": [
{
"index": 0,
"timestamp": "2018-04-18T09:51:34.690076698+09:00",
"data": "SGVsbG8sIFRDUFBDCg=="
}
]
}
tcppc
supports not only TCP handshake but also TLS handshake.
When both -C
and -K
options are specified, this program works as TLS
handshaker. You need to prepare for TLS certificate (in many cases,
self-signed) and key files (See 'Configuration' section).
Run tcppc-go program.
$ ./tcppc-go -T 86400 -C server.crt -K server.key -w log/tcppc-%Y%m%d.jsonl
Connect to the server from another terminal.
$ wget --no-check-certificate https://127.0.0.1:12345/index
The results of session data are the following (formatted by jq
command).
$ jq . log/tcppc-20180418.jsonl
{
"timestamp": "2018-04-18T10:06:08.104667676+09:00",
"flow": {
"proto": "tls",
"src": "127.0.0.1",
"sport": 53635,
"dst": "127.0.0.1",
"dport": 12345
},
"payloads": [
{
"index": 0,
"timestamp": "2018-04-18T10:06:08.111138967+09:00",
"data": "R0VUIC9pbmRleCBIVFRQLzEuMQ0KVXNlci1BZ2VudDogV2dldC8xLjE5LjIgKGRhcndpbjE3LjMuMCkNCkFjY2VwdDogKi8qDQpBY2NlcHQtRW5jb2Rpbmc6IGd6aXANCkhvc3Q6IDEyNy4wLjAuMToxMjM0NQ0KQ29ubmVjdGlvbjogS2VlcC1BbGl2ZQ0KDQo="
}
]
}
# decode "data" as base64.
$ echo "R0VUIC9pbmRleCBIVFRQLzEuMQ0KVXNlci1BZ2VudDogV2dldC8xLjE5LjIgKGRhcndpbjE3LjMuMCkNCkFjY2VwdDogKi8qDQpBY2NlcHQtRW5jb2Rpbmc6IGd6aXANCkhvc3Q6IDEyNy4wLjAuMToxMjM0NQ0KQ29ubmVjdGlvbjogS2VlcC1BbGl2ZQ0KDQo=" | base64 -D
GET /index HTTP/1.1
User-Agent: Wget/1.19.2 (darwin17.3.0)
Accept: */*
Accept-Encoding: gzip
Host: 127.0.0.1:12345
Connection: Keep-Alive
The template of configuration file in TOML format is ready. See tcppc.toml.orig.
$ cp tcppc.toml.orig /etc/tcppc.toml
$ vim /etc/tcppc.toml
... (edit) ...
If you want to use tcppc
as TLS handshaker, you need to prepare TLS
certificate file and TLS key file.
You can create these files by the following commands.
$ openssl genrsa 2048 > server.key
$ openssl req -new -key server.key > server.csr
$ openssl x509 -days 36500 -req -signkey server.key < server.csr > server.crt
Note that these commands create not a valid certificate file but a self-signed certificate file.
A simple unit file of systemd is ready (tcppc.service.orig
)
Edit it and enable/start tcppc
service.
# copy this file to systemd's directory.
cp -v tcppc.service.orig /etc/systemd/system/
# edit this file.
vim /etc/systemd/system/tcppc.service
# reload unit files.
systemctl daemon-reload
# start tcppc service.
systemctl start tcppc
# (optional) autostart tcppc service
systemctl enable tcppc
The easiest way to listen on all ports is to use TPROXY function of iptables
.
In this case, you should prepare a new (pseudo) network interface and an IP address (i.e. IP alias) to monitor and capture all the traffic.
# !!! DANGER !!!
$ iptables -t mangle -A PREROUTING -i <interface> -p tcp -d <honey-ip> -j TPROXY --tproxy-mark 0x1/0x1 --on-ip <honey-ip> --on-port 12345
$ iptables -t mangle -A PREROUTING -i <interface> -p udp -d <honey-ip> -j TPROXY --tproxy-mark 0x1/0x1 --on-ip <honey-ip> --on-port 12345
Session data file is JSON Lines format (i.e. each line holds a JSON string.) Each line represents each session data.
The following shows the data example with some comments.
{
// Time when the session is accepted.
// i.e.
// tcp/tls: time when the handshake is finished.
// udp: time when the UDP packet is received.
"timestamp": "2018-04-18T11:06:09.419437117+09:00",
// Flow (protocol (i.e., tcp/tls/udp, source IP address, source port, local address, local port)
"flow": {
"proto": "tcp",
"src": "127.0.0.1",
"sport": 54167,
"dst": "127.0.0.1",
"dport": 12345
},
// List of payloads
"payloads": [
{
// Index of payloads
"index": 0,
// Time when this payload was received.
"timestamp": "2018-04-18T11:06:13.830444868+09:00",
// Data encoded in base64
"data": "Rmlyc3QgcGF5bG9hZAo="
},
{
"index": 1,
"timestamp": "2018-04-18T11:06:18.015019663+09:00",
"data": "U2Vjb25kIHBheWxvYWQK"
}
]
}
You might be able to use nc
or socat
instead.
MIT License (link).
md (E-mail: md.irohas at gmail.com)