(Golang) SSL Sertifika Doğrulaması Nasıl Atlanır?

legandrary

Katılımcı Üye
Katılım
24 Ağu 2023
Mesajlar
670
Tepkime puanı
352
Konum
Петербург
Selamlar Nasılsınız Umarım İyisinizdir BUGÜN Go (Golang) uygulamalarında SSL sertifika doğrulamasını nasıl atlayacağınızı göstereceğim. Bu görev genellikle güvenliği analiz ederken ve kaynak kodu mevcut olmadığında HTTPS isteklerine müdahale ederken ortaya çıkar. Sertifika denetimini devre dışı bırakmak için ikili dosyayı değiştirmenin ve aynı zamanda bir Python betiği kullanarak bu işlemi otomatikleştirmenin yollarına bakacağım.


Ağ kitaplıklarında ve HTTP isteklerini işlerken, programcı genellikle yapılandırmayı değiştirerek veya HTTP işleyicisine bayraklar ekleyerek SSL denetimini devre dışı bırakabilir. Bu durumda da işe yarayabileceğini düşündüm. Arama sırasında yapılandırmada varsayılan olarak false olarak ayarlanmış InsecureSkipVerify parametresini buldum . SSL doğrulamasını devre dışı bırakmak için uygulamanıza aşağıdaki kodu eklemeniz gerekiyordu:
GCZS6c.png



Kod:
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
_, err := http.Get("https://golang.org/")

Kod:
tr := &http.Transport{
    TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}
_, err := client.Get("https://golang.org/")

Ancak önceden derlenmiş bir uygulamayla çalıştığım ve kaynak koduna erişimim olmadığı için bu yöntem uygun değildi. Farklı bir yaklaşım aramam gerekiyordu.

Bir sonraki adım, program ikili dosyasında InsecureSkipVerify bayrağının nerede kullanıldığını ve nasıl atlanabileceğini bulmaktı . Uygulamanın ikili dosya formatını ve derleme kodunu anlamaya çalışmak yerine net/http kütüphanesinin kaynak kodunu incelemeye karar verdim .

Go kodunda arama yaptığımda, InsecureSkipVerify bayrağının, validServerCertificate işlevindeki crypto/tls/handshake_client.go dosyasında kullanıldığını keşfettim :

Kod:
1

func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
    // ...
    if !c.config.InsecureSkipVerify {
        opts := x509.VerifyOptions{
            Roots:         c.config.RootCAs,
            CurrentTime:   c.config.time(),
            DNSName:       c.config.ServerName,
            Intermediates: x509.NewCertPool(),
        }
        // ...
    }
    // ...
}

Bu işlevi inceledikten sonra, işaret true olarak ayarlandığında sunucu sertifikası doğrulamasının atlandığı anlaşıldı. Böylece ilgili koşulu veya montaj kodunu değiştirerek sertifika doğrulamasını atlayabildim.

Gösterim amacıyla ipinfo için GET isteği oluşturan basit bir Go uygulaması yazdım . io'yu açar ve sonucu verir:


Kod:
package main
import (
    "io/ioutil"
    "log"
    "net/http"
)
func main() {
    resp, err := http.Get("https://ipinfo.io/")
    if err != nil {
        log.Fatalln(err)
    }
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatalln(err)
    }
    sb := string(body)
    log.Printf(sb)
}

Çoğu zaman programcılar, dizeler ve işlev adları gibi gereksiz bilgileri gizlemek için hata ayıklama sembollerini uygulamalarından kaldırır. Ancak gösteri amacıyla, tersine mühendislik sürecini kolaylaştırmak için ikili dosyayı değiştirmeden bıraktım.

Assembly kodunu analiz etmeye başlamadan önce, validServerCertificate fonksiyonunun kaynak koduna bakalım . Kodu üç bölüme ayırır:

  1. Önbellekte sunucunun varlığının kontrol edilmesi.
  2. InsecureSkipVerify bayrağı kontrol ediliyor .
  3. Ortak anahtarın ve sertifikanın doğrulanması.
İkinci kısımla ilgileniyoruz. İkili sistemde bu durum iki montajcı komutuyla temsil edilebilir: cmp ve jn .

Amacım, programın SSL kontrolünü atlaması için koşulu değiştirmekti. Bu, jnz komutunu "sıfırsa atla" anlamına gelen jz olarak değiştirerek yapılabilir . X86 assembler'da bu değişiklik bir baytlık bir değişikliktir (85'ten 84'e).

Bu yamayı gerçekleştirmek için IDA PRO kullandım . İlgili kod parçasını IDA'da buldum ve 85 baytını 84 olarak değiştirdim, ardından değişiklikleri dosyaya uyguladım. Bundan sonra program SSL doğrulaması yapmayı durdurdu.
pDHFoUY.png

tb76803.png



Süreci otomatikleştirmek için ikili dosyadaki
cmp ve jnz talimatlarını arayan ve bunları jz ile değiştiren küçük bir Python betiği yazılmıştır . buda kod
BdExlJ.gif

Kod:
#!/usr/bin/env python3
import subprocess
import argparse
 
supported_versions_to_bytes = {
    '11': [b"\x00\x0F\x85\xB3\x04\x00\x00", b"\x00\x0F\x84\xB3\x04\x00\x00"],
    '12': [b"\x00\x00\x0F\x85\x43\x05\x00\x00", b"\x00\x00\x0F\x84\x43\x05\x00\x00"],
    '13': [b"\x00\x00\x0F\x85\x32\x05\x00\x00", b"\x00\x00\x0F\x84\x32\x05\x00\x00"],
    '14': [b"\x00\x00\x0F\x85\x48\x05\x00\x00", b"\x00\x00\x0F\x84\x48\x05\x00\x00"],
    '15': [b"\x00\x00\x0F\x85\x3A\x06\x00\x00", b"\x00\x00\x0F\x84\x3A\x06\x00\x00"],
    '16': [b"\x00\x00\x0F\x85\x5A\x06\x00\x00", b"\x00\x00\x0F\x84\x5A\x06\x00\x00"],
    '17': [b"\x00\x00\x0F\x85\x7F\x01\x00\x00", b"\x00\x00\x0F\x84\x7F\x01\x00\x00"],
    '18': [b"\x00\x00\x0F\x85\x7C\x01\x00\x00", b"\x00\x00\x0f\x84\x7C\x01\x00\x00"],
    '19': [b"\x00\x00\x0F\x85\x7B\x01\x00\x00", b"\x00\x00\x0f\x84\x7B\x01\x00\x00"],
    '20': [b"\x00\x00\x0F\x85\x84\x01\x00\x00", b"\x00\x00\x0F\x84\x84\x01\x00\x00"],
    '21': [b"\x00\x00\x0F\x85\x82\x01\x00\x00", b"\x00\x00\x0F\x84\x82\x01\x00\x00"]
}
 
def replace_file_bytes(file_path, old_bytes, new_bytes):
    with open(file_path, 'rb') as f:
        data = f.read()
        position = data.find(old_bytes)
    
    if(-1 == position):
        raise Exception("cannot find bytes, maybe the program is already patched?")
    with open(file_path, 'rb+') as file:
        file.seek(position)
        existing_bytes = file.read(len(old_bytes))
            
        if existing_bytes == old_bytes:
            file.seek(position)
            file.write(new_bytes)
 
def run_command(command):
    result = subprocess.run(command, shell=True, capture_output=True, text=True)
    return result.stdout.strip()
      
def get_go_bin_version(filename):
    output = run_command(f"strings {filename} | grep '^go1' | head -n 1")
    if "" == output:
        output = run_command(f"strings {filename} | grep 'Go cmd/compile'  | head -n 1 | cut -d' ' -f 3")
        if "" == output:
 
 
            raise Exception("cannot determine go binary version")
    return output.replace("go", "").replace(".", "")
 
def patch_file(filename, version):
    if version not in supported_versions_to_bytes:
        raise Exception("unsupported version to patch. supported versions are: " + str(supported_versions_to_bytes.keys()))
    bytes_arr = supported_versions_to_bytes[version]
    replace_file_bytes(filename, bytes_arr[0], bytes_arr[1])
 
def main():
    parser = argparse.ArgumentParser(description="Patching Go binaries to ignore SSL")
    parser.add_argument('binary', type=str, help='Go binary to patch')
    args = parser.parse_args()
    bin_version = get_go_bin_version(args.binary)
    print(f"Found version: {bin_version}")
    patch_file(args.binary, bin_version)
 
if __name__ == "__main__":
    main()
BdExlJ.gif

Bu komut dosyası, SSL sertifikası doğrulamasını atlayarak derlenmiş Go ikili dosyalarını hızlı ve verimli bir şekilde değiştirmenize olanak tanır. Artık HTTPS isteklerini yakalamak ve Golang uygulamalarını analiz etmek çok daha kolay hale geliyor.


Kapanış
Bir, Sonraki Konuda Görüşmek Üzere.

 
Geri
Ü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.