Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚨 [security] Upgrade moment-timezone: 0.5.23 → 0.5.37 (minor) #95

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

depfu[bot]
Copy link
Contributor

@depfu depfu bot commented Aug 30, 2022


🚨 Your current dependencies have known security vulnerabilities 🚨

This dependency update fixes known security vulnerabilities. Please see the details below and assess their impact carefully. We recommend to merge and deploy this as soon as possible!


Here is everything you need to know about this upgrade. Please take a good look at what changed and the test results before merging this pull request.

What changed?

✳️ moment-timezone (0.5.23 → 0.5.37) · Repo · Changelog

Security Advisories 🚨

🚨 Command Injection in moment-timezone

Impact

All versions of moment-timezone from 0.1.0 contain build tasks vulnerable to command injection.

  • if Alice uses tzdata pipeline to package moment-timezone on her own (for example via grunt data:2014d, where 2014d stands for the version of the tzdata to be used from IANA's website),
  • and Alice let's Mallory select the version (2014d in our example), then Mallory can execute arbitrary commands on the machine running the grunt task, with the same privilege as the grunt task

Am I affected?

Do you build custom versions of moment-timezone with grunt?

If no, you're not affected.

Do you allow a third party to specify which particular version you want build?

If yes, you're vulnerable to command injection -- third party may execute arbitrary commands on the system running grunt task with the same privileges as grunt task.

Description

Command Injection via grunt-zdownload.js and MITM on iana's ftp endpoint

The tasks/data-download.js script takes in a parameter from grunt and uses it to form a command line which is then executed:

6  module.exports = function (grunt) {
7      grunt.registerTask('data-download', '1. Download data from iana.org/time-zones.', function (version) {
8          version = version || 'latest';

10 var done = this.async(),
11 src = 'ftp://ftp.iana.org/tz/tzdata-latest.tar.gz',
12 curl = path.resolve('temp/curl', version, 'data.tar.gz'),
13 dest = path.resolve('temp/download', version);
...
24 exec('curl ' + src + ' -o ' + curl + ' && cd ' + dest + ' && gzip -dc ' + curl + ' | tar -xf -', function (err) {

Ordinarily, one one run this script using something like grunt data-download:2014d, in which case version would have the value 2014d. However, if an attacker were to provide additional content on the command line, they would be able to execute arbitrary code

root@e94ba0490b65:/usr/src/app/moment-timezone# grunt 'data-download:2014d ; echo flag>/tmp/foo #'
\Running "data-download:2014d ; echo flag>/tmp/foo #" (data-download) task
>> Downloading https://data.iana.org/time-zones/releases/tzdata2014d ; echo flag>/tmp/foo #.tar.gz
>> Downloaded https://data.iana.org/time-zones/releases/tzdata2014d ; echo flag>/tmp/foo #.tar.gz

Done.
root@e94ba0490b65:/usr/src/app/moment-timezone# cat /tmp/foo
flag

Command Injection via data-zdump.js

The tasks/data-zdump.js script reads a list of files present in a temporary directory (created by previous tasks), and for each one, assembles and executes a command line without sanitization. As a result, an attacker able to influence the contents of that directory could gain code execution. This attack is exacerbated by timezone data being downloaded via cleartext FTP (described above), but beyond that, an attacker at iana.org able to modify the timezone files could disrupt any systems that build moment-timezone.

15              files     = grunt.file.expand({ filter : 'isFile', cwd : 'temp/zic/' + version }, '**/*');
...
27          function next () {
...
33              var file = files.pop(),
34                  src  = path.join(zicBase, file),
35                  dest = path.join(zdumpBase, file);
36              exec('zdump -v ' + src, { maxBuffer: 20*1024*1024 }, function (err, stdout) {

In this case, an attacker able to add a file to temp/zic/2014d (for example) with a filename like Z; curl www.example.com would influence the called to exec on line 36 and run arbitrary code. There are a few minor challenges in exploiting this, since the string needs to be a valid filename.

Command Injection via data-zic.js

Similar to the vulnerability in /tasks/data-download.js, the /tasks/data-zic.js script takes a version from the command line and uses it as part of a command line, executed without sanitization.

10          var done  = this.async(),
11              dest  = path.resolve('temp/zic', version),
...
22              var file = files.shift(),
23                  src = path.resolve('temp/download', version, file);
24
25              exec('zic -d ' + dest + ' ' + src, function (err) {

As a result, an attacker able to influence that string can run arbitrary commands. Of course, it requires an attacker able to influence the command passed to grunt, so may be unlikely in practice.

root@e94ba0490b65:/usr/src/app/moment-timezone# grunt 'data-zic:2014d; echo hi > /tmp/evil; echo '
Running "data-zic:2014d; echo hi > /tmp/evil; echo " (data-zic) task
exec: zid -d /usr/src/app/moment-timezone/temp/zic/2014d; echo hi > /tmp/evil; echo  /usr/src/app/moment-timezone/temp/download/2014d; echo hi > /tmp/evil; echo /africa
...

root@e94ba0490b65:/usr/src/app/moment-timezone# cat /tmp/evil
hi

Patches

The supplied patch on top of 0.5.34 is applicable with minor tweaks to all affected versions. It switches exec to execFile so arbitrary bash fragments won't be executed any more.

References

🚨 Cleartext Transmission of Sensitive Information in moment-timezone

Impact

  • if Alice uses grunt data (or grunt release) to prepare a custom-build, moment-timezone with the latest tzdata from IANA's website
  • and Mallory intercepts the request to IANA's unencrypted ftp server, Mallory can serve data which might exploit further stages of the moment-timezone tzdata pipeline, or potentially produce a tainted version of moment-timezone (practicality of such attacks is not proved)

Patches

Problem has been patched in version 0.5.35, patch should be applicable with minor modifications to all affected versions. The patch includes changing the FTP endpoint with an HTTPS endpoint.

Workarounds

Specify the exact version of tzdata (like 2014d, full command being grunt data:2014d, then run the rest of the release tasks by hand), or just apply the patch before issuing the grunt command.

Release Notes

0.5.37 (from changelog)

  • Re-publish npm package, because of extra folder present in 0.5.36, check #999

0.5.36 (from changelog)

  • IANA TZDB 2022c
  • improvements/fixes to data pipeline

0.5.35 (from changelog)

Thanks to the OpenSSF Alpha-Omega project for reporting these!

0.5.34

  • Updated data to IANA TZDB 2021e

0.5.33

  • Updated data to IANA TZDB 2021a

0.5.32

  • Updated data to IANA TZDB 2020d

0.5.31

Fixed Travis builds for Node.js 4 and 6

0.5.28

0.5.29 2020-02-21

Merged pull request #410 from @adgrace:

  • Added a method moment.tz.zonesForCountry(country_code) which returns all timezones for the country
  • Added a method moment.tz(timezone_id).countries() to get countries for some time zone
  • Added a method moment.tz.countries() to get all country codes
  • And as you know moment.tz.names() already exists

0.5.25

  • Fix moment.tz.dataVersion to return 2019a #742
  • Update path in bower.json

0.5.24

  • Updated data to IANA TZDB 2019a #737
  • Start shipping both a 1970-1930 file and a rolling 10-year file #614 #697
  • Fixed bug where _z time zone name was not cleared with .local() or .utcOffset(offset) #738

Does any of this look wrong? Please let us know.

Commits

See the full diff on Github. The new version differs by more commits than we can show here.


Depfu Status

Depfu will automatically keep this PR conflict-free, as long as you don't add any commits to this branch yourself. You can also trigger a rebase manually by commenting with @depfu rebase.

All Depfu comment commands
@​depfu rebase
Rebases against your default branch and redoes this update
@​depfu recreate
Recreates this PR, overwriting any edits that you've made to it
@​depfu merge
Merges this PR once your tests are passing and conflicts are resolved
@​depfu close
Closes this PR and deletes the branch
@​depfu reopen
Restores the branch and reopens this PR (if it's closed)
@​depfu pause
Ignores all future updates for this dependency and closes this PR
@​depfu pause [minor|major]
Ignores all future minor/major updates for this dependency and closes this PR
@​depfu resume
Future versions of this dependency will create PRs again (leaves this PR as is)

@depfu depfu bot added the depfu label Aug 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

0 participants