--restore: значения в файлах настроек копии – по формату каждого поля
Имена в kit.env, kit-backup.env и install-result.env проверялись по белому
списку, а значения – нет: MTPROTO_INNER из чужой копии попадал в выражение
sed в kit (флаг e – выполнение команды). Теперь у каждого имени свой формат
(порты – цифры, пути – буквы и цифры, хосты, флаги – допустимые слова),
кавычки – только пустые (''), неверное значение – копия отклоняется.
kit: sed с портом MTProto – только если порт число. Тесты на все поля.
This commit is contained in:
@@ -43,6 +43,32 @@ def check(p):
|
||||
|
||||
PEM = b"-----BEGIN CERTIFICATE-----\nAA==\n-----END CERTIFICATE-----\n"
|
||||
|
||||
# Проверка файлов настроек – те же строки, что в --restore, после распаковки архива.
|
||||
FUNCS = "".join(re.search(r"^%s\(\) \{.*?^\}\n" % n, src, re.S | re.M).group(0) for n in ("safe_env", "env_get"))
|
||||
ENV_CHECK = src[src.index(' safe_env "$tmp/kit-backup.env"'):src.index(' python3 -c "import sqlite3')]
|
||||
ENVS = {
|
||||
"kit-backup.env": b"BACKUP_KIT_VERSION=1.2\nBACKUP_HOST=1.2.3.4\nBACKUP_SSL=ip\nBACKUP_DATE=2026-10-06\n",
|
||||
"etc/x-ui/install-result.env": b"XUI_USERNAME=abcDEF1234\nXUI_PASSWORD=Pass1234567890abcdef\nXUI_PANEL_PORT=31234\n"
|
||||
b"XUI_WEB_BASE_PATH=AbCdEf123456789012\nXUI_ACCESS_URL=https://1.2.3.4:31234/AbCdEf123456789012\n"
|
||||
b"XUI_API_TOKEN=tok_ABCdef0123456789\nXUI_DB_TYPE=sqlite\n",
|
||||
"etc/kit/kit.env": b"HOST=1.2.3.4\nLINK_HOST=1.2.3.4\nPANEL_ON=ip\nSUB_BASE=https://1.2.3.4/AbC123/\nSUB_PATH=/AbC123/\n"
|
||||
b"SUB_INTERNAL=10446\nSINGLE=yes\nMTPROTO_INNER=10445\n",
|
||||
}
|
||||
# kit.env 1.1.x: без LINK_HOST и PANEL_ON, подписка на своём порту.
|
||||
KIT_11 = b"HOST=1.2.3.4\nSUB_BASE=https://1.2.3.4:2096/AbC123/\nSUB_PATH=/AbC123/\nSUB_INTERNAL=2096\nSINGLE=no\nMTPROTO_INNER=''\n"
|
||||
|
||||
|
||||
def restore_env(over=None):
|
||||
files = dict(ENVS)
|
||||
files.update(over or {})
|
||||
p = archive([(k, v) for k, v in files.items()])
|
||||
out = tempfile.mkdtemp()
|
||||
r = subprocess.run(["python3", "-", p, out], input=CHECK, capture_output=True, text=True)
|
||||
if r.returncode:
|
||||
return r
|
||||
script = 'set -Eeuo pipefail\ndie() { echo "DIE: $*"; exit 1; }\n' + FUNCS + 'tmp=$1\n' + ENV_CHECK + 'echo ENV-OK\n'
|
||||
return subprocess.run(["bash", "-c", script, "t", out], capture_output=True, text=True)
|
||||
|
||||
|
||||
class Archive(unittest.TestCase):
|
||||
def test_good(self):
|
||||
@@ -74,6 +100,37 @@ class Archive(unittest.TestCase):
|
||||
self.assertNotEqual(check(archive([("etc/x-ui/../../tmp/x", b"x")])).returncode, 0)
|
||||
|
||||
|
||||
class RestoreEnv(unittest.TestCase):
|
||||
def test_good_12(self):
|
||||
r = restore_env()
|
||||
self.assertIn("ENV-OK", r.stdout, r.stdout + r.stderr)
|
||||
|
||||
def test_good_11(self):
|
||||
r = restore_env({"etc/kit/kit.env": KIT_11,
|
||||
"kit-backup.env": b"BACKUP_KIT_VERSION=1.1.2\nBACKUP_HOST=1.2.3.4\nBACKUP_SSL=ip\nBACKUP_DATE=2026-09-01\n"})
|
||||
self.assertIn("ENV-OK", r.stdout, r.stdout + r.stderr)
|
||||
|
||||
def bad(self, over):
|
||||
r = restore_env(over)
|
||||
self.assertNotIn("ENV-OK", r.stdout)
|
||||
self.assertIn("Это не резервная копия 3X-UI KIT", r.stdout + r.stderr)
|
||||
|
||||
def test_mtproto_inner_sed(self):
|
||||
for v in (b"MTPROTO_INNER='[0-9]*.*/touch \\/tmp\\/pwn-test/e;#'", b"MTPROTO_INNER='1/x/;1e touch /tmp/pwn-test #'", b"MTPROTO_INNER=1/x/e"):
|
||||
self.bad({"etc/kit/kit.env": ENVS["etc/kit/kit.env"].replace(b"MTPROTO_INNER=10445", v)})
|
||||
|
||||
def test_panel_path_nginx(self):
|
||||
for v in (b"XUI_WEB_BASE_PATH='x/ { return 200; } location /zz'", b"XUI_WEB_BASE_PATH=x/../y", b"XUI_WEB_BASE_PATH=$(id)"):
|
||||
self.bad({"etc/x-ui/install-result.env": ENVS["etc/x-ui/install-result.env"].replace(b"XUI_WEB_BASE_PATH=AbCdEf123456789012", v)})
|
||||
|
||||
def test_values_every_file(self):
|
||||
for name in ENVS:
|
||||
for line in ENVS[name].splitlines():
|
||||
n = line.split(b"=")[0]
|
||||
for v in (b"'a;b'", b"$(touch /tmp/pwn-test)", b"a b", b"x" * 300):
|
||||
self.bad({name: ENVS[name].replace(line, n + b"=" + v)})
|
||||
|
||||
|
||||
def make_db():
|
||||
d = tempfile.mkdtemp()
|
||||
p = os.path.join(d, "x-ui.db")
|
||||
|
||||
Reference in New Issue
Block a user