Opened 7 years ago

Last modified 6 weeks ago

#7875 new defect

debian obfsproxies can't advertise ports under 1024

Reported by: arma Owned by: asn
Priority: Medium Milestone: Tor: unspecified
Component: Core Tor/Tor Version:
Severity: Normal Keywords: tor-bridge, tor-pt, privileges, low-ports, review-group-34
Cc: asn, mo, weasel, torvlnt33r@…, mttp, dgoulet, phw Actual Points:
Parent ID: Points:
Reviewer: Sponsor:

Description

We don't have (m)any obfsproxies running on port 443. That's a shame.

But if you're on debian and want to follow our instructions (https://www.torproject.org/projects/obfsproxy-debian-instructions), even if you know how to set up port forwarding, there's no way for your Tor to advertise that your obfsproxy is listening on a low-numbered port.

One option is for Tor to launch obfsproxy as root before Tor drops privs, and then obfsproxy binds its low-numbered port and then drops privs too. That sounds awful.

Another option is to complexify ServerTransportListenAddr, or add a new config option like it, so we can tell Tor what address to pretend obfsproxy listens on. That sounds less awful but still not great.

Other options? It would be ideal if the Tor and obfsproxy debs could somehow do this themselves, since an "add this line to your iptables" component in our instructions places it out of reach of most users.

Child Tickets

Change History (29)

comment:1 Changed 7 years ago by flaushy

You can grant priviledges to do so via setcap. (included in libcap2-bin)
setcap 'cap_net_bind_service=+ep' /path/to/obfsproxy

After granting this capability you are able to run obfsproxy with user rights on ports <1024

http://www.kernel.org/doc/man-pages/online/pages/man7/capabilities.7.html

comment:2 Changed 6 years ago by cwt96

Component: TorObfsproxy
Owner: set to asn

comment:3 Changed 6 years ago by rransom

Component: ObfsproxyTor

comment:4 in reply to:  1 ; Changed 6 years ago by torvlnt33r

Cc: torvlnt33r@… added

Replying to flaushy:

You can grant priviledges to do so via setcap. (included in libcap2-bin)
setcap 'cap_net_bind_service=+ep' /path/to/obfsproxy

After granting this capability you are able to run obfsproxy with user rights on ports <1024

This is not working for me, maybe because obfsproxy is now (version 0.2.1) a (Python) script (see caveat 2 in the first answer on http://stackoverflow.com/questions/413807/is-there-a-way-for-non-root-processes-to-bind-to-privileged-ports-1024-on-l ).

Indeed, with a downgrade of obfsproxy to 0.1.4, it works. (But obfs3 would be missing).

comment:5 in reply to:  4 Changed 6 years ago by torvlnt33r

Replying to torvlnt33r:

Replying to flaushy:

You can grant priviledges to do so via setcap. (included in libcap2-bin)
setcap 'cap_net_bind_service=+ep' /path/to/obfsproxy

After granting this capability you are able to run obfsproxy with user rights on ports <1024

This is not working for me, maybe because obfsproxy is now (version 0.2.1) a (Python) script (see caveat 2 in the first answer on http://stackoverflow.com/questions/413807/is-there-a-way-for-non-root-processes-to-bind-to-privileged-ports-1024-on-l ).

Ok, it works if you make a copy of the script interpreter and give it the capabilities, as described as workaround in above reference.

On my system, python is a symbolic link to /usr/bin/python2.7. So:
cp /usr/bin/python2.7 /path/to/copy/of/python2.7
setcap 'cap_net_bind_service=+ep' /path/to/copy/of/python2.7

and add the interpreter into the ServerTransportPlugin line in torrc:
ServerTransportPlugin obfs2,obfs3 exec /path/to/copy/of/python2.7 /usr/bin/obfsproxy managed

comment:6 Changed 6 years ago by asn

The setcap solution requires the operator to run the setcap command as root, right? I guess that's equally "bad" (from the point of view of a non-technical operator) to an iptables command that redirects traffic from the low order port to the obfsproxy port.

arma's ideas still stand (because they don't require operator intervention) but they both still sound awful :(

comment:7 Changed 6 years ago by arma

Actually, my option two doesn't sound so bad. It's basically a config option to specify what port Tor should advertise, as opposed to what port Tor should tell obfsproxy to listen on.

comment:8 Changed 6 years ago by arma

Hey, another (bad but not horrible) option is to for Tor to grow a new "redirect" conn type, which it opens when it starts, and which funnels bytes from incoming conns to the specified destination port, maybe using our 'linked conns' notion. That would be sort of like running the iptables rule, but more portable and less scary for novice operators.

comment:9 Changed 6 years ago by mttp

Cc: mttp added

comment:10 Changed 6 years ago by cypherpunks

Can the difference between options 2 and 3 be clarified? I think I read option 2 and I thought it was describing the same design as option 3, but apparently not if option 3 is a distinct option.

comment:11 in reply to:  10 Changed 5 years ago by asn

Replying to cypherpunks:

Can the difference between options 2 and 3 be clarified? I think I read option 2 and I thought it was describing the same design as option 3, but apparently not if option 3 is a distinct option.

Seems like pretty much the same idea to me. One comment describes the torrc side, the other describes how it could work using Tor's linked conns.

comment:12 Changed 5 years ago by asn

Cc: dgoulet added

#8195 might also be a step forward. It uses Linux capabilities(7) to let Tor bind to low listening ports even after it has dropped privs. David told me that Linux capabilities also do inheritance, so it might be possible for our PT processes to inherit this capability themselves.

comment:13 Changed 5 years ago by yawning

Cc: yawning added

comment:14 in reply to:  12 Changed 5 years ago by asn

Replying to asn:

#8195 might also be a step forward. It uses Linux capabilities(7) to let Tor bind to low listening ports even after it has dropped privs. David told me that Linux capabilities also do inheritance, so it might be possible for our PT processes to inherit this capability themselves.

Yawning posted some updates on this from the dev meeting:

At the dev meeting I was talking to dgoulet about having tor do the
appropriate work to preserve the CAP_NET_BIND_SERVICE when dropping root
so all PTs transparently get this capability.

He mentioned difficulties with our python PTs, probably because the
ServerTransportPlugin line was pointing directly at the script and it
was getting invoked via the #! handler in the kernel.  It may be
possible that this "just works" if the ServerTransportPlugin line
pointed at the python interpreter instead, but if it does not, this will
probably require a kernel patch, that won't ever get accepted upstream.

from https://lists.torproject.org/pipermail/tor-dev/2014-July/007139.html

comment:15 Changed 5 years ago by asn

And for completeness, this is the line I'm using in my bridge to make obfs3 reachable on port 443:
# iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 25429
where the actual port of obfs3 is 25429.

comment:16 Changed 4 years ago by isis

Status: newneeds_review

arma pointed out this afternoon that dgoulet's patches for #8195 might be applicable to fixing this. It would need testing for execing PT ServerTransportPlugin lines for both Go and Python PTs (with /usr/bin/python or via the #! line, as asn pointed out above).

comment:17 Changed 4 years ago by yawning

In the bright new obfs4proxy feature, setcaping the obfs4proxy binary behaves as expected, so any/all of:

  • #8195 assuming tor starts with sufficiently elevated privileges.
  • The admin manually setcaping the obfs4proxy binary.
  • The package automagically handling this somehow (don't ask me how).

will solve this for obfs2/3/4. FTE/ScrambleSuit still use the old python codebase so those require further investigation. Personally, I don't view manually calling setcap on installation/update as a huge hassle, but then again my bridge deployment procedure consists of scping the binary over, and running a shell script, so I'm probably not the person to make decisions here.

The fact that obfs4proxy works with setcap is also documented in the README.md file, so we're in a better situation than previously, and when we do our bridge deployment documentation revamp, we can also highlight this there.

comment:18 Changed 4 years ago by weasel

setcapping the binary would allow any user to listen on any low port using the binary. I don't think it's a good general purpose solution for a distribution.

comment:19 in reply to:  17 ; Changed 4 years ago by isis

Replying to yawning:

FTE/ScrambleSuit still use the old python codebase so those require further investigation.

setcaping Python scripts also works just fine. (We used to do it with OONI to give raw socket capabilities without giving the script root privileges.)

comment:20 in reply to:  19 ; Changed 4 years ago by yawning

Replying to weasel:

setcapping the binary would allow any user to listen on any low port using the binary. I don't think it's a good general purpose solution for a distribution.

I agree. IMO it's not a package's place to dictate security policy, at least not for something like obfs4proxy. I still think it should be mentioned along with a detailed port forwarding example in our documentation, since those are the two current solutions for this issue.

Replying to isis:

Replying to yawning:

FTE/ScrambleSuit still use the old python codebase so those require further investigation.

setcaping Python scripts also works just fine. (We used to do it with OONI to give raw socket capabilities without giving the script root privileges.)

It shouldn't unless you were setcaping the python binary....

As a simple test:

#!/usr/bin/python2
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 9))
s.listen(5)

Baseline behavior:

ypres :: ~ % ./discard.py                                                       
Traceback (most recent call last):
  File "./discard.py", line 4, in <module>
    s.bind(('127.0.0.1', 9))
  File "/usr/lib/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 13] Permission denied
ypres :: ~ % sudo ./discard.py
ypres :: ~ % 

setcap the script along with the #! handler, or /usr/bin/python2 discard.py:

ypres :: ~ % sudo setcap 'cap_net_bind_service=+ep' /home/yawning/discard.py
ypres :: ~ % ./discard.py                                                       
Traceback (most recent call last):
  File "./discard.py", line 4, in <module>
    s.bind(('127.0.0.1', 9))
  File "/usr/lib/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 13] Permission denied

Use a python interpreter with elevated privileges:

ypres :: ~ % cp /usr/bin/python2 ./python2-setcapped
ypres :: ~ % sudo setcap 'cap_net_bind_service=+ep' /home/yawning/python2-setcapped
ypres :: ~ % ./python2-setcapped discard.py 
ypres :: ~ % 

dgoulet's patch *should* produce behavior identical to the last case, unless there's other weirdness going on.

comment:21 in reply to:  20 Changed 4 years ago by isis

Replying to yawning:

It shouldn't unless you were setcaping the python binary....


Whoops, you're correct. I misremembered… we used to create Python virtualenvs, then setcap the copy of the Python binary in the virtualenv.

comment:22 Changed 2 years ago by nickm

Keywords: tor-pt privileges low-ports added
Severity: Normal

comment:23 Changed 17 months ago by teor

Milestone: Tor: unspecifiedTor: 0.3.4.x-final

Move all needs_review tickets without a release to 0.3.4

comment:24 Changed 17 months ago by nickm

Keywords: review-group-34 added

comment:25 Changed 16 months ago by dgoulet

Milestone: Tor: 0.3.4.x-finalTor: unspecified
Status: needs_reviewnew

comment:26 Changed 16 months ago by dcf

Cross-referencing #18356 / Debian #865495, which say that these days, setcap alone is not enough: you also have to work around systemd hardening. Specifically, you have to set NoNewPrivileges=no in /lib/systemd/system/tor@default.service and /lib/systemd/system/tor@.service and then run systemctl daemon-reload. This has been the case since 0.2.7.4-rc-1 (October 2015).

comment:27 Changed 16 months ago by yawning

Cc: yawning removed

comment:29 Changed 6 weeks ago by arma

Cc: phw added

cc'ing phw because we might want to work on this ticket as part of the obfs4 operator ux work (at least, say, documenting the workaround).

Note: See TracTickets for help on using tickets.