Skip to content

Commit

Permalink
[3.0.16] Fix: Add user script arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
mauricelambert committed Sep 28, 2023
1 parent 208bba9 commit b24a494
Show file tree
Hide file tree
Showing 13 changed files with 752 additions and 3 deletions.
2 changes: 1 addition & 1 deletion PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: WebScripts
Version: 3.0.15
Version: 3.0.16
Summary: This tool runs CLI scripts and displays output in a Web Interface.
Home-page: https://github.com/mauricelambert/WebScripts
Author: Maurice Lambert
Expand Down
2 changes: 1 addition & 1 deletion WebScripts.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: WebScripts
Version: 3.0.15
Version: 3.0.16
Summary: This tool runs CLI scripts and displays output in a Web Interface.
Home-page: https://github.com/mauricelambert/WebScripts
Author: Maurice Lambert
Expand Down
12 changes: 11 additions & 1 deletion WebScripts.egg-info/SOURCES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,14 @@ test/test.ini
test/test.json
test/modules/test.py
test/static/css/test.css
test/static/js/test.js
test/static/js/test.js
tests/test_RCE.py
tests/test_api.py
tests/test_dos_length.py
tests/test_enfant.py
tests/test_enfant2.py
tests/test_enfant3.py
tests/test_multiple_stdout.py
tests/test_parent.py
tests/test_parent2.py
tests/test_parent3.py
57 changes: 57 additions & 0 deletions tests/test_RCE.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from urllib.request import urlopen, Request
from json import dumps, loads


def send_RCE(injection):
body["arguments"]["--names"]["value"] = test
response = urlopen(
Request(
"http://127.0.0.1:8000/api/scripts/view_users.py",
method="POST",
headers={"Authorization": "Basic QWRtaW46QWRtaW4="},
data=dumps(body).encode("latin-1"),
)
)

print(f"[+] Injection: {injection}")
print(f"[*] Response: {loads(response.read())}")


tests_RCE = [
[";", "cat", " ", "/etc/passwd"],
["|", "cat", " ", "/etc/passwd"],
["&&", "cat", " ", "/etc/passwd"],
["\n", "cat", " ", "/etc/passwd"],
["&&", "cat", " ", "/etc/passwd", "&&"],
[";", "cat", " ", "/etc/passwd", ";"],
["|", "cat", " ", "/etc/passwd", "|"],
[";", "cat", " ", "/etc/passwd", "|"],
["\n", "cat", " ", "/etc/passwd", "\n"],
["\\etc\\passwd"],
[".|./.|./.|./.|./.|./.|./.|./.|./.|./.|./.|./.|./etc/passwd"],
["../../../../../../../bin/cat", " ", "/etc/passwd", "|"],
['"', ";", "system(cat /etc/passwd);"],
["`cat /etc/passwd`"],
[";", "system('cat /etc/passwd')"],
["&&", "system('cat /etc/passwd')"],
["|", "system('cat /etc/passwd')"],
["|", "system('cat /etc/passwd');"],
["perl", " ", "-e" '''"system('cat /etc/passwd');"''', "\n'"],
["/bin/cat", "/etc/passwd", "|", "'\n'"],
["/bin/cat", "/etc/passwd", "|'"],
['system("cat /etc/passwd")', ";", "die"],
['";cat /etc/passwd;echo "'],
]

body = {
"arguments": {
"--ids": {"value": "", "input": False},
"--names": {"value": "", "input": False},
}
}

print("[!] Start tests RCE (Remote Code Execution)... ")
for test in tests_RCE:
send_RCE(test)
send_RCE("".join(test))
print("[!] End.")
148 changes: 148 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
from urllib.request import urlopen, Request, HTTPError, URLError
from ssl import _create_unverified_context
from pprint import pprint
from json import load

###
# JSON RPC
###

try:
response = urlopen(
Request(
"http://127.0.0.1:8000/JsonRpc/JsonRpc/",
method="POST",
headers={"Authorization": "Basic QWRtaW46QWRtaW4="},
data=b'{"jsonrpc": "2.0", "id": 4, "method": "not"}',
)
)
except (HTTPError, URLError) as e:
response = e

print("Status", response.code, response.reason)
pprint(load(response))

try:
response = urlopen(
Request(
"http://127.0.0.1:8000/JsonRpc/JsonRpc/call",
method="POST",
headers={"Origin": "http://127.0.0.1:8000", "Authorization": "Basic QWRtaW46QWRtaW4=", "Content-Type": "application/json"},
data=b'{"jsonrpc": "2.0", "id": 1, "method": "call"}',
)
)
except (HTTPError, URLError) as e:
response = e

print("Status", response.code, response.reason)
pprint(load(response))

response = urlopen(
Request(
"http://127.0.0.1:8000/JsonRpc/JsonRpc/test_argument_list",
method="POST",
headers={"Origin": "http://127.0.0.1:8000", "Authorization": "Basic QWRtaW46QWRtaW4=", "Content-Type": "application/json"},
data=b'{"jsonrpc": "2.0", "id": 2, "method": "test_argument_list", "params": ["abc", 1, null, true]}',
)
)
pprint(load(response))

response = urlopen(
Request(
"http://127.0.0.1:8000/JsonRpc/JsonRpc/test_args_dict",
method="POST",
headers={"Origin": "http://127.0.0.1:8000", "Authorization": "Basic QWRtaW46QWRtaW4=", "Content-Type": "application/json"},
data=b'{"jsonrpc": "2.0", "id": 3, "method": "test_args_dict", "params": {"a": 2, "b": 3}}',
)
)
pprint(load(response))

exit()

###
# IP Spoofing
###

response = urlopen(
Request(
"https://127.0.0.1/api/",
method="GET",
headers={
"X-Forwarded-For": "0.0.0.0",
"Client-Ip": "1.1.1.1",
},
),
context=_create_unverified_context(),
)
pprint(loads(response.read()))

response = urlopen(
Request(
"http://127.0.0.1:8000/api/",
method="GET",
headers={
"X-Forwarded-For": "0.0.0.0",
"Client-Ip": "1.1.1.1",
},
)
)
pprint(loads(response.read()))

exit()

response = urlopen(
Request(
"http://127.0.0.1:8000/api/scripts/view_users.py",
method="POST",
headers={
"Api-Key": "AdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdmin",
},
)
)
pprint(loads(response.read()))

response = urlopen(
Request(
"http://127.0.0.1:8000/api/scripts/view_users.py",
method="POST",
headers={"Authorization": "Basic QWRtaW46QWRtaW4="},
data=b'{"arguments":{"--ids":{"value":[2],"input":false}}}',
)
)
pprint(loads(response.read()))
exit()

for a in range(5):
try:
response = urlopen(
Request(
"http://127.0.0.1:8000/api/scripts/password_generator.py",
method="POST",
headers={"Authorization": "Basic VGVzdDp0ZXN0"},
)
)
print(f"{a}. 200 OK Test")
except Exception as e:
assert e.status == 403

response = urlopen(
Request(
"http://127.0.0.1:8000/api/scripts/view_users.py",
method="POST",
headers={"Authorization": "Basic QWRtaW46QWRtaW4="},
)
)
assert response.status == 200
print("1. 200 OK Admin")

response = urlopen(
Request(
"http://127.0.0.1:8000/api/scripts/view_users.py",
method="POST",
headers={
"Api-Key": "AdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdmin"
},
)
)
assert response.status == 200
print("2. 200 OK Admin")
17 changes: 17 additions & 0 deletions tests/test_dos_length.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from os import system, name

if name == "nt":
system("echo " + "a" * 8155) # OK
system("echo " + "a" * 8156) # NOK
# Documentation say: La longueur maximale de la chaîne que vous pouvez utiliser à l’invite de commandes est de 8 191 caractères
else:
system("getconf ARG_MAX")
system("xargs --show-limits </dev/null")

exit(0)

for a in range(1000, 8191):
b = system("echo " + "a" * a)
if b:
print(a)
break
9 changes: 9 additions & 0 deletions tests/test_enfant.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from os import environ, system
from time import sleep

sleep(1)
test = environ.get("Test")
system("echo %Test%")
print(f"test_enfant.py: {test}")
assert test is not None
input("End test_enfant.py...")
15 changes: 15 additions & 0 deletions tests/test_enfant2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from os import environ, system
from sys import stdin

test = environ.get("Test")
print(f"test_enfant2.py: {test}")
assert test is not None
print(len(input("first input:")))
# Affiche la première ligne, n'est pas limité en caractètres
# input("End test_enfant2.py...")

print(stdin.read()) # Récupère tous les inputs jusqu'a la fin

# system('test_enfant.py')
# le stdin du process est un PIPE mais n'est pas le même que celui de ce process
# il faut donc capturer l'input est faire un comunicate dans ce script
25 changes: 25 additions & 0 deletions tests/test_enfant3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from time import sleep
import sys

print("abc")
print("abc")
# sys.stdout.flush()
sleep(5)
# print(f"1: {input()}")
# sys.stdin.flush()
# sys.stdout.flush()
# print(f"2: {sys.stdin.read(1)}")
# print(f"2: {sys.stdin.read(1)}")
# print(f"2: {sys.stdin.read(1)}")
# print(f"2: {sys.stdin.read(1)}")
# print(f"2: {sys.stdin.read(1)}")
# print(f"2: {sys.stdin.read(1)}")
# print(f"2: {sys.stdin.read(1)}")
# print(f"2: {sys.stdin.read(1)}")
# print(f"2: {sys.stdin.read(1)}")
# print(f"3: {sys.stdin.read()}")
# sys.stdin.flush()
# sys.stdout.flush()
print("abc")
# sys.stdout.flush()
sys.exit(0)
41 changes: 41 additions & 0 deletions tests/test_multiple_stdout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from urllib.request import urlopen, Request
from pprint import pprint
from json import loads, dumps
from time import time, sleep

start = time()
response = urlopen(
Request(
"http://127.0.0.1:8000/api/scripts/test_config.py",
method="POST",
headers={
"Api-Key": "AdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdminAdmin",
},
data=dumps(
{
"arguments": {
"test_i": {"value": "Admin", "input": True},
"select": {"value": "select", "input": False},
"--timeout": {"value": True, "input": False},
"password": {"value": ["Admin"], "input": False},
"select-input": {"value": "select", "input": True},
}
}
).encode(),
)
)
data = loads(response.read())
print(time() - start)
pprint(data)

while "key" in data:
response = urlopen(
Request(
f"http://127.0.0.1:8000/api/script/get/{data['key']}",
method="GET",
headers={"Authorization": "Basic QWRtaW46QWRtaW4="},
)
)
data = loads(response.read())
print(time() - start)
pprint(data)
8 changes: 8 additions & 0 deletions tests/test_parent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from os import system, environ
from threading import Thread

environ["Test"] = "Yes test is good !"
print(f"test_parent.py: {environ.get('Test')}")
Thread(target=system, args=("test_enfant.py",)).start()
environ["Test"] = "No is not good !"
system("test_enfant2.py")
12 changes: 12 additions & 0 deletions tests/test_parent2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from subprocess import run, Popen, PIPE
from threading import Thread
from os import environ

environ1 = {**environ}
environ2 = {**environ} # if not environ in env: Python fatal error
environ1["Test"] = "Yes test is good !"
environ2["Test"] = "No is not good !"

# Thread(target=run, args=(["python", "test_enfant.py"],), kwargs={"env": environ1}).start()
process = Popen(["python", "test_enfant2.py"], stdin=PIPE, env=environ2)
process.communicate(input=b"a" * 70000 + b"\na\na\na\xf4\xc3\xb4")
Loading

0 comments on commit b24a494

Please sign in to comment.