HeXA 1st CTF Rev 300
May the HeXA with you
Download
link :
https://www.dropbox.com/s/rypuwxcpj8taj6r/HeXATalk.apk
Category
A long time ago in a galaxy
far, far away...
Episode VII
May the hexa with you
It is a dark time for the Rebellion. Although the Death Star has been destroyed, Imperial troops have driven the Rebel forces from their hidden base and pursued them across the galaxy.
To overcome this serious crisis, Rebellion request for a hacker group, HeXA, to develope an encrypted network. Therefore, HeXA start work on the new project named HeXATalk.
However, just before the completion of HeXATalk, Imperial's assassin killed all the members of HeXA except you. Rebellion, who must get a secret message from Luke Skywalker, need you to complete the unfinished HeXATalk and find out what the secret message is.
Write-Up
- unzip apk
- extract jar with dex2jar : $dex2jar HeXATalk.apk
- jar analysis
source code : hexa.per.sh.hexatalk.MainActivity$p
package hexa.perl.sh.hexatalk;
import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.util.Log;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Random;
class MainActivity$p extends AsyncTask
{
private MainActivity$p(MainActivity paramMainActivity)
{
}
@SuppressLint({"NewApi"})
protected Void doInBackground(Void[] paramArrayOfVoid)
{
try
{
if (InetAddress.getByName(this.this$0.HOST).isReachable(1000))
{
this.this$0.suc = true;
ByteBuffer localByteBuffer = ByteBuffer.allocate(30);
localByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
// localByteBuffer1 = 4바이트 int (인덱스)
localByteBuffer.putInt(0, this.this$0.idx);
char[] arrayOfChar1;
int i; // 인덱스
if (this.this$0.idx == 1)
{
arrayOfChar1 = new char[] { 108, 111, 103, 105, 110 }; // char[] 'login'
i = 0;
if (i < arrayOfChar1.length); // 첫번째 단계
}
while (true)
{
// 소켓 연결
MainActivity.access$0(this.this$0, new Socket(this.this$0.HOST, this.this$0.PORT));
MainActivity.access$2(this.this$0, MainActivity.access$1(this.this$0).getInputStream());
MainActivity.access$3(this.this$0, MainActivity.access$1(this.this$0).getOutputStream());
MainActivity.access$4(this.this$0).write(localByteBuffer.array());
MainActivity.access$4(this.this$0).flush();
this.this$0.wsize = MainActivity.access$5(this.this$0).read(this.this$0.w);
MainActivity localMainActivity = this.this$0;
localMainActivity.idx = (1 + localMainActivity.idx);
MainActivity.access$6(this.this$0);
return null;
int j = i + 4;
// localByteBuffer = 4바이트 int (인덱스) + char[] 'login' (커맨드)
localByteBuffer.put(j, (byte)arrayOfChar1[i]);
i++; // 인덱스 증가
break;
if (this.this$0.idx == 2) // 두번째 단계
{
String str = new String(this.this$0.w, 0, this.this$0.wsize);
// 서버로부터 받은 메세지 => port : xxxxxxx
// this.this$0.PORT = xxxxxxx (새로 할당받은 포트번호)
this.this$0.PORT = Integer.parseInt(str.substring(3 + str.indexOf(" : ")));
char[] arrayOfChar2 = { 98, 117, 121 }; // char[] 'buy'
for (int k = 0; ; k++)
{
// 루프 마지막에 한번
if (k >= arrayOfChar2.length)
{
this.this$0.aes_key = new byte[16];
new Random().nextBytes(this.this$0.aes_key);
// aes_key에 랜덤 바이트 할당
for (int m = 0; m < this.this$0.aes_key.length; m++)
localByteBuffer.put(m + 14, this.this$0.aes_key[m]);
// localByteBuffer = 4바이트 int (인덱스) + char[10] 'buy' (커맨드) + aes_key (랜덤 바이트 AES 키)
break;
}
// localByteBuffer = 4바이트 int (인덱스) + char[4] 'buy' (커맨드)
localByteBuffer.put(k + 4, (byte)arrayOfChar2[k]);
}
}
if (this.this$0.idx == 3) // 세번째 단계
{
// 완성되지 않은 코드 = 서버로부터 데이터를 받는 부분
// 4바이트 int (암호화된 데이터 크기) + AES/CBC/PKCS7Padding 암호화된 데이터
Log.d("HeXA", "need to read 4byte ([x] = size of encrypted data) + [x] byte ( AES/CBC/PKCS7Padding encrypted data )");
byte[] arrayOfByte = new byte[16];
arrayOfByte[0] = 104;
arrayOfByte[1] = 101;
arrayOfByte[2] = 120;
arrayOfByte[3] = 97;
arrayOfByte[4] = 102;
arrayOfByte[5] = 111;
arrayOfByte[6] = 114;
arrayOfByte[7] = 101;
arrayOfByte[8] = 118;
arrayOfByte[9] = 101;
arrayOfByte[10] = 114;
}
}
}
}
catch (Exception localException)
{
while (true)
{
this.this$0.suc = false;
continue;
this.this$0.suc = false;
}
}
}
}
4. coding
import socket
import sys
import struct
import time
from Crypto.Cipher import AES
from pkcs7 import PKCS7Encoder
encoder = PKCS7Encoder()
def enc_aes(data):
iv = struct.pack('<16s','hexaforever')
aes = AES.new(key=aes_key, mode=AES.MODE_CBC, IV=iv)
pad_text = encoder.encode(data)
cipher = aes.encrypt(pad_text)
return cipher
def dec_aes(data):
iv = struct.pack('<16s','hexaforever')
aes = AES.new(key=aes_key, mode=AES.MODE_CBC, IV=iv)
pad_text = aes.decrypt(data)
plain_data = encoder.decode(pad_text)
return pad_text
HOST = "10.xx.xx.xx"
PORT = xxxx
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
data = " ".join(sys.argv[1:])
idx = 1
data = struct.pack('<I', idx)
data += struct.pack('<10s','login')
sock.sendall(data + "\n")
received = sock.recv(1024)
sock.close()
print "Sent: {}".format(data)
print "Received: {}".format(received)
port = received.split(" : ")[1]
print "port : " + str(port)
#print "sleep for 3 sec"
#time.sleep(10)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, int(port)))
aes_key='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
idx = 2
data = struct.pack('<I', idx)
data += struct.pack('<10s','buy')
data += aes_key
sock.sendall(data + "\n")
data = sock.recv(1024)
print data
sock.close()
size = struct.unpack('<I',data[:4])[0]
print "SIZE : " +str(size)
print dec_aes(data[4:4+size])
print "Received: {}".format(received)
Missing code
ByteBuffer bB = ByteBuffer.allocate(4);
bB.order(ByteOrder.LITTLE_ENDIAN);
bB.put(Arrays.copyOfRange(w, 0, 4));
int size = ByteBuffer.wrap(bB.array()).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
byte[] iv = new byte[] { 0x68, 0x65, 0x78, 0x61, 0x66, 0x6f, 0x72, 0x65, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00 };
javax.crypto.spec.SecretKeySpec keyspec = new javax.crypto.spec.SecretKeySpec(aes_key, "AES");
javax.crypto.spec.IvParameterSpec ivspec = new javax.crypto.spec.IvParameterSpec(iv);
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, keyspec, ivspec);
byte[] decrypted = cipher.doFinal(Arrays.copyOfRange(w, 4, 4 + size));
String key = new String(decrypted);