Автоматическое повышение уровня пакетного файла с использованием powershell и без искажения аргументов, но проблема с вызовом

Я пытаюсь реализовать функцию, предложенную

mklement0 на этот ответ

Моя цель - реализовать это как многоразовую пакетную подфункцию.

Но до этого я столкнулся с паттерном непоследовательного поведения

В основном в зависимости от того, как вызывается скрипт, где он находится и откуда вызывается.

Скрипт вообще работает если его вызывать из папки и он тоже в папке. Однако, если он вызывается из корня диска, может произойти сбой с ошибкой, касающейся каналов &&.

Для документирования поведения я сохранил скрипт в виде файлов

i:\Test privilege escalation powershell with arguments.bat

и i:\script\Test powershell повышения привилегий с arguments.bat

Точный сценарий

@echo off
setlocal

:: Test whether this invocation is elevated (`net session` only works with elevation).
:: If already running elevated (as admin), continue below.
net session >NUL 2>NUL && goto :elevated

:: If not, reinvoke with elevation.
set args=%*
if defined args set args=%args:^=^^%
if defined args set args=%args:<=^<%
if defined args set args=%args:>=^>%
if defined args set args=%args:&=^&%
if defined args set args=%args:|=^|%
if defined args set "args=%args:"=\"\"%"
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
  " Start-Process -Wait -Verb RunAs -FilePath cmd -ArgumentList \"/c \"\" cd /d \"\"%CD%\"\" ^&^& \"\"%~f0\"\" %args% \"\" \" "
exit /b

:elevated

:: =====================================================
:: Now we are running elevated, in the same working dir., with args passed through.
:: YOUR CODE GOES HERE.

echo First argument is "%~1"
echo Second argument is "%~2"

pause

Я пробовал вызывать эти скрипты из нескольких мест c:\d:\i:, из папки, из корня диска. Я даже пробовал несколько раз и не всегда получал одинаковые результаты.

Полный лог произошедшего можно посмотреть здесь https://pastebin.com/xCEJKE2f Я не буду копировать наиболее важные фрагменты здесь

В обычной консоли cmd.exe консоль не является привилегированной

C:\>"i:\Test privilege escalation powershell with arguments.bat" 1 2 3
C:\>"i:Test privilege escalation powershell with arguments.bat" 1 2 3
C:\>"i:\scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
All 3 fail to The token '&&' is not a valid statement separator in this version. https://i.imgur.com/5sUHPeB.png
C:\>"i:scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
Fails with The system cannot find the path specified.                            https://i.imgur.com/5sUHPeB.png
 
C:\Users\shodan>"i:\Test privilege escalation powershell with arguments.bat" 1 2 3
C:\Users\shodan>"i:Test privilege escalation powershell with arguments.bat" 1 2 3
C:\Users\shodan>"i:\scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
C:\Users\shodan>"i:scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
All 4 work https://i.imgur.com/DVGpJFI.png
 
d:\>"i:Test privilege escalation powershell with arguments.bat" 1 2 3
d:\>"i:\Test privilege escalation powershell with arguments.bat" 1 2 3
d:\>"i:\scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
all 3 don't work, "The token '&&' is not a valid statement separator in this version." https://i.imgur.com/60NHWLh.png
d:\>"i:scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
does not work The system cannot find the path specified.
 
Later attempt ??? Not the same result ?  d:\ vs D:\ ?!?
D:\>"i:\Test privilege escalation powershell with arguments.bat" 1 2 3
D:\>"i:Test privilege escalation powershell with arguments.bat" 1 2 3
D:\>"i:\scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
D:\>"i:scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
All four fail with "The token '&&' is not a valid statement separator in this version."  https://i.imgur.com/c9WcxCp.png
 
d:\share>"i:Test privilege escalation powershell with arguments.bat" 1 2 3
d:\share>"i:\Test privilege escalation powershell with arguments.bat" 1 2 3
d:\share>"i:\scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
all 3 work             https://i.imgur.com/0be7DkQ.png
d:\share>"i:scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
The system cannot find the path specified.
 
Later attempt, not the same results ?!?! again  d:\ vs D:\ ?!?
D:\share>"i:\Test privilege escalation powershell with arguments.bat" 1 2 3
D:\share>"i:Test privilege escalation powershell with arguments.bat" 1 2 3
D:\share>"i:\scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
D:\share>"i:scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
All four work and elevated properly ! https://i.imgur.com/EtfvRyb.png
 
I:\>"i:Test privilege escalation powershell with arguments.bat" 1 2 3
I:\>"i:\Test privilege escalation powershell with arguments.bat" 1 2 3
I:\>"i:scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
I:\>"i:\scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
all don't work, same error, "The token '&&' is not a valid statement separator in this version." https://i.imgur.com/HiJggQ4.png
This result tried twice, second time same result
 
I:\scripts>"i:Test privilege escalation powershell with arguments.bat" 1 2 3
I:\scripts>"i:\Test privilege escalation powershell with arguments.bat" 1 2 3
I:\scripts>"i:\scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
All 3 work
I:\scripts>"i:scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
does not work The system cannot find the path specified.
This result tried twice, second time same result
   
 
Double click on I:\Test privilege escalation powershell with arguments.bat
Does not work, console flashes briefly and disappear too fast to see what the error message was
It should pause, but doesn't !
 
Double clicking on I:\scripts\Test privilege escalation powershell with arguments.bat
works https://i.imgur.com/lFMD2MI.png
 
Drag and dropping a bunch of files onto I:\scripts\Test privilege escalation powershell with arguments.bat
works, dropped files are arguments https://i.imgur.com/nUXgWbA.png https://i.imgur.com/PtMT91d.png
 
Drag and dropping files onto 
https://i.imgur.com/AMMPXzf.png
Does not work, console flashes briefly and disappear too fast to see what the error message was
It should pause, but doesn't !
 
In a PRIVILEGE console
 
C:\Windows\system32>"i:Test privilege escalation powershell with arguments.bat" 1 2 3
C:\Windows\system32>"i:\Test privilege escalation powershell with arguments.bat" 1 2 3
C:\Windows\system32>"i:\scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
C:\Windows\system32>"i:scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
All 4 work https://i.imgur.com/60owFpJ.png
 
C:\>"i:Test privilege escalation powershell with arguments.bat" 1 2 3
C:\>"i:\Test privilege escalation powershell with arguments.bat" 1 2 3
C:\>"i:\scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
C:\>"i:scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
All 4 work  https://i.imgur.com/sgT3EUx.png
 
D:\>"i:Test privilege escalation powershell with arguments.bat" 1 2 3
D:\>"i:\Test privilege escalation powershell with arguments.bat" 1 2 3
D:\>"i:\scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
D:\>"i:scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
All 4 work  https://i.imgur.com/TJyNGy4.png
 
I:\>"i:Test privilege escalation powershell with arguments.bat" 1 2 3
I:\>"i:\Test privilege escalation powershell with arguments.bat" 1 2 3
I:\>"i:\scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
I:\>"i:scripts\Test privilege escalation powershell with arguments.bat" 1 2 3
All 4 work  https://i.imgur.com/S1mxGsF.png

Итак, мой вопрос: почему этот скрипт ведет себя по-разному в зависимости от того, откуда он вызывается, где он находится и как (i:\filename.bat против i:filename.bat). Тоже этот случай, когда вроде все было так же, а результат был не тот.

Наконец, моя цель — превратить этот скрипт в повторно используемую подфункцию, и она должна быть в следующем формате.

@echo off
 
Call :IsAdmin IsAdmin
if not %IsAdmin%==true Call :Elevate %*
 
if %IsAdmin%==true echo Admin privileges found
if %IsAdmin%==true echo First argument is "%~1"
if %IsAdmin%==true echo Second argument is "%~2"
if %IsAdmin%==true echo third argument is "%~3"
if %IsAdmin%==true echo fourth argument is "%~4"
if %IsAdmin%==true echo fifth argument is "%~5"
if %IsAdmin%==true echo sixth argument is "%~6"
if %IsAdmin%==true echo seventh argument is "%~7"
if %IsAdmin%==true echo eigth argument is "%~8"
if %IsAdmin%==true echo nineth argument is "%~9"
if %IsAdmin%==true pause
 
:END
GoTo :EOF
 
:IsAdmin
  set %1=false
  net session >nul 2>&1
  if %ERRORLEVEL% == 0 set %1=true
GoTo :EOF
 
:Elevate
set args=%*
if defined args set args=%args:^=^^%
if defined args set args=%args:<=^<%
if defined args set args=%args:>=^>%
if defined args set args=%args:&=^&%
if defined args set args=%args:|=^|%
if defined args set "args=%args:"=\"\"%"
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
  " Start-Process -Wait -Verb RunAs -FilePath cmd -ArgumentList \"/c \"\" cd /d \"\"%CD% \"\" ^&^& \"\"%~f0\"\" %args% \"\" \" "
exit /b
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
75
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема возникает, когда пакетный файл вызывается из корневого каталога диска, потому что %CD% затем расширяется до значения, которое заканчивается на \, что нарушает синтаксический анализ командной строки PowerShell, поскольку он мешает экранированному " (\"), который следует за ним. .

Прагматичный обходной путь — просто добавить пробел перед следующим \", что все еще работает, потому что cmd.exe игнорирует конечные пробелы в путях файловой системы:

Другими словами: замените %CD%\" на %CD% \"

Я также обновил связанный ответ соответственно.


Что касается вашего желания разбить код на модули с помощью подпрограмм, которые вы вызываете с помощью call, включая размещение повышающего вызова powershell.exe в подпрограмме Elevate:

  • Не пытайтесь передавать аргументы через %* в подпрограмму :Elevate. Вместо этого запишите их в переменную на верхнем уровне командного файла, которую подпрограмма также увидит и сможет с ней работать.

  • Причина, по которой следует избегать передачи аргументов %* через call, заключается в том, что это неизбежно и необъяснимо заставляет cmd.exe удваивать любые ^ символы в аргументах.

    • Эта давняя ошибка, которая вряд ли будет исправлена, подробно описана в разделе «Этап 6) Обработка CALL/Удвоение каретки» в этом ответе, в котором подробно описывается синтаксический анализ cmd.exe и его особенности.

Вот упрощенная версия вашего кода:

  • Обратите внимание на упрощение подпрограммы :IsAdmin для использования кода выхода из команды net session для сообщения об успехе (0) и отказе (отличном от нуля), что позволяет оператору || (а также &&) работать с этим кодом выхода.

  • Вызов без повышенных прав запускает воплощение с повышенными правами и ожидает его завершения, а затем завершает работу. Это означает, что любой код после строки, начинающейся с call :IsAdmin ..., выполняется только в воплощении с повышенными правами.

@echo off & setlocal
 
:: If not already running elevated, self-elevate and exit.
:: Note: A helper variable must be used to capture %*,
::       because passing %* to a subroutine doubles ^ chars.
call :IsAdmin || set args=%* && (call :Elevate & exit /b)

:: Getting here means this is (now) an elevated session.

::Print the arguments received.
echo Now running elevated; arguments received:
echo.  %*
pause

:: End of the main body. 
goto :EOF

:: === Helper subroutines

:: Test if this session is elevated.
:: `net session` only succeeds and therefore reports exit code 0 
:: in an elevated session.
:IsAdmin
  net session >NUL 2>&1
goto :EOF
 
 :: Perform self-elevation, passing all arguments through.
:Elevate
  if defined args set args=%args:^=^^%
  if defined args set args=%args:<=^<%
  if defined args set args=%args:>=^>%
  if defined args set args=%args:&=^&%
  if defined args set args=%args:|=^|%
  if defined args set "args=%args:"=\"\"%"
  :: Note: 
  ::  * To not make the non-elevated incarnation wait for the
  ::    elevated one to complete, remove -Wait      
  ::  * To keep the elevated session open until explicitly exited by the user,
  ::    use /k instead of /c
  powershell -NoProfile -ExecutionPolicy Bypass -Command ^
    " Start-Process -Wait -Verb RunAs -FilePath cmd -ArgumentList \"/c \"\" cd /d \"\"%CD% \"\" ^&^& \"\"%~f0\"\" %args% \"\" \" "
goto :EOF

Как в сторону:

  • Обычно переменные среды наследуются дочерними процессами, и, учитывая, что все переменные cmd.exe (созданные с помощью SET) неизменно являются переменными среды, существует по крайней мере гипотетическая озабоченность по поводу «загрязнения» среды дочернего процесса вспомогательными переменными от вызывающей стороны (в в данном случае %args%).

  • Хотя это можно было бы решить в целом, в данном случае в этом нет необходимости, потому что дочерние процессы с повышенными правами — из соображений безопасности — не наследуют среду своего (не повышенного) вызывающего объекта.

О, подождите, на самом деле set args=%args:^^^^=^^% не работает ... Ну, только частично, хммм. Я подумал, что было бы неплохо иметь только Call :Elevate %* в качестве одной команды. Я полагаю, что могу вызвать IsAdmin из функции :Elevate и даже больше не нуждаться в IF

Shodan 22.04.2023 09:19

Из чтения статьи о разборе cmd.exe я вижу, что для аргументов без кавычек и кавычек автоматически удваиваются только аргументы в кавычках. Таким образом, потребуется код, чтобы определить части %*, которые указаны в кавычках, и применить дедублирование каретки только к этим частям.

Shodan 22.04.2023 09:35

И в настоящее время, с set args=%args:^^^^=^^% , почему одна каретка удваивается, но не удваивается. Да, четыре каретки, превратиться в восемь кареток, а затем удвоиться до четырех. Почему set args=%args:^^^^=^^% несовместим?

Shodan 22.04.2023 09:36

@Shodan, я не думаю, что вы сможете отменить логику удвоения во всех случаях, и я предлагаю вообще обойти ее, используя aux. переменная. Пожалуйста, посмотрите мое обновление, которое теперь использует одну строку в основном теле и упрощает вашу подпрограмму :IsAdmin.

mklement0 22.04.2023 23:55

О, вау, я люблю это! Я не знал, как напрямую использовать вывод подпрограммы, как вы сделали с IsAdmin, это будет очень полезно! Я думаю, что это в значительной степени идеально, единственное изменение, которое я собираюсь внести в свою приватную версию, это то, что я собираюсь вызвать args ElevatedArgs, чтобы сделать его уникальным именем переменной. Хотя это не должно иметь значения, как вы указали, локальные переменные теряются на высоте. Но таким образом вам даже не нужно спрашивать себя: "имеет ли значение, если я использовал аргументы в другом месте"

Shodan 23.04.2023 03:24

Да, я принимаю ответ, я также хочу убедиться, что каждый, кто ищет в Google «как поднять мой командный файл», найдет этот ответ, я искал повсюду, и я думаю, что это лучший, если вы пытаетесь сделать это чисто. Я также нашел другие методы повышения привилегий, такие как использование runas, а также создание vbscript, который повторно запускает пакетный файл с повышенным процессом. Я попытаюсь сформулировать вопрос, который сделает его номером 1 в Google, а также представлю все альтернативы.

Shodan 24.04.2023 03:43

Другие вопросы по теме