Audit

如何解釋審計日誌的“saddr”欄位?

  • March 4, 2020

我正在嘗試記錄 的參數connect,所以我添加了一條規則auditctl

現在在 audit.log 我得到這樣的行:

類型=SOCKADDR 消息=審計(1385638181.866:89758729):saddr=十六進製字元串

那麼我應該如何從十六進製字元串中解釋目標地址(我不確定該十六進製字元串中儲存了什麼)?

我找到了這個 Perl 腳本parse-audit-log.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 頁面的一部分,位於LinuxSupport下。標題為:IDSNetConnectionLogger的頁麵包含 2 個感興趣的文件。一個是我上面提到的腳本parse-audit-log.pl,另一個是範例audit.log文件。

執行腳本

如果您下載這 2 個文件,您會注意到這就是您要詢問的內容。

例子

$ ./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 的打包/解包函式

一旦您了解了它們的工作原理,這些都是非常強大的功能。如果您以前從未使用過它們,那麼我會看一下教程perlpacktut

這些函式背後的想法是,它們接收數據並使用模板返回數據,使用模板作為數據應該如何組織的結構。

同樣,這裡有一個簡單的 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 次。前 4A2個塊,實際上每個塊只有 2 個字元,儲存在變數中:$f1, $f2, $p1, $p2。剩餘的字元儲存在數組中@addr

引用自:https://unix.stackexchange.com/questions/102926