feat(util): add keys module for terminal control sequences (#2368) - #2724
feat(util): add keys module for terminal control sequences (#2368)#2724ChrisJr404 wants to merge 5 commits into
Conversation
peace-maker
left a comment
There was a problem hiding this comment.
Very cool, this will make exploits dealing with control sequences way easier to read.
Can you add links to references where the different codes are defined please?
A test interacting with QEMU monitor using ctrl('a')+c would be nice to show how to use it.
| elif isinstance(char, (bytes, bytearray, memoryview)): | ||
| char = bytes(char) | ||
| else: | ||
| raise TypeError("alt(): char must be str or bytes-like") |
There was a problem hiding this comment.
We have logic for this in pwnlib.util.packing._need_bytes instead of reimplementing it here.
| if 0x40 <= code <= 0x5f: | ||
| return bytes((code & 0x1f,)) | ||
| if char == '?': | ||
| # Ctrl-? is conventionally DEL (0x7f) |
There was a problem hiding this comment.
Can you link to some reference for such quirks please?
|
Added the reference links (ECMA-6/ECMA-48 + the xterm ctlseqs page) to the module docstring, plus a runnable example using On reusing term/key.py: that module goes the other way, it decodes bytes coming back from the terminal into Key objects (kc.KEY_* integers), there's no table of sendable sequences in there to pull from. This module is just the encode side. Happy to move the constants somewhere shared if you'd rather they live next to the term code. |
…d#2368) New pwnlib.util.keys module with constants for C0 control characters and common ANSI/xterm escape sequences (arrow keys, function keys, line/screen clear), plus generators ctrl(), alt(), and csi(). Lets tube callers send readable values like CTRL_C / UP / ctrl('a') instead of opaque byte literals like b'\\x03'. Closes Gallopsled#2368
e2cf1b2 to
f7f48ad
Compare
The QEMU-monitor example uses listen()/remote(), but the keys.rst testsetup only pulled in the keys module, so those names were undefined under the Sphinx doctest run (NameError). Import them explicitly, same as proc.rst does for process().
Address review feedback:
- alt()/csi() now route str/bytes coercion through
pwnlib.util.packing._need_bytes instead of hand-rolling latin-1
encoding. min_wrong is set past the latin-1 range so the ergonomic
str form (alt('x'), csi('H')) stays warning-free while >0xff still
falls back to the shared helper's behaviour.
- Link the xterm FAQ for the Ctrl-? -> DEL (0x7f) rubout convention.
|
@peace-maker I dug into L306 is _csi_ss3s = {
'A': (kc.TYPE_KEYSYM, kc.KEY_UP),
'B': (kc.TYPE_KEYSYM, kc.KEY_DOWN),
...
}
_csi_funcs = {
3 : (kc.TYPE_KEYSYM, kc.KEY_DELETE),
5 : (kc.TYPE_KEYSYM, kc.KEY_PAGEUP),
...
}Two things make them awkward as a source of truth for the send side:
On top of that, the decoder's real source of truth at runtime is terminfo — So my read is that sharing the tables would make both sides harder to follow rather than removing duplication. That said, I'm not attached to keeping it separate: if you and @Arusekk would rather these live next to the term code, or want me to add a small keysym → canonical-bytes table that the encoder owns and the parser could optionally cross-check in a test, I'm glad to do either — just say which you'd prefer. While I was in here I also took care of your other two notes: Last thing — the red CI was self-inflicted, not the flaky libcdb/network doctests: the new QEMU example calls |
Closes #2368.
What
Adds
pwnlib.util.keys, a tiny new module that gives readable names to the bytes most CTF / exploit scripts otherwise spell as opaque literals when interacting with a tube, e.g.The module exports:
NUL…US) plusDEL, withCTRL_A…CTRL_Zaliases and the symbolicCTRL_BACKSLASH/CTRL_RBRACKET/CTRL_CARET/CTRL_UNDERSCORE.BACKSPACE,ENTER,NEWLINE,TAB_KEY,ESCAPE,SPACE.HOME,END,PAGE_UP,PAGE_DOWN,INSERT,DELETE), andF1…F12xterm sequences.CLEAR_SCREEN,CLEAR_LINE.ctrl(char)for anyCtrl+<x>(letters, plus@[\\]^_?),alt(char)for anyAlt/Meta+<x>(str or bytes-like), andcsi(rest)to compose ad-hoc CSI escapes.Why
#2368(filed by @peace-maker) asks for "some nice enum/abstraction" so that things like Ctrl-C through a socket aren't written asb'\x03'. There's already a place in pwntools where a maintainer left a breadcrumb in code:https://github.com/Gallopsled/pwntools/blob/dev/pwnlib/tubes/ssh.py#L254
This change replaces the need for those comments — callers can write
CTRL_Cdirectly.Tests
The module ships with doctests for every documented surface. Verified locally:
Plus error-path checks (single-char enforcement on
ctrl(), type checks onalt()/csi()):Notes
pwnlib.util.__all__and gets a normal Sphinx docs page atdocs/source/util/keys.rst, matching the layout of the otherpwnlib.util.*modules.\x1bOP…\x1bOSfor F1–F4,\x1b[N~for F5–F12). Real terminals also have alternate forms; if any consumer needs those they can usecsi(...)directly.