외로운 Nova의 작업실
insecurebankv2 - 취약한 암호화 실행 본문
insecurebankv2 - 취약한 암호화 실행
Nova_ 2023. 5. 15. 12:54- 취약점 소개
해당 취약점은 암호 알고리즘에대한 취약점입니다. 알고리즘을 사용할때는 아래와 같은 것을 고려해야합니다.
- 어떤 암호알고리즘을 사용할 것 인가
- 키값은 어떻게 할 것인가
- 솔트값은 어떻게 할 것 인가
- 초기화 벡터는 어떻게 할 것인가.
알고리즘에도 취약한 알고리즘이 있을 수 있어서 안전한 알고리즘을 사용해야합니다. 또한, 키값은 하드코딩이 아닌 소프트코딩으로 진행하는 것이 좋으면 항상 변경되야합니다. 솔트값은 항상 사용하는 것이 좋습니다. 초기화 벡터는 알고리즘을 수행한이후 계산해서 사용하고, 끝나면 0으로 채워놓는 것이 좋습니다. insecurebankv2에서는 암호알고리즘을 잘 사용하고 있는지 봐보겠습니다.
- 취약점 진단
<어떤 암호알고리즘을 사용할 것인가>
LoginActivity.class 파일의 일부분을 보겠습니다.
protected void fillData() throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
SharedPreferences var1 = this.getSharedPreferences("mySharedPreferences", 0);
String var2 = var1.getString("EncryptedUsername", (String)null);
String var5 = var1.getString("superSecurePassword", (String)null);
if (var2 != null && var5 != null) {
byte[] var6 = Base64.decode(var2, 0);
try {
String var3 = new String(var6, "UTF-8");
this.usernameBase64ByteString = var3;
} catch (UnsupportedEncodingException var4) {
var4.printStackTrace();
}
this.Username_Text = (EditText)this.findViewById(2131558520);
this.Password_Text = (EditText)this.findViewById(2131558521);
this.Username_Text.setText(this.usernameBase64ByteString);
var5 = (new CryptoClass()).aesDeccryptedString(var5);
this.Password_Text.setText(var5);
} else if (var2 != null && var5 != null) {
Toast.makeText(this, "No stored credentials found!!", 1).show();
} else {
Toast.makeText(this, "No stored credentials found!!", 1).show();
}
}
아이디는 base64로 비밀번호는 AES 암호알고리즘을 사용하여 공유 프리퍼런스에 저장되어 있고, 사용할때 디코딩해서 사용하고 있음을 알 수 있습니다. base64는 암호 알고리즘이 아닌 문자관련 인코딩 방식입니다. 암호화에는 어울리지 않은 암호 알고리즘을 사용하고 있음을 알 수 있습니다. 비밀번호는 AES 암호알고리즘으로 적절한 알고리즘을 사용하고 있음을 알 수 있습니다.
<키값은 어떻게 할 것인가>
그렇다면 AES 알고리즘에서 키값은 어떻게 사용하고 있는지 봐보겠습니다. CryptoToClass.class 파일의 일부분을 보겠습니다.
public class CryptoClass {
String base64Text;
byte[] cipherData;
String cipherText;
byte[] ivBytes = new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
String key = "This is the super secret key 123";
String plainText;
public static byte[] aes256decrypt(byte[] var0, byte[] var1, byte[] var2) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
IvParameterSpec var4 = new IvParameterSpec(var0);
SecretKeySpec var3 = new SecretKeySpec(var1, "AES");
Cipher var5 = Cipher.getInstance("AES/CBC/PKCS5Padding");
var5.init(2, var3, var4);
return var5.doFinal(var2);
}
public static byte[] aes256encrypt(byte[] var0, byte[] var1, byte[] var2) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
IvParameterSpec var4 = new IvParameterSpec(var0);
SecretKeySpec var5 = new SecretKeySpec(var1, "AES");
Cipher var3 = Cipher.getInstance("AES/CBC/PKCS5Padding");
var3.init(1, var5, var4);
return var3.doFinal(var2);
}
public String aesDeccryptedString(String var1) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
byte[] var2 = this.key.getBytes("UTF-8");
this.cipherData = aes256decrypt(this.ivBytes, var2, Base64.decode(var1.getBytes("UTF-8"), 0));
this.plainText = new String(this.cipherData, "UTF-8");
return this.plainText;
}
public String aesEncryptedString(String var1) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
byte[] var2 = this.key.getBytes("UTF-8");
this.plainText = var1;
this.cipherData = aes256encrypt(this.ivBytes, var2, this.plainText.getBytes("UTF-8"));
this.cipherText = Base64.encodeToString(this.cipherData, 0);
return this.cipherText;
}
}
String key = "This is the super secret key 123";
키값이 하드코딩 되어있는 것을 확인할 수 있습니다. 좋은 방식이 아닙니다. 리버싱을 하게되면 다 보이기때문입니다. 키값은 외부서버에서 불러오고, 외부서버에서는 키값을 주기적으로 변경해야 좋습니다.
<솔트 값은 어떻게 할 것 인가>
인시큐어뱅크앱은 솔트값을 사용하지않는 것을 확인 할 수 있습니다.
Cipher var5 = Cipher.getInstance("AES/CBC/PKCS5Padding");
<초기화 벡터는 어떻게 할 것인가>
byte[] ivBytes = new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
초기화 벡터또한 하드코딩으로 되어있는 것을 확인할 수 있습니다. 초기화 벡터가 같으면 처음 블록부분을 유추할 수 있기때문에 항상 같으면 안됩니다. 사용하기직전에 계산해서 사용하고 끝난 후에는 0으로 채워두는 것이 좋습니다.
- 대응책
- 알고리즘에도 취약한 알고리즘이 있을 수 있어서 안전한 알고리즘을 사용해야합니다.
- 키값은 하드코딩이 아닌 소프트코딩으로 진행하는 것이 좋으면 항상 변경되야합니다.
- 솔트값은 항상 사용하는 것이 좋습니다.
- 초기화 벡터는 알고리즘을 수행한이후 계산해서 사용하고, 끝나면 0으로 채워놓는 것이 좋습니다.
또한, 아래 사이트를 참고해서 안전한 알고리즘을 사용해야합니다.
https://seed.kisa.or.kr/kisa/kcmvp/EgovVerification.do
'Mobile App Penetesting > Android App Vulnerability' 카테고리의 다른 글
insecurebankv2 - 메모리내 민감한 정보 저장 (0) | 2023.05.19 |
---|---|
insecurebankv2 - 애플리케이션 패칭 (0) | 2023.05.18 |
insecurebankv2 - 안전하지 않은 콘텐츠 프로바이더 접근 (0) | 2023.05.13 |
insecurebankv2 - 루팅 탐지 우회 (0) | 2023.05.12 |
insecurebankv2 - 액티비티 컴포넌트 취약점 (0) | 2023.05.11 |