awk의 역참조에 문제가 있습니다.

awk의 역참조에 문제가 있습니다.

최근에는 보안 로깅에 관심이 많아 bash-shell을 더 잘 다루고 싶습니다. awk는 9개의 역참조만 저장한다는 것을 발견했습니다. 하지만 10개의 역참조를 사용해야 합니다.

시험을 마친

awk '{print gensub(/^([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}).+?\sID\s(\[[0-9]{4}\]).+?\sTargetUserName\s=\s(.+?)\sTargetDomainName\s=\s(.+?)\sTargetLogonId\s=\s(.+?)\sLogonType\s=\s([0-9]{1,2})\s(.+?\sWorkstationName\s=\s(.+?)\sLogonGuid\s=\s.+?TransmittedServices\s=\s.+?\sLmPackageName\s=\s.+?KeyLength\s=\s.+?\sProcessId\s=\s.+?\sProcessName\s=\s.+?\sIpAddress\s=\s(.+?)\sIpPort\s\=\s([0-9]{1,}))?.+?$/,"\\5,\\4,\\3,\\2\\6,\\1,\\8,\\9,","g") }'

대상 문자열(실제로는 수천 개의 문자열)

2017-03-21T02:00:00 kornawesome Security/Microsoft-Windows-Security-Auditing ID [4624] :EventData/Data -> SubjectUserSid = S-1-5-18 SubjectUserName = PRETENDERS$ SubjectDomainName = WORKGROUP SubjectLogonId = 0x00000000000004j7 TargetUserSid = X-12-54-181 TargetUserName = SYSTEMS TargetDomainName = NT AUTHORITY TargetLogonId = 0x00000000000003e7 LogonType = 8 LogonProcessName = Lxxoi   AuthenticationPackageName = Negotiate WorkstationName = - LogonGuid = {00344000-0000-0000-0000-0000000003440} TransmittedServices = - LmPackageName = Stainless KeyLength = 0 ProcessId = 0x0000000000000244 ProcessName = C:/Windows/System32/services.exe IpAddress = 10.0.0.0 IpPort = 10.5.3.2 ImpersonationLevel = %%1122

awk를 사용하여 수행할 수 있는 다른 방법이 있다면 기본 bash 및 연관 배열을 사용하고 싶습니다. 저(초보)를 위해...친절한 설명도 부탁드립니다.

답변1

보안 로그의 한 가지 문제는 일부 텍스트가 사용자 제어하에 있을 수 있으므로 정규식을 사용하여 콘텐츠를 분할하는 것이 문제가 된다는 것입니다. 그러나 여러 표현식을 사용하여 문제를 나눌 수 있으며 이는 9개의 역참조 제한을 중심으로 작동합니다. 예를 들어 모든 로그 항목이 타임스탬프로 시작하는 경우 해당 항목을 제거할 수 있습니다.

awk '{t=$1 ;$1=""; 
print gensub(/^.+?\sID\s(\[[0-9]{4}\]).+?\sTargetUserName\s=\s(.+?)\sTargetDomainName\s=\s(.+?)\sTargetLogonId\s=\s(.+?)\sLogonType\s=\s([0-9]{1,2})\s(.+?\sWorkstationName\s=\s(.+?)\sLogonGuid\s=\s.+?TransmittedServices\s=\s.+?\sLmPackageName\s=\s.+?KeyLength\s=\s.+?\sProcessId\s=\s.+?\sProcessName\s=\s.+?\sIpAddress\s=\s(.+?)\sIpPort\s\=\s([0-9]{1,}))?.+?$/,"\\4,\\3,\\2,\\1\\5" t ",\\7,\\8,","g") }'

선택적일 수 있으므로 WorkstationName\s=\s(.+?)\sLogonGuid패턴의 일부로 사용할 수 있습니다.

awk {t=$1; $1="" ; printf("%s", gensub(/^.+?WorkstationName\s=\s(.+?)\sLogonGuid.*$/,"\\1,")); printf("%s,", t)}

필드를 꺼내면 이 작업이 반복될 수 있습니다.

@cas는 댓글에서 데이터를 이전 콘텐츠 EventData/Data ->와 다음 콘텐츠의 두 부분으로 볼 수 있고 다음 콘텐츠를 분할할 수 있다고 지적했습니다 =(공백은 공백과 동일). 한 단계 더 나아가 이를 키/값 쌍으로 처리한 다음 /\s\S+\s=\s/선택적 네 번째 매개변수를 분할하여 사용하여 split키를 가져옵니다. 몇 가지 중요한 가정이 있습니다. 즉, 사용자가 행에 등호를 넣을 수 없고 각 데이터에 단어 키가 있다는 가정이 있습니다. 키와 값의 인덱스는 1만큼 다르며 행의 초기 부분은 로 끝납니다 v[1].

/usr/bin/awk '{
    n=split($0,v,/\s\S+\s=\s/,k)
    printf("There are %d fields\n",n)
    for(i=0;i<n;i++) { printf("%d key \"%s\" value \"%s\"\n",i,k[i],v[i+1]) }
}'

샘플 데이터와 함께 제공됨

There are 22 fields
0 key "" value "2017-03-21T02:00:00 kornawesome Security/Microsoft-Windows-Security-Auditing ID [4624] :EventData/Data ->"
1 key " SubjectUserSid = " value "S-1-5-18"
2 key " SubjectUserName = " value "PRETENDERS$"
3 key " SubjectDomainName = " value "WORKGROUP"
4 key " SubjectLogonId = " value "0x00000000000004j7"
5 key " TargetUserSid = " value "X-12-54-181"
6 key " TargetUserName = " value "SYSTEMS"
7 key " TargetDomainName = " value "NT AUTHORITY"
8 key " TargetLogonId = " value "0x00000000000003e7"
9 key " LogonType = " value "8"
10 key " LogonProcessName = " value "Lxxoi  "
11 key " AuthenticationPackageName = " value "Negotiate"
12 key " WorkstationName = " value "-"
13 key " LogonGuid = " value "{00344000-0000-0000-0000-0000000003440}"
14 key " TransmittedServices = " value "-"
15 key " LmPackageName = " value "Stainless"
16 key " KeyLength = " value "0"
17 key " ProcessId = " value "0x0000000000000244"
18 key " ProcessName = " value "C:/Windows/System32/services.exe"
19 key " IpAddress = " value "10.0.0.0"
20 key " IpPort = " value "10.5.3.2"
21 key " ImpersonationLevel = " value "%%1122"

여기에서 한 단계 더 나아가 데이터라는 연관 배열을 만들 수 있습니다.

for(i=1;i<n;i++) {gsub(/[ =]/,"",k[i]);data[k[i]]=v[i+1]}

data["IpPort"]그러면 필드 20인지 21인지 걱정하지 않고 이와 같은 내용을 인쇄할 수 있습니다 .

답변2

icarus는 이미 이 질문에 답변했으므로 awk다음을 사용하여 날짜와 ID를 변수로 추출하고 이벤트 데이터를 해시(연관 배열)로 추출하는 방법은 다음과 같습니다 perl.

#!/usr/bin/perl -l

use strict;

while(<>) {
  if (m/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}).+?\sID\s(\[\d{4}\]).*?Data -> (.*)$/) {
    my ($date,$id,$eventdata) = ($1,$2,$3);

    print $date;
    print $id;

    # decorate the key names with a tab (i.e. add a tab before each) 
    $eventdata =~ s/([^[:blank:]]+) *= */\t$1=/g;
    # remove tab from beginning of $eventdata
    $eventdata =~ s/^\t//;       #/

    # split $eventdata on tabs, and split again into key=value pairs
    # and store in %data hash.    
    my %data = map { my($k,$v) = split("=",$_,2); $k => $v } split(/ *\t/,$eventdata);

    foreach my $key (sort keys %data) { printf "%s=%s\n", $key, $data{$key} };
  };
};

(이 #/설명은 U&L의 깨진 Perl 구문 강조를 수정하기 위한 것입니다.)

,2작업은 각 키=값 쌍을 최대로 분할하여 종료 됩니다 split("=",$_,2).필드: 까지첫 번째 =기호와 그 이후의 모든 것. 즉, 값에 부호가 포함되어 있는지 여부는 중요하지 않습니다 =. 이와 같은 작업은 awk보다 Perl에서 수행하기가 더 쉽습니다. 루프 시작 부분의 처음 두 줄에 표시된 것처럼 정규식과 캡처 그룹을 사용하는 것이 더 쉽습니다 while(<>).

예를 들어 다른 이름으로 저장하고 kei.pl실행 가능하게 만들고 chmod +x kei.pl다음과 같이 실행합니다.

$ ./kei.pl input 
2017-03-21T02:00:00
[4624]
AuthenticationPackageName=Negotiate
ImpersonationLevel=%%1122
IpAddress=10.0.0.0
IpPort=10.5.3.2
KeyLength=0
LmPackageName=Stainless
LogonGuid={00344000-0000-0000-0000-0000000003440}
LogonProcessName=Lxxoi
LogonType=8
ProcessId=0x0000000000000244
ProcessName=C:/Windows/System32/services.exe
SubjectDomainName=WORKGROUP
SubjectLogonId=0x00000000000004j7
SubjectUserName=PRETENDERS$
SubjectUserSid=S-1-5-18
TargetDomainName=NT AUTHORITY
TargetLogonId=0x00000000000003e7
TargetUserName=SYSTEMS
TargetUserSid=X-12-54-181
TransmittedServices=-
WorkstationName=-

그런데 날짜와 ID도 해시에 포함하려면 %data = map ...줄 뒤에 다음을 추가하고 print $date;& print $id;줄을 제거하세요.

$data{'DATE'} = $date;
$data{'ID'} = $id;

관련 정보