{"id":22140877,"url":"https://github.com/stealth/7350topless","last_synced_at":"2025-07-25T23:31:45.936Z","repository":{"id":142556606,"uuid":"369454346","full_name":"stealth/7350topless","owner":"stealth","description":null,"archived":false,"fork":false,"pushed_at":"2021-05-25T07:03:42.000Z","size":122,"stargazers_count":8,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2023-10-20T23:14:30.486Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stealth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-05-21T07:41:03.000Z","updated_at":"2023-10-20T23:14:31.049Z","dependencies_parsed_at":"2023-03-21T15:57:19.790Z","dependency_job_id":null,"html_url":"https://github.com/stealth/7350topless","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stealth%2F7350topless","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stealth%2F7350topless/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stealth%2F7350topless/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stealth%2F7350topless/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stealth","download_url":"https://codeload.github.com/stealth/7350topless/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227629068,"owners_count":17796054,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-01T21:08:27.130Z","updated_at":"2024-12-01T21:08:27.731Z","avatar_url":"https://github.com/stealth.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"80-update-htop-and-offload-tx\n=============================\n\n[![asciicast](https://asciinema.org/a/FQEhw8yQ63Q4Adw3HDNjliT5u.svg)](https://asciinema.org/a/FQEhw8yQ63Q4Adw3HDNjliT5u)\n\n[Armbian](https://www.armbian.com) is a Debian based Linux distro\nfor virtually every ARM dev board. As it is slim, easy to use and configure\nit is one of my favorite distros for my ARM-boards zoo.\n\nYet, there is a LPE vulnerability in Armbian's *NetworkManager* dispatcher script\n`80-update-htop-and-offload-tx`.\n\nThe script goes like this:\n\n```bash\n#!/bin/bash\n#\n# adjust htop settings for all normal users and root\n#\n\n. /etc/armbian-release\n\nfor homedir in $(awk -F'[:]' '{if ($3 \u003e= 1000 \u0026\u0026 $3 != 65534 || $3 == 0) print $6}' /etc/passwd); do\n\n\tunset FIELDS FIELD_PARA\n\n\t# start with a clean copy\n\tcp /etc/skel/.config/htop/htoprc \"${homedir}\"/.config/htop/htoprc\n\n\tfor TYPE in ethernet wifi; do\n\n\t\ti=0\n\t\tfor INTERFAC in $(LC_ALL=C nmcli device status | grep $TYPE | grep -w connected | awk '{ print $1 }' | grep -v lo | grep -v p2p | head -2); do\n\n\t\t\t[[ $TYPE == ethernet ]] \u0026\u0026 type=\"eth\"; [[ $TYPE == wifi ]] \u0026\u0026 type=\"wlan\"\n\n\t\t\tFIELDS+=\"${type^}$i ${type^}${i}stat \"\n\t\t\tFIELD_PARA+=\"2 2 \"\n\t\t\tsed -i \"s/^${type}${i}_alias=.*/${type}${i}_alias=$INTERFAC/\" \"${homedir}\"/.config/htop/htoprc\n\n\t\t\t((i=i+1))\n\t\tdone\n\tdone\n\n\tFIELDS=$(echo $FIELDS | xargs)\n\tFIELD_PARA=$(echo $FIELD_PARA | xargs)\n\n\techo \"$FIELDS $FIELD_PARA\"\n\n\tsed -i \"s/right_meters.*$/\u0026 $FIELDS/\" \"${homedir}\"/.config/htop/htoprc\n\tsed -i \"s/right_meter_modes.*$/\u0026 $FIELD_PARA/\" \"${homedir}\"/.config/htop/htoprc\n\n\t# enable GPU where this works\n\tif [[ $LINUXFAMILY == meson64 || $LINUXFAMILY == odroidxu4 ]]; then\n\t        sed -i \"s/left_meters.*$/\u0026 GpuTemp/\" \"${homedir}\"/.config/htop/htoprc\n        \tsed -i \"s/left_meter_modes.*$/\u0026 2/\" \"${homedir}\"/.config/htop/htoprc\n\tfi\n\ndone\n```\n\nThe interesting part is that while the dispatcher script is run as root when a network device is\ncoming up, it will operate on files in every users home directory. We will exploit the call to `sed`.\nLet me repeat that the vulnerability is not within *sed*, but we are using it as a vector since the\nsequence of syscalls allow us to drop arbitrary content to (almost) arbitrary files. We aim to\ncreate content inside `/etc/sudoers.d/` that allows us to *sudo* to root without password.\n\nHere's a strace of a *sed* call:\n```\n5248  [b6e6bbe6] openat(AT_FDCWD, \".config/htop/htoprc\", O_RDONLY|O_LARGEFILE) = 3\n[...]\n5248  [b6e6bbe6] openat(AT_FDCWD, \".config/htop/sedlMbD4Z\", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600) = 4\n5248  [b6e6bbe6] read(3, \"# Beware! This file is rewritten\"..., 4096) = 967\n5248  [b6e6bbe6] fstat64(4, {st_mode=S_IFREG|000, st_size=0, ...}) = 0\n5248  [b6e6bbe6] read(3, \"\", 4096)      = 0\n[...]\n5248  [b6e6bbe6] close(3)               = 0\n5248  [b6e6bbe6] write(4, \"# Beware! This file is rewritten\"..., 981) = 981\n5248  [b6e6bbe6] close(4)               = 0\n5248  [b6e6bbe6] rename(\".config/htop/sedlMbD4Z\", \".config/htop/htoprc\") = 0\n```\n\nThe sed invocation will edit the file in place and creates a temporary file which is then renamed\nto `$HOME/.config/htop/htoprc`. The exploit will switch the `.config/htop` directory after the first\n`openat()` to point to `/etc/sudoers.d`. This will land controlled content into a root owned file\nthat is accepted by *sudo*.\n\nHere is a sample run:\n\n![screenshot](https://github.com/stealth/7350topless/blob/master/screenshot.jpg)\n\nThe vulnerable dispatcher script will be called when DHCP rebind time is reached, so you either setup\na hostile DHCP server who offers short rebind time or wait until it triggers, which can take a couple\nof hours as most DHCP servers offer DHCP leases with ~6h of rebind time.\n\nThere are some nifty details about the directory switch which you can enjoy by reading the\nexploit code. As the PoC potentially waits quite long, we will try to reduce CPU usage. In\nother circumstances, due to multi-core environments, spinning would be an option.\n\nNote that the exploit is generic and works on almost all *Armbian* installs.\n\nAs a hotfix, you could remove the `80-update-htop-and-offload-tx` dispatcher script.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstealth%2F7350topless","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstealth%2F7350topless","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstealth%2F7350topless/lists"}