使用 powershell 进行批处理文件自动提升,并且不处理参数,但调用有问题

Batch file auto-elevation using powershell and not mangling the arguments but problem with invokation

提问人:Shodan 提问时间:4/18/2023 最后编辑:mklement0Shodan 更新时间:4/23/2023 访问量:116

问:

我正在尝试实现

mklement0 关于这个答案

我的目标是将其实现为可重用的批处理子函数

但在此之前,我遇到了一种不一致的行为模式

主要取决于脚本的调用方式、脚本的位置以及调用位置

如果从文件夹调用该脚本,并且该脚本也位于文件夹中,则该脚本通常有效。 但是,如果从驱动器的根目录调用它,它可能会失败,并出现有关&&管道的错误。

为了记录行为,我将脚本保存为文件

i:\Test privilege escalation powershell with arguments.bat

和 i:\script\Test 权限提升 powershell 带参数 .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 vs 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
PowerShell 批处理文件 转义 引用提升 的权限

评论


答:

2赞 mklement0 4/19/2023 #1

当批处理文件恰好从驱动器的根目录调用时,会出现此问题,因为随后会扩展为 结尾的值,这会中断 PowerShell 的命令行分析,因为它会干扰它后面的转义 ()。%CD%\"\"

一种实用的解决方法是简单地在以下内容之前附加一个空格,这仍然有效,因为会忽略文件系统路径中的尾随空格:\"cmd.exe

换言之:改为%CD%\"%CD% \"

我还相应地更新了链接的答案。


至于你希望用你调用的子例程来模块化代码,包括将提升调用放在子例程中:callpowershell.exeElevate

  • 不要试图将参数传递给子例程。相反,将它们捕获在批处理文件顶层的变量中,子例程也可以看到并可以对其进行操作。%*:Elevate

  • 必须避免参数传递 via 的原因是,它总是 - 并且莫名其妙地 - 使参数中的任何 ^ 字符加倍%*callcmd.exe

    • 这个长期存在的错误,不太可能得到修复,在本答案的“第 6 阶段)CALL 处理/插入符号加倍”下进行了详细描述,其中详细描述了 的解析及其怪癖。cmd.exe

下面是代码的简化版本:

  • 请注意,子例程的简化是使用命令中的退出代码来传达成功 () 与失败 (非零) ,这使操作员(以及 )能够对该退出代码进行操作。:IsAdminnet session0||&&

  • 非提升的调用启动提升的化身并等待其完成,然后退出。这意味着以 开头的行之后的任何代码都只会在提升的化身中执行。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.exeSET%args%

  • 虽然这通常可以解决,但这里没有必要这样做,因为提升的子进程(出于安全原因)不会继承其(非提升的)调用方的环境。

评论

0赞 Shodan 4/22/2023
我在所有排列中都运行了上面的脚本,它的工作原理 pastebin.com/bqATQFkv 但是,它会总是将卡雷特加倍吗?因为如果是,如果定义了 args set args=%args:^^^^=^^%,那么添加到函数中呢,我刚刚测试过,它也可以 i.imgur.com/g09GIbv.png
0赞 Shodan 4/22/2023
哦等等,实际上设置args=%args:^^^^=^^%不起作用......嗯,只有部分嗯。我认为将 Call :Elevate %* 作为单个命令会很好。我想我可以从 :Elevate 函数内部调用 IsAdmin,甚至不再需要 IF
0赞 Shodan 4/22/2023
我从阅读 cmd.exe 解析文章中看到,对于未带引号和带引号的参数,只有带引号的参数会自动加倍。因此,需要代码来确定引用的 %* 部分,并且仅对这些部分应用插入符号加倍。
1赞 Shodan 4/23/2023
哦,哇,我喜欢这个!我不知道如何像使用 IsAdmin 那样直接使用子例程的输出,这将非常有用!我认为这非常完美,我要对我的私人版本进行的唯一更改是我将调用 args ElevatedArgs 以使其成为唯一的变量名称。尽管正如您指出的那样,这应该无关紧要,但局部变量在高程中丢失了。但这样一来,你甚至不必问自己“如果我在其他地方使用参数有关系吗”
1赞 Shodan 4/24/2023
是的,我接受这个答案,我也想确保每个在谷歌上搜索“如何提升我的批处理文件”的人都能找到这个答案,我搜索了很多,我认为如果你试图干净利落地做到这一点,我认为这是最好的。我还发现了其他权限提升方法,例如使用 runas 并创建一个 vbscript,该 vbscript 使用提升的进程重新启动批处理文件。我将尝试提出一个问题,该问题将进入谷歌的#1,并提出所有替代方案。