Use TCP retransmission mechanism to play port knocking service

TCP cannot authenticate before the connection is established, or it will not be possible for connectionless UDP.

TCP has a fastopen mechanism, but it is not easy to use. The idea of ​​this article is based on fastopen. Let the first SYN packet carry data, but it cannot reach the TCP layer. Authentication must be completed at the IP layer.

So there is the so-called knock-on service.

The meaning of knocking is to avoid interference from illegal connections. Even if it does not constitute a DoS, the server needs to respond to illegally connected clients. This is not only insecure, it exposes open port information, but also wastes bandwidth resources.

The Internet is an open environment, don't talk to strangers! It is much better to silently drop illegal connections than to reply with a RST.

In this article, we will play a knocking service implemented through TCP retransmission mechanism:
Insert picture description here

Suppose we want to protect port 22 of SSH, first we perform the following configuration on the server side:

# 以下配置部署在 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

The following is a client-side module based on 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");

Come and see the effect:

# 不加载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)
... # 成功连接

It is worth noting that:

  • This article is just a POC, in fact, very complicated authentication can be completed.
  • The padding hook does not have to be deployed locally on the client, it can also be a separate knocking agent.
  • This solution is independent of DDoS protection, which is just an idea.
  • The padding hook uses conntrack, don't lift the bar, conntrack is not so unbearable, let alone it is deployed on the client.
  • If you use this POC idea on a web page, you can realize the anti-leech, but I don't understand the front-end technology and can only give up.
  • Taking a step back, can you not use the kernel mechanism? The answer is yes, you can also use out-of-band UDP to complete the knock.

I originally wanted to use systemtap to write a targeted fork bomb to amuse the operation and maintenance, the manager and his subordinates, but I did not expect to do this, hey...


The leather shoes in Wenzhou, Zhejiang are wet, so they won’t get fat in the rain.

Guess you like

Origin blog.csdn.net/dog250/article/details/108479651