Validating the data is pretty easy.  The only data is the rate and it
is supposed to be a floating point number.   Switching to https is easy too.
The attached patch does both.

Is it enough?  


On Tue, Jul 03, 2018 at 09:04:14PM +0200, Stephen Kitt wrote:
> Control: forwarded adri...@gnu.org
> 
> Hi Adrian,
> 
> I thought you’d be interested in this bug report... A straightforward partial
> fix would be to switch to the https URIs, better still would be to add
> certificate validation of some sort, but I think a real fix would involve
> format validation and data sanitization (as Jakub mentions).
> 
> Regards,
> 
> Stephen
> 
> 
> On Tue, 3 Jul 2018 18:55:40 +0200, Jakub Wilk <jw...@jwilk.net> wrote:
> 
> > Package: units
> > Version: 2.17-1
> > Tags: security
> > 
> > units_cur does no sanitization of the data it downloads. Malicious 
> > operators of the servers or man-in-the-middle attackers[*] could exploit 
> > this to execute arbitrary code.
> > 
> > As a proof of concept, I patched units_cur to emulate Yahoo returning 
> > malicious data. After updating the data, /var/lib/units/currency.units 
> > looks like this:
> > 
> >    southkoreawon            1|0
> >    !set PAGER cowsay${IFS}pwned;exit;
> >    # US$
> > 
> > And this happens:
> > 
> >    $ units
> >    Currency exchange rates from finance.yahoo.com on 2018-07-03
> >    3048 units, 109 prefixes, 109 nonlinear units
> > 
> >    You have: help kg
> >     _______
> >    < pwned >
> >     -------
> >            \   ^__^
> >             \  (oo)\_______
> >                (__)\       )\/\
> >                    ||----w |
> >                    ||     ||
> > 
> > 
> > [*] Conveniently, all the data in downloaded over HTTP, so there's no 
> > authentication.
> > 
> > -- 
> > Jakub Wilk


--- /home/adrian/src/units/units_cur    2018-06-03 23:28:46.023000324 -0400
+++ units_cur   2018-07-20 16:52:16.000000000 -0400
@@ -28,8 +28,12 @@
 #
 #
 
-version = '4.2'
+version = '4.3'
 
+# Version 4.3: 20 July 2018
+#
+# Validate rate data from server
+#
 # Version 4.2: 18 April 2018
 #
 # Handle case of empty/malformed entry returned from the server
@@ -275,7 +279,7 @@
 verbose = ap.parse_args().verbose
 
 try:
-  res = requests.get('http://finance.yahoo.com/webservice/v1/symbols'
+  res = requests.get('https://finance.yahoo.com/webservice/v1/symbols'
                      '/allcurrencies/quote?format=json')
   res.raise_for_status()
   webdata = res.json()['list']['resources']
@@ -299,7 +303,12 @@
         stderr.write('Got unknown currency with code {}\n'.format(code))
     else:
       if not currency[code][rate_index]:
-        currency[code][rate_index] = '1|{} US$'.format(rate)
+        try:
+          float(rate)
+          currency[code][rate_index] = '1|{} US$'.format(rate)
+        except ValueError:
+          stderr.write('Got invalid rate "{}" for currency "{}"\n'.format(
+                                    rate, code))
       elif verbose:
         stderr.write('Got value "{}" for currency "{}" but '
                      'it is already defined\n'.format(rate, code))
@@ -313,7 +322,7 @@
     del currency[code]
   
 try:
-  req = requests.get('http://services.packetizer.com/spotprices/?f=json')
+  req = requests.get('https://services.packetizer.com/spotprices/?f=json')
   req.raise_for_status()
   metals = req.json()
 except requests.exceptions.RequestException as e:
@@ -323,7 +332,7 @@
 del metals['date']
 
 try:
-  req = requests.get('http://services.packetizer.com/btc/?f=json')
+  req = requests.get('https://services.packetizer.com/btc/?f=json')
   req.raise_for_status()
   bitcoin = req.json()
 except requests.exceptions.RequestException as e:

Reply via email to