من بعد ما نزل تطبيق Telephony اللي بيتيح لمصلحة الجمارك المصرية للتحقق من حالة الهواتف المستوردة إلى البلاد بدأ تظهر تخوفات تجاه التطبيق ده و انه ليه مساحته كبيرة جدا مقارنة ب اللي المفروض بيعمله و هو انه مجرد بيعمل تحقق لموديل الهاتف من خلال كود ال IMEI فقط ؟ طيب اول حاجة خلينا نشوف ازاي التطبيق ده بيشتغل و نحاول نعمله هندسه عكسية سريعه و ناخد فكره عنه.
اول حاجة خلينا نعمل decompile لل APK ب apktool .. انا حملت التطبيق من Apkpure : https://apkpure.com/telephony/com.ntra.citizen
التطبيق لما بينزل من apkpure بينزل بصيغة .xapk و بيكون عبارة عن zip file عادي .. انا هنا عملتله extract ب 7z و طلع معايا 4 apk
- com.ntra.citizen.apk : 118M
- config.arm64_v8a.apk : 59M
- config.en.apk : 95k
- config.mdpi.apk : 204k
طبعا التركيز هيكون علي com.ntra.citizen.apk .. لو بصينا علي ال files بعد ال decompilation هنلاقي فيه directories مساحتها مبالغ فيها شوية
- assets: 86M خلينا من ال smali classes دلوقتي هنرجعلها بعدين و خلينا نروح علي ال assets
لما عملت find علي ال files الموجودة جوا ال directory بتاع assets علي الفايلات اللي اكبر من 10MB هتلاقي فايل db.dat مساحته 76MB
طبعا الفايل مش واضح هو ايه حتي لو فتحناه ف hex viewer مش هنلاقي حاجة ف ال magic bytes بتاعت الفايل تحدد ايه ال file type ده لكن واضح من ال extension بتاعته انه database
لما عملت binwalk علي db.dat لقيت فيه ZIP Archives كتير ف عملتلهم extract
ال files اللي اتعملها extract ال extensions بتاعتها عبارة عن:
- .dat
- .dnn
- .onnx
لو بصينا علي ال strings في file عشوائي من onnx files دول هنلاقي strings مشتركة ليها علاقة ب onnx modules و onnx runtime
ف نلاقي ان دي files تابعة ل framework اسمه Onnx
ONNX is an open format built to represent machine learning models
لو عملنا سيرش بقي علي Regula اللي موجود ف ال path هنلاقي انه ليه علاقة ب Regula Forensics و اللي بيستخدم ال AI ف انه يعمل تحقق للبطاقات و الباسبورات و التعرف علي الوجه و خلافه https://regulaforensics.com/solutions/industries/banking/
Regula Forensics Helps organizations make document authentication and identity verification seem easy
و اللي ليهم اصلا تطبيق منفصل
نقدر نتأكد لو حملنا التطبيق ده و نعمله decompile بنفس الطريقة و نشوف محتواه هنلاقي نفس ال db.dat بنفس ال architectures
خلينا نطلع من ال rabbit hole ده بقي و نشوف التطبيق ده بيشتغل ازاي و بيعمل تحقق لل IMEI منين. المرة دي هنعمل decompile ب jadx عشان نقدر نشوف الكود بطريقة نفهمها .. توقعت ان الكود ممكن يكون معموله obfuscation بس في واقع الامر لا.
خلينا نشوف اول حاجة خالص ال permissions
ال Google API key
لما قلبت شوية ف الكود بتاع التطبيق لقيت فيه حاجات تبع efinance sdk و mastercard و intuit و JakeWharton ThreeTenABP كلها ليها علاقة بال online payment المهم ان ركزت علي com/ntra .. فيه file اسمه Constants.java و ده فيه URLs متخزنة ف constant variables نقدر نقول عليها APIs
- https://login.di.gov.eg/realms/digitalegypt/protocol/openid-connect/logout?client_id=ceir-portal&post_logout_redirect_uri=https://api-citizens-prod-imei.gs-ef.com : بوابة تسجيل الدخول مصر الرقمية
- https://login.di.gov.eg/realms/digitalegypt/protocol/openid-connect/auth?response_type=code&redirect_uri=https://api-citizens-prod-imei.gs-ef.com&client_id=ceir-portal
- https://minio-prod-imei.gs-ef.com:9000/logo
- https://api-citizens-prod-imei.gs-ef.com
و في ال app/common/core/util برضو فيه فايل Constant.java فيه API URLs تانيه
- https://sandbox.di.gov.eg/realms/sandbox/protocol/openid-connect/auth?state=7F9CC7E9-0D3C-4867-A2C4-702B3435C7B4&response_type=code&scope=openid&client_id=ceir_portal&redirect_uri=https://imei.tra.gov.eg/userportal
- https://sandbox.di.gov.eg/realms/sandbox/protocol/openid-connect/auth?state=7F9CC7E9-0D3C-4867-A2C4-702B3435C7B4&response_type=code&scope=openid&client_id=ceir_portal&redirect_uri=https://imei.tra.gov.eg/userportal
- https://sandbox.di.gov.eg/realms/sandbox/protocol/openid-connect/logout?client_id=ceir_portal&post_logout_redirect_uri=https://imei.tra.gov.eg/userportal
هنلاقي فايل اسمه RefreshApi.java و ده بيعمل Post Request علي واحد من ال APIs اللي فوق عشان يعمل refresh لل API tokens
و في نفس ال path هنلاقي فايل Api.java و ده فيه كل ال POST Requests اللي بتتعمل علي ال APIs
هنا هنلاقي انه بيبعت Post request لل data بتاعت ال user لل API .. و اللي ملاحظه هنا ف الكود انه بيبعت IMEI مع اسم المستخدم و صورته و رقم الباسبور و ميعاد الوصول
و هنا هنلاقي results برضو بس اقل و ده معناه انه فيه registered check و unregistered check
لو جمعنا كل جزء مع بعض نقدر نفهم ان التطبيق بيبعت Post Request لل Base API و ال data بيكون فيها ال imeiNumber
هنا هيبدأ يعمل Authenticated Request و بيضيف ال headers
"Content-Type", "application/json"
كده الداتا بتتبعت jsonHttpHeaders.ACCEPT, "*/*"
"clientType", "Android"
بعد شوية كتير فضلت اجرب curl و ابعت post request زي ما ال application بيبعت لحد ما عملت سكريبت بايثون بسيط اقدر اعمل منه check علي IMEI مفيش اي validations ولا tokens لكن فيه rate limitation و عدد 10 trials
#!/usr/bin/python3
import requests
import sys
from optparse import OptionParser
def api_request(host, url, imei_num):
headers = {
"Host": host,
"User-Agent": "NTRA",
"Content-Type": "application/json",
"Connection": "keep-alive",
"Accept-Language": "en",
"Accept-Encoding": "gzip, deflate, br",
"Accept": "*/*"
}
data = {"imeiNumber": [imei_num]}
response = requests.post(f"https://{host}/{url}", json=data, headers=headers)
return response
def main(imei):
api_host = "api-citizens-prod-imei.gs-ef.com"
api_url_path = "ceirimeicheck/api/v1/imei/check"
resp_info = api_request(api_host, api_url_path, imei)
match resp_info.status_code:
case 403:
if "supportID" in resp_info.text:
print("[x] Your IP might have been blocked because you have exceeded submission trials.")
print(resp_info.json())
case 400:
if resp_info.json()["status"]["error"] == "Invalid IMEI Exception" or resp_info.json()["status"]["error"] == "An error occurred in the data sent!":
print("[x] Invalid IMEI number")
case 404:
if resp_info.json()["status"]["error"] == "Device Model Does Not Exit Exception":
print("[x] Device model is not exist")
case 200:
if "model" in resp_info.text:
print("[*] IMEI number is valid")
print("[+] Manufacturer: " + resp_info.json()["result"]["manufacturerName"])
print("[+] Model: " + resp_info.json()["result"]["model"])
print("[+] Registeration Status: " + resp_info.json()["result"]["status"])
print("[+] Activity Status: " + resp_info.json()["result"]["active"])
print("[*] Number of trials left: " + str(resp_info.json()["result"]["numberOfTrialsLeft"]))
case default:
print(resp_info.json())
if __name__ == '__main__':
print("NTRA IMEI fees checker - r0ttenbeef")
parser = OptionParser(usage="%prog [options]")
parser.add_option("-i", "--imei", dest="imei", default=None, help="Provide IMEI number of device model")
(options, args) = parser.parse_args()
if options.imei != None:
main(options.imei)
else:
parser.error("[-] Please provide IMEI number of device model, Use -h, --help for help menu.")
sys.exit(1)
Useful Indicators
- Filenames:
exported_model_Korea1042.onnx exported_model_China2052.onnx exported_model_Korea1042.onnxPK exported_model_China2052.onnxPK handwritten_model.onnx epoch_00068-test_0.98437-train_0.97540-validation_0.99218_recipient_model_Quant_freeze.onnx handwritten_model.onnxPK epoch_00068-test_0.98437-train_0.97540-validation_0.99218_recipient_model_Quant_freeze.onnxPK epoch_00043-test_0.99999-train_0.99629-validation_0.99813_model_Global.onnx epoch_00043-test_0.99999-train_0.99629-validation_0.99813_model_Global.onnx are_1102875519_20220923.onnx are_1102875519_20220923.onnx checkpoint_0300_with_nms.onnx checkpoint_0300_with_nms.onnx are_-1381771989_20220922.onnx are_-1381771989_20220922.onnx epoch_00295-test_1.0-train_0.96093-validation_1.0_model_Global.pth.onnx epoch_00295-test_1.0-train_0.96093-validation_1.0_model_Global.pth.onnx mex_448926514_20220718.onnx mex_448926514_20220718.onnx deu_454858311_20220727.onnx deu_454858311_20220727.onnx model.onnx model.onnx DocumentHologramModel_128x128_Paraguay_fixed_labels5_14.08.2023.onnx DocumentHologramModel_128x128_Paraguay_fixed_labels5_14.08.2023.onnx border_detector.onnx russian_stamp_segmentator.onnx border_detector.onnxPK russian_stamp_segmentator.onnxPK