CVE-2024-21488 (JavaScript, published 2024-01-30T05:15Z)
Description: value: Versions of the package network before 0.7.0 are vulnerable to Arbitrary Command Injection due to use of the child_process exec function without input sanitization. If (attacker-controlled) user input is given to the mac_address_for function of the package, it is possible for the attacker to execute arbitrary commands on the operating system that this package is being run on.
Severity: nan (CVSS v3 base score: 9.8)
Weakness: CWE-77 \u2014 Improper Neutralization of Special Elements used in a Command ('Command Injection')
The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.
Repository: https://github.com/tomas/network
Files changed:
.gitignore
README.md
bin/network
lib/darwin.js
lib/index.js
lib/linux.js
lib/win32.js
package.json
test.js
Commit message: Ensure valid nic in darwin too

Vulnerable code:

Fixed code:
*~
.DS_Store
node_modules
Network Utilies for Node.js
===========================

# Install

    $ npm install network

# Usage

## Get public IP

Returns your public IP address, as reported by DynDNS.org or other services.

``` js
var network = require('network');

network.get_public_ip(function(err, ip) {
  console.log(err || ip); // should return your public IP address
})
```

##### CLI

    $ network public_ip

## Get private IP

Returns the IP address assigned to your first active network inteface.

``` js
network.get_private_ip(function(err, ip) {
  console.log(err || ip); // err may be 'No active network interface found'.
})
```

##### CLI

    $ network private_ip

## Get gateway IP

Returns the IP of the gateway that your active network interface is linked to.

``` js
network.get_gateway_ip(function(err, ip) {
  console.log(err || ip); // err may be 'No active network interface found.'
})
```

##### CLI

    $ network gateway_ip

## Get active interface

Returns the IP, MAC address and interface type for the active network
interface. On OS X and Linux you also get the IP of its assigned gateway.

``` js
network.get_active_interface(function(err, obj) {

  /* obj should be:

  { name: 'eth0',
    ip_address: '10.0.1.3',
    mac_address: '56:e5:f9:e4:38:1d',
    type: 'Wired',
    netmask: '255.255.255.0',
    gateway_ip: '10.0.1.1' }

  */
})
```

##### CLI

    $ network active_interface

## Get interfaces list

Returns list of network interfaces, including MAC addresses and the such, just
as in the example above.

``` js
network.get_interfaces_list(function(err, list) {

  /* list should be:

  [{
    name: 'eth0',
    ip_address: '10.0.1.3',
    mac_address: '56:e5:f9:e4:38:1d',
    type: 'Wired',
    netmask: '255.255.255.0',
    gateway_ip: '10.0.1.1' 
   },
   { ... }, { ... }]

  */
})
```

##### CLI

    $ network interfaces_list

# Copyright

Written by Tomás Pollak. Copyright (c) Fork, Ltd.

# License

MIT.
#!/usr/bin/env node

var program = require('commander'),
    network = require('..'),
    pkg     = require('../package.json');

function print(results, json) {
  if (json) console.log(JSON.stringify(results, null, 2))
  else console.log(results)
}

program.version(pkg.version)

program
  .command('public_ip')
  .description('Print public ip address')
  .option('-j --json', 'Print results in JSON format')
  .on('--help', function () {
    console.log('  Examples:')
    console.log()
    console.log('    $ network public_ip')
    console.log()
  })
  .action(function () {
    network.get_public_ip(function (err, results) {
      if (err) {
        console.error(err)
        process.exit(1)
      }

      print(results, program.json)
      process.exit(0)
    })
  })

program
  .command('private_ip')
  .description('Print private ip address')
  .option('-j --json', 'Print results in JSON format')
  .on('--help', function () {
    console.log('  Examples:')
    console.log()
    console.log('    $ network private_ip')
    console.log()
  })
  .action(function () {
    network.get_private_ip(function (err, results) {
      if (err) {
        console.error(err)
        process.exit(1)
      }

      print(results, program.json)
      process.exit(0)
    })
  })

program
  .command('mac_address_for <interface>')
  .description('Print mac address for given network interface')
  .option('-j --json', 'Print results in JSON format')
  .on('--help', function () {
    console.log('  Examples:')
    console.log()
    console.log('    $ network mac_address_for Wi-Fi')
    console.log()
  })
  .action(function (nInterface) {
    network.mac_address_for(nInterface, function (err, results) {
      if (err) {
        console.error(err)
        process.exit(1)
      }

      print(results, program.json)
      process.exit(0)
    })
  })

program
  .command('gateway_ip')
  .description('Print gateway ip address')
  .option('-j --json', 'Print results in JSON format')
  .on('--help', function () {
    console.log('  Examples:')
    console.log()
    console.log('    $ network gateway_ip')
    console.log()
  })
  .action(function () {
    network.get_gateway_ip(function (err, results) {
      if (err) {
        console.error(err)
        process.exit(1)
      }

      print(results, program.json)
      process.exit(0)
    })
  })

program
  .command('active_interface')
  .description('Print active network interface')
  .option('-j --json', 'Print results in JSON format')
  .on('--help', function () {
    console.log('  Examples:')
    console.log()
    console.log('    $ network active_interface')
    console.log()
  })
  .action(function () {
    network.get_active_interface(function (err, results) {
      if (err) {
        console.error(err)
        process.exit(1)
      }

      print(results, program.json)
      process.exit(0)
    })
  })

program
  .command('interfaces_list')
  .description('Print all network interfaces')
  .option('-j --json', 'Print results in JSON format')
  .on('--help', function () {
    console.log('  Examples:')
    console.log()
    console.log('    $ network interfaces_list')
    console.log()
  })
  .action(function () {
    network.get_interfaces_list(function (err, results) {
      if (err) {
        console.error(err)
        process.exit(1)
      }

      print(results, program.json)
      process.exit(0)
    })
  })

program.parse(process.argv)

if (!program.args.length) program.help()
"use strict";

var os    = require('os'),
    exec  = require('child_process').exec,
    async = require('async');

//////////////////////////////////////////
// helpers

function trim_exec(cmd, cb) {
  exec(cmd, function(err, out) {
    if (out && out.toString() != '')
      cb(null, out.toString().trim())
    else
      cb(err)
  })
}

function ensure_valid_nic(str) {
  if (str.match(/[^\w]/))
    throw new Error("Invalid nic name given: " + str);
}

function determine_nic_type(str) {
  return str.match(/Ethernet/)
    ? "Wired"
    : str.match(/Wi-?Fi|AirPort/i)
    ? "Wireless"
    : str.match(/FireWire/)
    ? "FireWire"
    : str.match(/Thunderbolt/)
    ? "Thunderbolt"
    : str.match(/Bluetooth/)
    ? "Bluetooth"
    : str.match(/USB 10\/100\/1000 LAN/)
    ? "USB Ethernet Adapter"
    : "Other";
}

//////////////////////////////////////////
// exports

exports.get_active_network_interface_name = function(cb) {
  var cmd = "netstat -rn | grep UG | awk '{print $NF}'";
  exec(cmd, function(err, stdout) {
    if (err) return cb(err);

    var raw = stdout.toString().trim().split('\n');
    if (raw.length === 0 || raw === [''])
      return cb(new Error('No active network interface found.'));

    cb(null, raw[0]);
  });
};

/* unused

exports.interface_type_for = function(nic_name, cb) {
  exec('networksetup -listnetworkserviceorder | grep ' + nic_name, function(err, out) {
    if (err) return cb(err);

    var type = out.toString().match(/ethernet|lan/i) ? 'Wired' : 'Wireless';
    cb(null, type);
  })
};
*/

exports.mac_address_for = function(nic_name, cb) {
  ensure_valid_nic(nic_name);
  var cmd = "networksetup -getmacaddress " + nic_name + " | awk '{print $3}'";
  trim_exec(cmd, cb);
};

exports.gateway_ip_for = function(nic_name, cb) {
  ensure_valid_nic(nic_name);
  var cmd = "ipconfig getoption " + nic_name + " router";
  trim_exec(cmd, cb);
};

exports.netmask_for = function(nic_name, cb) {
  ensure_valid_nic(nic_name);
  var cmd = "ipconfig getoption " + nic_name + " subnet_mask";
  trim_exec(cmd, cb);
};
exports.status_for = function(nic_name, cb) {
  ensure_valid_nic(nic_name);
  var cmd = "netstat -rn | grep " + nic_name + ' | grep UG | wc -l | sed -e "s/1/active/" | sed -e "s/0/inactive/"'
  trim_exec(cmd, cb)
}

exports.get_network_interfaces_list = function(cb) {

  var count = 0,
      list  = [],
      nics  = os.networkInterfaces();

  function append_data(obj) {
    async.parallel([
      function(cb) {
        exports.gateway_ip_for(obj.name, cb)
      },
      function(cb) {
        exports.netmask_for(obj.name, cb)
      },
      function(cb){
        exports.status_for(obj.name, cb)
      }
    ], function(err, results) {
      if (results[0]) obj.gateway_ip = results[0];
      if (results[1]) obj.netmask    = results[1];
      if (results[2]) obj.status = results[2]
      
      list.push(obj);
      --count || cb(null, list);
    })
  }

  exec('networksetup -listallhardwareports', function(err, out) {
    if (err) return cb(err);

    var blocks = out.toString().split(/Hardware/).slice(1);
    count = blocks.length;

    blocks.forEach(function(block) {
      var parts = block.match(/Port: (.+)/),
          mac   = block.match(/Address: ([A-Fa-f0-9:-]+)/),
          name  = block.match(/Device: (\w+)/);
          

      if (!parts || !mac || !name) 
        return --count;

      var obj   = {},
          port  = parts[1];

      obj.name  = name[1];
      obj.desc  = port;
      obj.type  = determine_nic_type(port);
      obj.ip_address  = null;
      obj.mac_address = mac[1];

      (nics[obj.name] || []).forEach(function(type) {
        if (type.family == 'IPv4') {
          obj.ip_address = type.address;
        }
      });

      append_data(obj);
    })

    if (count == 0) cb(new Error('No interfaces found.'))
  })

};
"use strict";

var needle = require('needle');
var os_functions;
switch (process.platform) {
  case 'win32':
    os_functions = require('./win32');
    break;
  case 'linux':
    os_functions = require('./linux');
    break;
  case 'darwin':
    os_functions = require('./darwin');
    break;
}
// var ip_regex = /((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})/;
var ip_regex = /(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)/;

var public_ip_urls = [
  'http://checkip.dyndns.org',
  'http://wtfismyip.com/text',
  'http://ipecho.net/plain',
  'http://ifconfig.me/ip'
];

function is_ip_address(str) {
  return ip_regex.test(str);
};

function nic_by_name(name, cb) {
  os_functions.get_network_interfaces_list(function(err, list) {
    if (err) return cb(err);

    var nics = list.filter(function(nic) { return nic.name === name; });

    if (nics.length > 0)
      cb(null, nics[0]);
    else
      cb(new Error('No network interface named ' + name));
  });
};

exports.get_public_ip = function(options, cb) {

  if (typeof options == 'function') { // no options passed
    cb = options;
    options = {};
  }

  var urls = options.urls || public_ip_urls;

  function get(i) {
    var url = urls[i];
    if (!url) return cb(new Error('Unable to fetch IP address.'));

    needle.get(url, function(err, resp) {
      var body = resp && resp.body.toString();
      if (body && body.match(ip_regex)) {
        return cb(null, body.match(ip_regex)[1]);
      }

      get(i+1);
    })
  };

  get(0);
}

exports.get_private_ip = function(cb) {
  os_functions.get_network_interfaces_list(function(err, list) {
    if (err || !list)
      return cb(err || new Error('No network interfaces found.'));

    os_functions.get_active_network_interface_name(function(err, active_nic) {
      if (err) return cb(err);

      var ips = list.filter(function(nic) {
        if (is_ip_address(nic.ip_address))
          return active_nic ? active_nic == nic.name : true;
      });

      if (ips.length > 0)
        cb(null, ips[0].ip_address);
      else
        cb(new Error('No private IPs found (' + list.length + ' interfaces)'));
    });
  });
};

exports.get_gateway_ip = function(cb) {
  os_functions.get_active_network_interface_name(function(err, nic_name) {
    if (err || nic_name.trim() == '')
      return cb(err || new Error('No active network interface found.'));

    os_functions.gateway_ip_for(nic_name, function(err, out) {
      if (err || !out || out.toString() == '')
        return cb(err || new Error('No gateway IP assigned to ' + nic_name));

      cb(null, out.toString().trim())
    })
  });
};

exports.get_active_interface = function(cb) {
  os_functions.get_active_network_interface_name(function(err, nic_name) {
    if (err || !nic_name) return cb(err || new Error("No active interfaces detected."));

    nic_by_name(nic_name, function(err, nic) {
      if (err) return cb(err);

      os_functions.netmask_for(nic_name, function(err, netmask) {
        if (!err && netmask)
          nic.netmask = netmask.trim();

        os_functions.gateway_ip_for(nic_name, function(err, ip) {
          if (!err && ip)
            nic.gateway_ip = ip.toString().trim();

          cb(null, nic);
        })
      });
    });
  });
};

exports.get_interfaces_list = os_functions.get_network_interfaces_list;
exports.mac_address_for = os_functions.mac_address_for;
exports.gateway_ip_for = os_functions.gateway_ip_for;
"use strict";

var os    = require('os'),
    exec  = require('child_process').exec,
    async = require('async');

function trim_exec(cmd, cb) {
  exec(cmd, function(err, out) {
    if (out && out.toString() != '')
      cb(null, out.toString().trim())
    else
      cb(err)
  })
}

function ensure_valid_nic(str) {
  if (str.match(/[^\w]/))
    throw new Error("Invalid nic name given: " + str);
}

// If no wifi, then there is no error but cbed get's a null in second param.
exports.get_active_network_interface_name = function(cb) {
  var cmd = "netstat -rn | grep UG | awk '{print $NF}'";
  exec(cmd, function(err, stdout, stderr) {
    if (err) return cb(err);

    if (stderr.toString().match('not found')) {
      return cb(new Error('Command failed: ' + stderr.toString().trim()))
    }

    var raw = stdout.toString().trim().split('\n');
    if (raw.length === 0 || raw === [''])
      return cb(new Error('No active network interface found.'));

    cb(null, raw[0]);
  });
};

exports.interface_type_for = function(nic_name, cb) {
  ensure_valid_nic(nic_name);
  exec('cat /proc/net/wireless | grep ' + nic_name, function(err, out) {
    return cb(null, err ? 'Wired' : 'Wireless')
  })
};

exports.mac_address_for = function(nic_name, cb) {
  ensure_valid_nic(nic_name);
  var cmd = 'cat /sys/class/net/' + nic_name + '/address';
  trim_exec(cmd, cb);
};

exports.gateway_ip_for = function(nic_name, cb) {
  ensure_valid_nic(nic_name);
  trim_exec("ip r | grep " + nic_name + " | grep default | cut -d ' ' -f 3 | head -n1", cb);
};

exports.netmask_for = function(nic_name, cb) {
  ensure_valid_nic(nic_name);
  var cmd = "ifconfig " + nic_name + " 2> /dev/null | egrep 'netmask|Mask:' | awk '{print $4}' | sed 's/Mask://'";
  trim_exec(cmd, cb);
};

exports.get_network_interfaces_list = function(cb) {

  var count = 0,
      list = [],
      nics = os.networkInterfaces();

  function append_data(obj) {
    async.parallel([
      function(cb) {
        exports.mac_address_for(obj.name, cb)
      },
      function(cb) {
        exports.gateway_ip_for(obj.name, cb)
      },
      function(cb) {
        exports.netmask_for(obj.name, cb)
      },
      function(cb) {
        exports.interface_type_for(obj.name, cb)
      }
    ], function(err, results) {
      if (results[0]) obj.mac_address = results[0];
      if (results[1]) obj.gateway_ip  = results[1];
      if (results[2]) obj.netmask     = results[2];
      if (results[3]) obj.type        = results[3];
      
      list.push(obj);
      --count || cb(null, list);
    })
  }

  for (var key in nics) {
    if (key != 'lo0' && key != 'lo' && !key.match(/^tun/)) {

      count++;
      var obj = { name: key };

      nics[key].forEach(function(type) {
        if (type.family == 'IPv4') {
          obj.ip_address = type.address;
        }
      });

      append_data(obj);
    }
  }

  if (count == 0)
    cb(new Error('No interfaces found.'))
}

"use strict";

var wmic = require('wmic'),
    exec = require('child_process').exec,
    os   = require('os');

function get_wmic_ip_value(what, nic_name, cb){
  exports.mac_address_for(nic_name, function(err, mac){
    if (err || !mac)
      return cb(err || new Error('No MAC Address found.'));

    wmic.get_value('nicconfig', what, 'MACAddress = \'' + mac + '\'', function(err, out){
      if (err) return cb(err);

      cb(null, out.split(',')[0].replace(/[^0-9\.]/g, ''));
    });
  })
}

exports.get_active_network_interface_name = function(cb) {
  wmic.get_value('nic', 'NetConnectionID', 'NetConnectionStatus = 2', cb);
};

exports.netmask_for = function(nic_name, cb) {
  get_wmic_ip_value('IPSubnet', nic_name, cb);
};

exports.gateway_ip_for = function(nic_name, cb) {
  get_wmic_ip_value('DefaultIPGateway', nic_name, cb);
};

exports.mac_address_for = function(nic_name, cb) {
  var cond = 'NetConnectionID = \'' + nic_name + '\'';
  wmic.get_value('nic', 'MACAddress', cond, cb);
}

exports.get_network_interfaces_list = function(callback) {

  var count, 
      list = [],
      node_nics = os.networkInterfaces();

  function done() {
    --count || callback(null, list);
  }

  function set_gateway(obj) {
    exports.gateway_ip_for(obj.name, function(err, res) {
      obj.gateway_ip = res && res != '' ? res : null;
      done();
    })
  }

  function set_netmask(obj) {
    exports.netmask_for(obj.name, function(err, res) {
      obj.netmask = res && res != '' ? res : null;
    })
  }

  wmic.get_list('nic', function(err, nics) {
    if (err) return callback(err);    
    count = nics.length;
    if (count == 0){
      return cb(new Error('No interfaces found.'))
    }
    nics.forEach(function(nic) {
      if (nic.Name && nic.NetConnectionID != '' && nic.MACAddress != '') {

        var obj = {
          name: nic.NetConnectionID,
          // description: nic.Name,
          mac_address: nic.MACAddress,
          ip_address: nic.IPAddress,
          vendor: nic.Manufacturer,
          model: nic.Description,
          type: nic.Name.match(/wi-?fi|wireless/i) ? 'Wireless' : 'Wired'
        }

        var node_nic = node_nics[obj.name] || [];

        node_nic.forEach(function(type) {
          if (type.family == 'IPv4') {
            obj.ip_address = type.address;
          }
        });

        list.push(obj);
        set_netmask(obj);        
        set_gateway(obj);
      } else {
        done();
      }
    })
  });

};
{
  "name": "network",
  "version": "0.6.1",
  "description": "Cross platform network utilities for Node.js (gateway_ip, MAC address, etc)",
  "main": "./lib/index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "bin": {
    "network": "./bin/network"
  },
  "dependencies": {
    "async": "^1.5.2",
    "commander": "2.9.0",
    "needle": "^3.0.0",
    "wmic": "^1.0.1"
  },
  "author": {
    "name": "Tomas Pollak",
    "email": "tomas@forkhq.com"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/tomas/network.git"
  },
  "license": "MIT"
}
var network = require('./lib');

network.get_public_ip(function(err, res) {
  console.log('Public IP --- ');
  console.log(err || res);
});

network.get_private_ip(function(err, res) {
  console.log('Private IP --- ');
  console.log(err || res);
});

network.get_gateway_ip(function(err, res) {
  console.log('Gateway IP --- ');
  console.log(err || res);
});

network.get_active_interface(function(err, res) {
  console.log('Active Network Interface --- ');
  console.log(err || res);
});

network.get_interfaces_list(function(err, res) {
  console.log('Network Interfaces List --- ');
  console.log(err || res);
});