Skip to main content
  1. Posts/

按图索骥:osquery 探索

·

用 SQL 语法查询系统信息。

由于相比直接执行命令缺少必要的灵活性(例如:查看指定文件内容),使用 osquery 进行排查的方案暂时搁置。

安装 #

wget https://pkg.osquery.io/linux/osquery-5.15.0_1.linux_x86_64.tar.gz
tar -zxvf osquery-5.15.0_1.linux_x86_64.tar.gz -C / --skip-old-files --no-overwrite-dir

避免性能问题 #

systemctl mask --now systemd-journald-audit.socket

启动 osqueryd #

应急响应手动排查中通常只使用 osqueryi,但如果需要启动 osqueryd:

sudo cp /opt/osquery/share/osquery/osquery.example.conf /etc/osquery/osquery.conf
sudo systemctl start osqueryd

卸载 #

rm -rf /var/osquery /var/log/osquery /opt/osquery /etc/osquery /usr/bin/osquery*

查询示例 #

用户 #

非默认、可登录用户 #

SELECT
  uid,
  gid,
  username,
  description,
  directory,
  shell
FROM
  users
WHERE
  shell NOT IN ('/bin/false', '/sbin/nologin')
  AND username NOT IN ('root','sync','shutdown','halt');

当前登录用户 #

SELECT
  user,
  tty,
  host,
  datetime(time, 'unixepoch', 'localtime') as login_time
FROM
  logged_in_users
WHERE
  type = 'user';

登录历史 #

SELECT
  username,
  tty,
  pid,
  host,
  datetime(time, 'unixepoch', 'localtime') as login_time
FROM
  last
WHERE
  type = 7
  AND time >= strftime('%s', 'now', '-6 months')
ORDER BY
  time DESC;

进程 #

CPU 占用前 20 进程 #

SELECT
  pid,
  parent,
  u.username,
  name,
  CONCAT(
    ROUND(
      (
        (user_time + system_time) / (cpu_time.tsb - cpu_time.itsb)
      ) * 100,
      2
    ),
    '%'
  ) AS cpu,
  CONCAT(ROUND((total_size * '10e-7'), 2), 'MB') AS mem,
  datetime(start_time, 'unixepoch', 'localtime') as start_time,
  cwd,
  path,
  cmdline
FROM
  processes p
  JOIN users u ON p.uid = u.uid,
  (
    SELECT
      (
        SUM(user) + SUM(nice) + SUM(system) + SUM(idle) * 1.0
      ) AS tsb,
      SUM(COALESCE(idle, 0)) + SUM(COALESCE(iowait, 0)) AS itsb
    FROM
      cpu_time
  ) AS cpu_time
ORDER BY
  user_time + system_time DESC
LIMIT
  20;

内存占用前 20 进程 #

SELECT
  pid,
  parent,
  u.username,
  name,
  CONCAT(
    ROUND(
      (
        (user_time + system_time) / (cpu_time.tsb - cpu_time.itsb)
      ) * 100,
      2
    ),
    '%'
  ) AS cpu,
  CONCAT(ROUND((total_size * '10e-7'), 2), 'MB') AS mem,
  datetime(start_time, 'unixepoch', 'localtime') as start_time,
  cwd,
  path,
  cmdline
FROM
  processes p
  JOIN users u ON p.uid = u.uid,
  (
    SELECT
      (
        SUM(user) + SUM(nice) + SUM(system) + SUM(idle) * 1.0
      ) AS tsb,
      SUM(COALESCE(idle, 0)) + SUM(COALESCE(iowait, 0)) AS itsb
    FROM
      cpu_time
  ) AS cpu_time
ORDER BY
  total_size DESC
LIMIT
  20;

可执行文件已不存在的进程 #

注意针对部分 python 进程存在误报:

SELECT
  pid,
  parent,
  u.username,
  name,
  CONCAT(
    ROUND(
      (
        (user_time + system_time) / (cpu_time.tsb - cpu_time.itsb)
      ) * 100,
      2
    ),
    '%'
  ) AS cpu,
  CONCAT(ROUND((total_size * '10e-7'), 2), 'MB') AS mem,
  datetime(start_time, 'unixepoch', 'localtime') as start_time,
  cwd,
  path,
  cmdline
FROM
  processes p
  JOIN users u ON p.uid = u.uid,
  (
    SELECT
      (
        SUM(user) + SUM(nice) + SUM(system) + SUM(idle) * 1.0
      ) AS tsb,
      SUM(COALESCE(idle, 0)) + SUM(COALESCE(iowait, 0)) AS itsb
    FROM
      cpu_time
  ) AS cpu_time
WHERE
  on_disk = 0
  AND name <> 'tuned'
ORDER BY
  start_time DESC;

非默认、用户态进程 #

SELECT
  pid,
  parent,
  u.username,
  name,
  CONCAT(
    ROUND(
      (
        (user_time + system_time) / (cpu_time.tsb - cpu_time.itsb)
      ) * 100,
      2
    ),
    '%'
  ) AS cpu,
  CONCAT(ROUND((total_size * '10e-7'), 2), 'MB') AS mem,
  datetime(start_time, 'unixepoch', 'localtime') as start_time,
  cwd,
  path,
  cmdline
FROM
  processes p
  JOIN users u ON p.uid = u.uid,
  (
    SELECT
      (
        SUM(user) + SUM(nice) + SUM(system) + SUM(idle) * 1.0
      ) AS tsb,
      SUM(COALESCE(idle, 0)) + SUM(COALESCE(iowait, 0)) AS itsb
    FROM
      cpu_time
  ) AS cpu_time
WHERE
  parent <> 2
  AND name NOT IN(
    'kthreadd',
    'tuned',
    'aliyun-service',
    'AliYunDunUpdate',
    'AliYunDun',
    'AliYunDunMonito'
  )
  AND path NOT IN(
    '/usr/lib/systemd/systemd',
    '/usr/sbin/chronyd',
    '/usr/lib/polkit-1/polkitd',
    '/usr/sbin/gssproxy',
    '/usr/sbin/rpcbind',
    '/usr/bin/dbus-daemon',
    '/usr/lib/systemd/systemd-logind',
    '/usr/sbin/auditd',
    '/usr/lib/systemd/systemd-udevd',
    '/usr/lib/systemd/systemd-journald',
    '/usr/sbin/dhclient',
    '/usr/sbin/agetty',
    '/usr/sbin/crond',
    '/usr/sbin/atd',
    '/usr/sbin/rsyslogd',
    '/usr/libexec/postfix/qmgr',
    '/usr/libexec/postfix/master',
    '/usr/libexec/postfix/pickup',
    '/usr/sbin/sshd',
    '/usr/local/cloudmonitor/bin/argusagent',
    '/usr/local/share/assist-daemon/assist_daemon'
  )
ORDER BY
  start_time DESC;

网络 #

开放端口 #

SELECT
	(
    CASE
      l.family
      WHEN 2 THEN 'IPv4'
      WHEN 10 THEN 'IPv6'
      ELSE l.family
    END
  ) AS family,
  (
    CASE
      l.protocol
      WHEN 6 THEN 'TCP'
      WHEN 17 THEN 'UDP'
      ELSE l.protocol
    END
  ) AS protocol,
  l.port,
  p.name,
  p.path,
  p.pid
FROM
  listening_ports l
  JOIN processes p ON l.pid = p.pid
WHERE
  l.address IN ('0.0.0.0', '::')
  AND p.path NOT IN(
    '/usr/sbin/rpcbind',
    '/usr/sbin/dhclient'
  );

非默认网络连接 #

SELECT
  (
    CASE
      l.family
      WHEN 2 THEN 'IPv4'
      WHEN 10 THEN 'IPv6'
      ELSE l.family
    END
  ) AS family,
  (
    CASE
      l.protocol
      WHEN 6 THEN 'TCP'
      WHEN 17 THEN 'UDP'
      ELSE l.protocol
    END
  ) AS protocol,
  l.local_address,
  l.local_port,
  l.remote_address,
  l.remote_port,
  l.state,
  p.name,
  p.path,
  p.pid
FROM
  process_open_sockets l
  LEFT JOIN processes p ON l.pid = p.pid
WHERE
	l.protocol <> 0
  AND l.state <> 'LISTEN'
  AND l.remote_address NOT LIKE '140.205.11.%'
  AND p.path NOT IN('/usr/sbin/rpcbind', '/usr/sbin/dhclient', '/usr/sbin/chronyd')
  AND p.name <> 'AliYunDun';

网卡地址 #

SELECT * FROM interface_addresses;

DNS 解析 #

SELECT * FROM dns_resolvers;

/etc/hosts #

SELECT * FROM etc_hosts;

文件 #

文件属性 #

/etc/hosts 为例:

SELECT
	path,
  f.directory,
  u.username AS own_user,
  g.groupname AS own_group,
  mode,
  (
    CASE
      WHEN size < 1024 THEN printf ('%.2f B', size)
      WHEN size < 1048576 THEN printf ('%.2f KB', size / 1024.0)
      WHEN size < 1073741824 THEN printf ('%.2f MB', size / 1048576.0)
      ELSE printf ('%.2f GB', size / 1073741824.0)
    END
  ) AS readable_size,
  datetime(atime, 'unixepoch', 'localtime') as last_access_time,
  datetime(mtime, 'unixepoch', 'localtime') as last_modify_time,
  datetime(ctime, 'unixepoch', 'localtime') as last_change_time,
  datetime(btime, 'unixepoch', 'localtime') as birth_time
FROM
  file f
  JOIN users u ON f.uid = u.uid
  JOIN groups g ON f.gid = g.gid
WHERE
  path = '/etc/hosts';

非默认 SUID 二进制文件 #

SELECT
  *
FROM
  suid_bin
WHERE
  path NOT IN(
    '/bin/atq',
    '/bin/gpasswd',
    '/bin/fusermount',
    '/bin/pkexec',
    '/bin/write',
    '/bin/sudo',
    '/bin/chsh',
    '/bin/su',
    '/bin/mount',
    '/bin/wall',
    '/bin/at',
    '/bin/passwd',
    '/bin/sudoedit',
    '/bin/sg',
    '/bin/umount',
    '/bin/chfn',
    '/bin/newgrp',
    '/bin/crontab',
    '/bin/chage',
    '/bin/atrm',
    '/bin/ssh-agent',
    '/sbin/umount.nfs4',
    '/sbin/mount.nfs4',
    '/sbin/postqueue',
    '/sbin/unix_chkpwd',
    '/sbin/netreport',
    '/sbin/postdrop',
    '/sbin/umount.nfs',
    '/sbin/pam_timestamp_check',
    '/sbin/mount.nfs',
    '/sbin/usernetctl',
    '/usr/bin/atq',
    '/usr/bin/gpasswd',
    '/usr/bin/fusermount',
    '/usr/bin/pkexec',
    '/usr/bin/write',
    '/usr/bin/sudo',
    '/usr/bin/chsh',
    '/usr/bin/su',
    '/usr/bin/mount',
    '/usr/bin/wall',
    '/usr/bin/at',
    '/usr/bin/passwd',
    '/usr/bin/sudoedit',
    '/usr/bin/sg',
    '/usr/bin/umount',
    '/usr/bin/chfn',
    '/usr/bin/newgrp',
    '/usr/bin/crontab',
    '/usr/bin/chage',
    '/usr/bin/atrm',
    '/usr/bin/ssh-agent',
    '/usr/sbin/umount.nfs4',
    '/usr/sbin/mount.nfs4',
    '/usr/sbin/postqueue',
    '/usr/sbin/unix_chkpwd',
    '/usr/sbin/netreport',
    '/usr/sbin/postdrop',
    '/usr/sbin/umount.nfs',
    '/usr/sbin/pam_timestamp_check',
    '/usr/sbin/mount.nfs',
    '/usr/sbin/usernetctl'
  );

SSH #

所有用户公钥文件 #

SELECT
  *
FROM
  authorized_keys a
  JOIN users u ON a.uid = u.uid;

计划任务 #

非默认 crontab #

SELECT
  *
FROM
  crontab
WHERE
  command NOT IN(
    'root run-parts /etc/cron.hourly',
    'root /usr/lib64/sa/sa1 1 1',
    'root /usr/lib64/sa/sa2 -A'
  );

服务 #

运行中的非默认 systemd 服务 #

SELECT
  id,
  description,
  unit_file_state,
  fragment_path,
  source_path
FROM
  systemd_units
WHERE
	sub_state='running'
  AND id NOT IN (
    'chronyd.service',
    'aliyun.service',
    'systemd-udevd.service',
    'polkit.service',
    'systemd-logind.service',
    'systemd-journald.socket',
    'rsyslog.service',
    'tuned.service',
    'proc-sys-fs-binfmt_misc.automount',
    'cloudmonitor.service',
    'gssproxy.service',
    'dbus.socket',
    'serial-getty@ttyS0.service',
    'rpcbind.service',
    'crond.service',
    'postfix.service',
    'sshd.service',
    'systemd-udevd-kernel.socket',
    'dbus.service',
    'systemd-journald.service',
    'rpcbind.socket',
    'network.service',
    'aegis.service',
    'auditd.service',
    'systemd-udevd-control.socket',
    'atd.service',
    'AssistDaemon.service',
    'getty@tty1.service'
  );

其他 #

内核模块 #

SELECT * FROM kernel_modules;