Всем привет. Недавно тов. R_Voland рассказал о своём http ханипоте. Он меня и вдохновил к написанию этого поста. Но в этом случае, будем ловить все tcp и udp сканы, а не только http. Запросы будем ловить с помощью tcpdump.
Для tcp ловим только syn пакеты:
Для udp все входящие udp пакеты
В теории вывод от tcpdump'а можно перенаправить в файл и дальше парсить его по необходимости, но я ещё тот извращенец, поэтому напишем сервис на nodejs, который будет слушать tcpdump и сохранять результаты в mysql базу.
Шапка скрипта со всем необходимым:
lastTcpLine — нужен для временного хранения последней строки полученной из stdout. Т.к мы получаем данные не строка за строкой, а блоками, в которых последняя строка может быть не полной, и её 2я половина прилетит со вторым блоком данных.
excludePorts и excludeAddrs нам нужны для исключения каких-нибудь своих собственных коннектов. На 80 порту у нас будет отдельный расширенный логгер, локалхост тоже слушать не будем.
Вешаем листенер:
IP к нам прилетают в виде address.port, например 192.168.1.1.443, разбираем на адрес и порт:
Сохраняем результат в базу данных:
Код для udp листенера совподает на 100%, не буду повторяться, исходники можно посмотреть на гитхабе: github.com/hololoev/honeypot_tcpdump_logger.git
Теперь нам нужна новая виртуалочка, на которую ставим nginx с заглушкой «Under construction» и наш логгер. НЕ направляем на него никакой домен, всячески изображаем вид свежесозданного сервера, среднестатистического вебмастера. Через пару дней (с 5 по 9 мая) получаем результаты:
Топ 5 tcp портов:
Топ 5 udp портов:
Топ 10 самых активных ip адресов:
Карта с топ 100 самых активных адресов:

Для tcp ловим только syn пакеты:
tcpdump -n "tcp[tcpflags] & (tcp-syn) != 0"
Для udp все входящие udp пакеты
tcpdump -n inbound and udp
В теории вывод от tcpdump'а можно перенаправить в файл и дальше парсить его по необходимости, но я ещё тот извращенец, поэтому напишем сервис на nodejs, который будет слушать tcpdump и сохранять результаты в mysql базу.
Шапка скрипта со всем необходимым:
#!/usr/bin/nodejs 'use strict'; const net = require('net'); const spawn = require('child_process').spawn; const mysql = require('mysql2'); const config = require('./config'); const connection = mysql.createConnection(config.mysql); const tcpdump = spawn('tcpdump', ['-n', 'tcp[tcpflags] & (tcp-syn) != 0']); const excludePorts = [ 80 ]; const excludeAddrs = [ '127.0.0.1', ]; let lastTcpLine = '';
lastTcpLine — нужен для временного хранения последней строки полученной из stdout. Т.к мы получаем данные не строка за строкой, а блоками, в которых последняя строка может быть не полной, и её 2я половина прилетит со вторым блоком данных.
excludePorts и excludeAddrs нам нужны для исключения каких-нибудь своих собственных коннектов. На 80 порту у нас будет отдельный расширенный логгер, локалхост тоже слушать не будем.
Вешаем листенер:
tcpdump.stdout.on('data', (data) => { let lines = `${data}`.split('\n'); // разбиваем блок данных на строки // далее идёт немного логики которая узнаёт нужно или нет дополнять первую строку сохранённым в lastTcpLine куском, и нужно ли сохранять новый фрагмент в lastTcpLine let lastTcpLineNum = lines.length - 1; let toNum = lines.length - 1; lines[ 0 ] = lines[ 0 ] + lastTcpLine; if( lines[ lastTcpLineNum ].indexOf('\n') == -1 ) { lastTcpLine = lines[ lastTcpLineNum ]; toNum --; } else lastTcpLine = ''; for(let i=0; i<=toNum; i++) { saveLog( parseLine(lines[ i ], 'tcp') ); // парсим и сохраняем всё в бд } });
IP к нам прилетают в виде address.port, например 192.168.1.1.443, разбираем на адрес и порт:
function parseLine(line, proto) { let parts = line.split(' '); // разбиваем строку на запчасти let dstAddrParts = parseIP(parts[ 4 ]); // тут будет адрес, куда прилетел запрос let srcAddrParts = parseIP(parts[ 2 ]); // тут откуда return { addr: srcAddrParts.addr, port: dstAddrParts.port, proto: proto, req_time: parseInt(new Date() / 1000), }; } function parseIP(ipStr) { let addrParts = ipStr.split('.'); // разбиваем строку на куски, разделённые точкой let port = addrParts[ addrParts.length - 1 ]; // последний кусок - это порт let ipOctets = []; // собираем оставшиеся куски в строку for(let i=0; i<=(addrParts.length-2); i++) ipOctets.push(addrParts[ i ]); let addr = ipOctets.join('.'); if( !net.isIP(addr) ) // и, на всякий случай проверяем, что мы разобрали, если что-то не так, отдаём null вместо адреса addr = null; return { addr: addr, port: parseInt(port) }; }
Сохраняем результат в базу данных:
function saveLog(info) { if( excludePorts.indexOf(info.port) > -1 ) // если порт в исключениях - ничего не делаем return; if( excludeAddrs.indexOf(info.addr) > -1 ) // если ип в исключениях - ничего не делаем return; for(let key in info) // если какое-то из значений не определено - ничего не делаем if( !info[ key ] ) { console.log('Bad info:', info); return; } let fields = []; // собираем заголовки столбцов for(let key in info) fields.push('`' + key + '`'); let values = []; // и значений for(let key in info) { if( typeof(info[ key ]) == 'number' ) values.push(info[ key ]); else values.push(`'` + info[ key ] + `'`); } let query = 'INSERT INTO access_logs (' + fields.join(',') + ') VALUES(' + values.join(',') + ')'; // и фигачим это всё в запрос connection.query(query); }
Код для udp листенера совподает на 100%, не буду повторяться, исходники можно посмотреть на гитхабе: github.com/hololoev/honeypot_tcpdump_logger.git
Теперь нам нужна новая виртуалочка, на которую ставим nginx с заглушкой «Under construction» и наш логгер. НЕ направляем на него никакой домен, всячески изображаем вид свежесозданного сервера, среднестатистического вебмастера. Через пару дней (с 5 по 9 мая) получаем результаты:
| Total adresses | tcp Scans | udp Scans | http Scans |
|---|---|---|---|
| 4324 | 38558 | 543 | 101 |
Топ 5 tcp портов:
| tcp port | Scans |
|---|---|
| 445 | 2538 |
| 23 | 1515 |
| 22 | 1304 |
| 3306 | 151 |
| 3389 | 148 |
Топ 5 udp портов:
| udp port | Scans |
|---|---|
| 5060 | 95 |
| 161 | 41 |
| 1900 | 32 |
| 123 | 30 |
| 137 | 23 |
Топ 10 самых активных ip адресов:
| Address | Total scans | Location | http | tcp | udp |
|---|---|---|---|---|---|
| 40.115.124.127 | 25822 | IE/Dublin | 0 | 25822 | 0 |
| 77.72.82.101 | 861 | RU/ | 0 | 861 | 0 |
| 77.72.82.22 | 760 | RU/ | 0 | 760 | 0 |
| 145.239.134.1 | 550 | GB/ | 0 | 550 | 0 |
| 101.128.72.140 | 282 | ID/Jakarta | 0 | 282 | 0 |
| 77.72.85.25 | 244 | RU/ | 0 | 244 | 0 |
| 181.214.87.34 | 208 | US/Las Vegas | 0 | 208 | 0 |
| 5.188.11.91 | 189 | RU/Saint Petersburg | 0 | 189 | 0 |
| 128.199.141.239 | 173 | SG/Singapore | 0 | 173 | 0 |
| 5.188.11.79 | 156 | RU/Saint Petersburg | 0 | 156 | 0 |
Карта с топ 100 самых активных адресов:

