redhat audit 学习笔记

 

一. audit 介绍

 

二. audit 规则

 1. 记录系统所有执行的命令

 

临时生效:

auditctl -a exit,always -F arch=b64 -F auid=0  -S execve -k op_sec_cmd
auditctl -a exit,always -F arch=b32 -F auid=0 -S execve -k op_sec_cmd

持续生效:

/etc/audit/audit.rules 添加如下规则:
#删除所有规则
auditctl -D

#监控execve系统调用

-a exit,always -F arch=b64 -F auid=0 -S execve -k op_sec_cmd
-a exit,always -F arch=b32 -F auid=0 -S execve -k op_sec_cmd 

#监控文件夹/tmp 读写执行和改变属性 注意auid 指定特定用户
-w /tmp/ -p rwxa -F auid=500 -k op-sec-dir-tmp
#只有重启才能修改规则
auditctl  -e 2

#监控rm命令执行

-a exit,always -F arch=b64 -S execve -F path=/bin/rm -k rm   
重新启动 service auditd restart
查看规则列表 auditctl -l

更新日志回滚

service auditd rotate

  

注意: auid=0表示 只是监听 uid为0的用户执行命令,即只记录root用户的所有命令,如果要记录所有用户执行命令,则去掉 -F auid=0即可。(auid审计ID,或者用户登录时使用的原始ID)。

 

加入规则方法:

 查看规则列表

  

 3. 将audit.log发送到远程syslog服务器 修改/etc/rsyslog.conf

$ModLoad imfile
$InputFileName /var/log/audit/audit.log
$InputFileTag tag_audit_log:
$InputFileStateFile audit_log
$InputFileSeverity info
$InputFileFacility local6
$inputRunFileMonitor
local6.*                          @10.8.96.14

  

三、实际例子

  1. 记录ssh登录的用户(密码登录),执行命令结果

   

# -*- coding: utf-8 -*-
import os
import json
import re
import sys
import time
import datetime
import pyinotify
import logging

'''
audit rule:
-a exit,always -F arch=b64  -S execve -k op_sec_cmd
-a exit,always -F arch=b32  -S execve -k op_sec_cmd

功能:
   打印每个用户登录ssh后所有命令操作,相同用户同时登录,只记录最后一次登录结果
   
对日志结果进行解析:
  1. 使用pyinotify 监控日志文件/var/log/audit/audit.log的变化,实时读取最新记录,并且处理日志切割情况
  2. 逐行读取日志,进行分析,标记值:
                             本行消息id: lid
                             上一行消息id: oid
                             本行记录的的类型: type
      2.1 if lid != oid, 上一条消息完毕,打印
      2.2   if type == USER_AUTH && op == PAM:authentication && exe == /usr/sbin/sshd: 如果是登录失败的记录,则进行统计,留着继续开发
      2.3   if type == USER_START && terminal == ssh && exe == /usr/sbin/sshd && res == sucess: 表示登录成功 获得记录的auid作为唯一标识,存储
      2.4   if type == SYSCALL && key == op_sec_cmd: 表示我们需要的记录,则记录消息信息,根据auid加入到消息池中,并且重置oid=lid 开始记录相同id的消息
      2.5   else if lid == oid:
      
           type == 'CWD' or type == 'EXECVE': 提取数据合并消息
      2.6   if type ==USER_END: 根据auid 找到对应记录 显示所有输出


'''
msg = {}
login_msg = {}
curid = ''
pos = 0
path = '/var/log/audit/audit.log'

#将原始日志 转换成json格式
def split_msg(mystr):
    try:
        tdict = {}
        data = mystr
        #如果存在msg 则首先提取msg
        if mystr.find("msg='") > -1:
            msg = re.findall("msg='(.+?)'",mystr)
            if len(msg) > 0:
                data = msg[0]
                data = mystr[0:mystr.index('msg=\'')] + data
        
         #mystr.split(' ')
        data = data.split(' ')
        for d in data:
            if d.find('=') > -1:
                key = d.split('=')[0]
                val = d.split('=')[1]
                val = val.strip('"')
                                
                if key.startswith('msg') and val.endswith(':'):
                    msg = re.findall('audit\((.+?)\):',val)
                    #tdict['timstamp'] = msg.split(':')[0]
                    #tdict['serialnum'] = msg.split(':')[1]
                    tdict['time_num'] = msg[0]
                else:
                    tdict[key] = val
        
        return tdict
    except Exception,e:
        print str(e)
#将时间转换成 可读格式
def change_time(mytime):
    try:

        if mytime.find(':') > -1:
            mytime = mytime.split(':')[0]
            x = time.localtime(float(mytime))
            mytime = time.strftime('%Y-%m-%d %H:%M:%S', x)
        #print mytime
        return mytime
    except Exception,e:
        print str(e)
        
#记录每条消息
def print_msg(msg):
    global login_msg
    try:
        if 'time_num' in msg:
            msg['time_num'] = change_time(msg['time_num'])
        if msg['auid'] in login_msg:
            if 'msg' not in login_msg[msg['auid']]:
                #print 'here not in msg'
                login_msg[msg['auid']]['msg'] = []
            
                
            login_msg[msg['auid']]['msg'].append(msg)
        #print msg
    except Exception,e:
        print str(e)

#处理一条记录
def handle_line(line):
    global curid,msg
    try:
        line = line.strip()
        if not line:
            return
        tdict = split_msg(line)
        
        timeid = tdict['time_num']
        if timeid != curid:  #新消息,关闭上一次记录
            if len(msg) > 1:
                print_msg(msg)
                pass
            curid = ''
            msg = {}
        etype = tdict['type']
        #通过CRED_ACQ 可以获得ssh登录后,创建bash的pid
        if etype == 'CRED_ACQ':
            if 'exe' in tdict and tdict['exe'] == "/usr/sbin/sshd":
                #login_msg[tdict['pid']] = tdict
                
                if 'auid' in tdict:
                    if int(tdict['auid']) < 10000:  #创建的ssh, 该ssh记录用于创建bash
                        #print_msg(tdict)
                        pass
                        
                    else:
                        pass
                        
            
        elif etype == 'USER_AUTH':   #USER_AUTH

            if 'op' in tdict and tdict['op'] == 'PAM:authentication':  #第一条认证信息
                
                if 'exe' in tdict and tdict['exe'] == "/usr/sbin/sshd": # 对ssh进行认证
                
                    if 'res' in tdict and tdict['res'] == 'failed': #通过ssh登录失败的记录
                        #print 'failed:'
                        #print tdict
                    
                        pass
                
        elif etype == 'USER_START':  #用户开始操作
            if 'terminal' in tdict and tdict['terminal'] != 'ssh':
                return
            if 'exe' in tdict and tdict['exe'] == "/usr/sbin/sshd":  #暂时只考虑sshd进行登录的情况, 不考虑用户内部切换情况
                if 'res' in tdict and tdict['res'] == 'success': #通过ssh登录成功的记录
                    
                    if tdict['auid'] not in login_msg:
                        #print '111111111111111'
                        #print login_msg
                        login_msg[tdict['auid']]= {}
                        login_msg[tdict['auid']]['pid'] = tdict['pid']
                        #print tdict
                        print_msg(tdict)
                        #print '22222222222222222'
                        #print login_msg
                        #login_msg[tdict['pid']] = tdict
                        #print 'login by ssh:'
                        #print_msg(tdict)
                    elif tdict['pid'] not in login_msg[tdict['auid']]:
                         login_msg.pop(tdict['auid'])
                         login_msg[tdict['auid']] = {}
                         login_msg[tdict['auid']]['pid'] = tdict['pid']
                         print_msg(tdict)
        elif etype == 'USER_END':  #用户退出时 产生的日志
            if 'terminal' in tdict and tdict['terminal'] != 'ssh':
                return
            if 'exe' in tdict and tdict['exe'] == "/usr/sbin/sshd": #暂时只考虑sshd退出情况
                if 'res' in tdict and tdict['res'] == 'success':
                    if tdict['auid']  in login_msg:
                        
                        
                        print_msg(tdict)
                        #login_msg.pop(tdict['pid'])
                        if tdict['auid'] in login_msg and tdict['pid'] == login_msg[tdict['auid']]['pid']:
                            #print 'here'
                            #print tdict
                            #print login_msg[tdict['auid']]
                            #for i in login_msg:
                            #    print login_msg[i]
                            
                            #print 'logout by ssh'
                            username = ''
                            cwd = ''
                            for m in login_msg[tdict['auid']]['msg']:
                                #print m
                                if 'type' in m and m['type'] == 'USER_START':
                                    print 'login start'
                                    #print m
                                    username = m['acct']
                                    print '%s user:%s loginIN from %s by ssh  pid: %s ' % (m['time_num'], m['acct'], m['addr'], m['pid'])
                                elif 'type' in m and m['type'] == 'USER_END':
                                    print 'logout '
                                    #print m
                                    print '%s user:%s loginOUT from %s by ssh pid: %s' % (m['time_num'], m['acct'], m['addr'], m['pid'])
                                else:
                                    if 'cwd' in m:
                                        cwd = m['cwd']
                                    else:
                                        cwd = ''
                                    print '%s [%s@%s]:%s' % (m['time_num'], username, cwd,m['exe'])
                                    
                            login_msg.pop(tdict['auid'])
        elif etype == 'SYSCALL':
            #只获取需要监控的命令 -a exit,always -F arch=b32 -F auid=0 -S execve -k op_sec_cmd
            if 'key' in tdict and tdict['key'] == 'op_sec_cmd':  
                
            #if 'syscall' in tdict and tdict['syscall'] == '11':
                
                msg['time_num'] = timeid
                curid = timeid
                msg['key'] = tdict['key']
                msg['exe'] = tdict['exe']
                
                if 'pid' in tdict:
                    msg['pid'] = tdict['pid']
                if 'ppid' in tdict:
                    msg['ppid'] = tdict['ppid']

                if 'auid' in tdict:
                    msg['auid'] = tdict['auid']
                if 'euid' in tdict:
                    msg['euid'] = tdict['euid']
                
                
        elif timeid == curid:
            if etype == 'CWD':
                msg['cwd'] = tdict['cwd']
            elif etype == 'EXECVE':
                if 'argc' in tdict:
                    argc = int(tdict['argc'])
                    for i in range(1,argc,1):
                        if 'a'+str(i) in tdict:
                            msg['exe'] = msg['exe'] + '  ' + tdict['a'+str(i)]
        else:
             pass
    except Exception,e:
        print line
        print str(e)






def printlog():
    global pos
    try:
            fd = open(path)
            if pos != 0:
                fd.seek(pos,0)
            while True:
                line = fd.readline()
                if line.strip():
                    handle_line(line.strip())
                pos = pos + len(line)
                if not line.strip():
                    break
            fd.close()
    except Exception,e:
        print str(e)
        
class MyEventHandler(pyinotify.ProcessEvent):
    
    #当文件被修改时调用函数
    def process_IN_MODIFY(self, event):
        try:
            printlog()
        except Exception,e:
            print str(e)
    #文件自动被删除
    # 文件被删除 或者切割
    def process_IN_MOVE_SELF(self,event):
        global notifier
        try:
            notifier.stop()
            #wm.rm_watch(0)
        except Exception,e:
            print str(e)
notifier = None
def main():
    global notifier,pos
    
    
    while True:
        if os.path.isfile(path):
            pos = 0
            #输出前面的log
            printlog()
            # watch manager
            wm = pyinotify.WatchManager()
            eh = MyEventHandler()
            notifier = pyinotify.Notifier(wm, eh)
            wm.add_watch(path, pyinotify.IN_MOVE_SELF|pyinotify.IN_MODIFY, rec=True)
            

            # notifier
            try:
                notifier.loop()
            except Exception,e:
                print str(e)
            print 'end one time'
        else:
            time.sleep(60)

if __name__ == '__main__':
    main()

  实际执行效果:

 

 

 2. 搭建nginx+php-fpm 环境,详细安装过程如:http://blog.csdn.net/seanchan/article/details/7680354

    安装后,查看php-fpm的用户名为apache

    

    查看apache帐号的uid

   

[root@localhost Desktop]# cat /etc/passwd | grep apache
apache:x:48:48:Apache:/var/www:/sbin/nologin

  添加auid规则

   

-a exit,always -F arch=b64  -S execve -k op_sec_cmd
-a exit,always -F arch=b32  -S execve -k op_sec_cmd

  创建/usr/share/nginx/html/system.php

     

<?php
system("whoami");
?>

  可以看到访问页面产生的日志格式

    

 

   可以看到euid为48 及apache帐号, cwd为webroot目录(更确切说该值表示的脚本所在目录,但是并不知道哪个脚本执行的命令)。因此如果使用php执行系统命令时,可以通过audit进行审计,并且cwd为web目录。但是auid为什么为0(因为php-fpm最开始的进程是root启动的,auid应该表示哪个最开始启动的用户id,所以表示的是0)?

   如果修改代码为命令注入格式

   

<?php
$cmd = "ls -lh ". $_GET['path'];
print $cmd;
system($cmd);

?>

  发现产生的日志如下:

       说明在底层看到的命令注入 和php层看到的是不一样的,php层输入一条完成路径,但是命令是分开执行的,比如php 输入ls /tmp && whoami, 那么底层系统调用先执行ls /tmp 然后在下一个系统调用执行whoami,所以在底层检测还是不容易判断出是命令注入还是正常执行的命令,php层通过hook 执行命令api应该比较容易判断,通过对& 和| 和`` 字符的检测。可见,检测是各有利弊的。

     还有一个比较有意思现象:

    

echo 向一个文件写入内容,如果单纯监控命令执行符号表,是没有办法获得这条记录的,分析echo 是bash内部函数,不存在系统调用? 重定向符号不会产生系统调用,而是会产生文件相关系统调用,调整监控规则如下:

-a exit,always -F arch=b64 -F euid=48|euid=apache  -S execve -k op_sec_cmd
-w /tmp/ -p wxa -F euid=48 -k op_tmp

  获得到的监控结果

发现与猜测一样,重定向符合导致的是写入文件操作,并非系统调用api

 

audit看到的是上层处理过的结果,因此中间的一些过程,是没有办法看到的,比如如下的目录穿越操作:

php中是文件穿越的,但是到audit我们看到已经还原成/tmp/ok.txt了

 

 

 

     

    

 

 

   实例- web提权audit日志

 

   实例- 监控特定进程对某个文件的夹的操作

   使用php读取文件/etc/passwd测试

   配置审计规则,对所有读取/etc下文件进行记录

-a exit,always -F arch=b64 -F euid=48|euid=apache|auid=48|auid=apache  -S execve -k op_sec_cmd
-a exit,always -F arch=b32  -S execve -k op_sec_cmd 
-a exit,always -F arch=b64 -S open -F dir=/etc  -k read_file

 建立测试php文件读取/etc/passwd

 

[root@localhost html]# cat /usr/share/nginx/html/test/read_pass.php 
<?php

echo file_get_contents("/etc/passwd");

?>

  产生的日志记录

type=SYSCALL msg=audit(1494228252.232:241): arch=c000003e syscall=2 success=yes exit=4 a0=fae5d8 a1=0 a2=1b6 a3=b items=1 ppid=2924 pid=2926 auid=0 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=1 comm="php-fpm" exe="/usr/sbin/php-fpm" subj=unconfined_u:system_r:initrc_t:s0 key="read_file"
type=CWD msg=audit(1494228252.232:241):  cwd="/usr/share/nginx/html/test"
type=PATH msg=audit(1494228252.232:241): item=0 name="/etc/passwd" inode=263012 dev=08:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:etc_t:s0

  可以看到产生的是进程php-fpm 触发的系统调用,所在目录是/usr/share/nginx/html/test目录,读取的PATH是/etc/passwd,

     修改后的审计规则: 监控读取/etc/passwd

     

-a exit,always -F arch=b64 -S open -F dir=/etc -F euid=48|euid=apache  -k read_file

  

 

 总结: audit 监控web操作 好处:

          1. 可以捕获到所有操作的最终版本,上层操作无法逃过不产生日志

          2. 但由于一些原因,上层操作会分解成多个系统调用,每个系统调用之间比较难关联到一起,使得确定问题比较难

 

   有一个比较麻烦的问题,在分析audit的日志时,audit.log的日志有些时候是经过编码的,因此需要使用

ausearch --interpret 参数将其转化成人可以看懂的形式,但是如果我们使用python java等程序,貌似没有办法转换c语言的格式。

   比如监控connect系统调用时,会生成一个sockaddr 类型的记录,这个记录的saddr是一个c语言的struct sockaddr 的序列化后结果,具体还原过程在audit-userspace-master\audit-userspace-master\auparse\interpret.c 的print_sockaddr中,但是用python还原可能还是比较麻烦

  比如监控connect系统调用,使用wget访问网络时,产生如下的日志信息

 

type=USER_END msg=audit(1495123801.271:1864): user pid=36628 uid=0 auid=0 ses=264 subj=system_u:system_r:crond_t:s0-s0:c0.c1023 msg='op=PAM:session_close acct="root" exe="/usr/sbin/crond" hostname=? addr=? terminal=cron res=success'
type=SYSCALL msg=audit(1495309150.729:1864): arch=c000003e syscall=42 success=yes exit=0 a0=4 a1=1291bb0 a2=10 a3=1c items=0 ppid=5227 pid=5228 auid=0 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=1 comm="wget" exe="/usr/bin/wget" subj=unconfined_u:system_r:initrc_t:s0 key="op_sec_cmd"
type=SOCKADDR msg=audit(1495309150.729:1864): saddr=02000035C0A86D020000000000000000

 这里看到一个saddr后面是一串数字,使用ausearch的友好显示命令,ausearch -i   -a 1864

 

可以看到,saddr显示的友好结果是,连接的主机是192.168.109.2 端口号是53,应该是dns查询请求,查看ausearch源代码

audit-userspace-master\audit-userspace-master\auparse\interpret.c 的print_sockaddr中

static const char *print_sockaddr(const char *val)
{
        int slen, rc = 0;
        const struct sockaddr *saddr;
        char name[NI_MAXHOST], serv[NI_MAXSERV];
        const char *host;
        char *out = NULL;
        const char *str;

        slen = strlen(val)/2;
        host = au_unescape((char *)val);  #进入的字符串序列,调用au_unescape函数进行解码
	if (host == NULL) {
		if (asprintf(&out, "malformed-host(%s)", val) < 0)
			out = NULL;
		return out;
	}
        saddr = (struct sockaddr *)host; #解码后,数据转换成struct socketaddr 结构体,进一步判断


        str = fam_i2s(saddr->sa_family);
        if (str == NULL) {
		if (asprintf(&out, "unknown-family(%d)", saddr->sa_family) < 0)
			out = NULL;
		free((char *)host);
		return out;
	}

 将字符串解码的具体函数

char *au_unescape(char *buf)
{
        int olen, len, i;
        char saved, *str, *ptr = buf;

        /* Find the end of the name */
        if (*ptr == '(') {
                ptr = strchr(ptr, ')');
                if (ptr == NULL)
                        return NULL;
                else
                        ptr++;
        } else {
                while (isxdigit(*ptr))
                        ptr++;
        }
	// Make the buffer based on size of original buffer.
	// This is in case we have unexpected non-hex digit
	// that causes truncation of the conversion and passes
	// back a buffer that is not sized on the expectation of
	// strlen(buf) / 2.
	olen = strlen(buf);
	str = malloc(olen+1);

        saved = *ptr;
        *ptr = 0;
	strcpy(str, buf);
        *ptr = saved;

	/* See if its '(null)' from the kernel */
        if (*buf == '(')
                return str;

        /* We can get away with this since the buffer is 2 times
         * bigger than what we are putting there.
         */
        len = strlen(str);
        if (len < 2) {
                free(str);
                return NULL;
        }
        ptr = str;
        for (i=0; i<len; i+=2) {
                *ptr = x2c((unsigned char *)&str[i]);
                ptr++;
        }
        *ptr = 0;
	len = ptr - str - 1;
	olen /= 2;
	// Because *ptr is 0, writing another 0 to it doesn't hurt anything
	if (olen > len)
		memset(ptr, 0, olen - len);
        return str;
}

/*
 * This function will take a pointer to a 2 byte Ascii character buffer and
 * return the actual hex value.
 */
static unsigned char x2c(const unsigned char *buf)
{
        static const char AsciiArray[17] = "0123456789ABCDEF";
        char *ptr;
        unsigned char total=0;

        ptr = strchr(AsciiArray, (char)toupper(buf[0]));
        if (ptr)
                total = (unsigned char)(((ptr-AsciiArray) & 0x0F)<<4);
        ptr = strchr(AsciiArray, (char)toupper(buf[1]));
        if (ptr)
                total += (unsigned char)((ptr-AsciiArray) & 0x0F);

        return total;
}

最终找到 au_unescape 的python实现binascii.a2b_hex.

import binascii
print binascii.a2b_hex('0A0A09202020206675') 可以将十六进制字符串转成 字符串

     

但是怎样在python中实现类似c语言 saddr = (struct sockaddr *)host; 着实花费了一些功夫。

吃水不忘挖井人,在此非常感谢 http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=20764167&id=1854706 博文

整理后的测试代码:

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>

#define MYPORT  8887
#define BUFFER_SIZE 1024

int main()
{
    ///定义sockfd
    int sock_cli = socket(AF_INET,SOCK_STREAM, 0);

    ///定义sockaddr_in
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(MYPORT);  ///服务器端口
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  ///服务器ip

    ///连接服务器,成功返回0,错误返回-1
    if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
        perror("connect");
        exit(1);
    }

    int len = sizeof(struct sockaddr_in);
	char send[len + 1];
	memset(send, 0, len + 1);
	memcpy(send, &servaddr, len);
	
	unsigned short sa_family = servaddr.sin_family;
	unsigned short sin_port = servaddr.sin_port;
	unsigned short s_addr= servaddr.sin_addr.s_addr;
	
	printf("%u %u %u\n", sa_family, sin_port, s_addr);
	int n =0;
	n = write(sock_cli, send, len);
	if(n != len){
	   printf("write error\n");
	 }
	
	printf("write over\n");
    close(sock_cli);
    return 0;
}

 server端代码

from socket import *
from time import time, ctime

 
Host = '127.0.0.1'
Port = 8887
BUFSIZ = 1024
ADDR = (Host, Port)

 
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)


try:
    while 1:
        print 'waiting for connection...'
        tcpCliSock, addr = tcpSerSock.accept()
        print '...connected from :' ,addr
        while 1:
            data = tcpCliSock.recv(BUFSIZ)
            if not data: break
            print "received :", len(data)
            import struct
            ip = struct.unpack('HHIII0l', data)  #line 24
            print "ip[0] ",ip[0]
            print "ip[1] ",ip[1]
            #netip = struct.unpack('!I', ip[2])
            print "ip[2] ",ip[2]
            print "ip[3] ",ip[3]
            print "ip[4] ",ip[4]
            #tcpCliSock.send("hello ack")
            break
            #tcpCliSock.send('[%s] %s' %
            #           (ctime(time()), data))
        tcpCliSock.close()

except EOFError:

    print 'EOFError  Occur'



    print 'KeyboardInterrupt catched'

finally:

tcpSerSock.close()

  测试结果:

  客户端和服务端显示结果,通过上面的例子,可以看出其实是实现了一个类似序列化和反序列化的过程,将c语言的结构体,在内存中的数据直接发送到python端,python结合结构体的结构进行解析,还原出各个字段。但是我们看到的字段,比如ip和端口,还不是我们想要的。

看一下端口和ip的处理方式:

  servaddr.sin_port = htons(MYPORT); 

servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  

是经过两个函数htons和inet_addr处理过的,因此在python中找到对应的解码函数,即可实现解码

socket.htons

socket.inet_ntoa

最终python解析字符串的代码如下:

import binascii
import socket
import struct
import sys

ip = struct.unpack('HHIII',binascii.a2b_hex('02000035C0A86D020000000000000000'))
if len(ip) == 5:
    print socket.htons(ip[1])
    print socket.inet_ntoa(struct.pack('I',ip[2]))

 补充发现,connect连接还会产生如下的日志

type=SOCKADDR msg=audit(1495441774.973:2695): saddr=01002F7661722F72756E2F6E7363642F736F636B6574000003000000300000005B0000007C000000770000006E0000000500000000000000010000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000050000003100

  使用上述方法解析报错,使用ausearch进行解析

 

 发现是一个字符串,但是使用

binascii.a2b_hex('01002F7661722F72756E2F6E7363642F736F636B6574000003000000300000005B0000007C000000770000006E0000000500000000000000010000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000050000003100
')

 会导致报错,但是字符串貌似也没有特别大作用,但是为了兼容上面的获得saddr中的值,需要判断字符串长度是否为struct sockaddr 32个字符, 

 

问题1:

什么时候audit会使用编码形式表示字符串:

type=EXECVE msg=audit(1495279249.378:187): argc=3 a0="sh" a1="-c" a2=6C73202D6C68202F746D702026262077686F616D69 #ls -lh /tmp && whoami
type=EXECVE msg=audit(1495279261.797:190): argc=3 a0="/bin/sh" a1="-c" a2=6E6963652072756E2D7061727473202F6574632F63726F6E2E6461696C79 #nice run-parts /etc/cron.daily
type=EXECVE msg=audit(1495279261.833:198): argc=4 a0="awk" a1="-v" a2="progname=/etc/cron.daily/cups" a3=70726F676E616D65207B0A090909092020207072696E742070726F676E616D6520223A5C6E220A0909090920202070726F676E616D653D22223B0A090909202020202020207D0A090909202020202020207B207072696E743B207D

progname {
print progname ":\n"
progname="";
}
{ print; }

  

发现一个规律,就是当不是以"开始的字符,即为编码字符,并且被编码原因是因为里面包含空格,导致格式错乱

如果一个字段的长度超长,那么要怎么记录?采用分段的形式,如下所示:

type=SYSCALL msg=audit(1494228191.629:233): arch=c000003e syscall=2 success=yes exit=3 a0=7f9d258f2cbc a1=0 a2=1b6 a3=2 items=1 ppid=3175 pid=3523 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts1 ses=1 comm="vim" exe="/usr/bin/vim" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key="read_file"
type=CWD msg=audit(1494228191.629:233):  cwd="/usr/share/nginx/html"
type=PATH msg=audit(1494228191.629:233): item=0 name="/etc/nsswitch.conf" inode=261713 dev=08:02 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:etc_t:s0
type=SYSCALL msg=audit(1495279262.058:233): arch=c000003e syscall=59 success=yes exit=0 a0=1a00c20 a1=19ebd70 a2=1a004b0 a3=38 items=2 ppid=3114 pid=3132 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=5 comm="awk" exe="/bin/gawk" subj=system_u:system_r:system_cronjob_t:s0-s0:c0.c1023 key="op_sec_cmd"
type=EXECVE msg=audit(1495279262.058:233): argc=6 a0="/bin/awk"
type=EXECVE msg=audit(1495279262.058:233):  a1_len=14368 a1[0]=0A0A092020202066756E6374696F6E20726561646C696E652829207B0A2020202020202020202020202020696620287573655F7A636174207C7C207573655F627A636174207C7C207573655F6C7A63617429207B0A0909726573756C74203D2028706970655F636D64207C206765746C696E65293B0A090969662028726573756C74203C203029207B0A090920207072696E74202250697065206572726F723A202220706970655F636D6420222022204552524E4F203E20222F6465762F737464657272223B0A09097D0A092020202020207D20656C7365207B0A0909726573756C74203D20286765746C696E65203C2066696C656E616D65293B0A090969662028726573756C74203C203029207B0A090920207072696E742022526561642066696C65206572726F723A20222066696C656E616D6520222022204552524E4F203E20222F6465762F737464657272223B0A09097D0A092020202020207D0A0920202020202072657475726E20726573756C743B0A09202020207D0A09202020200A092020202066756E6374696F6E20636C6F73656C696E652829207B0A2020202020202020202020202020696620287573655F7A636174207C7C207573655F627A636174207C7C207573655F6C7A63617429207B0A090972657475726E20636C6F736528706970655F636D64293B0A092020202020207D20656C7365207B0A090972657475726E20636C6F73652866696C656E616D65293B0A092020202020207D0A09202020207D0A09202020200A092020202066756E6374696F6E20646F5F6F6E652829207B0A09202020202020696E7368203D20303B20746869736A6F696E203D20313B20646F6E65203D20303B0A09202020202020656E746972655F6C696E65203D2022223B0A0A0920202020202069662028766572626F736529207B0A09097072696E742022616464696E6720222066696C656E616D65203E20222F6465762F737464657272220A092020202020207D0A092020202020200A092020202020207573655F7A636174203D206D617463682866696C656E616D652C225C5C2E5A242229207C7C0A090909206D617463682866696C656E616D652C225C5C2E7A242229207C7C206D617463682866696C656E616D652C225C5C2E677A2422293B0A0920202020202069662028217573655F7A636174290A09097573655F627A636174203D206D617463682866696C656E616D652C225C5C2E627A3222293B0A2020202020202020202020202020696628217573655F627A63617420262620217573655F7A636174290A202020202020202020202020202020207573655F6C7A636174203D206D617463682866696C656E616D652C225C5C2E6C7A6D6122293B0A2020202020202020202020202020696620287573655F7A636174207C7C207573655F627A636174207C7C207573655F6C7A6361742029207B0A090966696C656E616D655F6E6F5F677A203D207375627374722866696C656E616D652C20302C20525354415254202D2031293B0A092020202020207D20656C7365207B0A090966696C656E616D655F6E6F5F677A203D2066696C656E616D653B0A092020202020207D0A092020202020206D617463682866696C656E616D655F6E6F5F677A2C20222F5B5E2F5D2B2422293B0A0920202020202070726F676E616D65203D207375627374722866696C656E616D652C20525354415254202B20312C20524C454E475448202D2031293B0A09202020202020696620286D617463682870726F676E616D652C20225C5C2E222073656374696F6E20225B412D5A612D7A5D2B222929207B0A090961637475616C5F73656374696F6E203D207375627374722870726F676E616D652C20525354415254202B20312C20524C454E475448202D2031293B0A092020202020207D20656C7365207B0A090961637475616C5F73656374696F6E203D2073656374696F6E3B0A092020202020207D0A09202020202020737562282F5C2E2E2A2F2C2022222C2070726F676E616D65293B0A2020202020202020202020202020696620287573655F7A636174207C7C207573655F627A636174207C7C207573655F6C7A63617429207B0A0909696620287573655F7A63617429207B0A09092020706970655F636D64203D20227A636174205C22222066696C656E616D6520225C2220323E2F6465762F6E756C6C223B0A202020202020202020202020202020207D20656C736520696620287573655F627A63617429207B0A09092020706970655F636D64203D2022627A636174205C22222066696C656E616D6520225C2220323E2F6465762F6E756C6C223B0A202020202020202020202020202020207D20656C7365207B0A202020202020202020202020202020202020706970655F636D64203D20226C7A636174205C22222066696C656E616D6520225C2220323E2F6465762F6E756C6C223B0A202020202020202020202020202020207D0A202020202020202020202020202020202320436875636B206F757470757420756E6C657373206974206973207574662D380A20202020202020202020202020202020706970655F636D64203D20706970655F636D642022207C69636F6E76202D66207574662D38202D74207574662D3820323E2F6465762F6E756C6C220A0909232074727920746F2061766F696420737573706963696F75732073747566660A09096966202866696C656E616D65207E202F5B3B267C6024285D2F29207B0A090920207072696E74202269676E6F72656420737472616E67652066696C65206E616D6520222066696C656E616D65202220696E202220637572646972203E20222F6465762F737464657272223B0A0909202072657475726E3B0A09097D0A092020202020207D0A09202020200A092020202020207768696C65202821646F6E6520262620726561646C696E652829203E203029207B0A090967737562282F2E5C622F2C202222293B0A090969662028282431207E202F5E5C2E5B53735D5B48685D2F2026260A09092020282432207E202F5B4E6E5D5B41615D5B4D6D5D5B45655D2F207C7C0A09092020202432207E202F5E4A4DC94E4F2F207C7C202432207E202F5E4E41564E2F207C7C202432207E202F5E4E554D452F207C7C0A09092020202432207E202F5E42455A454943484E554E472F207C7C202432207E202F5E4E4F4D4252452F207C7C0A09092020202432207E202F5E4E494D492F207C7C202432207E202F5E4E4F4D2F207C7C202432207E202F5E494D452F207C7C0A09092020202432207E202F5E4E5BC9455D562F207C7C202432207E202F5E4E414D412F207C7C202432207E202F5ECCBEC1B02F207C7C0A09092020202432207E202F5ECCBEBECE2F207C7C202432207E202F5EC0CCB8A72F207C7C202432207E202F5E4E415A57412F207C7C0A09092020202432207E202F5EEEE1FAF7E1EEE9E52F207C7C202432207E202F5EC3FBB3C62F207C7C202432207E202F5EA657BAD92F207C7C0A09092020202432207E202F5E4E4F4D452F207C7C202432207E202F5E4E41414D2F207C7C202432207E202F5EC8CCC52F2929207C7C0A09092020287061676573203D3D202263617422202626202431207E202F5E4E414D452F2929207B0A0909202020206966202821696E736829207B0A0909202020202020696E7368203D20313B0A0909202020207D20656C7365207B0A0909202020202020646F6E65203D20313B0A0909202020207D0A09097D20656C73652069662028696E736829207B0A09092020696620282431207E202F5E5C2E5B53735D5B486859535D2F207C7C0A090920202020287061676573203D3D2022636174222026260A090920202020282431207E202F5E535B795965455D2F207C7C202431207E202F5E4445534352495054494F4E2F207C7C0A090920202020202431207E202F5E434F4D4D414E442F207C7C202431207E202F5E4F564552564945572F207C7C0A090920202020202431207E202F5E535452554354555245532F207C7C202431207E202F5E494E54524F44554354494F4E2F207C7C0A090920202020202430207E202F5E5B5E205D2F292929207B0A09092020202020202320656E6420696E736820666F722053796E6F707369732C2053796E7461782C2062757420616C736F20666F720A090920202020202023204445534352495054494F4E2028652E672E2C20584672656538362E3178292C0A09092020202020202320434F4D4D414E442028652E672E2C20787370726561642E31290A090920202020202023204F564552564945572028652E672E2C2054636C436F6D6D616E6457726974696E672E33290A09092020202020202320535452554354555245532028652E672E2C20584576656E742E3378290A09092020202020202320494E54524F44554354494F4E2028652E672E2C2054636C582E6E290A09092020202020202320616E6420616E797468696E6720617420616C6C207468617420626567696E7320696E20436F6C756D6E20312C20736F200A0909202020202020232069732070726F6261626C7920612073656374696F6E206865616465722E0A090920202020646F6E65203D20313B0A090920207D20656C7365207B0A232054686965206F766572776F726B20627265616B20746865207265636F72647320666F72206D616E2D706167657320636F6E73697374696E67206461736820696E207468656972206E616D650A23090920202020696620282430207E2070726F676E616D65222D2229207B20202320466978206F6C64206361742070616765730A230909097375622870726F676E616D65222D222C2070726F676E616D6522202D2022293B0A230909202020207D0A090920202020696620282430207E202F5B5E205C5C5D2D242F29207B0A0909202020202020737562282F2D242F2C202222293B092020232048616E646C652048797068656E6174696F6E730A09092020202020206E6578746A6F696E203D20313B0A0909202020207D20656C736520696620282430207E202F5C5C63242F29207B0A0909202020202020737562282F5C5C63242F2C202222293B092020232048616E646C6520436F6E74696E756174696F6E730A09092020202020206E6578746A6F696E203D20313B0A0909202020207D20656C73650A09092020202020206E6578746A6F696E203D
type=EXECVE msg=audit(1495279262.058:233):  a1[1]=20303B0A0A090920202020737562282F5E2E5B49425D202F2C202222293B2020202020202023204B696C6C20626F6C6420616E64206974616C6963730A090920202020737562282F5E2E4249202F2C202222293B202020202020202020230A090920202020737562282F5E2E534D202F2C202222293B20202020202020202023204B696C6C20736D616C6C0A090920202020737562282F5E2E4E6D202F2C202222293B20202020202020202023204B696C6C20626F6C640A090920202020737562282F5E2E546E202F2C202222293B20202020202020202023204B696C6C206E6F726D616C0A09202020202020202020202020737562282F5E2E4C69202F2C202222293B20202020202020202023204B696C6C202E4C690A09202020202020202020202020737562282F5E2E4471202F2C202222293B20202020202020202023204B696C6C202E44710A09202020202020202020202020737562282F5E2E4E64202A2F2C20222D2022293B2020202020202320436F6E76657274202E4E6420746F20646173680A090920202020737562282F5C5C5C222E2A2F2C202222293B202020202020202023205472696D2070656E64696E6720636F6D6D656E74730A090920202020737562282F20202A242F2C202222293B2020202020202020202023205472696D2070656E64696E67207370616365730A090920202020737562282F5E5C2E242F2C202222293B2020202020202020202023204B696C6C20626C616E6B20636F6D6D656E74730A090920202020737562282F5E272E2A2F2C202222293B20202020202023204B696C6C20636F6D6D656E742F74726F6666206C696E65730A090920202020737562282F5E2E696E202E2A2F2C202222293B2020202020202023204B696C6C20766172696F7573206D6163726F730A090920202020737562282F5E2E7469202E2A2F2C202222293B0A090920202020737562282F5E2E7461202E2A2F2C202222293B0A090920202020737562282F5E2E5662202E2A2F2C202222293B0A090920202020737562282F5E2E5B504C54485D50242F2C202222293B2020202023202E50502F2E4C502F2E54502F2E48500A090920202020737562282F5E2E5070242F2C202222293B0A090920202020737562282F5E2E5B69495D58202E2A242F2C202222293B0A090920202020737562282F5E2E6E6F6C696E6B73242F2C202222293B0A090920202020737562282F5E2E42242F2C202222293B0A090920202020737562282F5E2E6E66242F2C202222293B0A0A09092020202069662028282431207E202F5E5C2E2E2E2F207C7C202431203D3D202222292026260A0909202020202020202028656E746972655F6C696E65207E202F202D202F207C7C20656E746972655F6C696E65207E202F205C5C2D202F2929207B0A09092020202020202320417373756D652074686174207468697320656E647320746865206465736372697074696F6E206F66206F6E65206C696E650A09092020202020202320536F6D6574696D657320746865726520617265207365766572616C206465736372697074696F6E7320696E206F6E6520706167652C0A09092020202020202320617320696E206F7574622832292E0A090920202020202068616E646C655F656E746972655F6C696E6528293B0A0909202020202020656E746972655F6C696E65203D2022223B0A0909202020202020746869736A6F696E203D20313B0A0909202020207D20656C7365207B0A090920202020202069662028746869736A6F696E29207B0A090909656E746972655F6C696E65203D20656E746972655F6C696E652024303B0A09092020202020207D20656C7365207B0A090909656E746972655F6C696E65203D20656E746972655F6C696E65202220222024303B0A09092020202020207D0A0909202020202020746869736A6F696E203D206E6578746A6F696E3B0A0909202020207D0A090920207D0A09097D0A092020202020207D0A0920202020202068616E646C655F656E746972655F6C696E6528293B0A09202020202020636C6F73656C696E6528293B0A09202020207D0A0A092020202066756E6374696F6E2068616E646C655F656E746972655F6C696E652829207B0A0920202020202078203D20656E746972655F6C696E653B2020202020202020202020202023204B6565702069742073686F72740A0A0920202020202067737562282F5C3031352F2C2022222C2078293B20202020202020202023204B696C6C20444F532072656D61696E730A0920202020202067737562282F092F2C202220222C2078293B202020202020202023205472616E736C617465207461627320746F207370616365730A0920202020202067737562282F20202B2F2C202220222C2078293B2020202020202020202320436F6C6C61707365207370616365730A0920202020202067737562282F202A2C202A2F2C20222C20222C2078293B202020202020232046697820636F6D6D612073706163696E67730A09202020202020737562282F5E202F2C2022222C2078293B20202020202020202020202023204B696C6C20696E697469616C207370616365730A09202020202020737562282F20242F2C2022222C2078293B20202020202020202020202023204B696C6C20747261696C696E67207370616365730A09202020202020737562282F5F5F2B2F2C20225F222C2078293B202020202020202020202320436F6C6C6170736520756E64657273636F7265730A0A0920202020202067737562282F5C5C665C282E2E2F2C2022222C2078293B20202020202020202023204B696C6C20666F6E74206368616E6765730A0920202020202067737562282F5C5C665B50524942303132335D2F2C2022222C2078293B20202023204B696C6C20666F6E74206368616E6765730A0920202020202067737562282F5C5C735B2D2B302D395D2A2F2C2022222C2078293B202020202023204B696C6C2073697A65206368616E6765730A0920202020202067737562282F5C5C262F2C2022222C2078293B2020202020202020202020202023204B696C6C205C260A0920202020202067737562282F5C5C5C7C2F2C2022222C2078293B20202020202020202020202023204B696C6C205C7C0A0920202020202067737562282F5C5C5C282872757C756C292F2C20225F222C2078293B2020202023205472616E736C6174650A0920202020202067737562282F5C5C5C28286D697C68797C656D292F2C20222D222C2078293B2023205472616E736C6174650A0920202020202067737562282F5C5C5C2A5C282E2E2F2C2022222C2078293B202020202020202023204B696C6C2074726F666620737472696E67730A0920202020202067737562282F5C5C2F2C2022222C2078293B202020202020202020202020202023204B696C6C20616C6C206261636B736C61736865730A0920202020202067737562282F222F2C2022222C2078293B20202020202020202020202020202023204B696C6C2071756F746573202866726F6D202E4E642022666F6F2062617222290A09202020202020737562282F3C683120616C69676E3D63656E7465723E2F2C2022222C2078293B232059756B212048544D4C2063727566740A0920202020202067737562282F5C3030302E2A2F2C202258222C2078293B202020202020202020232042696E61727920637275667420696E204C415041434B2070616765730A0920202020202067737562282F20202B2F2C202220222C2078293B2020202020202020202020202320436F6C6C61707365207370616365732028616761696E290A09202020202020737562282F5E202F2C2022222C2078293B20202020202020202020202020202023204B696C6C20696E697469616C207370616365732028616761696E290A09202020202020737562282F20242F2C2022222C2078293B20202020202020202020202020202023204B696C6C20747261696C696E67207370616365732028616761696E290A09202020202020737562282F5C2E242F2C2022222C2078293B202020202020202020202020202023204B696C6C20747261696C696E6720706572696F640A0A20202020202069662028216D6174636828782C202F202D2D3F202F29290A090972657475726E3B0A0A0920202020202061667465725F64617368203D2073756273747228782C20525354415254293B0A0920202020202068656164203D2073756273747228782C20312C205253544152542D312920222C20223B0A092020202020207768696C6520286D6174636828686561642C202F2C202F2929207B0A090970726F67203D2073756273747228686561642C20312C205253544152542D31293B0A090968656164203D2073756273747228686561642C205253544152542B32293B0A09096966202870726F6720213D2070726F676E616D65290A0909202070726F67203D2070726F672022205B222070726F676E616D6520225D223B0A09097072696E74662022252D2A7320282573292025735C6E222C2032302C2070726F672C2061637475616C5F73656374696F6E2C2061667465725F646173683B0A092020202020207D0A09202020207D0A0A09202020207B09090923204D61696E20616374696F6E202D2070726F6365737320656163682066696C656E616D65207265616420696E2E0A0920202020202066696C656E616D65203D2024303B0A09202020202020646F5F6F6E6528293B0A09202020207D0A0920202020 a2="pages=man" a3="section=8" a4="verbose=" a5="curdir=/usr/share/man/overrides/man8"
type=CWD msg=audit(1495279262.058:233):  cwd="/usr/share/man/overrides/man8"
type=PATH msg=audit(1495279262.058:233): item=0 name="/bin/awk" inode=919818 dev=08:02 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:bin_t:s0
type=PATH msg=audit(1495279262.058:233): item=1 name=(null) inode=654491 dev=08:02 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:ld_so_t:s0

 argc = 6 并且a1 是一个数组,除了a1_len ,貌似没有看到哪里有标志 a1数组长度的字段,解析过程大概为:

  根据event id将相同事件的记录汇总,

  然后根据type=EXECVE,将相同类型的事件进行汇聚,

  继续根据argc个数进行合并,

  根据空格 进行分割,然后取=之前内容,作为key,如果是len则表示长度,(可以忽略),如果key包含[或],则表示是数组,进行合并,

  然后进行解码

 问题2: 特定字段特殊解码,比如sockaddr的saddr字段

 

 问题3: java版怎么转换这种格式数据

 

 

网络数据转换

import binascii
import socket
import struct
import sys
for string_address in [ '192.168.1.1','127.0.0.1' ]:
    packed =socket.inet_aton(string_address)
    print 'Original:', string_address
    print 'Packed  :', binascii.hexlify(packed)
    print 'Unpacked:',socket.inet_ntoa(packed)

参考 http://you2late.blog.51cto.com/6782917/1158783

 

 

2. 参考资料:

 1) https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/chap-system_auditing.html#sec-audit_system_architecture

 2) 所有系统调用

    /usr/include/asm/unistd_64.h 

   中文系统调用解释:

   https://www.ibm.com/developerworks/cn/linux/kernel/syscall/part1/appendix.html

 3) http://blog.csdn.net/u012085379/article/details/50790340 

 

4) 日志格式详见

 https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/sec-Understanding_Audit_Log_Files.html

 

5) 日志中各个字段的详见介绍

 http://biancheng.dnbcw.net/linux/348711.html

 

6) 系统自带的配置规则

/usr/share/doc/audit-version/

 

日志各个字段说明

https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/app-Audit_Reference.html#sec-Audit_Events_Fields

 

查看所有的系统调用和对应数据

ausyscall --dump

 

很多时候看不到日志记录 使用 --interpret选项,可以获得人类可以看懂的代码

ausearch --interpret --exit -13 

 

items=1

The items field contains the number of path records in the event.
 
auid=500
The auid field records the Audit user ID, that is the loginuid. This ID is assigned to a user upon login and is inherited by every process even when the user's identity changes (for example, by switching user accounts with the su - john command).
 
euid=500
The euid field records the effective user ID of the user who started the analyzed process.
 
tty=pts0
The tty field records the terminal from which the analyzed process was invoked.
 
 
查找源代码解读
http://man7.org/linux/man-pages/man5/ausearch-expression.5.html
http://people.redhat.com/sgrubb/audit/
最终源代码在github上
https://github.com/linux-audit/audit-userspace/blob/master/src/ausearch-parse.c
 
posted @ 2017-04-21 07:08  woxiaohaha  阅读(2501)  评论(0)    收藏  举报