TCP再送信メカニズムを使用してポートノッキングサービスを再生します

TCPは、接続が確立される前に認証できないか、接続のないUDPでは認証できません。

TCPにはfastopenメカニズムがありますが、使い方は簡単ではありません。この記事のアイデアはfastopenに基づいています。最初のSYNパケットにデータを伝送させますが、TCPレイヤーに到達できません。認証はIPレイヤーで完了する必要があります。

つまり、いわゆるノックオンサービスがあります。

ノッキングの意味は、不正な接続による干渉を回避することです。DoSを構成していなくても、サーバーは不正に接続されたクライアントに応答する必要があります。これは安全でないだけでなく、開いているポート情報を公開するだけでなく、帯域幅リソースを浪費します。

インターネットはオープンな環境です。見知らぬ人と話をしないください。RSTで応答するよりも、不正な接続をサイレントにドロップする方がはるかに優れています。

この記事では、TCP再送信メカニズムを介して実装されたノッキングサービスを再生します。
ここに写真の説明を挿入

SSHのポート22を保護する場合、最初にサーバー側で次の構成を実行します。

# 以下配置部署在 192.168.56.101 这台Ubuntu上。
ipset create knockset hash:ip,port timeout 60 # 一分钟无活动即断开
iptables -t mangle -F
# 加入set的二元组允许建立连接
iptables -t mangle -A PREROUTING -p tcp --dport 22 -m set --match-set knockset src,src -j ACCEPT
# 过滤敲门包,将成功敲门的二元组加入ipset
iptables -t mangle -A PREROUTING -p tcp --dport 22 -m string --string "skinshoe" --algo bm --to 65535 -j SET --add-set knockset src,src
# 丢弃敲门包,因为正式包(也就是客户端重传的SYN包)马上就会到来
iptables -t mangle -A PREROUTING -p tcp --dport 22 -m string --string "skinshoe" --algo bm --to 65535 -j DROP
# 静默丢弃
iptables -t mangle -A PREROUTING -p tcp --dport 22 ! -s 192.168.56.1/32  -j DROP

以下は、Netfilterに基づくクライアント側モジュールです。

// padding.c 部署在192.168.56.110上
#include <linux/module.h>
#include <net/netfilter/nf_conntrack.h>
#include <linux/netfilter/nf_conntrack_common.h>
#include <net/tcp.h>

int port = 22;
module_param(port, int, 0644);

char *templ = NULL;
module_param(templ, charp, 0);

unsigned int knock_out_hook(const struct nf_hook_ops *ops, struct sk_buff *skb,
                             const struct net_device *in, const struct net_device *out,
                             const struct nf_hook_state *state)
{
    
    
	struct iphdr *iph = ip_hdr(skb);
	struct tcphdr *th = NULL;
	enum ip_conntrack_info ctinfo;
	struct nf_conn *ct;
	unsigned int extra, len;
	char *cookie;

	if (templ == NULL)
		return NF_ACCEPT;

	ct = nf_ct_get(skb, &ctinfo);
	// 过滤一个连接的第一个SYN包。
	if (!ct || (ct->status & IPS_CONFIRMED))
		return NF_ACCEPT;

	if (iph->version != 4 || iph->protocol != IPPROTO_TCP)
		return NF_ACCEPT;

	iph = ip_hdr(skb);
	th = (struct tcphdr *)((unsigned char *)iph + (iph->ihl * 4));

	if (ntohs(th->dest) != port)
		return NF_ACCEPT;

	// 在一个连接的第一个SYN包后面padding我们的认证魔术字。
	cookie = kmalloc(32, GFP_ATOMIC);
	memcpy(cookie, templ, strlen(templ));
	extra = strlen(templ);
	skb_put(skb, extra);
	memcpy((char *)th + sizeof(struct tcphdr), cookie, extra);
	len = ntohs(iph->tot_len) + extra;
	iph->tot_len = htons(len);
	iph->check = 0;
	ip_send_check(iph);

	return NF_ACCEPT;
}

static struct nf_hook_ops knock_out_ops = {
    
    
	.hook     = knock_out_hook,
	.owner    = THIS_MODULE,
	.pf       = AF_INET,
	.hooknum  = NF_INET_LOCAL_OUT,
	.priority = NF_IP_PRI_LAST,
};

static int __init knock_init(void)
{
    
    
	if (nf_register_hook(&knock_out_ops) < 0) {
    
    
		return -1;
	}

	return 0;
}

static void __exit knock_exit(void)
{
    
    
	nf_unregister_hook(&knock_out_ops);
}

module_init(knock_init);
module_exit(knock_exit);
MODULE_LICENSE("GPL");

来て、効果を見てください:

# 不加载padding hook的时候:
[root@localhost ~]# ssh [email protected]
... # 无响应,抓包无内容,无回复,无RST

[root@localhost ~]# insmod ./padding.ko port=22 templ="skinshoe"
[root@localhost ~]# ssh [email protected]
[email protected]'s password:
Welcome to Ubuntu 19.10 (GNU/Linux 5.3.0-62-generic x86_64)
... # 成功连接

注目に値するのは:

  • この記事は単なるPOCであり、実際、非常に複雑な認証を完了することができます。
  • パディングフックは、クライアントにローカルに展開する必要はありません。別のノッキングエージェントにすることもできます。
  • このソリューションは、単なるアイデアであるDDoS保護から独立しています。
  • パディングフックはconntrackを使用し、バーを持ち上げないでください。conntrackはそれほど耐え難いものではなく、クライアントに展開されることは言うまでもありません。
  • このPOCのアイデアをWebページで使用すると、アンチリーチを実現できますが、フロントエンドテクノロジーが理解できず、諦めるしかありません。
  • 一歩後退して、カーネルメカニズムを使用できませんか?答えは「はい」です。帯域外UDPを使用してノックを完了することもできます。

私はもともとsystemtapを使って、運用と保守、マネージャーとその部下を楽しませるためにターゲットを絞ったフォーク爆弾を書きたかったのですが、そうすることを期待していませんでしたね...


浙江文州の革靴は濡れているので、雨でも太りません。

おすすめ

転載: blog.csdn.net/dog250/article/details/108479651