Mobil Sızma Testlerinde Şifrelenmiş HTTP Parametrelerinin Çözümlenmesi

Bugün ki yazımda mobil sızma testleri sırasında giderek artan şifrelenmiş HTTP Parametrelerinin çözümlenmesi ile ilgili bir senaryoyu inceleyeceğiz. Normalde bir mobil uygulama testi sırasında cihaz üzerinde ki testlerden sonra API (Application Programming Interface) testleri yapılır. Bunun için uygulama Burp Suite ve ZAP gibi proxy yazılımları ile kontrol edilir. SSL Pinning varsa API istekleri düşmeyecektir. Bunun için SSL Pinning atlatma yöntemleri kullanılarak bu sorun aşılabilir. Bu aşamaya kadar geldiğimizde beklediğimiz uygulamanın HTTP isteğini görüntüleyip burada zafiyet kontrolleri yapmaktır. Bir id, değer gidiyorsa bunu değiştirip, bozacak ya da bu değeri artırıp, azaltarak dönen HTTP cevabı ile zafiyet analizine başlanabilir.

Ancak aşağıdaki şekilde ki gibi HTTP üzerinden iletilen parametreler/JSON verileri şifreli olarak iletiliyorsa, her bir istek ve cevabın çözülmesi ve incelenmesi gerekecektir.

Yukarıda görüldüğü gibi HTTP isteğine ulaştık fakat bir sorun var. Data parametresinin değeri şifrelenmiş bir halde. Bu şekilde herhangi bir değişiklik yapıp zafiyet tespit etmemiz oldukça zor. Uygulama ve sunucu arasında iletişimi kuran bu web servisin kullandığı HTTP parametesi şifreli bir şekilde gitse de her iki tarafında bunu çözümleyebilmesi gerekmektedir. Buradan yola çıkarak mobil uygulamanın kurulum dosyası olan APK dosyasını dex2jar aracı ile jar dosyasını elde edilerek  JD-GUI ile decompile ederek kaynak kodunu incelemeye başladım.

Yukarıda ki resimde gördüğünüz gibi kullanılan şifreleme yönteminin AES/CBC/PKCS5Padding olduğunu kaynak kod üzerinde görebilmekteyiz. Blok şifreleme türü olan AES (Advanced Encryption Standard)  CBC (Cipher Block Chaning) ile şifrelemek ve çözümlemek için bir adet key ve bir adet IV  değeri gerekmektedir.

Yine uygulamanın kaynak kodunda görüldüğü üzere key değeri hardcoded olarak tanımlanmıştır. Uygulamanın kaynak kodu karmaşıklaştırılmış (obfuscated) olduğu için parametre ve değerlere ulaşmak biraz vakit alabilmektedir. Key değerine ulaştık, şifreleme standartınıda biliyorduk şu an tek eksiğimiz IV değeri.  Kod detaylıca incelendiğinde IV değeri olarak key değeri ile aynı hardcoded string ifadenin kullanıldığı ulaştım. Bu bilgiler ile birlikte şifrelenmiş değeri çözümlemeye çalıştığımda malesef bir sonuç alamadım. Uygulamanın isteklerine ve kaynak kodunu incelemeye devam ettiğimde ise bu değerler ile sunucudan gelen CryptoKey değerinin çözümlendiği ve çözümlenen değerin şifrelenmiş Data değeri şifrelenirken kullanılan key ve IV değeri olduğunu tespit edebildim. Burada aslında  AES/CBC/PKCS5Padding  ile iki kere şifreleme yapılmaktadır.

İlk HTTP İsteği :

Uygulama açıldığında ilk olarak yukarıda ki isteği yapmaktadır. Ve bu isteğin cevabı aşağıda görüldüğü gibi CryptoKey değeri bulunmaktadır. Sunucudan gelen bu değer biraz önce kaynak kodda bulduğumuz key ve aynı zamanda IV değeri olarak kullanıldığı için  AES/CBC/PKCS5Padding  çözümlemesi yapılarak yeni key ve IV değerine ulaşabiliriz.

İlk HTTP Cevabı:

Uygulama içerinde  AES/CBC/PKCS5Padding kullanıldığı için key ve IV değeri verildiğinde şifreleme ve çözümleme yapan iki methodu bulunan bir java kodu yazdık. Bunu farklı dillerde yazabileceğiniz gibi online platformlar ve araçlarıda kullanabilirsiniz.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;

public class Decrypt {
	public static void main(String[] args) {
		if (args.length < 2) {
			System.out.println("Encrypt: java Encrypt 1 key \"data\" ");
			System.out.println("Decrypt: java Decrypt 2 key \"data\" ");

			return;
		}

        String islem = args[0];
        byte[] key = tobyte(args[1]);
        String dirty = args[2];
        
        try {
        	System.out.println("Islem: " + islem);

        	if (islem.equals("1")) {
        		byte[] encrypted = encrypt(dirty.getBytes("UTF-8"), key);
			
				System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(encrypted));	
        	} else {
        		byte[] dirtybytes = Base64.getDecoder().decode(dirty);
				byte[] decrypted = decrypt(dirtybytes, key);

				System.out.println("Decrypted: " + new String(decrypted, "UTF-8"));
        	}
        } catch (Exception e) {
        	System.out.println(e.toString());
        }
	}

	public static byte[] tobyte(String paramString) {
		try {
			byte[] arrayOfByte = new byte[16];
			byte[] array2 = paramString.getBytes("UTF-8");

			System.arraycopy(array2, 0, arrayOfByte, 0, Math.min(array2.length, arrayOfByte.length));

			return arrayOfByte;

		} catch (Exception e) {
			
		}

		byte[] ret = new byte[16];

		return ret;
	}

    public static byte[] encrypt(byte[] plainText, byte[] key) throws Exception {
        // Encrypt.
        Cipher cipherEncrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipherEncrypt.init(1, new SecretKeySpec(key, "AES"), new IvParameterSpec(key));
        byte[] encrypted = cipherEncrypt.doFinal(plainText);

        return encrypted;
    }

    public static byte[] decrypt(byte[] encryptedData, byte[] key) throws Exception {
        // Decrypt.
        Cipher cipherDecrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipherDecrypt.init(2, new SecretKeySpec(key, "AES"), new IvParameterSpec(key));
        byte[] decrypted = cipherDecrypt.doFinal(encryptedData);

        return decrypted;
    }
}

Şimdi yukarıda görülen uygulamanın HTTP parametresinde ki şifrelenmiş veriyi çözümlemek için önce sunucudan gelen CryptoKey değerini uygulamanın kaynak kodunda ele geçirdiğimiz key ve IV kodu aynı olduğu için onunla çözümlüyoruz. Daha sonra ise şifrelenmiş HTTP parametresini alıyoruz ve CryptoKey değerinden çözdüğümüz key ile çözümlediğimizde aşağıda gördüğünüz üzere açık metin olarak ulaşabilmekteyiz.

Burada ki değerleri değiştirerek bu işlemi keyleri sırasıyla kullanarak  şifreleyen method ile şifreleyerek sunucuya gönderip, zafiyet tespiti yapabilmekteyiz. Eğer bu kısımda kendiniz kod yazmak istemezseniz bunun için alternatif yollar var.

BurpSuite AES Payload Eklentisi ile Çözümlenmesi:

Yukarıda ki gibi Burp BApp store üzerinden ve ya  https://github.com/PortSwigger/aes-payloads  adresinden AES Payload eklentisini kullanarak bu işlemi yapabilirsiniz. Eklenti key ve IV değerlerini hex olarak istediği için kaynak koddan ele geçirdiğimiz değeri hex değerini girmemiz gerekmektedir. Daha sonra uygulamayı yeniden açtığımızda sunucudan gelen CryptoKey değerini çözümleyeceğiz.

Yukarda yaptığımız gibi ilk olarak sunucudan gelen CryptoKey değerini, kaynak koddan ele geçirdiğimiz değer ile çözümleyerek HTTP parametresmizi şifreleyen key ve IV değerine ulaşıyoruz. Bu değerinde yeniden hex değerini alıyoruz.

Ve son olarakta şifrelenmiş HTTP parametre değerimizi bu key ve IV değeri ile çözümleyerek açık metin haline ulaşabilmekteyiz.

 

Online AES Şifrelemesinin Çözümlenmesi:

Bup Suite eklentisi haricinde de http://www.devglan.com/online-tools/aes-encryption-decryption adresinden online olarak AES şifreleme ve çözümleme işlemi gerçekleştirebilirsiniz. Burada çıkan sonuçlar Base64 encoding olduğu için bu değeride Base64 decode etmemiz gerekmektedir. CryptoKey değerini key ve IV değerimizi girerek aşağıda ki görselde gördüğünüz gibi çözümlüyoruz.

Çözümlenen AES çıktısı Base64 olduğu için bunuda Base64 decode ederek şifrelenmiş HTTP isteğimizi çözümlemek için kullanacağımız key ve IV değerine ulaşmaktayız.

Şifrelenmiş HTTP parametre verisini girip, ulaştığımız key ve IV değerini giriyoruz.

Ulaştığımız AES çözümlenmiş çıktısını Base64 decode ettiğimizde açık metin olarak HTTP parametresini görüntüleyebilmekteyiz.

İsterseniz kendiniz bir script yazın, isterseniz Burp eklentisi veya online araç kullanarak şifrelenmiş veriyi çözümleyebilirsiniz. Burada sunucudan gelen CryptoKey ile iki kere şifreleme yapıldığı için işimiz  biraz daha zorlaşmıştır. Farklı şifreleme yöntemleri ve farklı senaryolar benzer şekilde karşınıza çıkabilir.

Bu güvenlik önlemini atlatmamda beni yönlendiren  Canberk BOLAT‘a yardımlarından dolayı teşekkür ederim.

Başka bir yazıda görüşmek üzere.

Ahmet Gürel

Cyber Security Researcher | Penetration Tester

Leave a Reply