Add local PS5 guide DNS gateway
This commit is contained in:
@@ -10,5 +10,6 @@ app/.codex
|
|||||||
app/LICENSE
|
app/LICENSE
|
||||||
app/README.md
|
app/README.md
|
||||||
app/serve.py
|
app/serve.py
|
||||||
|
docs
|
||||||
**/__pycache__
|
**/__pycache__
|
||||||
**/*.pyc
|
**/*.pyc
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ before including them in an image.
|
|||||||
- `Dockerfile`: runtime image and payload-integrity checks.
|
- `Dockerfile`: runtime image and payload-integrity checks.
|
||||||
- `compose.yaml`: hardened local deployment.
|
- `compose.yaml`: hardened local deployment.
|
||||||
- `docker/server.py`: static HTTP server and security headers.
|
- `docker/server.py`: static HTTP server and security headers.
|
||||||
|
- `docker/guide_gateway.py`: restricted DNS plus HTTP/HTTPS User Guide redirect.
|
||||||
- `payloads.sha256`: approved payload digests for the pinned submodule commit.
|
- `payloads.sha256`: approved payload digests for the pinned submodule commit.
|
||||||
- `docs/PS5_SETUP.md`: user and operator guide.
|
- `docs/PS5_SETUP.md`: user and operator guide.
|
||||||
- `docs/HANDOFF.md`: current infrastructure state and durable session handoff.
|
- `docs/HANDOFF.md`: current infrastructure state and durable session handoff.
|
||||||
@@ -69,6 +70,9 @@ Then perform a disposable smoke test and verify:
|
|||||||
- `/.git/config` returns 404;
|
- `/.git/config` returns 404;
|
||||||
- the process runs as UID/GID `65532:65532`;
|
- the process runs as UID/GID `65532:65532`;
|
||||||
- the configured security headers remain present.
|
- the configured security headers remain present.
|
||||||
|
- `manuals.playstation.net` resolves to the configured gateway address;
|
||||||
|
- unrelated DNS names return NXDOMAIN;
|
||||||
|
- HTTP and HTTPS User Guide requests redirect to the local exploit URL.
|
||||||
|
|
||||||
Do not leave smoke-test containers running.
|
Do not leave smoke-test containers running.
|
||||||
|
|
||||||
|
|||||||
+13
@@ -1,4 +1,15 @@
|
|||||||
ARG PYTHON_IMAGE=python:3.14-alpine
|
ARG PYTHON_IMAGE=python:3.14-alpine
|
||||||
|
FROM ${PYTHON_IMAGE} AS certificates
|
||||||
|
|
||||||
|
RUN apk add --no-cache openssl \
|
||||||
|
&& install -d -m 0755 /certificates \
|
||||||
|
&& openssl req -x509 -newkey rsa:2048 -sha256 -nodes -days 3650 \
|
||||||
|
-subj "/CN=manuals.playstation.net" \
|
||||||
|
-addext "subjectAltName=DNS:manuals.playstation.net" \
|
||||||
|
-keyout /certificates/manuals.key \
|
||||||
|
-out /certificates/manuals.crt \
|
||||||
|
&& chmod 0600 /certificates/manuals.key
|
||||||
|
|
||||||
FROM ${PYTHON_IMAGE}
|
FROM ${PYTHON_IMAGE}
|
||||||
|
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
@@ -13,6 +24,8 @@ COPY app/src /srv/public/src
|
|||||||
COPY app/offsets /srv/public/offsets
|
COPY app/offsets /srv/public/offsets
|
||||||
COPY app/payloads /srv/public/payloads
|
COPY app/payloads /srv/public/payloads
|
||||||
COPY docker/server.py /srv/server.py
|
COPY docker/server.py /srv/server.py
|
||||||
|
COPY docker/guide_gateway.py /srv/guide_gateway.py
|
||||||
|
COPY --from=certificates /certificates /srv/certificates
|
||||||
|
|
||||||
RUN cd /srv/public && sha256sum -c /tmp/payloads.sha256 \
|
RUN cd /srv/public && sha256sum -c /tmp/payloads.sha256 \
|
||||||
&& rm /tmp/payloads.sha256 \
|
&& rm /tmp/payloads.sha256 \
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ Container packaging for [PS5 Relapse Exploit](https://github.com/ntfargo/Relapse
|
|||||||
The upstream project is pinned as a Git submodule, and the image build verifies the
|
The upstream project is pinned as a Git submodule, and the image build verifies the
|
||||||
SHA-256 digest of every executable payload before including it.
|
SHA-256 digest of every executable payload before including it.
|
||||||
|
|
||||||
|
The Compose stack also includes a local PS5 User Guide gateway: authoritative DNS
|
||||||
|
for `manuals.playstation.net`, HTTP/HTTPS redirect to the local exploit, and NXDOMAIN
|
||||||
|
for every other domain so the console cannot resolve PSN or update services.
|
||||||
|
|
||||||
Use this only on consoles you own or are authorized to test. The exploit can panic
|
Use this only on consoles you own or are authorized to test. The exploit can panic
|
||||||
the console, corrupt kernel state, expose administrative services, and execute
|
the console, corrupt kernel state, expose administrative services, and execute
|
||||||
arbitrary code with elevated privileges.
|
arbitrary code with elevated privileges.
|
||||||
|
|||||||
@@ -13,3 +13,29 @@ services:
|
|||||||
security_opt:
|
security_opt:
|
||||||
- no-new-privileges:true
|
- no-new-privileges:true
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
|
ps5-guide-gateway:
|
||||||
|
image: relapse-exploit:local
|
||||||
|
command: ["python", "/srv/guide_gateway.py"]
|
||||||
|
environment:
|
||||||
|
GATEWAY_IP: "${GATEWAY_IP:-192.168.20.30}"
|
||||||
|
REDIRECT_URL: "${GUIDE_REDIRECT_URL:-http://192.168.20.30:8000/}"
|
||||||
|
ports:
|
||||||
|
- "${GATEWAY_BIND_IP:-192.168.20.30}:53:8053/udp"
|
||||||
|
- "${GATEWAY_BIND_IP:-192.168.20.30}:53:8053/tcp"
|
||||||
|
- "${GATEWAY_BIND_IP:-192.168.20.30}:80:8081/tcp"
|
||||||
|
- "${GATEWAY_BIND_IP:-192.168.20.30}:443:8443/tcp"
|
||||||
|
read_only: true
|
||||||
|
tmpfs:
|
||||||
|
- /tmp:size=1m,mode=1777
|
||||||
|
cap_drop:
|
||||||
|
- ALL
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges:true
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8081/_health', timeout=2).close()"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 3s
|
||||||
|
start_period: 5s
|
||||||
|
retries: 3
|
||||||
|
restart: unless-stopped
|
||||||
|
|||||||
@@ -0,0 +1,204 @@
|
|||||||
|
import http.server
|
||||||
|
import ipaddress
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import socket
|
||||||
|
import socketserver
|
||||||
|
import ssl
|
||||||
|
import struct
|
||||||
|
import threading
|
||||||
|
|
||||||
|
|
||||||
|
DNS_PORT = int(os.environ.get("DNS_PORT", "8053"))
|
||||||
|
HTTP_PORT = int(os.environ.get("HTTP_PORT", "8081"))
|
||||||
|
HTTPS_PORT = int(os.environ.get("HTTPS_PORT", "8443"))
|
||||||
|
GATEWAY_IP = ipaddress.IPv4Address(os.environ.get("GATEWAY_IP", "192.168.20.30"))
|
||||||
|
REDIRECT_URL = os.environ.get("REDIRECT_URL", f"http://{GATEWAY_IP}:8000/")
|
||||||
|
TARGET_DOMAIN = "manuals.playstation.net"
|
||||||
|
CERTIFICATE = "/srv/certificates/manuals.crt"
|
||||||
|
PRIVATE_KEY = "/srv/certificates/manuals.key"
|
||||||
|
|
||||||
|
|
||||||
|
def parse_question(packet):
|
||||||
|
if len(packet) < 17:
|
||||||
|
raise ValueError("short DNS query")
|
||||||
|
|
||||||
|
labels = []
|
||||||
|
offset = 12
|
||||||
|
while True:
|
||||||
|
if offset >= len(packet):
|
||||||
|
raise ValueError("unterminated DNS name")
|
||||||
|
length = packet[offset]
|
||||||
|
offset += 1
|
||||||
|
if length == 0:
|
||||||
|
break
|
||||||
|
if length & 0xC0 or length > 63 or offset + length > len(packet):
|
||||||
|
raise ValueError("unsupported DNS name")
|
||||||
|
labels.append(packet[offset : offset + length].decode("ascii"))
|
||||||
|
offset += length
|
||||||
|
|
||||||
|
if offset + 4 > len(packet):
|
||||||
|
raise ValueError("short DNS question")
|
||||||
|
qtype, qclass = struct.unpack_from("!HH", packet, offset)
|
||||||
|
return ".".join(labels).lower(), qtype, qclass, offset + 4
|
||||||
|
|
||||||
|
|
||||||
|
def dns_response(packet):
|
||||||
|
if len(packet) < 12:
|
||||||
|
return b""
|
||||||
|
|
||||||
|
transaction_id, request_flags, question_count = struct.unpack_from("!HHH", packet, 0)
|
||||||
|
response_flags = 0x8400 | (request_flags & 0x0100) # response, authoritative, preserve RD
|
||||||
|
try:
|
||||||
|
name, qtype, qclass, question_end = parse_question(packet)
|
||||||
|
if question_count != 1:
|
||||||
|
raise ValueError("expected one DNS question")
|
||||||
|
except (UnicodeDecodeError, ValueError):
|
||||||
|
return struct.pack("!HHHHHH", transaction_id, response_flags | 1, 0, 0, 0, 0)
|
||||||
|
|
||||||
|
question = packet[12:question_end]
|
||||||
|
if name != TARGET_DOMAIN:
|
||||||
|
return struct.pack("!HHHHHH", transaction_id, response_flags | 3, 1, 0, 0, 0) + question
|
||||||
|
|
||||||
|
if qclass == 1 and qtype in (1, 255):
|
||||||
|
answer = (
|
||||||
|
b"\xc0\x0c"
|
||||||
|
+ struct.pack("!HHIH", 1, 1, 60, 4)
|
||||||
|
+ GATEWAY_IP.packed
|
||||||
|
)
|
||||||
|
return struct.pack("!HHHHHH", transaction_id, response_flags, 1, 1, 0, 0) + question + answer
|
||||||
|
|
||||||
|
# NOERROR with no data prevents IPv6 or unsupported record fallback.
|
||||||
|
return struct.pack("!HHHHHH", transaction_id, response_flags, 1, 0, 0, 0) + question
|
||||||
|
|
||||||
|
|
||||||
|
class ThreadingUDPServer(socketserver.ThreadingUDPServer):
|
||||||
|
allow_reuse_address = True
|
||||||
|
daemon_threads = True
|
||||||
|
|
||||||
|
|
||||||
|
class ThreadingTCPServer(socketserver.ThreadingTCPServer):
|
||||||
|
allow_reuse_address = True
|
||||||
|
daemon_threads = True
|
||||||
|
|
||||||
|
|
||||||
|
class UDPDNSHandler(socketserver.BaseRequestHandler):
|
||||||
|
def handle(self):
|
||||||
|
packet, connection = self.request
|
||||||
|
try:
|
||||||
|
name, qtype, _, _ = parse_question(packet)
|
||||||
|
print(f"DNS UDP {self.client_address[0]} {name} type={qtype}", flush=True)
|
||||||
|
except (UnicodeDecodeError, ValueError):
|
||||||
|
print(f"DNS UDP {self.client_address[0]} malformed", flush=True)
|
||||||
|
response = dns_response(packet)
|
||||||
|
if response:
|
||||||
|
connection.sendto(response, self.client_address)
|
||||||
|
|
||||||
|
|
||||||
|
class TCPDNSHandler(socketserver.BaseRequestHandler):
|
||||||
|
def handle(self):
|
||||||
|
length_bytes = self._receive_exactly(2)
|
||||||
|
if length_bytes is None:
|
||||||
|
return
|
||||||
|
wanted = struct.unpack("!H", length_bytes)[0]
|
||||||
|
packet = self._receive_exactly(wanted)
|
||||||
|
if packet is None:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
name, qtype, _, _ = parse_question(packet)
|
||||||
|
print(f"DNS TCP {self.client_address[0]} {name} type={qtype}", flush=True)
|
||||||
|
except (UnicodeDecodeError, ValueError):
|
||||||
|
print(f"DNS TCP {self.client_address[0]} malformed", flush=True)
|
||||||
|
response = dns_response(packet)
|
||||||
|
if response:
|
||||||
|
self.request.sendall(struct.pack("!H", len(response)) + response)
|
||||||
|
|
||||||
|
def _receive_exactly(self, wanted):
|
||||||
|
chunks = []
|
||||||
|
received = 0
|
||||||
|
while received < wanted:
|
||||||
|
chunk = self.request.recv(wanted - received)
|
||||||
|
if not chunk:
|
||||||
|
return None
|
||||||
|
chunks.append(chunk)
|
||||||
|
received += len(chunk)
|
||||||
|
return b"".join(chunks)
|
||||||
|
|
||||||
|
|
||||||
|
class RedirectHandler(http.server.BaseHTTPRequestHandler):
|
||||||
|
protocol_version = "HTTP/1.1"
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
if self.path == "/_health":
|
||||||
|
body = b"ok\n"
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "text/plain")
|
||||||
|
self.send_header("Content-Length", str(len(body)))
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(body)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.send_response(302)
|
||||||
|
self.send_header("Location", REDIRECT_URL)
|
||||||
|
self.send_header("Cache-Control", "no-store")
|
||||||
|
self.send_header("Content-Length", "0")
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
def do_HEAD(self):
|
||||||
|
self.send_response(302)
|
||||||
|
self.send_header("Location", REDIRECT_URL)
|
||||||
|
self.send_header("Cache-Control", "no-store")
|
||||||
|
self.send_header("Content-Length", "0")
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
def log_message(self, message, *args):
|
||||||
|
user_agent = self.headers.get("User-Agent", "-")
|
||||||
|
print(
|
||||||
|
f"HTTP {self.client_address[0]} {message % args} user-agent={user_agent!r}",
|
||||||
|
flush=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPServer(http.server.ThreadingHTTPServer):
|
||||||
|
allow_reuse_address = True
|
||||||
|
daemon_threads = True
|
||||||
|
|
||||||
|
|
||||||
|
def serve(server, name):
|
||||||
|
thread = threading.Thread(target=server.serve_forever, name=name, daemon=True)
|
||||||
|
thread.start()
|
||||||
|
return thread
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
dns_udp = ThreadingUDPServer(("0.0.0.0", DNS_PORT), UDPDNSHandler)
|
||||||
|
dns_tcp = ThreadingTCPServer(("0.0.0.0", DNS_PORT), TCPDNSHandler)
|
||||||
|
http = HTTPServer(("0.0.0.0", HTTP_PORT), RedirectHandler)
|
||||||
|
https = HTTPServer(("0.0.0.0", HTTPS_PORT), RedirectHandler)
|
||||||
|
|
||||||
|
tls = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||||
|
tls.load_cert_chain(CERTIFICATE, PRIVATE_KEY)
|
||||||
|
https.socket = tls.wrap_socket(https.socket, server_side=True)
|
||||||
|
|
||||||
|
servers = [dns_udp, dns_tcp, http, https]
|
||||||
|
serve(dns_udp, "dns-udp")
|
||||||
|
serve(dns_tcp, "dns-tcp")
|
||||||
|
serve(http, "http-redirect")
|
||||||
|
serve(https, "https-redirect")
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"PS5 guide gateway: {TARGET_DOMAIN} -> {GATEWAY_IP}; redirect -> {REDIRECT_URL}",
|
||||||
|
flush=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
stopped = threading.Event()
|
||||||
|
|
||||||
|
def stop(*_):
|
||||||
|
stopped.set()
|
||||||
|
|
||||||
|
signal.signal(signal.SIGTERM, stop)
|
||||||
|
signal.signal(signal.SIGINT, stop)
|
||||||
|
stopped.wait()
|
||||||
|
for server in servers:
|
||||||
|
server.shutdown()
|
||||||
|
server.server_close()
|
||||||
+14
-8
@@ -68,6 +68,11 @@ kadinho <[email protected]>
|
|||||||
- container port: `8080/TCP`;
|
- container port: `8080/TCP`;
|
||||||
- restart policy: `unless-stopped`.
|
- restart policy: `unless-stopped`.
|
||||||
|
|
||||||
|
The same Compose project also runs `ps5-guide-gateway`, bound specifically to
|
||||||
|
`192.168.20.30` on DNS UDP/TCP 53 and HTTP/HTTPS TCP 80/443. It resolves only
|
||||||
|
`manuals.playstation.net`, returns NXDOMAIN for every other name, and redirects the
|
||||||
|
User Guide to `http://192.168.20.30:8000/`.
|
||||||
|
|
||||||
Port `8080` on the host is already used by `unifi-network-application`; do not move
|
Port `8080` on the host is already used by `unifi-network-application`; do not move
|
||||||
this service there. At the last verification, the Relapse container was healthy,
|
this service there. At the last verification, the Relapse container was healthy,
|
||||||
ran as `65532:65532`, used a read-only root filesystem, and returned HTTP 200 over
|
ran as `65532:65532`, used a read-only root filesystem, and returned HTTP 200 over
|
||||||
@@ -133,15 +138,16 @@ The local HTTP endpoint is available and verified at:
|
|||||||
http://192.168.20.30:8000/
|
http://192.168.20.30:8000/
|
||||||
```
|
```
|
||||||
|
|
||||||
The upstream project recommends public primary DNS `45.56.67.85`. The user reported
|
The upstream public DNS `45.56.67.85` was used initially, but the PS5 did not contact
|
||||||
successful access through the User Guide. No DNS container was installed on
|
the local container. The local gateway was therefore added. Configure the PS5 with
|
||||||
`net-utils01`, and this repository's Compose publishes no DNS service.
|
primary DNS `192.168.20.30` and secondary DNS `0.0.0.0`, then restart the console and
|
||||||
|
accept the self-signed certificate warning in the User Guide.
|
||||||
|
|
||||||
A local DNS service and an HTTP/HTTPS reverse proxy for the PS5 User Guide are
|
The gateway intentionally provides no recursive DNS forwarding. Only
|
||||||
possible future improvements, but must be designed separately. DNS only maps names
|
`manuals.playstation.net` resolves; all other names receive NXDOMAIN. This blocks
|
||||||
to IP addresses; it cannot redirect the User Guide from ports 80/443 to port 8000.
|
PSN and update resolution and keeps the setup independent of a public DNS operator.
|
||||||
Before binding ports 53, 80, or 443 on `net-utils01`, inspect for conflicts and agree
|
The PS5 was identified as `192.168.10.26`; requests from `192.168.10.6` seen earlier
|
||||||
on the desired DNS forwarding and logging policy.
|
were from a different client.
|
||||||
|
|
||||||
Full PS5 instructions and DNS options are in `docs/PS5_SETUP.md`.
|
Full PS5 instructions and DNS options are in `docs/PS5_SETUP.md`.
|
||||||
|
|
||||||
|
|||||||
+40
-20
@@ -18,6 +18,8 @@ Na rede onde este projeto foi inicialmente instalado:
|
|||||||
- imagem: `relapse-exploit:local`;
|
- imagem: `relapse-exploit:local`;
|
||||||
- porta interna: `8080`;
|
- porta interna: `8080`;
|
||||||
- porta publicada: `8000`.
|
- porta publicada: `8000`.
|
||||||
|
- DNS local: `192.168.20.30:53` (UDP e TCP);
|
||||||
|
- gateway do Guia: `192.168.20.30:80` e `192.168.20.30:443`.
|
||||||
|
|
||||||
A porta 8080 do host já pertence ao UniFi e não deve ser reutilizada.
|
A porta 8080 do host já pertence ao UniFi e não deve ser reutilizada.
|
||||||
|
|
||||||
@@ -127,15 +129,17 @@ Um DNS público implica confiar no respetivo operador. Pode ficar indisponível,
|
|||||||
alterar o destino do Guia do Utilizador ou ser contornado por um ISP que intercepte
|
alterar o destino do Guia do Utilizador ou ser contornado por um ISP que intercepte
|
||||||
DNS. Confirmar sempre a página e o endereço apresentados antes de executar.
|
DNS. Confirmar sempre a página e o endereço apresentados antes de executar.
|
||||||
|
|
||||||
### Opção 3: DNS local
|
### Opção 3: DNS local (configuração instalada)
|
||||||
|
|
||||||
A solução preferível a longo prazo é um DNS controlado na LAN, por exemplo no
|
O Compose inclui um DNS controlado no `net-utils01` que:
|
||||||
`net-utils01`, que:
|
|
||||||
|
|
||||||
- bloqueie domínios PlayStation/PSN e servidores de atualização;
|
- bloqueie domínios PlayStation/PSN e servidores de atualização;
|
||||||
- encaminhe as restantes consultas apenas se isso for desejado;
|
- responda `manuals.playstation.net` com `192.168.20.30`;
|
||||||
- redirecione `manuals.playstation.net` para o host de exploit apropriado;
|
- devolva `NXDOMAIN` para todos os restantes nomes, bloqueando PSN, updates,
|
||||||
- registe consultas para permitir auditoria.
|
telemetria e acesso geral à Internet por DNS;
|
||||||
|
- registe as consultas nos logs do container;
|
||||||
|
- apresente um gateway HTTPS local e redirecione o browser para o exploit em
|
||||||
|
`http://192.168.20.30:8000/`.
|
||||||
|
|
||||||
Nesse cenário, a PS5 usaria:
|
Nesse cenário, a PS5 usaria:
|
||||||
|
|
||||||
@@ -144,14 +148,15 @@ DNS primário: 192.168.20.30
|
|||||||
DNS secundário: 0.0.0.0
|
DNS secundário: 0.0.0.0
|
||||||
```
|
```
|
||||||
|
|
||||||
O serviço DNS não faz parte deste Compose e deve ser instalado e auditado
|
Depois de guardar o DNS na PS5, reiniciar completamente a consola se o Guia continuar
|
||||||
separadamente. Também é possível bloquear o acesso WAN da PS5 no router, mantendo
|
a usar uma resolução antiga. Abrir o Guia e aceitar o aviso de certificado não
|
||||||
apenas a comunicação LAN; esta é uma camada de proteção mais forte do que DNS.
|
confiável: o certificado é self-signed para `manuals.playstation.net` e existe apenas
|
||||||
|
para permitir que o Guia chegue ao redirecionamento local.
|
||||||
|
|
||||||
DNS só traduz nomes para endereços IP; não redireciona portas. Para servir o Guia do
|
O gateway liga-se por defeito apenas ao endereço `192.168.20.30`. Para outra rede,
|
||||||
Utilizador a partir do host local, é também necessário disponibilizar o site nas
|
definir `GATEWAY_BIND_IP`, `GATEWAY_IP` e `GUIDE_REDIRECT_URL` antes de executar o
|
||||||
portas HTTP/HTTPS esperadas pelo manual ou colocar um reverse proxy à frente da
|
Compose. Também é possível bloquear o acesso WAN da PS5 no router, mantendo apenas
|
||||||
porta 8000. O Compose atual publica apenas HTTP em `8000`.
|
a comunicação LAN; esta continua a ser uma camada adicional mais forte do que DNS.
|
||||||
|
|
||||||
## Abrir pelo Guia do Utilizador
|
## Abrir pelo Guia do Utilizador
|
||||||
|
|
||||||
@@ -161,11 +166,16 @@ Com um DNS que redirecione o manual:
|
|||||||
2. abrir `Guia do Utilizador, saúde e segurança e outras informações`;
|
2. abrir `Guia do Utilizador, saúde e segurança e outras informações`;
|
||||||
3. abrir `Guia do Utilizador`;
|
3. abrir `Guia do Utilizador`;
|
||||||
4. confirmar que aparece a página Relapse esperada;
|
4. confirmar que aparece a página Relapse esperada;
|
||||||
5. se for importante usar a instalação local, confirmar que o destino é
|
5. aceitar o aviso de certificado self-signed, se aparecer;
|
||||||
`192.168.20.30:8000` e não um host público inesperado.
|
6. confirmar nos logs que o cliente `192.168.10.26` consultou o DNS e abriu o
|
||||||
|
gateway;
|
||||||
|
7. confirmar que o destino final é `192.168.20.30:8000`.
|
||||||
|
|
||||||
O DNS público pode abrir diretamente uma página de exploit própria. Isso não prova
|
Ver os logs do gateway:
|
||||||
que a página veio do container local.
|
|
||||||
|
```sh
|
||||||
|
docker compose logs -f ps5-guide-gateway
|
||||||
|
```
|
||||||
|
|
||||||
## Executar o exploit
|
## Executar o exploit
|
||||||
|
|
||||||
@@ -193,6 +203,8 @@ uma mensagem genérica de conclusão prova que todas as etapas terminaram corret
|
|||||||
## Portas e serviços posteriores
|
## Portas e serviços posteriores
|
||||||
|
|
||||||
- `8000/TCP` no servidor: página Relapse;
|
- `8000/TCP` no servidor: página Relapse;
|
||||||
|
- `53/UDP` e `53/TCP` no servidor: DNS local restritivo;
|
||||||
|
- `80/TCP` e `443/TCP` no servidor: gateway do Guia do Utilizador;
|
||||||
- `9021/TCP` na PS5: ELF loader;
|
- `9021/TCP` na PS5: ELF loader;
|
||||||
- `10101/TCP` na PS5: API HTTP do ShadowMount+, por defeito em loopback.
|
- `10101/TCP` na PS5: API HTTP do ShadowMount+, por defeito em loopback.
|
||||||
|
|
||||||
@@ -259,9 +271,17 @@ impede comunicação com `192.168.20.30`.
|
|||||||
|
|
||||||
### O Guia do Utilizador abre a página oficial ou outro host
|
### O Guia do Utilizador abre a página oficial ou outro host
|
||||||
|
|
||||||
O DNS configurado não está a redirecionar `manuals.playstation.net` para o destino
|
Confirmar que o DNS primário da PS5 é `192.168.20.30`, que não existe um DNS
|
||||||
esperado, ou o ISP/router está a interferir com DNS. Isto é independente do container
|
secundário normal e que o gateway está saudável:
|
||||||
HTTP. Usar o URL local diretamente ou instalar um DNS local controlado.
|
|
||||||
|
```sh
|
||||||
|
docker compose ps
|
||||||
|
docker compose logs --tail=100 ps5-guide-gateway
|
||||||
|
```
|
||||||
|
|
||||||
|
Depois reiniciar completamente a consola para limpar resoluções antigas. Se não
|
||||||
|
existir qualquer consulta proveniente do IP da PS5, verificar regras entre as VLANs
|
||||||
|
`192.168.10.0/24` e `192.168.20.0/24`, incluindo UDP/TCP 53 e TCP 80/443/8000.
|
||||||
|
|
||||||
### O build falha nos hashes
|
### O build falha nos hashes
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user