text: # Author:
  #  Romain Bentz (pixis - @hackanddo)
  # Website:
  #  https://beta.hackndo.com [FR]
  #  https://en.hackndo.com [EN]
  
  # Based on Impacket atexec implementation by @agsolino
  # https://github.com/SecureAuthCorp/impacket/blob/429f97a894d35473d478cbacff5919739ae409b4/examples/atexec.py
  
  import random
  import string
  import time
  
  from impacket.dcerpc.v5 import tsch, transport
  from impacket.dcerpc.v5.dtypes import NULL
  from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_GSS_NEGOTIATE
  
  
  class TASK_EXEC:
      def __init__(self, conn, log):
          self._conn = conn
          self._log = log
  
          stringbinding = r'ncacn_np:%s[\pipe\atsvc]' % self._conn.hostname
          self._rpctransport = transport.DCERPCTransportFactory(stringbinding)
  
          if hasattr(self._rpctransport, 'set_credentials'):
              self._rpctransport.set_credentials(self._conn.username, self._conn.password, self._conn.domain_name,
                                                self._conn.lmhash, self._conn.nthash, self._conn.aesKey)
              self._rpctransport.set_kerberos(self._conn.kerberos, self._conn.dc_ip)
  
      def execute(self, commands):
          dce = self._rpctransport.get_dce_rpc()
  
          dce.set_credentials(*self._rpctransport.get_credentials())
          if self._conn.kerberos:
              dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
          dce.connect()
          dce.bind(tsch.MSRPC_UUID_TSCHS)
          xml = self.gen_xml(commands)
          tmpName = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(8))
          self._log.debug("Register random task {}".format(tmpName))
          tsch.hSchRpcRegisterTask(dce, '\\%s' % tmpName, xml, tsch.TASK_CREATE, NULL, tsch.TASK_LOGON_NONE)
          tsch.hSchRpcRun(dce, '\\%s' % tmpName)
          done = False
          while not done:
              resp = tsch.hSchRpcGetLastRunInfo(dce, '\\%s' % tmpName)
              if resp['pLastRuntime']['wYear'] != 0:
                  done = True
              else:
                  time.sleep(2)
  
          time.sleep(3)
          tsch.hSchRpcDelete(dce, '\\%s' % tmpName)
          dce.disconnect()
  
      def gen_xml(self, commands):
  
          return """<?xml version="1.0" encoding="UTF-16"?>
  <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
    <Triggers>
      <TimeTrigger>
        <StartBoundary>1989-09-17T02:20:00</StartBoundary>
        <Enabled>true</Enabled>
      </TimeTrigger>
    </Triggers>
    <Principals>
      <Principal id="LocalSystem">
        <UserId>S-1-5-18</UserId>
        <RunLevel>HighestAvailable</RunLevel>
      </Principal>
    </Principals>
    <Settings>
      <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
      <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
      <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
      <AllowHardTerminate>true</AllowHardTerminate>
      <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
      <IdleSettings>
        <StopOnIdleEnd>true</StopOnIdleEnd>
        <RestartOnIdle>false</RestartOnIdle>
      </IdleSettings>
      <AllowStartOnDemand>true</AllowStartOnDemand>
      <Enabled>true</Enabled>
      <Hidden>true</Hidden>
      <RunOnlyIfIdle>false</RunOnlyIfIdle>
      <WakeToRun>false</WakeToRun>
      <ExecutionTimeLimit>P3D</ExecutionTimeLimit>
      <Priority>7</Priority>
    </Settings>
    <Actions Context="LocalSystem">
      {}
    </Actions>
  </Task>
  """.format(self.gen_commands(commands))
  
      def gen_commands(self, commands):
          ret = ""
          for command in commands:
              ret += """
       <Exec>
        <Command>cmd.exe</Command>
        <Arguments>/C {}</Arguments>
       </Exec>""".format(command)
  
          return ret
  