Nmap Development mailing list archives

Re: ncat - UNIX-domain sockets support


From: Tomas Hozza <thozza () redhat com>
Date: Mon, 26 Nov 2012 10:44:53 -0500 (EST)

----- Original Message -----
I used tempnam() function which uses TMPDIR and TMP, so "/tmp" is
not
hardcoded. It was done so also in the last bunch of patches.

http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/avoid-race.html#TEMPORARY-FILES

There is example of how to use tempnam function to be more safe,
but unfortunately this can not be used in this case. The problem is
that after the temporary name is generated, we are not
opening/creating
any file/socket. It is done later when calling bind() on the source
socket FD
together with the temporary name (so the socket binds to the
path/name).

This is the way I was thinking before too. But netcat-openbsd calls
mkstemp, at least if I understand correctly. Apparently it is no
problem for the file to exist as a regular file before binding to it?

If the file already exists it is a real problem. The bind() call will fail
with errno 98 "Address already in use". Therefore when creating source socket
"file" (when bind() is called) file with the given/generated path MUST NOT exist.

Another thing I found out after discussion with my colleagues is, that
Ncat's configure script should let user specify the directory for creating
temporary source DGRAM Unix sockets generated by Ncat. Therefore I added
new argument into Ncat configure script called TMP_UNIX_SOCK_DIR. If it is
specified, then configure will define macro in config.h header. Depending on
whether it is specified, tempnam() is compiled with or without specific
directory set:

#ifdef TMP_UNIX_SOCK_DIR 
                if ((tmp_name = tempnam(TMP_UNIX_SOCK_DIR, "ncat.")) == NULL)
#else
                if ((tmp_name = tempnam(NULL, "ncat.")) == NULL)
#endif

Even if TMP_UNIX_SOCK_DIR is specified, tempnam() prefers TMPDIR environment
variable if it is set.

My motivation for this is, that regarding to FSH 2.3 standard 
(http://www.pathname.com/fhs/pub/fhs-2.3.html#VARRUNRUNTIMEVARIABLEDATA)
System programs that maintain transient UNIX-domain sockets must place
them in "/var/run". Therefore we would like to have a way to specify
the directory in compilation time.


If so, then that is what we should do. I want to avoid a race condition
like the following:
 1. tempnam generates a nonexistent name in /tmp.

This is a MUST for Ncat to connect successfully.

 2. Attacker guesses the name and puts something there.
 3. Ncat binds to the file name.

If the file already exist, Ncat will exit.

 4. Ncat calls unlink on the attacker-controlled file name.

I modified the code, so Ncat does not call unlink on socket, that
it did not create.

Offhand I can't think of what harm an attacker can do with such an
unlink, but since the implications are unknown, it's better to be
safe.

Please correct me if I misunderstand something.

I'd also like to be sure to unlink the socket even if there is an
error.
Would you check if it's possible to replace
        exit(1);
with
        nsock_loop_quit(nsp);
        return;
in the ncat_connect callbacks?

Thank you for this idea. I used it in every handler function, so now
the created socket is deleted if any ERROR occurs.

Regarding to this I discovered one Bug in Nsock library, that caused
bad statistic output when client tried to send some data to server,
but the server was not running any more. I this case it caused output
like the following (where you can see "18446744073709551615 bytes sent"):

$ ./ncat -Uu -vvvvvvvvvvvvvvvvvvv -s source_socket9 /tmp/socket
Ncat: Version 6.20BETA1 ( http://nmap.org/ncat )
Ncat: [source_socket9] used as source DGRAM Unix domain socket.
NSOCK (0.0010s) UNIX domain socket (DGRAM) connection requested to /tmp/socket (IOD #1) EID 8
NSOCK (0.0010s) Callback: CONNECT SUCCESS for EID 8 [/tmp/socket]
Ncat: Connected to /tmp/socket.
NSOCK (0.0010s) Read request from IOD #1 [/tmp/socket] (timeout: -1ms) EID 18
NSOCK (0.0010s) Read request for 0 bytes from IOD #2 (peer unspecified) EID 26

NSOCK (7.3750s) Callback READ SUCCESS for EID 26 (peer unspecified) (1 bytes)
NSOCK (7.3750s) Write request for 1 bytes to IOD #1 EID 35 [/tmp/socket]
NSOCK (7.3750s) Callback: WRITE ERROR [Connection refused (111)] for EID 35 [/tmp/socket]
Ncat: Connection refused.
NSOCK (7.3750s) Read request for 0 bytes from IOD #2 (peer unspecified) EID 42
Ncat: 18446744073709551615 bytes sent, 0 bytes received in 7.38 seconds.
Ncat: Deleting source DGRAM Unix domain socket. [source_socket9]
NSOCK (7.3750s) Callback: READ KILL for EID 18 [/tmp/socket]
NSOCK (7.3750s) Callback: READ KILL for EID 42 (peer unspecified)


Regards,

Tomas Hozza

Attachment: 0001-Bring-back-generation-of-src-DGRAM-socket-name-v2.patch
Description:

_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://seclists.org/nmap-dev/

Current thread: