mirror of
https://github.com/troglobit/finit.git
synced 2026-10-06 15:50:12 +07:00
Add protection against UDP inetd looping attacks
This patch adds protection against a common inetd attack vector wherein the reply port to UDP inetd services is forged to an internal inetd service port. Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
@@ -476,7 +476,11 @@ default port. To run ssh on port 222, and all others on port 22:
|
||||
```
|
||||
|
||||
Compared to Finit v1.12 you must *explicitly deny* access from `eth0`!
|
||||
|
||||
|
||||
To protect against looping attacks, the inetd server will refuse UDP
|
||||
service if the reply port corresponds to any internal service. Similar
|
||||
to how the FreeBSD inetd operates.
|
||||
|
||||
|
||||
**Internal Services**
|
||||
|
||||
|
||||
@@ -189,6 +189,33 @@ static void socket_cb(uev_t *UNUSED(w), void *arg, int UNUSED(events))
|
||||
service_step(task);
|
||||
}
|
||||
|
||||
/*
|
||||
* Refuse service if the request specifies a reply port corresponding to any internal service.
|
||||
* This is done as a defense against looping attacks; the remote IP address is logged.
|
||||
* http://www.freebsd.org/cgi/man.cgi?inetd(8)
|
||||
* https://svnweb.freebsd.org/base/head/usr.sbin/inetd/inetd.c?revision=298909&view=markup#l2094
|
||||
*/
|
||||
int inetd_check_loop(struct sockaddr *sa, socklen_t len, char *name)
|
||||
{
|
||||
svc_t *svc;
|
||||
char pname[NI_MAXHOST];
|
||||
|
||||
for (svc = svc_inetd_iterator(1); svc; svc = svc_inetd_iterator(0)) {
|
||||
inetd_t *i = &svc->inetd;
|
||||
|
||||
if (!i->builtin || i->type != SOCK_DGRAM)
|
||||
continue;
|
||||
|
||||
if (((const struct sockaddr_in *)sa)->sin_port == i->port) {
|
||||
getnameinfo(sa, len, pname, sizeof(pname), NULL, 0, NI_NUMERICHOST);
|
||||
FLOG_WARN("%s/%s:%s/%s loop request REFUSED from %s", i->name, "UDP", name, "UDP", pname);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Launch Inet socket for service.
|
||||
* TODO: Add filtering ALLOW/DENY per interface.
|
||||
*/
|
||||
|
||||
@@ -46,6 +46,7 @@ typedef struct {
|
||||
int proto;
|
||||
int port;
|
||||
int forking;
|
||||
int builtin; /* Set by built-in inetd services only */
|
||||
int next_id; /* Next child job's id */
|
||||
char name[10];
|
||||
int (*cmd)(int type); /* internal inetd service, like 'time' */
|
||||
@@ -53,6 +54,8 @@ typedef struct {
|
||||
TAILQ_HEAD(, inetd_filter) filters;
|
||||
} inetd_t;
|
||||
|
||||
int inetd_check_loop (struct sockaddr *sa, socklen_t len, char *name);
|
||||
|
||||
int inetd_start (inetd_t *inetd);
|
||||
void inetd_stop (inetd_t *inetd);
|
||||
|
||||
|
||||
+5
-1
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
#define NAME "chargen"
|
||||
#define PATTERN "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "
|
||||
|
||||
static char *generator(char *buf, size_t len)
|
||||
@@ -61,6 +62,9 @@ static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, sockle
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
if (inetd_check_loop(sa, *sa_len, NAME))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -86,7 +90,7 @@ static int cb(int type)
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = "chargen", /* Must match the inetd /etc/services entry */
|
||||
.name = NAME, /* Must match the inetd /etc/services entry */
|
||||
.inetd = {
|
||||
.cmd = cb
|
||||
},
|
||||
|
||||
+7
-1
@@ -28,6 +28,9 @@
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
#define NAME "daytime"
|
||||
|
||||
|
||||
static char *daytime(char *buf, size_t len)
|
||||
{
|
||||
time_t t;
|
||||
@@ -48,6 +51,9 @@ static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, sockle
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
if (inetd_check_loop(sa, *sa_len, NAME))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -72,7 +78,7 @@ static int cb(int type)
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = "daytime", /* Must match the inetd /etc/services entry */
|
||||
.name = NAME, /* Must match the inetd /etc/services entry */
|
||||
.inetd = {
|
||||
.cmd = cb
|
||||
}
|
||||
|
||||
+16
-2
@@ -27,6 +27,20 @@
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
#define NAME "echo"
|
||||
|
||||
static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t *sa_len)
|
||||
{
|
||||
len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, sa, sa_len);
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
if (inetd_check_loop(sa, *sa_len, NAME))
|
||||
return -1;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int cb(int type)
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
@@ -35,7 +49,7 @@ static int cb(int type)
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
|
||||
len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *)&sa, &sa_len);
|
||||
len = recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len);
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
@@ -43,7 +57,7 @@ static int cb(int type)
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = "echo", /* Must match the inetd /etc/services entry */
|
||||
.name = NAME, /* Must match the inetd /etc/services entry */
|
||||
.inetd = {
|
||||
.cmd = cb
|
||||
},
|
||||
|
||||
+6
-1
@@ -28,6 +28,8 @@
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
#define NAME "time"
|
||||
|
||||
/* UNIX epoch starts midnight, 1st Jan, 1970 */
|
||||
#define EPOCH_OFFSET 2208988800ULL
|
||||
|
||||
@@ -59,6 +61,9 @@ static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, sockle
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
if (inetd_check_loop(sa, *sa_len, NAME))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -87,7 +92,7 @@ static int cb(int type)
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = "time", /* Must match the inetd /etc/services entry */
|
||||
.name = NAME, /* Must match the inetd /etc/services entry */
|
||||
.inetd = {
|
||||
.cmd = cb
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user