通过 telegram bot 监控设备的远程登录情况

之前我先后白嫖了 azure 的 windows server,以及做了 zerotier 用于远控,但前者我提过 3389 端口老是被撞,后者要通过密码和 zerotier 网域两重保险,应该够安全了,但毕竟是把我的主用设备暴露出去,还得更安全一点才行。
我听说有些脚本可以登录时从 telegram bot 通知所有者,找了一下,ssh 的和 rdp 的都有,那就一起上了。

工具:

前期准备

参考:Telegram Bot 控制 Aria2 下载并自动上传到 Google Drive、OneDrive - P3TERX ZONE

创建 bot,获取 bot token

访问 telegram bot 管理 bot @botfather,通过三个步骤就能获得一个 bot:

  1. 输入 /newbot,会询问你 bot 起什么昵称(即 tg 窗口左上角的名字),按自己喜好起就行。
  2. 回车后,会询问你 bot 想起一个什么用户名。以后可以通过用户名来直接找到这个 bot。需要以 Bot 或者 _bot 结尾,同时不可以和已有的 bot 名字冲突,所以这里要起复杂一点。
  3. 然后就能从机器人的回答中获得一串字体颜色为黄色的长长一串 token 了。 顺便回答里面 You will find it at 后面的蓝色链接可以直接通向创建的机器人,先过去 /start 一下,以免待会还要回来找。监测几个 ssh/rdp 就要建立几个 bot,可以建一个,做完建立提醒步骤后再建,也可以先一次建一堆(因为我看 botfather 这边有批量建立的功能,不过我没用过)。

获取 userid

进入刚刚获取的其中一个 bot,随便输点东西。

然后在浏览器中访问 https://api.telegram.org/bot<bot_token>/getUpdates,不同的 bot,bot token 不一样,别填错了。

不出意料的话,result 中 id 后面跟的数字就是账号的 userid。userid 每个 telegram 账号唯一,获取过一次就不用再获取了。

如果 result 为空,证明离上次和 bot 互动时间相隔太久,重新去 bot 里再输点东西就好。

获取 chatid

参考:Telegram Bot - how to get a group chat id? - Stack Overflow

仅 rdp 登录提醒需要(因为我找到的 rdp 提醒脚本只能在群内提醒,没法在 bot 里面直接提醒)。

  1. 把相应 bot 拉入群中。

  2. 在群中发一句

    1
    /my_id @my_bot
  3. 访问 https://api.telegram.org/bot<bot_token>/getUpdates,在 chat 这个代码块的 id,就是 chatid(带个负号的很显眼)

chatid 每个群唯一,所以也获取一次,然后把所有 rdp 监测 bot 拉到同一个群中就好了。就是建群还需要好友配合这点比较烦(实在不行办个小号呗)。

linux ssh 登录提醒

  1. 从参考文章 1 中下载或者复制粘贴源码得到 telegram-alert.sh

  2. 修改其中的

    1
    2
    3
    4
    5
    6
    # Your USERID or Channel ID to display alert and key, create a new bot with @BotFather on Telegram
    # Ask to @IDBot for your id (/getid)
    USERID="********"
    # Create a new bot with @BotFather and start a new discussion with it
    KEY="*********:***********************************"
    URL="https://api.telegram.org/bot${KEY}/sendMessage"

    key 就是 bot token,把我们前期准备获取的两个值填进去。

  3. telegram-alert.sh 放到被检测机 usr/local/bin 里,加权限

    1
    chmod +x /usr/local/bin/telegram-alert.sh
  4. /etc/pam.d/sshd 新增 session optional pam_exec.so type=open_session seteuid /usr/local/bin/telegram-alert.sh

    1
    echo "session optional pam_exec.so type=open_session seteuid /usr/local/bin/telegram-alert.sh" >> /etc/pam.d/sshd
  5. (可选)重启 sshd

    1
    service sshd restart

如果是开启 SELinux 的系统(如 centos),参考文章后面还有两部,我用的是 debian 就不写上来了。

rdp 登录提醒

  1. 从参考文章 1 中下载或者复制粘贴源码得到 rdp-telegram.ps1

  2. 修改其中的

    1
    2
    $botToken = 'ADD UR TOKEN HERE'
    $chatID = 'ADD UR CHAT ID HERE'

    把我们前期准备获取的两个值填进去。

  3. rdp-telegram.ps1 放到被检测机里一个好找的地方,我就直接放到我的 user 目录下了 C:\Users\zbttl

  4. 按下 win 键,敲入「事件查看器」并打开

  5. 找到应用程序和服务日志 -> Microsoft -> Windows -> TerminalServices-RemoteConnectionManager。

  6. 新一点的系统,比如 win10,登录过 rdp 的话在 Admin 这项里面会有 20521 这项代表已登录成功的日志

    旧一些的,比如 windows server 2012 可能就没有。不过旧系统在 operational 这里会有类似 1149 的记录,同样是代表登录成功。

    哪个都可以,参考文章中提到的是前一个,然后我发现前一个如果用微软商店的第三方 rdp(名字就叫远程桌面,系统自带的远程桌面遇到屏幕分辨率不一样的情况会拉跨),日志中没提示,所以自行选择。

    右键其中一个包含上面提到的这两种其中一种的记录选择「将任务附加到此事件」。在打开的窗口中,创建基本任务的名字随便取,然后一路下一步来到「启动程序」这一项。程序或脚本,填入 POWERSHELL;添加参数(可选)填入 rdp-telegram.ps1 所在路径(记得打引号),对我来说那就是 "C:\Users\zbttl\rdp-telegram.ps1"

  7. 完成后,再次按下 win 键,搜索任务计划程序,打开,在任务计划程序库 -> 事件查看器任务处,就能看到我们刚刚创建的任务。选择那个任务,点右侧的属性,在弹出的窗口中看到常规 -> 安全选项,勾选「使用最高权限运行」。

    不进行这一步的话,待会在 telegram 群虽然会弹通知,但通知中各项属性的值都是空:

    如果显示操作参数错误的话,把上面「只在用户登录时运行」改为「不管用户是否登录都要运行」,然后输入本机账号密码即可。

    另外还建议在设置 -> 如果此任务已运行,改为「停止现有实例」或者「并行运行新实例」,以免网络原因导致前面的任务运行不成功一直卡着。

  8. 因为被监控机在国内,要给 telegram 发东西的话,你懂得,记得还得是全局代理才行。

补充

两个问题:

  1. 开 rdp 的时候能看见一个 cmd 框框弹出。万一攻击者看到这个框框眼疾手快关掉了,程序没跑完那通知不就过不来了。
  2. 我不赞成时时刻刻开着全局代理。

解决方法:

参考

rdp-telegram.ps1 同目录下新建一个 rdp.js 文件。文件内容类似于:

1
2
var wshShell = new ActiveXObject("WScript.Shell"); 
wshShell.Run('%SystemRoot%\\system32\\WindowsPowerShell\\v1.0\\powershell.exe -ExecutionPolicy Bypass -File "C:\\\Users\\zbttl\\rdp-telegram.ps1"', 0, false);

用火绒的,把这个文件加到火绒的信任区里(这都能被当成病毒文件可还行)。

修改计划任务。回到上面第七步,找到操作,双击启动程序项,程序与脚本修改为 wscript,添加参数修改为 rdp.js 地址,如 "C:\Users\zbttl\rdp.js"

修改 rdp-telegram.ps1,加入两行

1
2
[system.net.webrequest]::defaultwebproxy = new-object system.net.webproxy('[代理地址]')
[system.net.webrequest]::defaultwebproxy.BypassProxyOnLocal = $true

代理地址这里,格式为 http://127.0.0.1:7890 这样。

即可。

(这样设置和全局代理也不冲突,不用担心 loopback)

(21.4.2 更新) vps 上的 windows server 中无需关心代理问题,也不需要进计划任务中开启管理员模式运行。不过又出现了限制网址访问的问题。具体来说是这样,开 ie 浏览网页的时候经常就会弹这个网页不在信任列表中,是否加入信任列表并访问。对于我们的 ps1 脚本来说,就需要把其中的 *.telegram.org 加入信任列表中,否则就连不上 api 发不出讯息。