我正在尝试记录 的参数connect
,因此我添加了一条带有 的规则auditctl
。
现在在audit.log中我得到这样的行:
类型=SOCKADDR msg=audit(1385638181.866:89758729):saddr=十六进制字符串
那么我应该如何解释十六进制字符串中的目标地址(我不确定该十六进制字符串中存储了什么)?
答案1
我找到了这个 Perl 脚本,解析审计日志.pl,它显示了一个可以解析该字符串的函数,如下所示:
sub parse_saddr
{
my $sockfd = $_[0];
my $saddr = $_[1];
# 0 - sys_bind(), 1 - sys_connect(), 2 - sys_accept()
my $action = $_[2];
($f1, $f2, $p1, $p2, @addr) = unpack("A2A2A2A2A2A2A2A2", $saddr);
$family = hex2dec($f1) + 256 * hex2dec($f2);
$port = 256 * hex2dec($p1) + hex2dec($p2);
$ip1 = hex2dec($addr[0]);
$ip2 = hex2dec($addr[1]);
$ip3 = hex2dec($addr[2]);
$ip4 = hex2dec($addr[3]);
#print "$saddr\n";
if ($family eq 2) { #&& $ip1 ne 0) {
my $dst_addr = "$ip1.$ip2.$ip3.$ip4:$port";
# print "family=$family $dst_addr\n\n";
# todo: avoid code duplication
if ($action eq 0) {
$sockfd_hash{ $sockfd } = $dst_addr;
} elsif ($action eq 1) {
my $src_addr;
if (exists $sockfd_hash{ $sockfd }) {
$src_addr = $sockfd_hash{ $sockfd };
} else {
$src_addr = "x.x.x.x:x";
}
print "$src_addr -> $dst_addr\n";
} elsif ($action eq 2) {
my $src_addr;
if (exists $sockfd_hash{ $sockfd }) {
$src_addr = $sockfd_hash{ $sockfd };
} else {
$src_addr = "x.x.x.x:x";
}
print "$dst_addr <- $src_addr\n";
} else {
print "unknown action\n";
}
} elsif ($family eq 1) {
$tmp1 = 0;
($tmp1, $tmp2) = unpack("A4A*", $saddr);
my $file = pack("H*", $tmp2);
# print "family=$family file=$file\n";
} else {
# print "$saddr\n";
}
}
这个脚本是这个的一部分CERN 网站上的 TWiki 页面, 在下面Linux支持。该页面标题为:IDSNet连接记录器包含 2 个感兴趣的文件。我上面提到的脚本之一,解析审计日志.pl,另一个是样本审计日志文件。
运行脚本
如果您下载这两个文件,您会发现这就是您所询问的内容。
例子
$ ./parse-audit-log.pl -l audit.log
x.x.x.x:x -> 0.0.0.0:22
x.x.x.x:x -> 137.138.32.52:22
137.138.32.52:22 <- x.x.x.x:x
x.x.x.x:x -> 0.0.0.0:22
x.x.x.x:x -> 137.138.32.52:0
x.x.x.x:x -> 137.138.16.5:53
x.x.x.x:x -> 137.138.16.5:53
x.x.x.x:x -> 137.138.16.5:53
x.x.x.x:x -> 137.138.128.158:88
x.x.x.x:x -> 137.138.16.5:53
x.x.x.x:x -> 137.138.16.5:53
x.x.x.x:x -> 137.138.16.5:53
x.x.x.x:x -> 137.138.128.148:750
x.x.x.x:x -> 137.138.16.5:53
x.x.x.x:x -> 137.138.16.5:53
x.x.x.x:x -> 137.138.16.5:53
x.x.x.x:x -> 137.138.128.158:88
x.x.x.x:x -> 137.138.32.52:0
x.x.x.x:x -> 137.138.16.5:53
x.x.x.x:x -> 137.138.16.5:53
x.x.x.x:x -> 137.138.16.5:53
x.x.x.x:x -> 137.138.128.158:88
x.x.x.x:x -> 127.0.0.1:6010
提取解析器逻辑
我们可以对上面的内容进行压缩,使其只是一个saddr
解析器。这是我的精简版本。
$ cat parse_saddr.pl
#!/usr/bin/perl -w
# Getopt::Std module from the perl package
use Getopt::Std;
my %Options;
getopt('s', \%Options);
if (defined($Options{'s'})) {
$saddr = $Options{'s'};
} else {
print "saddr not given\n";
exit(-1);
}
sub hex2dec($) { return hex $_[0] }
sub parse_saddr
{
my $saddr = $_[0];
($f1, $f2, $p1, $p2, @addr) = unpack("A2A2A2A2A2A2A2A2", $saddr);
$family = hex2dec($f1) + 256 * hex2dec($f2);
$port = 256 * hex2dec($p1) + hex2dec($p2);
$ip1 = hex2dec($addr[0]);
$ip2 = hex2dec($addr[1]);
$ip3 = hex2dec($addr[2]);
$ip4 = hex2dec($addr[3]);
#print "$saddr\n";
if ($family eq 2) { #&& $ip1 ne 0) {
my $dst_addr = "$ip1.$ip2.$ip3.$ip4:$port";
print "family=$family $dst_addr\n\n";
} elsif ($family eq 1) {
$tmp1 = 0;
($tmp1, $tmp2) = unpack("A4A*", $saddr);
my $file = pack("H*", $tmp2);
print "family=$family file=$file\n";
} else {
print "$saddr\n";
}
}
&parse_saddr($saddr);
Saddr 解析器脚本的示例运行
我们可以像这样运行它:
$ ./parse_saddr.pl -s 02000035898A1005000000000000000030BED20858D83A0010000000
family=2 137.138.16.5:53
然后,您可以使用这样的命令来解析上述文件saddr=..
中的所有行:audit.log
$ for i in $(grep saddr audit.log | cut -d"=" -f4);do echo $i; \
./parse_saddr.pl -s $i;done | less
上面的代码被拼凑在一起,因此它不能处理 family=1 类型的saddr
.您必须深入研究,但这为您提供了如何处理所有这些问题的一个粗略的开始。
输出示例
$ for i in $(grep saddr audit.log | cut -d"=" -f4);do echo $i; \
./parse_saddr.pl -s $i;done | less
...
01002F6465762F6C6F67000000000000
family=1 file=/dev/log^@^@^@^@^@^@
...
02000035898A10050000000000000000726E2E6368009A0900000000
family=2 137.138.16.5:53
...
02000058898A809E0000000000000000
family=2 137.138.128.158:88
...
020002EE898A80940000000000000000
family=2 137.138.128.148:750
...
0200177A7F0000010000000000000000
family=2 127.0.0.1:6010
...
Perl 的打包/解包函数
一旦您了解了它们的工作原理,这些功能就会非常强大。如果您以前从未使用过它们,那么我会看一下教程,佩尔帕克图特。
这些函数背后的想法是,它们接收数据并使用模板返回该数据,并使用模板作为数据组织结构。
这里又是一个简单的 Perl 脚本,它显示了saddr
.
$ cat unpack.pl
#!/usr/bin/perl
$saddr = "02000035898A1005000000000000000030BED20858D83A0010000000";
($f1, $f2, $p1, $p2, @addr) = unpack("A2A2A2A2A2A2A2A2", $saddr);
printf "org string: $saddr\n";
printf "org values==> f1: %s f2: %s p1: %s p2: %s addr: %s\n",
$f1,$f2,$p1,$p2,join("",@addr);
printf "new values==> f1: %2s f2: %2s p1: %2s p2: %2s addr: %s.%s.%s.%s\n\n",
hex($f1),hex($f2),hex($p1),hex($p2),hex($addr[0]),hex($addr[1]),hex($addr[2]),hex($addr[3]);
产生这个:
$ ./unpack.pl
org string: 02000035898A1005000000000000000030BED20858D83A0010000000
org values==> f1: 02 f2: 00 p1: 00 p2: 35 addr: 898A1005
new values==> f1: 2 f2: 0 p1: 0 p2: 53 addr: 137.138.16.5
在这里,我们获取其中包含的数据$saddr
并调用unpack()
告诉函数一次获取 2 个字节的数据 (A2)。这样做 10 次。前 4 个A2
块实际上每个块只有 2 个字符,存储在变量中:$f1
, $f2
, $p1
, $p2
。剩余的字符存储在数组中@addr
。
答案2
使用该-i
选项ausearch
-i,--解释
将数字实体解释为文本。例如,uid 转换为帐户名。转换是使用运行搜索的计算机的当前资源完成的。如果您已重命名帐户,或者计算机上没有相同的帐户,则可能会得到误导性的结果。
这也解码了条目saddr
中的 s type=SOCKADDR
。
答案3
从 2.6 开始,有一个新的日志记录选项auditd
可以启用丰富的日志。
在 /etc/audit/auditd.conf 中将 log_format 更改为ENRICHED
:
log_format = ENRICHED
这将为各个字段输出具有有意义名称的字段,包括用户和组以及系统调用。资本化的领域是丰富的领域。SOCKADDR
事件具有解码后的套接字 IP、端口或文件名。
例子:
类型=SYSCALL msg=audit(1583352267.747:333333): arch=c000003e syscall=59 success=yes exit=0 a0=19eed30 a1=19e7360 a2=19e6ff0 a3=7ffce315f1e0 items=2 ppid=28317 pid=30555 auid=0 u编号= 0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=1681 comm="tail" exe="/usr/bin/tail" subj=unconfined_u:unconfined_r:unconfined_t :s0-s0:c0.c1023 key="EXECVE" ARCH=x86_64 SYSCALL=execve AUID="root" UID="root" GID="root" EUID="root" SUID="root" FSUID="root" EGID =“根” SGID=“根” FSGID=“根”
类型 = SOCKADDR msg = 审核(1583352273.046:333334):saddr = 0200028F000000000000000000000000SADDR = {fam = inet laddr = 0.0.0.0 lport = 655 }
答案4
我使用以下方法在 powershell 中实现此目的
function parseSocketAddr {
[CmdletBinding()]
param(
[parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
[string]$Saddr
)
begin {
$re = [regex]"^(?<socket>(?:02|0A)00)(?<port>[a-fA-F0-9]{4})(?<ip>[a-fA-F0-9]{8})(?<remainder>[a-fA-F0-9]+)$"
}
process {
$socket, $port, $ip, $remainder = $re.Match($saddr).groups.Where({$_.Name -ne '0'}).value
$ipRev = ($ip -split "(\w{2})").Where({$_ -ne ""})[4..0] -join ""
return [PSCustomObject]@{
type = $socket
IPAddress = ([IPAddress][convert]::ToInt64($ip,16)).IPAddressToString
Port = [convert]::ToInt32($port,16)
Remainder = $remainder
}
}
}