Let’s put all the components from Part1, Part2, and Part3 together and execute the PowerShell script to see what will happens and how the Telegram Messenger client can interact with PowerShell Telegram Bot. Note that you can use -Verbose to see a detailed log on console on what is going on.
Table of Contents
Required Parameters for Telegram PowerShell bot
The Telegram PowerShell bot script requires the following parameter to start interacting with the Telegram APIs, if you don’t know where these parameters come from, maybe you can go and check the previous posts.
- Token: the HTTP API Token
- PassPhase: A text that will be send from the Telegram Messenger client to authenticate. Consider it as the password.
- FirstName: The Telegram messenger client user first name.
- Lastname: The Telegram messenger client last name.
- AllowedCommands: A text file contains all the allowed whitelist PowerShell commands.
You can get the first name and the last name information by sending a message to your bot and check the /getUpdate endpoint.
.\Telegram.ps1 -Token -PassPhrase -FirstName -LastName -Verbose
#I did not use the -AllowedCommands Yet, will use it later
Hit enter and let the fun begin. You will notice that the application start a loop of checking incoming message with a No authentication made, or Auth Failure. This is OK as the script is waiting for the authentication message, which is the pass-phrase we set.
The first message in the session must be the passphrase.
Let’s try to send a dummy message and see what will happen.
You will notice that there is no response at all, and even in the console the No Authentication made, or auth Failure… will continue to loop as the first message must be the passphrase we set, don’t forget other parameters which also should match such the first name and last name.
Authentication success
let’s send the correct passphrase $uperM@n and see what will happens.
The Passphrase stored in the memory and passed through the parameter
let’s try to send some commands. For example, Get-Process explorer
The command was executed, and the result is prepared in JSON format and sent to the Client
Keep in mind that there is a limit of 4K Characters send or receive per message, don’t exceed this otherwise you will get an error. So try to limit your command result by using filters ( Select, Where, Filter…).
Using the AllowedCommands
PowerShell parameter
Now we need to set a limit on which commands are considered as safe and its OK for the script to execute after authentication.
.\Telegram.ps1 -Token '1418701162:AAEIklEHZowjxorXL6VNfgzV54CmnPoUa3c' -PassPhrase '$uperM@n' -FirstName Faris -LastName Malaeb -AllowedCommands C:\Telegram\AllowedCommands.txt -Verbose
The Content of the C:\Telegram\AllowedCommands.txt is just a list of cmdlets that its OK to execute, for this example I will use only 2 commands.
Lets start the script again and perform the required authentication and try to run PowerShell cmdlets outside the AllowedCommands scope
The user who sends the message won’t get a response back, no need.
Feel free to send /Disconnect
any time to end the session and un-authenticate yourself, aka Logoff :).
You can get the script from my Github repo, and also if you want you can send PR for updates.
Telegram PowerShell Bot Script
[cmdletbinding()]
param(
[parameter(Mandatory=$true)]$Token,
[parameter(Mandatory=$true)]$PassPhrase,
[parameter(Mandatory=$true)]$FirstName,
[parameter(Mandatory=$true)]$LastName,
[parameter(Mandatory=$false)]$AllowedCommands
)
#region Variables
$URL='https://api.telegram.org/bot{0}' -f $Token
$AcceptedSession=""
$LastUnAuthenticatedMessage=""
$lastexecMessageID=""
#endregion Variables
#region Function
Function FixTheStream {
param(
$Stream
)
Write-Verbose -Message "Fixing the stream, Text is stored in $($env:TMP)\TGPSMessages.txt"
$FixedResult=@()
$Stream | Out-File -FilePath (Join-Path $env:TMP -ChildPath "TGPSMessages.txt") -Force
$ReadAsArray= Get-Content -Path (Join-Path $env:TMP -ChildPath "TGPSMessages.txt") | where {$_.length -gt 0}
foreach ($line in $ReadAsArray){
$ArrObj=New-Object psobject
$ArrObj | Add-Member -MemberType NoteProperty -Name "Line" -Value ($line).tostring()
$FixedResult +=$ArrObj
}
Write-Verbose -Message "Done fixing the message, the return will be $($FixedResult)"
return $FixedResult
}
Function SendTGMessage{ #Send Message to Telegram Service
param(
$Messagetext,
$ChatID
)
Write-Verbose -Message "Preparing to send TG Message"
$FixedText=FixTheStream -Stream $Messagetext
$MessageToSend = New-Object psobject
$MessageToSend | Add-Member -MemberType NoteProperty -Name 'chat_id' -Value $ChatID
$MessageToSend | Add-Member -MemberType NoteProperty -Name 'text' -Value $FixedText.line
$JsonData=($MessageToSend | ConvertTo-Json)
Write-Verbose -Message "----------------- Message that will be sent ----------------"
Write-Verbose -Message $JsonData
Write-Verbose -Message " ---------------- End of Message ---------------------------"
Invoke-RestMethod -Method Post -Uri ($URL +'/sendMessage') -Body $JsonData -ContentType "application/json"
Write-Verbose -Message "Message should be sent"
}
Function ReadTGMessage{ #Read Incomming message
try{
$inMessage=Invoke-RestMethod -Method Get -Uri ($URL +'/getUpdates') -ErrorAction Stop
Write-Verbose -Message "Checking for new Messages $($inMessage.result[-1])"
return $inMessage.result[-1]
}
Catch{
Write-Host $_.exception.message -ForegroundColor red
return "TGFail"
}
}
Function IsAuthenticated{
param(
$CheckMessage
)
Write-Verbose -Message "Checking Authentication Function..."
if (($messages.message.date -ne $LastUnAuthenticatedMessage) -and ($CheckMessage.message.text -like $PassPhrase) -and ($CheckMessage.message.from.first_name -like $FirstName) -and ($CheckMessage.message.from.last_name -like $LastName) -and ($CheckMessage.message.from.is_bot -like $false)){
Write-Verbose -Message "Yes yes, Authenticated ...$($messages.message.chat.id)"
$script:AcceptedSession="Authenticated"
Write-Host "Auth Accepted..." -ForegroundColor Green
return $messages.message.chat.id
}
Else{
Write-Host "No Authentication made, or auth failure.." -ForegroundColor Red
return 0
}
}
Function CommandShouldBeExecuted {
Param(
$cmdlet
)
Write-Verbose -Message "Checking if the command is safe ..."
try{
if ($cmdlet -like "/disconnect"){
Write-Host "Bye Bye ..." -ForegroundColor Green
SendTGMessage -Messagetext "See You.. loging off" -ChatID $messages.message.chat.id
$script:AcceptedSession=$null
return 0
}
if (Test-Path $AllowedCommands){
$commands=Get-Content -Path $AllowedCommands
if (($commands |where {$_ -like ($cmdlet.split("")[0])}).count -gt 0) {
Write-Verbose -Message "Command is safe and can be executed"
return 1
}
Else{
Write-Verbose -Message "Not Accepted Command.. "
return 0
}
}
}
catch{
Write-Verbose -Message "Allowed list not found.. executing anything is accepted."
return 1
}
}
#endregion Function
Write-Host "Script is activated and will require authentication..."
Write-Host "Waiting for Authentication phrase..."
while ($true){
sleep 1
$messages=ReadTGMessage
if ($messages -like "TGFail"){
Write-Host "it seems we got a problem... lets wait for 10 seconds and then try again"
Write-Host "Maybe you need to check the authentication Key..."
sleep -Seconds 10
}
if (!($messages)){
Write-Host "No data to parse ... will sleep for a while :)"
}
Else{
if ($LastUnAuthenticatedMessage -like $null){
$LastUnAuthenticatedMessage=$messages.message.date
}
if (!($AcceptedSession)){
$CheckAuthentication=IsAuthenticated -CheckMessage $messages
}
Else{
if (($CheckAuthentication -ne 0) -and ($messages.message.text -notlike $PassPhrase) -and ($messages.message.date -ne $lastexecMessageID)){
Write-Verbose -Message "I got $($messages.message.text) and MessageID $($messages.message.message_id)"
$DoOrDie=CommandShouldBeExecuted -cmdlet $messages.message.text
if ($DoOrDie -eq 1){
try{
$Result=Invoke-Expression($messages.message.text) -ErrorAction Stop
Write-Host "The Output of the command was the following" -ForegroundColor Green
$Result
Write-Host "End of Execution--------------" -ForegroundColor Green
SendTGMessage -Messagetext $Result -ChatID $messages.message.chat.id
}
catch {
SendTGMessage -Messagetext ($_.exception.message) -ChatID $messages.message.chat.id
}
Finally{
$lastexecMessageID=$messages.message.date
}
}
}
}
}
}
Yes, we made it, hope you like it, I might do a video which walks through all the components and details
<– Control your Infrastructure using… Telegram Messenger (Part 1 – Create the Bot)
<– Control your Infrastructure using… Telegram Messenger (Part 2 – Send and Receive.)
<– Control your Infrastructure using… Telegram Messenger (Part 3 – Basic Security)
Control your Infrastructure using… Telegram Messenger (Part 4 – Execution)