Oyun Bitti: FlareOn 2015 CTF> Mücadelesi 5
Herkese selam! Geçenlerde bu yılki FireEye FLARE On CTF'ye katılarak uykusuz geceler geçirdim.
Ne yazık ki boş zaman eksikliği, uykusuzluk ve 0xc0ff33 eksikliği nedeniyle Challenge 9'u bombaladım.
Tüm şakalar bir yana, harika bir yolculuktu ve bir sürü yeni şey öğrendim.
Bunu bir araya getirdikleri için tüm FLARE ekibine çok teşekkürler!
Bu gönderi, Challenge 5'in bir yazımıdır. Bu zorluğu birkaç nedenden ötürü seçtim:
(1) çok karmaşık değil,
(2) kötü amaçlı yazılım benzeri bir bileşeni var
(3) oldukça zevkliydi !
Tamam, kemerlerinizi bağlayın ve başlayalım!
Mmm Büyüleyici Gerçekten ..
Bu yüzden, meydan okumanın nereye gittiğine dair bazı göstergeler veren aşağıdaki postayı alıyoruz.
JavaScript gizlenmesinin söz konusu olacağını umuyordum ama durum böyle değildi.
Ekli arşiv iki dosya içeriyordu: "challenge.pcap " ve "Sender(gönderen)"olarak adlandırılan bir 32bit PE.
challenge.pcap
Önce trafik yakalamasına bir göz atalım ve ihtiyacımız olan her şeyi sökelim, böylece pcap'yi bir kenara koyabiliriz.
Daha yakın bir inceleme, pcap'nin 12 HTTP POST isteği içerdiğini gösterir.
Hepsi aynı boyuta sahip ve oldukça küçük görünüyorlar, bu da cesaret verici. Aşağıdaki resim, son post isteğini ve yanıtını göstermektedir.
Her isteğin biçimi aynıdır, ikili, "1"göndererek yanıt veren dinleyiciye 4 karakter gönderir.
Son isteği göstermemin nedeni, 4 karakterin iki eşit işaret içerdiğini görebilmemizdir. Hemen, base64 çığlık atıyor.
Ek olarak, eşit işaretler son istekte olduğundan, bu bize ikili verinin doğru sırayla gönderildiğini gösteren oldukça iyi bir gösterge verir.
İletilen tüm karakterleri ayıklamak bize aşağıdaki base64 dizesini verir.
Tabii ki, bu gerçekten mantıklı bir şey için deşifre değil, çok sıkıcı olurdu!
Neden bu kadar başarısız oldun?
IDA'daki işlenenlere hızlı bir bakış, başarısız koşullara işaret eden bazı dizeleri gösterir.
Bu dizelere bakarak ve pcap'de gördüklerimizi kullanarak, ikili dosyanın düzgün çalışması için neye ihtiyacı olduğunu kolayca anlayabiliriz.
En azından bir anahtar gerektirir.txt var (muhtemelen içeriği bir arabelleğe okuyor) ve HTTP POST isteklerini almak için localhost üzerinde bir dinleyici.
Pcap'den, sunucunun aldığı her şey için "1" döndürmesi gerektiğini biliyoruz.
Ayrıca garip dize "flarebearstare" (0x66 = f) dikkat edin, daha sonra buna geri döneceğiz.
Basit bir python dinleyicisini hızlı bir şekilde bir araya getirebiliriz, bu da hata ayıklama sırasında yararlı olacaktır, çünkü başarısız koşullarla uğraşmaya devam etmek istemiyoruz.
Anahtar oluşturduktan sonra.txt bazı örnek metin "AAAABBBB" ile aşağıdaki yanıtı alıyoruz.
Bingo, şimdi ikili tarafından işlendiğinde giriş arabelleğine ne olduğunu anlayıp anlayamayacağımızı görelim.
Girdiyi Değiştirme
İkili, key.txt'deki metni okuduktan hemen sonra, aşağıdaki montaj talimat bloklarına ulaşır.
Buradaki önemli parçalar, bir kesme noktası belirlediğim iki işlev çağrısıdır (bilginize, bu işlevleri yeniden adlandırdım).
Bu iki işlev, programa aktardığımız girdiyi değiştirmekten sorumludur. Her ikisini de sırayla inceleyeceğiz.
Shift_ASCII_Input
Bu özellik oldukça küçüktür, aşağıda tamamen görebilirsiniz.
Yukarıdaki resimde, en alakalı kısımda yürütmeyi duraklattım.
EBX, test arabelleğimize ("AAAABBBB") işaret ediyor ve 0x41 (A) arabelleğimizin ilk baytı 0x66 (f) ile artırılıyor gibi görünüyor.
Daha önce bulduğumuz garip işleneni hatırlıyor musun?
Bazı hızlı araştırmalar aşağıdakileri göstermektedir:
EBX: tamponumuzun başlangıcına işaret ediyor. Biz de yığında görebilirsiniz.
ESI: bir sayaç, döngü her çalıştığında artar ve giriş arabelleğimiz için bir dizin olarak kullanılır.
EDI: tamponumuzun uzunluğunu içerir, döngüden ne zaman çıkılacağını belirlemek için ESI ile karşılaştırılır.
AL: "flarebearstare" dizesinden tek bir bayt içerir, döngünün her yinelemesi bu değerdir
sağa kaymış.
Esasen, olan şey, giriş arabelleğimizin her karakterinin "flarebearstare"dizesinden bir karakter tarafından artırılmasıdır.
Bu, ikili dosyaya verdiğimiz herhangi bir girişi etkili bir şekilde karıştırır.
Anahtarın uzunluğunun 14 karakter olduğuna dikkat edin, eğer anahtardan daha uzun olan program girişini sağlarsak, basit bir döngü yapar ve ilk karakterden tekrar başlar.
Aşağıdaki örnek, giriş arabelleğimizi kullanarak gösterilecek, umarım bunu göstermelidir:
Döngüden geçerken EBX kaydını takip ederek bunu kolayca doğrulayabiliriz.
Giriş tamponumuz bundan değişir:
Bu:
İlk bölüm için bu kadar, base64'e geçelim.
Base64_Encode
Girişimizi "muhtemelen" değiştiren ikinci işlev, baytları doğrudan base64'e dönüştürür.
Genel olarak, her üç baytın (her türlü bayt) 4 ASCII yazdırılabilir bayta dönüştürülmesidir.
Giriş baytları üçe bölünemez olduğunda, dolgu uygulanır.
Dönüştürme işlemi, her üç baytı ikili olarak çevirerek, elde edilen bitleri 6 bitlik gruplara gruplayarak ve daha sonra bu baytların ondalık gösterimini kullanarak base64 tablosunda karşılık gelen karakteri arayarak gerçekleşir.
Standart base64 arama tablosu aşağıda görülebilir.
Biliyorum biliyorum, sadece bunu uydurmuş gibi geliyor ama base64 gerçekten böyle çalışıyor.
Değiştirilmiş giriş arabelleğimizin ilk üç baytı için bunu deneyelim:
Base64 işlevi, işleri basitleştirmek için biraz uzundur, aşağıdaki resim dönüştürme işleminin son adımında kesme noktalarını gösterir (ondalık - > base64 arama tablosu).
Doğal olarak, 4 kesme noktası vardır; her arama için bir tane.
Ne olması gerektiğini zaten biliyoruz, ancak ikili dosyanın ne yaptığını görelim.
İlk karakter:
İkinci karakter:
Üçüncü karakter:
Dördüncü karakter:
Açıkçası burada uğursuz bir şey oluyor, base64 iyi görünüyor ama ... durum ters çevrilmiştir ("p62i "vs"P62İ").
Base64 arama tablosunu hatırlayın, ikili de bir tane vardır, sadece büyük ve küçük harf karakterlerinin sırası ters çevrilir.
Base64 işlevinin yürütülmesi sırasında arama tablosu yığında görülebilir.
Gizem çözüldü, bu sorunu çözmek için ihtiyacımız olan tüm bilgilere sahibiz.
İkili dosyanın geri kalanı, base64'ü parçalara ayırır ve dinleyiciye gönderir.
Çözüm
Açıkçası, bu zorluğu biraz ayrıntılı olarak açıkladım, ama gerçek şu ki, ilk çözdüğümde her şey biraz daha kaotik oldu.
Böyle... Base64'ü orijinal girdiye dönüştüren güzel bir python betiği yazabilirim, ancak bitiş çizgisine acele etmeye çalışırken tembel bir kişinin (yani: ben) ne yapabileceğini göstereceğim.
İlk olarak, değiştirilmiş arama tablosunu göz önünde bulundurarak base64'ü doğru baytlara geri dönüştürelim:
İkili, çok fazla çaba harcamadan bizim için zor işin geri kalanını yapmasına izin verebiliriz.
Unutmayın, ilk ASCII baytları aşağıdaki komut add [ESI+EBX], al kullanılarak kodlanır.
Eğer ikili kodu çözdüğümüz baytlarla tedarik edersek ve bu talimatı sub [ESI+EBX] ' e eklersek, o zaman sadece çözümü tükürmelidir(göstermelidir)!
Önce ikili dosyayı yeniden başlatıyoruz ve yukarıda belirtilen talimata ulaşana kadar yürütmeye devam ediyoruz:
Sonra bellekte base64 gelen çözdük byte ile byte yerine talimat tamir edersek.
Geriye kalan tek şey döngüyü çalıştırmak ve çözümün bellekte çözülmesini izlemek!
OYUN BİTTİ!
Translator: Qgenays
Source: https://www.fuzzysecurity.com/tutorials/23.html
Herkese selam! Geçenlerde bu yılki FireEye FLARE On CTF'ye katılarak uykusuz geceler geçirdim.
Ne yazık ki boş zaman eksikliği, uykusuzluk ve 0xc0ff33 eksikliği nedeniyle Challenge 9'u bombaladım.
Tüm şakalar bir yana, harika bir yolculuktu ve bir sürü yeni şey öğrendim.
Bunu bir araya getirdikleri için tüm FLARE ekibine çok teşekkürler!
Bu gönderi, Challenge 5'in bir yazımıdır. Bu zorluğu birkaç nedenden ötürü seçtim:
(1) çok karmaşık değil,
(2) kötü amaçlı yazılım benzeri bir bileşeni var
(3) oldukça zevkliydi !
Tamam, kemerlerinizi bağlayın ve başlayalım!
Mmm Büyüleyici Gerçekten ..
Bu yüzden, meydan okumanın nereye gittiğine dair bazı göstergeler veren aşağıdaki postayı alıyoruz.
JavaScript gizlenmesinin söz konusu olacağını umuyordum ama durum böyle değildi.
Ekli arşiv iki dosya içeriyordu: "challenge.pcap " ve "Sender(gönderen)"olarak adlandırılan bir 32bit PE.
challenge.pcap
Önce trafik yakalamasına bir göz atalım ve ihtiyacımız olan her şeyi sökelim, böylece pcap'yi bir kenara koyabiliriz.
Daha yakın bir inceleme, pcap'nin 12 HTTP POST isteği içerdiğini gösterir.
Hepsi aynı boyuta sahip ve oldukça küçük görünüyorlar, bu da cesaret verici. Aşağıdaki resim, son post isteğini ve yanıtını göstermektedir.
Her isteğin biçimi aynıdır, ikili, "1"göndererek yanıt veren dinleyiciye 4 karakter gönderir.
Son isteği göstermemin nedeni, 4 karakterin iki eşit işaret içerdiğini görebilmemizdir. Hemen, base64 çığlık atıyor.
Ek olarak, eşit işaretler son istekte olduğundan, bu bize ikili verinin doğru sırayla gönderildiğini gösteren oldukça iyi bir gösterge verir.
İletilen tüm karakterleri ayıklamak bize aşağıdaki base64 dizesini verir.
Kod:
UDYs1D7bNmdE1o3g5ms1V6RrYCVvODJF1DpxKTxAJ9xuZW==
Tabii ki, bu gerçekten mantıklı bir şey için deşifre değil, çok sıkıcı olurdu!
Neden bu kadar başarısız oldun?
IDA'daki işlenenlere hızlı bir bakış, başarısız koşullara işaret eden bazı dizeleri gösterir.
Bu dizelere bakarak ve pcap'de gördüklerimizi kullanarak, ikili dosyanın düzgün çalışması için neye ihtiyacı olduğunu kolayca anlayabiliriz.
En azından bir anahtar gerektirir.txt var (muhtemelen içeriği bir arabelleğe okuyor) ve HTTP POST isteklerini almak için localhost üzerinde bir dinleyici.
Pcap'den, sunucunun aldığı her şey için "1" döndürmesi gerektiğini biliyoruz.
Ayrıca garip dize "flarebearstare" (0x66 = f) dikkat edin, daha sonra buna geri döneceğiz.
Basit bir python dinleyicisini hızlı bir şekilde bir araya getirebiliriz, bu da hata ayıklama sırasında yararlı olacaktır, çünkü başarısız koşullarla uğraşmaya devam etmek istemiyoruz.
Kod:
#!/usr/bin/python
import SocketServer
class EchoRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
while 1:
data = self.request.recv(1024)
print data + "\n"
self.request.send("1")
return
SocketServer.TCPServer.allow_reuse_address = 1
server = SocketServer.ThreadingTCPServer(("0.0.0.0", 80), EchoRequestHandler)
server.serve_forever()
Anahtar oluşturduktan sonra.txt bazı örnek metin "AAAABBBB" ile aşağıdaki yanıtı alıyoruz.
Bingo, şimdi ikili tarafından işlendiğinde giriş arabelleğine ne olduğunu anlayıp anlayamayacağımızı görelim.
Girdiyi Değiştirme
İkili, key.txt'deki metni okuduktan hemen sonra, aşağıdaki montaj talimat bloklarına ulaşır.
Buradaki önemli parçalar, bir kesme noktası belirlediğim iki işlev çağrısıdır (bilginize, bu işlevleri yeniden adlandırdım).
Bu iki işlev, programa aktardığımız girdiyi değiştirmekten sorumludur. Her ikisini de sırayla inceleyeceğiz.
Shift_ASCII_Input
Bu özellik oldukça küçüktür, aşağıda tamamen görebilirsiniz.
Yukarıdaki resimde, en alakalı kısımda yürütmeyi duraklattım.
EBX, test arabelleğimize ("AAAABBBB") işaret ediyor ve 0x41 (A) arabelleğimizin ilk baytı 0x66 (f) ile artırılıyor gibi görünüyor.
Daha önce bulduğumuz garip işleneni hatırlıyor musun?
Bazı hızlı araştırmalar aşağıdakileri göstermektedir:
EBX: tamponumuzun başlangıcına işaret ediyor. Biz de yığında görebilirsiniz.
ESI: bir sayaç, döngü her çalıştığında artar ve giriş arabelleğimiz için bir dizin olarak kullanılır.
EDI: tamponumuzun uzunluğunu içerir, döngüden ne zaman çıkılacağını belirlemek için ESI ile karşılaştırılır.
AL: "flarebearstare" dizesinden tek bir bayt içerir, döngünün her yinelemesi bu değerdir
sağa kaymış.
Esasen, olan şey, giriş arabelleğimizin her karakterinin "flarebearstare"dizesinden bir karakter tarafından artırılmasıdır.
Bu, ikili dosyaya verdiğimiz herhangi bir girişi etkili bir şekilde karıştırır.
Anahtarın uzunluğunun 14 karakter olduğuna dikkat edin, eğer anahtardan daha uzun olan program girişini sağlarsak, basit bir döngü yapar ve ilk karakterden tekrar başlar.
Aşağıdaki örnek, giriş arabelleğimizi kullanarak gösterilecek, umarım bunu göstermelidir:
Kod:
Input : 0x41(A) 0x41(A) 0x41(A) 0x41(A) 0x42(B) 0x42(B) 0x42(B) 0x42(B) # Sample input "AAAABBBB"
Key : 0x66(f) 0x6c(l) 0x61(a) 0x72(r) 0x65(e) 0x62(b) 0x65(e) 0x61(a) + # Key "flarebea"
---------------------------------------------------------------
Scrambled: 0xA7(?) 0xAD(?) 0xA2(?) 0xB3(?) 0xA7(?) 0xA4(?) 0xA7(?) 0xA3(?) # Output
Döngüden geçerken EBX kaydını takip ederek bunu kolayca doğrulayabiliriz.
Giriş tamponumuz bundan değişir:
Bu:
İlk bölüm için bu kadar, base64'e geçelim.
Base64_Encode
Girişimizi "muhtemelen" değiştiren ikinci işlev, baytları doğrudan base64'e dönüştürür.
Genel olarak, her üç baytın (her türlü bayt) 4 ASCII yazdırılabilir bayta dönüştürülmesidir.
Giriş baytları üçe bölünemez olduğunda, dolgu uygulanır.
Dönüştürme işlemi, her üç baytı ikili olarak çevirerek, elde edilen bitleri 6 bitlik gruplara gruplayarak ve daha sonra bu baytların ondalık gösterimini kullanarak base64 tablosunda karşılık gelen karakteri arayarak gerçekleşir.
Standart base64 arama tablosu aşağıda görülebilir.
Biliyorum biliyorum, sadece bunu uydurmuş gibi geliyor ama base64 gerçekten böyle çalışıyor.
Değiştirilmiş giriş arabelleğimizin ilk üç baytı için bunu deneyelim:
Kod:
Input : A7 AD A2
8-bit binary : 10100111 10101101 10100010
6-bit split : 101001 111010 110110 100010
Decimal : 41 58 54 34
base64 Lookup: p 6 2 i ----> p62i
Base64 işlevi, işleri basitleştirmek için biraz uzundur, aşağıdaki resim dönüştürme işleminin son adımında kesme noktalarını gösterir (ondalık - > base64 arama tablosu).
Doğal olarak, 4 kesme noktası vardır; her arama için bir tane.
Ne olması gerektiğini zaten biliyoruz, ancak ikili dosyanın ne yaptığını görelim.
İlk karakter:
İkinci karakter:
Üçüncü karakter:
Dördüncü karakter:
Açıkçası burada uğursuz bir şey oluyor, base64 iyi görünüyor ama ... durum ters çevrilmiştir ("p62i "vs"P62İ").
Base64 arama tablosunu hatırlayın, ikili de bir tane vardır, sadece büyük ve küçük harf karakterlerinin sırası ters çevrilir.
Base64 işlevinin yürütülmesi sırasında arama tablosu yığında görülebilir.
Gizem çözüldü, bu sorunu çözmek için ihtiyacımız olan tüm bilgilere sahibiz.
İkili dosyanın geri kalanı, base64'ü parçalara ayırır ve dinleyiciye gönderir.
Çözüm
Açıkçası, bu zorluğu biraz ayrıntılı olarak açıkladım, ama gerçek şu ki, ilk çözdüğümde her şey biraz daha kaotik oldu.
Böyle... Base64'ü orijinal girdiye dönüştüren güzel bir python betiği yazabilirim, ancak bitiş çizgisine acele etmeye çalışırken tembel bir kişinin (yani: ben) ne yapabileceğini göstereceğim.
İlk olarak, değiştirilmiş arama tablosunu göz önünde bulundurarak base64'ü doğru baytlara geri dönüştürelim:
İkili, çok fazla çaba harcamadan bizim için zor işin geri kalanını yapmasına izin verebiliriz.
Unutmayın, ilk ASCII baytları aşağıdaki komut add [ESI+EBX], al kullanılarak kodlanır.
Eğer ikili kodu çözdüğümüz baytlarla tedarik edersek ve bu talimatı sub [ESI+EBX] ' e eklersek, o zaman sadece çözümü tükürmelidir(göstermelidir)!
Önce ikili dosyayı yeniden başlatıyoruz ve yukarıda belirtilen talimata ulaşana kadar yürütmeye devam ediyoruz:
Sonra bellekte base64 gelen çözdük byte ile byte yerine talimat tamir edersek.
Geriye kalan tek şey döngüyü çalıştırmak ve çözümün bellekte çözülmesini izlemek!
OYUN BİTTİ!
Translator: Qgenays
Source: https://www.fuzzysecurity.com/tutorials/23.html