1

Why does the command break when I try to pipe a yes reply with echo in subprocess, but works perfectly fine when I manually enter it into the command prompt?

Notice I tried with and without spacing and the results are the same, but if you put either EXACTLY as you see it into command prompt, it works instead of giving the error

WindowsError: [Error 2] The system cannot find the file specified


Python Interpreter Output

C:\Windows\System32>python
Python 2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016, 20:42:59) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> p = subprocess.Popen("echo y|cacls {0} /d SYSTEM".format("C:\\ProgramData\\Microsoft\\Diagnosis\\ETLLogs\\AutoLogger\\AutoLogger-Diagtrack-Listener.etl", stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\subprocess.py", line 390, in __init__
    errread, errwrite)
  File "C:\Python27\lib\subprocess.py", line 640, in _execute_child
    startupinfo)
WindowsError: [Error 2] The system cannot find the file specified
>>> p = subprocess.Popen("echo y|cacls {0} /d SYSTEM".format("C:\ProgramData\Microsoft\Diagnosis\ETLLogs\AutoLogger\AutoLogger-Diagtrack-Listener.etl", stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\subprocess.py", line 390, in __init__
    errread, errwrite)
  File "C:\Python27\lib\subprocess.py", line 640, in _execute_child
    startupinfo)
WindowsError: [Error 2] The system cannot find the file specified
>>> p = subprocess.Popen("echo y| cacls {0} /d SYSTEM".format("C:\\ProgramData\\Microsoft\\Diagnosis\\ETLLogs\\AutoLogger\\AutoLogger-Diagtrack-Listener.etl", stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\subprocess.py", line 390, in __init__
    errread, errwrite)
  File "C:\Python27\lib\subprocess.py", line 640, in _execute_child
    startupinfo)
WindowsError: [Error 2] The system cannot find the file specified
>>> p = subprocess.Popen("cacls {0} /d SYSTEM".format("C:\\ProgramData\\Microsoft\\Diagnosis\\ETLLogs\\AutoLogger\\AutoLogger-Diagtrack-Listener.etl", stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE))
>>> Are you sure (Y/N)?

Notice it works at the end when I remove the echo completely, but then I can never actually finish running it because it never gets the "yes" (echo y|) reply... and there isn't a /yes switch built into the command, unfortunately.

DeeJayh
  • 333
  • 3
  • 9
  • Did you run `whoami` from your parent process too for verification? `IsNTAdmin()` might not be aware of UAC. – kichik Apr 28 '17 at 01:05
  • @kichik no, actually, even running a Command Prompt as Administrator and then running python interpreter and doing `print os.popen("whoami").read();` or `print getpass.getuser()` both return User, rather than Administrator... So the fact that the parent process is Admin, doesn't affect child processes... That sucks. My question remains... Is there a way to call subprocesses using the elevation of the main process? – DeeJayh Apr 28 '17 at 05:21
  • That is not normal behavior. `CreateProcess` uses the current access token to create a new process, except a medium-integrity process will create a low-integrity process if the executable file security has a low-integrity label. – Eryk Sun Apr 28 '17 at 05:41
  • @eryksun what is not "normal behavior"? Is it not normal because it's not inheriting the elevation, or is it normal because it's not SUPPOSED to inherit elevated privileges? Are you trying to say it's working as expected and I'm mis-using it? `To your second comment:` I think you misunderstand what I'm doing. The question was vague, so I went ahead and edited the question, please read everything after "EDIT:" and let me know if you have any other questions. I'll be glad to answer them to figure it out. – DeeJayh Apr 28 '17 at 08:31
  • 1
    The expected, normal behavior is to inherit a copy of the parent's access token, so a process that's created by an elevated process should have high integrity, the administrators group enabled, and the full set of administrator privileges. – Eryk Sun Apr 28 '17 at 08:46
  • @eryksun ok thank you for elaborating, re-writing it simplified with step by step output shows success, so I guess I just screwed something up and now need to go back over ever piece of code leading up to the bad call. You can see my success in the new "EDIT 2:" – DeeJayh Apr 28 '17 at 08:47
  • Why do you use the old `cacls` program to deny SYSTEM access? It seems like you could do all of this using `icacls`, including setting the owner via `/setowner` since it's originally owned by the administrators group. – Eryk Sun Apr 28 '17 at 08:56
  • @eryksun straight from the commands help: ICACLS name /setowner user [/T] [/C] [/L] [/Q] changes the owner of all matching names. This option does not force a change of ownership; use the takeown.exe utility for that purpose. – DeeJayh Apr 28 '17 at 09:44
  • 1
    Not forcing it means it doesn't enable `SeTakeOwnerShipPrivilege`, which allows an administrator to take ownership of a file regardless of the DACL. But I confirmed it will work in this case. The file is already owned by the administrators group, and you're in that group with full control. You have the right to take ownership. – Eryk Sun Apr 28 '17 at 09:49
  • @eryksun so it turns out it's an issue with the ECHO... Idk why, but here's a gist with the output from an interpreter. Completely rewriting and changing the question, as everything else is working perfectly, it's this echo that's the issue with subprocess... https://gist.github.com/Ruined1/4932d2696fa5b5ee8e3cb8188b2dbe70 Please see revised question – DeeJayh Apr 28 '17 at 10:30
  • I overlooked that you're using a shell command without passing `shell=True`. That said, you should be using `icacls` for this anyway. – Eryk Sun Apr 28 '17 at 10:42
  • @eryksun if you want to do the work for me, whats the icacls alternative to `echo y|cacls file /d SYSTEM` Also, thank you, shell=True fixed the piping issue. Order has been restored and it's working. – DeeJayh Apr 28 '17 at 10:48
  • `cmd_setowner = 'icacls.exe "{}" /setowner "{}"'.format(filepath, os.environ['USERNAME'])` (or use `takeown`). `cmd_setdacl = 'icacls.exe "{}" /inheritance:r /deny SYSTEM:F /grant Administrators:F'.format(filepath)`. – Eryk Sun Apr 28 '17 at 11:08
  • @eryksun I lied, it's still not working even with shell=True, returning error code 2 (file not found). still works fine without the `echo y|` but that kind of defeats the purpose. – DeeJayh Apr 28 '17 at 11:08
  • `'icacls.exe "{}" /inheritance:r /deny SYSTEM:F /grant Administrators:F'.format(filepath)` passed gives the same error code 2 (file not found) and as a precursor, yes I reworked it to fit my code. The command ends up being `icacls C:\ProgramData\Microsoft\Diagnosis\ETLLogs\AutoLogger\AutoLogger-Diagtrack-Listener.etl /inheritance:r /deny SYSTEM:F /grant Administrators:F` and of course if I run that command manually through the command prompt it works great... I'm so confused. – DeeJayh Apr 28 '17 at 11:13
  • Hmm.. echoing in the shell command worked fine for me using `p = subprocess.Popen("echo y|cacls {0} /d SYSTEM".format(filepath), stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, shell=True)`. – Eryk Sun Apr 28 '17 at 11:16
  • @eryksun I rewrote the code from scratch, it's working now. No idea what happened, but it's 7:38 AM here, I haven't been to sleep yet, and the problem is solved so that's good enough for me. Thank you again! – DeeJayh Apr 28 '17 at 11:38

1 Answers1

1

Looks like this problem is similar to this: How to use Subprocess in Windows

"echo" is not program, but built-in functionality for shell, so directive "shell=True" is needed for correct functionality, so your command should be:

p = subprocess.Popen("echo y|cacls {0} /d SYSTEM".format("C:\\ProgramData\\Microsoft\\Diagnosis\\ETLLogs\\AutoLogger\\AutoLogger-Diagtrack-Listener.etl", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE))

That is also reason for errors (because of echo) and because cacls is program, then it runs after generating errors (without echo y| that you needed)

Matej Ridzon
  • 86
  • 1
  • 3