wp_hub


Checking for sudo privileges of the wp_hub user after performing a manual system enumeration

wp_hub@wallpaperhub:~$ sudo -l
Matching Defaults entries for wp_hub on wallpaperhub:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty,
    !env_reset
 
User wp_hub may run the following commands on wallpaperhub:
    (root) NOPASSWD: /usr/bin/web-scraper /root/web_src_downloaded/*.html

The wp_hub user is able to execute the /usr/bin/web-scraper /root/web_src_downloaded/*.html command as the root account without getting prompted for password

web-scraper


wp_hub@wallpaperhub:/$ sudo -u root /usr/bin/web-scraper /root/web_src_downloaded/*.html
Error reading file /root/web_src_downloaded/*.html: [Error: ENOENT: no such file or directory, open '/root/web_src_downloaded/*.html'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: '/root/web_src_downloaded/*.html'
}

Executing the command returns an error that no such file or directory for; /root/web_src_downloaded/*.html Additionally, it seems to perform a syscall; open

wp_hub@wallpaperhub:/$ ll /usr/bin/web-scraper
lrwxrwxrwx 1 root root 23 Feb 11 10:11 /usr/bin/web-scraper -> /opt/scraper/scraper.js*

Checking the executable, /usr/bin/web-scraper, reveals that it’s just a symlink to a JavaScript file; /opt/scraper/scraper.js

/opt/scraper/scraper.js


wp_hub@wallpaperhub:/$ ll /opt/scraper/scraper.js
-rwxr-xr-x 1 root root 1659 Feb 11 10:11 /opt/scraper/scraper.js*
 
wp_hub@wallpaperhub:/$ cat /opt/scraper/scraper.js
#!/usr/bin/env node
 
const fs = require('fs');
const { Window } = require("happy-dom");
 
// Check if a file path is provided as a command-line argument
const filePath = process.argv[2];
 
if (!filePath) {
    console.error('Please provide a file path as an argument.');
    process.exit(1);
}
 
const window = new Window();
const document = window.document;
 
// Read the content of the provided file path
fs.readFile(filePath, 'utf-8', (err, data) => {
    if (err) {
        console.error(`Error reading file ${filePath}:`, err);
        return;
    }
 
    // Use document.write() to add the content to the document
    document.write(data);
 
    // Log all external imports (scripts, stylesheets, meta tags)
    const links = document.querySelectorAll('link');
    const scripts = document.querySelectorAll('script');
    const metaTags = document.querySelectorAll('meta');
    
    console.log('----------------------------');
    // Output the links (CSS imports)
    console.log('CSS Links:');
    links.forEach(link => {
        console.log(link.href);
    });
 
    console.log('----------------------------');
 
    // Output the scripts (JS imports)
    console.log('JavaScript Links:');
    scripts.forEach(script => {
        if (script.src) {
            console.log(script.src);
        } else {
            console.log('Inline script found.');
        }
    });
 
    console.log('----------------------------');
 
    // Output the meta tags (for metadata)
    console.log('Meta Tags:');
    metaTags.forEach(meta => {
        console.log(`Name: ${meta.name}, Content: ${meta.content}`);
    });
 
    console.log('----------------------------');
});

The /opt/scraper/scraper.js file is a simple NodeJS application that takes a file as an argument to scrape its data, such as CSS/JS import links and metadata Interesting thing is that it uses the happy-dom module to open up a new window. This must be what the earlier syscall was

happy-dom


wp_hub@wallpaperhub:/opt$ ll
total 12
drwxr-xr-x  3 root root 4096 Feb 11 10:11 ./
drwxr-xr-x 23 root root 4096 Nov  7 00:33 ../
drwxr-xr-x  3 root root 4096 Feb 11 10:11 scraper/
 
wp_hub@wallpaperhub:/opt$ cd scraper/ ; ll
total 24
drwxr-xr-x 3 root root 4096 Feb 11 10:11 ./
drwxr-xr-x 3 root root 4096 Feb 11 10:11 ../
drwxr-xr-x 6 root root 4096 Feb 11 10:11 node_modules/
-rw-r--r-- 1 root root  273 Feb 11 10:11 package.json
-rw-r--r-- 1 root root 1794 Feb 11 10:11 package-lock.json
-rwxr-xr-x 1 root root 1659 Feb 11 10:11 scraper.js*
 
wp_hub@wallpaperhub:/opt/scraper$ cat package.json
{
  "name": "scraper",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "happy-dom": "^15.9.0"
  }
}

It uses happy-dom 15.9.0

Vulnerabilities

Checking happy-dom 15.9.0 online for vulnerabilities reveals a code injection vulnerability; CVE-2024-51757 Given that the sudo command contains a wildcard bit(*), the first argument to the /opt/scraper/scraper.js file can be controlled Moving on to the Privilege Escalation phase