今天突然发现公司服务器遭到非常密集的SSH暴力攻击,开始的时候使用手动的方式将攻击方的IP地址添加防火墙过滤规则中。但是有发现攻击者IP地址不断发生变动。如果这样下去,就是有100个手来不及添加过滤规则。因此不才在这种压力之下,灵机暗动,计上心来。
何不整一个能够自动检查攻击的IP地址,并将攻击者丢入18层地狱,让其百千万劫不得出离。
基本的原理是:
1 定时启动lastb 读取最新的20行攻击记录
2 统计记录中频次超过5次的IP地址,
3 将高频次攻击的IP地址添加到防火墙过滤规则中
/**
* @brief 发现公司服务器收到SSH频繁攻击,因此编制这个程序作为后台监测软件。
* 检查ssh登录失败次数,并且获取对应的IP地址,然后根据情况将对应的IP地址
* 通过防火墙禁止。
* @note 这个程序运行在Linux下。通过iptables操作防火墙
* @author 宋炜
* @date 2017-8-2
* @version 1.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <vector>
#include <regex>
#include <map>
typedef std::vector< std::string > ArrayString;
struct stBadRecordItem
{
std::string ip;
int count;
stBadRecordItem(){
ip.clear();
count = 0;
}
stBadRecordItem(const stBadRecordItem& b )
{
ip = b.ip;
count = b.count;
}
stBadRecordItem& operator=( const stBadRecordItem& b )
{
ip = b.ip;
count = b.count;
return *this;
}
};
typedef std::map< std::string , struct stBadRecordItem > Record;
int main()
{
ArrayString a_str;
FILE *fail_log_host;
char *line = NULL;
size_t line_size = 0;
Record record;
do{
/*从ssh操作失败记录中读取20行数据*/
line = (char*)malloc(300);
if( line == NULL ) return -1;
fail_log_host = popen("lastd -n 20" , "r");
for( int i = 0; i < 20; i ++ ){
getline( &line , &line_size , fail_log_host );
std::string str( line );
a_str.push_back( str );
}
free( line );
pclose( fail_log_host );
//记录IP
std::regex reg("\\d{1,3}(\\.\\d{1,3}){3}");
for( int i = 0; i < a_str.size(); i ++ ){
std::smatch m;
if( std::regex_search( a_str[ i ] , m , reg ) ){
if( record.find( m[ 0 ] ) != record.end() ){
//如果IP已经在map中则,增加出现次数
record[ m[ 0 ] ].count ++;
}
else{
//如果IP没有记录则,登记到map中
stBadRecordItem item;
item.ip = m[ 0 ];
item.count = 1;
record.insert( std::pair< std::string , struct stBadRecordItem >( item.ip , item ) );
}
}
}
//检查IP地址登录的次数
for( Record::iterator it=record.begin(); it != record.end(); it ++ ){
if( it->second.count >= 5 ){//将IP地址添加到防火墙过滤黑名单中
std::string str = "iptables -I INPUT -s " + it->second.ip;
str += " -j DROP";
std::cout << str << std::endl;
system(str.c_str() );
}
}
a_str.erase( a_str.begin() , a_str.end() );
record.erase( record.begin() , record.end());
sleep(120);//等候2分钟重新检查
}while( 1 );
return 0;
}
转载于:https://my.oschina.net/u/3071588/blog/1542019