From b347c82b4260556fbf32bd3444a49e8c9673ea47 Mon Sep 17 00:00:00 2001 From: Javier Acuna Date: Wed, 29 Dec 2021 16:19:37 -0300 Subject: [PATCH 1/3] Ask location with sudo on macOS Monterey --- lib/agent/providers/network/mac.js | 70 ++++++++++++++++------------- lib/conf/tasks/utils/create_user.sh | 2 + 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/lib/agent/providers/network/mac.js b/lib/agent/providers/network/mac.js index e75dba4b5..1e482deaa 100644 --- a/lib/agent/providers/network/mac.js +++ b/lib/agent/providers/network/mac.js @@ -6,6 +6,7 @@ ////////////////////////////////////////// var fs = require('fs'), + sudo = require('sudoer'), exec = require('child_process').exec, common = require('../../common'), airport_cmd = '/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport'; @@ -15,12 +16,25 @@ var mac_address_regex = /([0-9a-f]{2}[:-]){5}([0-9a-f]{2})/i; var attemps = 100, current_attemp; +var access_points_function = function(cmd, args, cb) { + if (common.os_release >= "12.0") { + sudo(cmd, args, function(err, stdout, stderr) { + return cb(err, stdout); + }); + } else { + exec(cmd + " " + args.join(' '), function(err, stdout) { + return cb(err, stdout); + }); + } +} + var get_ap_list_retry = function(out, cb) { current_attemp++; if (current_attemp >= attemps) return cb(null, out); else if (out && out != '') return cb(null, out); else { - exec(airport_cmd + ' -s', function(err, stdout) { + access_points_function(airport_cmd, ["-s"], (err, stdout) => { + if (err && err.message.includes("No sudo access")) return; get_ap_list_retry(stdout, cb); }); } @@ -38,15 +52,25 @@ exports.get_wireless_interfaces_list = function(cb) { }; exports.get_active_access_point_mac = function(callback) { - var cmd = airport_cmd + " -I | grep 'BSSID:' | awk '{print $2}'"; - exec(cmd, function(err, out) { - callback(err, out.toString().trim().split('\n')[0]); + var output; + access_points_function(airport_cmd, ["-I"], (err, stdout) => { + if (err) return callback(err); + + stdout = stdout.toString().split("\n"); + stdout.forEach(function(line, index) { + var data = line.split(": "); + if (data[0].trim() == "BSSID") { + output = data[1]; + } + + if (index == stdout.length - 1) { + return callback(null, output); + } + }) }); }; exports.get_active_access_point = function(callback) { - var cmd = airport_cmd + " -I"; - var process_active_ap = function(stdout) { if (stdout.includes('AirPort: Off') || !stdout.includes('SSID')) return callback(new Error('Wifi connection unavailable')); @@ -69,18 +93,10 @@ exports.get_active_access_point = function(callback) { callback(null, ap); } - if (common.os_release >= "12.0") { - fs.readFile('/tmp/active_ap.txt', (err, data) => { - if (err) return callback(err); - process_active_ap(data.toString()); - }); - - } else { - exec(cmd, function(err, stdout){ - if (err) return callback(err); - process_active_ap(stdout); - }) - } + access_points_function(airport_cmd, ["-I"], (err, stdout) => { + if (err) return callback(err); + process_active_ap(stdout); + }) } ///////////////////////////////////////////////////////////////// @@ -101,19 +117,11 @@ exports.get_access_points_list = function(callback) { callback(new Error("No access points found.")); } - if (common.os_release >= "12.0") { - fs.readFile('/tmp/list_ap.txt', (err, data) => { - if (err) return callback(err); - process_ap_list(data.toString()); - }); - } - else { - current_attemp = 0; - get_ap_list_retry(null, function(err, stdout) { - if (err) return callback(err); - process_ap_list(stdout) - }); - } + current_attemp = 0; + get_ap_list_retry(null, function(err, stdout) { + if (err) return callback(err); + process_ap_list(stdout) + }); } exports.parse_access_points_list = function(stdout) { diff --git a/lib/conf/tasks/utils/create_user.sh b/lib/conf/tasks/utils/create_user.sh index 13e80f217..26a839fd1 100755 --- a/lib/conf/tasks/utils/create_user.sh +++ b/lib/conf/tasks/utils/create_user.sh @@ -26,6 +26,8 @@ if [ "$(uname)" == "Linux" ]; then else USERS_PATH="/Users" SHELL="/sbin/nologin" + AIRPORT_CMD="/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport" + SUDOERS_ARGS="$SUDOERS_ARGS, $AIRPORT_CMD" fi SUDOERS_LINE="${USER_NAME} ALL = NOPASSWD: ${SUDOERS_ARGS}" From aa3b5ccca718abe890c5e36394a76cca3780ba09 Mon Sep 17 00:00:00 2001 From: Javier Acuna Date: Mon, 3 Jan 2022 08:31:22 -0300 Subject: [PATCH 2/3] New sudoers file for macOS on install --- lib/conf/tasks/utils/create_user.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/conf/tasks/utils/create_user.sh b/lib/conf/tasks/utils/create_user.sh index 26a839fd1..91bfa5533 100755 --- a/lib/conf/tasks/utils/create_user.sh +++ b/lib/conf/tasks/utils/create_user.sh @@ -12,11 +12,11 @@ FULL_NAME="Prey Anti-Theft" SU_CMD=$(command -v su) || SU_CMD="/bin/su" -# this means user will be able to run commands as other users except root -SUDOERS_FILE="/etc/sudoers.d/50_${USER_NAME}_switcher" +# With SUDOERS_FILE user will be able to run commands as other users except root SUDOERS_ARGS="${SU_CMD} [A-z]*, !${SU_CMD} root*, !${SU_CMD} -*" if [ "$(uname)" == "Linux" ]; then + SUDOERS_FILE="/etc/sudoers.d/50_${USER_NAME}_switcher" USERS_PATH="/home" [ -n "$(which dmidecode)" ] && SUDOERS_ARGS="$(which dmidecode), ${SUDOERS_ARGS}" [ -n "$(which iwlist)" ] && SUDOERS_ARGS="$(which iwlist), ${SUDOERS_ARGS}" @@ -24,6 +24,7 @@ if [ "$(uname)" == "Linux" ]; then # also, since nologin path changes between linux distros, lets use /bin/false instead SHELL="/bin/false" else + SUDOERS_FILE="/etc/sudoers.d/51_${USER_NAME}_switcher" # New version for macOS USERS_PATH="/Users" SHELL="/sbin/nologin" AIRPORT_CMD="/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport" @@ -108,6 +109,11 @@ grant_privileges() { ( umask 226 && echo "${SUDOERS_LINE}" > "$SUDOERS_FILE" ) + # Delete old sudoers file on macOS + if [ "$(uname)" == "Darwin" ]; then + rm -rf "/etc/sudoers.d/etc/sudoers.d/50_${USER_NAME}_switcher" + fi + } test_impersonation() { From c82373c2eadc0815931b52bcd0938c708e528de6 Mon Sep 17 00:00:00 2001 From: Javier Acuna Date: Mon, 3 Jan 2022 08:40:28 -0300 Subject: [PATCH 3/3] Daemon binary to set sudo airport permissions --- bin/prey-user | Bin 38544 -> 38848 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/prey-user b/bin/prey-user index 0e8c06301a72ed95b4449bbdc0afbbb7538de5ad..25af429833d7c7be5daf0b8a2fcf56e6a7289d20 100755 GIT binary patch delta 9260 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 Ui{@_Y{O!%I2M6iKhKQ*D1FB=0V*mgE delta 8201 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