lynis插件编写:从入门到放弃 – 作者:nancce

*本文作者:nancce,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。

前言

lynis是一款采用shell脚本编写,适用于Linux,macOS和基于UNIX的系统的安全审核工具,相信小伙伴们在网上搜索lynis会有很多介绍lynis如何使用的文章,但是关于lynis插件编写的文章却很少,本文就来讨论下lynis的插件编写。

lynis-.jpg

lynis的使用也很是简单方便,一般来说我们使用以下的命令就可以了:

cd lynis; ./lynis audit system

除了使用lynis默认的规则来加固linux之外,lynis还提供了插件的功能,通过自己编写插件,我们可以把lynis改装成一款linux提权信息的收集器,或者将其改装成恶意程序的检测工具,本文我们将先介绍编写lynis插件的语法,然后基于lynis编写一个linux提权信息收集插件,希望通过这个案例可以启发小伙伴们开发出更精彩的插件。

插件介绍

脚本语言

Lynis采用shell脚本编写的,这是一种多功能脚本语言,可在在Linux或基于UNIX的操作系统的所有系统上运行。

Lynis执行步骤

我们先看看lynis完整的运行周期如下:

[Initialization] → [OS detection] → [Detection of binaries] → [Plugins phase 1] → [Built-in tests] → [Custom tests] → [Plugins phase 2] → [Report]

可以发现,在lynis中有两个阶段可以去运行插件,它们分别是Plugins phase 1,Plugins phase 2。

lynis SDK

lynis同时也提供lynis SDK的开发方式及下载。

开发步骤

第一步:找到插件目录

第一步是就了解Lynis的安装位置,特别是您的插件存储的目录。当运行Lynis时,插件目录就会显示在屏幕上,并存储在日志文件中(通常为/var/log/lynis.log),所以我们可以通过下面的命令来查看插件的目录文章:

grep -i plugin /var/log/lynis.log

第二步:决定加载插件的阶段

第一阶段

在第一阶段运行的插件将在内置测试之前执行。此阶段非常适合仅收集数据的测试。这有可能是获取已安装的软件包列表或系统上运行的进程。

第二阶段

插件的第二阶段发生在正常测试结束时。这是你希望分析先前发现的信息,处理它并可选择在屏幕上显示的时候。

提示:如果您是第一次创建插件,请使用第二阶段。这样你就可以使所有测试数据可用的同时向屏幕输出,因为它在审计周期最后阶段执行。

第三步:创建插件文件

在plugins目录,将customplugin.template文件复制到plugin [name] _phase [number]文件中。

Plugin Name and Phase

[name]的值应替换为插件的唯一名称。仅使用小写字符,数字和(可选)短划线( – )来链接两个单词。 [number]用以定义插件阶段,即1或2。

例如name的取值可为:companyname, custom-tests, iso27001, personal

命令:

cp custom_plugin.template plugin_custom-tests_phase2

第四步:配置插件

修改文件标题

对此文件的第一次调整就是修改标题。这些细节用于插件的部分说明,用于验证插件的正确格式。

#########################################################################
#
#    * DO NOT REMOVE *
#-----------------------------------------------------
# PLUGIN_AUTHOR=Mr Auditor <[email protected]>
# PLUGIN_CATEGORY=Custom
# PLUGIN_DESC=This are my custom tests
# PLUGIN_NAME=custom-tests
# PLUGIN_REQUIRED_TESTS=
#-----------------------------------------------------
#########################################################################

PLUGIN_AUTHOR: 作者字段定义谁负责创建和更新此文件。

PLUGIN_CATEGORY: 这个字段描述了此插件所属的测试类型(例如,network)。可以使用“custom”。

PLUGIN_DESC: 描述字段,带有可选的解释,说明为什么创建此插件及其目标。

PLUGIN_NAME: 应该和你用作文件名的名称相同。

PLUGIN_REQUIRED_TESTS: 描述在执行该插件之前应该已经执行的依赖检测。通常可以跳过。

Tips:

检查是否正确定义了PLUGIN_NAME字段。

保留#符号,只更改每行的值。

第五步:创建插件

每个插件都包含一个或多个单独的检测单元。它们标有唯一的ID,以便正确的记录和存储测试结果。出于同样的原因,您创建的所有测试都应以“CUST-”开头,然后是四个数字(例如CUST-0010)。

检测单元使用通用的shell脚本语言创建。为了简化操作,lynis预先实现了几个函数(include / functions)。示例包括向屏幕,日志文件或报告文件添加文本。它还包括用于检查权限的检测等。

基础的函数:

Display: 向屏幕输出、打印

LogText: 向log文件中输出

Register: 测试单元队列执行

Report: 向report中输出

检测流程:

设置可选的先决条件;

注册检测(注册功能)。然后Lynis将检查是否需要执行或跳过;

检查注册功能的状态(if [ ${SKIPTEST} -eq 0 ]; then);

运行检测代码5、关闭检测(fi)。

可以在include/tests_custom.template文件中看到测试和函数的一些示例。另一个很好的资源是Lynis中的常规检测,也可以在include目录中找到。

第六步:运行lynis

在运行lynis之后,插件会被载入。

常见问题

如果,插件没有被激活,请按检查以下的项目:

在profile(.prf)中是否被开启;

插件名和插件代码中是否一致;

插件文件是否有权限。

日志文件(/var/log/lynis.log)中也将记录忽略该插件的原因。

linux提权信息收集插件

如何运行插件

虽然在上面的章节中我们介绍了在运行lynis后,插件会被载入,但是这样的话会在运行我们的插件的同时运行lynis自带的插件和很多其他的信息收集脚本,所以lynis提供了一种单独运行插件的选项–tests。

./lynis audit system --tests CUST-id1,CUST-id2

这里的id就是编写插件时自定义的独一无二的值

确认收集什么信息

目前该插件已经完成收集的信息有:

判断/etc/passwd中是否有hash的password,如果有提取出来后续可以使用hashcat等破解(插件id:PASS-0001,plugin_check_passwd_shadow_phase2);

判断/etc/shadow文件root之外的用户是否有权限读取,如果有提取出来后续可以使用hashcat等破解(插件id:PASS-0002,plugin_check_passwd_shadow_phase2);

判断/etc/passwd文件root之外的用户是否有写入的权限,可以直接修改密码(插件id:PASS-0003,plugin_check_passwd_shadow_phase2);

检测当前用户可以执行并且可被用以提权的程序(插件id:PWN-0001,plugin_check_pwnable_binary_phase2);

发现隐藏文件(插件id:HIDDEN-0001,plugin_check_hidden_file_phase2);

发现suid文件,经典提权(插件id:SUID-0001,plugin_check_suid_file_phase2);

检测是否有docker用户组并列出其中的用户(插件id:GROUP-0001,plugin_check_docker_group_phase2)。

目前收集的信息还是比较少的,后续会逐步的添加。

实战Lin.security

首先,简单介绍下插件的内容,定义检查/etc/passwd文件中是否有密文的函数:

check_password_hashes() {
    # define some constant
    IFS_OLD=$IFS
    IFS=$'\n'
    ENCRYPTEDPASS='x' 
    #start
    LogText "Test:obtain /etc/passwd file content"
    passwd_content=$(${AWKBINARY} '{print $0}' /etc/passwd)
    for each_passwd in ${passwd_content};
    do
        IFS=':'
        passwd_split_colon=($each_passwd)
        if [ "${passwd_split_colon[1]}" != "$ENCRYPTEDPASS" ];then
            IFS=$'\n'
            Report "sensetive_passwd_hashes[]=$each_passwd"
        fi
    done
    IFS=$IFS_OLD
}

然后在注册代码块里调用该函数在插件加载时运行:

#################################################################################
#
    # Test        : PASS-0001
    # Description : We show some lines on the screen

    # Register our first custom test
    # We consider it to be a lightweight test (no heavy IO, or long searches), no network connection needed
    Register --test-no PASS-0001 --weight L --network NO --description "A test for check if there is password hashess stored in /etc/passwd"
    if [ ${SKIPTEST} -eq 0 ]; then
        # The Display function makes it easy to show something on screen, with colors.
        # --indent  defines amount of spaces
        # --text    text to be displayed on screen
        # --result  text at end of line
        # --color   color of result text
        Display --indent 2 --text "- Checking if there is a password hashes on /etc/passwd file" --result OK --color GREEN
        check_password_hashes;
    fi
#

运行命令:

./lynis audit system --tests PASS-0001

查看收集结果的报告:

cat /var/log/lynis-report.dat | grep sensetive_passwd_hashes

Lin.security是一款提权练习的虚拟机,通过模拟真实漏洞,将帮助您完善本地权限提升技能,技术和工具集。

通过bob/secret登入到Lin.security中,ifconfig查看虚拟机的ip:

bob@linsecurity:~/lynis-master/plugins$ ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:8a:eb:21:07  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.137.196  netmask 255.255.255.0  broadcast 192.168.137.255
        inet6 fe80::a00:27ff:fed8:9fd6  prefixlen 64  scopeid 0x20<link>
        ether 08:00:27:d8:9f:d6  txqueuelen 1000  (Ethernet)
        RX packets 180  bytes 18259 (18.2 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 753  bytes 69400 (69.4 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 373  bytes 27495 (27.4 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 373  bytes 27495 (27.4 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

将插件拷贝进虚拟机plugins目录下:

scp plugin_check_* [email protected]:/home/bob/lynis-master/plugins/
[email protected]'s password: 
plugin_check_docker_group_phase2              100% 3858   899.2KB/s   00:00    
plugin_check_hidden_file_phase2               100% 3628     3.7MB/s   00:00    
plugin_check_passwd_shadow_phase2             100% 5010     6.4MB/s   00:00    
plugin_check_pwnable_binary_phase2            100% 4970     6.5MB/s   00:00    
plugin_check_suid_file_phase2                 100% 3578     3.7MB/s   00:00

记得将default.prf也拷贝进去,覆盖原来的配置:

scp default.prf [email protected]:/home/bob/lynis-master/
[email protected]'s password: 
default.prf                                   100%   20KB   6.7MB/s   00:00

运行lynis:

bob@linsecurity:~/lynis-master$ bash lynis audit system

查看插件收集到的信息:

cat /tmp/lynis-report.dat | grep -E 'suid_file|pwnable_programs|sensetive_passwd_hashes|hidden_file|docker_group'

plugin_enabled_phase2[]=check_hidden_file||
hidden_file[]=/snap/core/4917/etc/.pwd.lock
hidden_file[]=/snap/core/4917/etc/cron.d/.placeholder
hidden_file[]=/snap/core/4917/etc/cron.daily/.placeholder
hidden_file[]=/snap/core/4917/etc/cron.hourly/.placeholder
hidden_file[]=/snap/core/4917/etc/cron.monthly/.placeholder
hidden_file[]=/snap/core/4917/etc/cron.weekly/.placeholder
hidden_file[]=/snap/core/4917/etc/init.d/.depend.boot
hidden_file[]=/snap/core/4917/etc/init.d/.depend.start
hidden_file[]=/snap/core/4917/etc/init.d/.depend.stop
hidden_file[]=/snap/core/4917/etc/skel/.bash_logout
hidden_file[]=/snap/core/4917/etc/skel/.bashrc
hidden_file[]=/snap/core/4917/etc/skel/.profile
hidden_file[]=/snap/core/4917/var/lib/apparmor/profiles/.apparmor.md5sums
hidden_file[]=/snap/core/4486/etc/.pwd.lock
hidden_file[]=/snap/core/4486/etc/cron.d/.placeholder
hidden_file[]=/snap/core/4486/etc/cron.daily/.placeholder
hidden_file[]=/snap/core/4486/etc/cron.hourly/.placeholder
hidden_file[]=/snap/core/4486/etc/cron.monthly/.placeholder
hidden_file[]=/snap/core/4486/etc/cron.weekly/.placeholder
hidden_file[]=/snap/core/4486/etc/init.d/.depend.boot
hidden_file[]=/snap/core/4486/etc/init.d/.depend.start
hidden_file[]=/snap/core/4486/etc/init.d/.depend.stop
hidden_file[]=/snap/core/4486/etc/skel/.bash_logout
hidden_file[]=/snap/core/4486/etc/skel/.bashrc
hidden_file[]=/snap/core/4486/etc/skel/.profile
hidden_file[]=/snap/core/4486/var/lib/apparmor/profiles/.apparmor.md5sums
hidden_file[]=/snap/core/5328/etc/.pwd.lock
hidden_file[]=/snap/core/5328/etc/cron.d/.placeholder
...

我们可以聚焦于最简便的pwnable_program部分:

pwnable_programs[]=/bin/ash (For more details, visit:https://gtfobins.github.io/gtfobins/ash)
pwnable_programs[]=/usr/bin/awk (For more details, visit:https://gtfobins.github.io/gtfobins/awk)
pwnable_programs[]=/bin/bash (For more details, visit:https://gtfobins.github.io/gtfobins/bash)
pwnable_programs[]=/bin/csh (For more details, visit:https://gtfobins.github.io/gtfobins/csh)
pwnable_programs[]=/usr/bin/curl (For more details, visit:https://gtfobins.github.io/gtfobins/curl)
pwnable_programs[]=/bin/dash (For more details, visit:https://gtfobins.github.io/gtfobins/dash)
pwnable_programs[]=/bin/ed (For more details, visit:https://gtfobins.github.io/gtfobins/ed)
pwnable_programs[]=/usr/bin/env (For more details, visit:https://gtfobins.github.io/gtfobins/env)
pwnable_programs[]=/usr/bin/expect (For more details, visit:https://gtfobins.github.io/gtfobins/expect)
pwnable_programs[]=/usr/bin/find (For more details, visit:https://gtfobins.github.io/gtfobins/find)
pwnable_programs[]=/usr/bin/ftp (For more details, visit:https://gtfobins.github.io/gtfobins/ftp)
pwnable_programs[]=/usr/bin/less (For more details, visit:https://gtfobins.github.io/gtfobins/less)
pwnable_programs[]=/usr/bin/man (For more details, visit:https://gtfobins.github.io/gtfobins/man)
pwnable_programs[]=/bin/more (For more details, visit:https://gtfobins.github.io/gtfobins/more)
pwnable_programs[]=/usr/bin/scp (For more details, visit:https://gtfobins.github.io/gtfobins/scp)
pwnable_programs[]=/usr/bin/socat (For more details, visit:https://gtfobins.github.io/gtfobins/socat)
pwnable_programs[]=/usr/bin/ssh (For more details, visit:https://gtfobins.github.io/gtfobins/ssh)
pwnable_programs[]=/usr/bin/vi (For more details, visit:https://gtfobins.github.io/gtfobins/vi)
pwnable_programs[]=/usr/bin/zsh (For more details, visit:https://gtfobins.github.io/gtfobins/zsh)
pwnable_programs[]=/usr/bin/pico (For more details, visit:https://gtfobins.github.io/gtfobins/pico)
pwnable_programs[]=/usr/bin/perl (For more details, visit:https://gtfobins.github.io/gtfobins/perl)
pwnable_programs[]=/usr/bin/tclsh (For more details, visit:https://gtfobins.github.io/gtfobins/tclsh)
pwnable_programs[]=/usr/bin/git (For more details, visit:https://gtfobins.github.io/gtfobins/git)
pwnable_programs[]=/usr/bin/scp (For more details, visit:https://gtfobins.github.io/gtfobins/scp)

访问链接https://gtfobins.github.io/gtfobins/awk/,用以下命令提权:

bob@linsecurity:~/lynis-master$ sudo awk 'BEGIN {system("/bin/sh")}'
# id
uid=0(root) gid=0(root) groups=0(root)

当然,可以使用插件发现的其他信息进行提权

结语

本文总结了一下lynis的插件编写的过程,借助lynis我们可以开发出各种用途的lynis插件包括但不局限于攻击溯源,提权信息收集等等,希望可以给小伙伴以启发开发出更多提高工作效率的插件

完整的代码:https://github.com/nancheal/lynis-plugins,欢迎点star~

*本文作者:nancce,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。

来源:freebuf.com 2018-09-18 08:30:23 by: nancce

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论