利用Frida去呼叫java代碼中的類,然后爆破,算是一種主動呼叫的方法,主動呼叫可以用于爆破,模擬程式部分執行,需要注意的知識點是在java代碼中的static型別資料在爆破程序中需要每次都對這種型別值重新設定,因為static型別在所有實體中都是統一,修改一個實體就會修改所有實體,需要用變數.屬性.value = https://www.cnblogs.com/hetianlab/p/...的寫法重新設定值,
var bvar = b.$new(IntClass.$new(2));
for (...) {
bvar._static_val.value = https://www.cnblogs.com/hetianlab/p/...;
}
背景知識
java類中靜態值在爆破中需要修改
在java類中,一個屬性如果是static的,不是說這個值不能改,而是說這個屬性在程式中是唯一的,無論幾個實體,只要改了其中一個實體中static的值,其他實體對應的值也會被改變,
在爆破程序中,如果需要爆破程序中不停new一個新的類實體,記得看看其中有沒有static型別的變數,比如下面的這個例子
public class b {
public static ArrayList<Integer> a = new ArrayList<>();
static String b = "abcdefghijklmnopqrstuvwxyz";
static Integer d = 0;
Integer[] c = {8, 25, 17, 23, 7, 22, 1, 16, 6, 9, 21, 0, 15, 5, 10, 18, 2, 24, 4, 11, 3, 14, 19, 12, 20, 13};
?
?
public b(Integer num) {
for (int intValue = https://www.cnblogs.com/hetianlab/p/num.intValue(); intValue < this.c.length; intValue++) {
a.add(this.c[intValue]);
}
for (int i = 0; i < num.intValue(); i++) {
a.add(this.c[i]);
}
}
...
每次new一個b類,比如b bVar = new b(2).如果要不停呼叫這個類,并且使用其中的方法,要注意其中的static變數會不會變,如果會變,那么在爆破程序中,需要new完實體后,修改static變數的值,
frida呼叫java中靜態方法與動態方法
如果呼叫靜態方法,可以直接呼叫,比如java代碼如下
public class Verifier {
private Verifier() {
}
?
public static boolean verifyPassword(Context context, String input) {
...
}
那么如果呼叫verifyPassword可以直接在frida中呼叫
var verify = Java.use("org.teamsik.ahe17.qualification.Verifier");
verify.verifyPassword(a, b);
如果是動態方法,有兩種方法可以呼叫動態方法
【----幫助網安學習,以下所有學習資料免費領!加vx:yj009991,備注 “博客園” 獲取!】
① 網安學習成長路徑思維導圖
② 60+網安經典常用工具包
③ 100+SRC漏洞分析報告
④ 150+網安攻防實戰技術電子書
⑤ 最權威CISSP 認證考試指南+題庫
⑥ 超1800頁CTF實戰技巧手冊
⑦ 最新網安大廠面試題合集(含答案)
⑧ APP客戶端安全檢測指南(安卓+IOS)
第一種是,使用記憶體中已存在實體的方法,需要用到java.choose(...),這個是在記憶體中尋找物件
//從記憶體中(堆)直接搜索已存在的物件
Java.choose('xxx.xxx.xxx', //這里寫類名
{ //onMatch 匹配到物件執行的回呼函式
onMatch: function (instance) {
},
//堆中搜索完成后執行的回呼函式
onComplete: function () {
}
});
第二種是,我們new一個新的實體,然后呼叫實體中的方法
//獲取類的參考
var cls = Java.use('這里寫類名');
?
//呼叫建構式 創建新物件 這里注意引數
var obj = cls.$new();
Easy-QAHE17
首先是看吾愛破解的一道題目,核心代碼如下,
public void verifyPasswordClick(View view) {
String password = this.txPassword.getText().toString();
if (!Verifier.verifyPassword(this, password)) {
Toast.makeText(this, (int) org.teamsik.ahe17.qualification.easy.R.string.dialog_failure, 1).show();
} else {
showSuccessDialog();
}
}
?
public class Verifier {
private Verifier() {
}
?
public static boolean verifyPassword(Context context, String input) {
if (input.length() != 4) {
return false;
}
byte[] v = encodePassword(input);
byte[] p = "09042ec2c2c08c4cbece042681caf1d13984f24a".getBytes();
if (v.length == p.length) {
for (int i = 0; i < v.length; i++) {
if (v[i] != p[i]) {
return false;
}
}
return true;
}
return false;
}
...
...
...
輸入長度為4,通過分析后面知道輸入是數字,所以范圍是1000-9999.所以是可以爆破的,但是爆破是要用到encodePassword方法,自己寫一個當然也可以,但是很麻煩,這里就可以直接frida呼叫encodePassword函式.
注意這里encodePassword是靜態方法,所以可以直接呼叫
function main() {
Java.perform(function x() {
console.log("In Java perform")
var verify = Java.use("org.teamsik.ahe17.qualification.Verifier")
var stringClass = Java.use("java.lang.String")
var p = stringClass.$new("09042ec2c2c08c4cbece042681caf1d13984f24a")
for (var i = 999; i < 10000; i++){
var v = stringClass.$new(String(i))
var vSign = verify.encodePassword(v)
if (parseInt(p) == parseInt(stringClass.$new(vSign))) {
console.log("yes: " + v)
break
}
console.log("not :" + v)
}
})
}
setImmediate(main)
結果
not :9078
not :9079
not :9080
not :9081
not :9082
yes: 9083
需要注意的是,要呼叫parseInt決議記憶體中的記憶體再對比,因為string型別是java的string型別,對js代碼來說是一段記憶體,
EasyJava
這題是純java題,邏輯很清晰,對輸入的每一個字符單個檢查,加密并對比,所以可以很簡單的想到爆破的思路
public static Boolean b(String str) {
if (str.startsWith("flag{") && str.endsWith("}")) {
String substring = str.substring(5, str.length() - 1);
b bVar = new b(2);
a aVar = new a(3);
StringBuilder sb = new StringBuilder();
int i = 0;
for (int i2 = 0; i2 < substring.length(); i2++) {
sb.append(a(substring.charAt(i2) + "", bVar, aVar));
Integer valueOf = Integer.valueOf(bVar.b().intValue() / 25);
if (valueOf.intValue() > i && valueOf.intValue() >= 1) {
i++;
}
}
return Boolean.valueOf(sb.toString().equals("wigwrkaugala"));
}
return false;
}
所以可以單個字符爆破,但是要注意到,com.a.easyjava.b和com.a.easyjava.a兩個類中都存在static屬性的變數,下面是b類的
public class b {
public static ArrayList<Integer> a = new ArrayList<>();
static String b = "abcdefghijklmnopqrstuvwxyz";
static Integer d = 0;
Integer[] c = {8, 25, 17, 23, 7, 22, 1, 16, 6, 9, 21, 0, 15, 5, 10, 18, 2, 24, 4, 11, 3, 14, 19, 12, 20, 13};
?
public b(Integer num) {
for (int intValue = https://www.cnblogs.com/hetianlab/p/num.intValue(); intValue < this.c.length; intValue++) {
a.add(this.c[intValue]);
}
for (int i = 0; i < num.intValue(); i++) {
a.add(this.c[i]);
}
}
?
public static void a() {
int intValue = a.get(0).intValue();
a.remove(0);
a.add(Integer.valueOf(intValue));
b +="" + b.charAt(0);
b = b.substring(1, 27);
Integer num = d;
d = Integer.valueOf(d.intValue() + 1);
}
?
public Integer a(String str) {
int i = 0;
if (b.contains(str.toLowerCase())) {
Integer valueOf = Integer.valueOf(b.indexOf(str));
for (int i2 = 0; i2 < a.size() - 1; i2++) {
if (a.get(i2) == valueOf) {
i = Integer.valueOf(i2);
}
}
} else {
i = str.contains(" ") ? -10 : -1;
}
a();
return i;
}
?
public Integer b() {
return d;
}
}
b類中的a,b,d變數都是static型別的同時,這三個變數都會被下面的方法所改變,所以如果要爆破,需要重新修改實體中的屬性值,如果不重新修改屬性的值,我們通過觀察b類中的b變數可以看到會有什么問題,
這個腳本是爆破第一個字符在加密后所有的可能性,爆破范圍通過分析b類可以縮小到
a-z,然后模仿加密程序,加密一個字符看看結果,中間每回圈一次會重新申請一個b和a類的實體,想通過申請新的實體來避免類中變數的修改.
function main() {
Java.perform(function x() {
console.log('[+] script load');
var b = Java.use("com.a.easyjava.b");
var a = Java.use("com.a.easyjava.a");
var StringClass = Java.use("java.lang.String");
var IntClass = Java.use("java.lang.Integer");
var MainActivity = Java.use("com.a.easyjava.MainActivity");
?
try { // try catch 用來查看報錯的,可以去掉
for (var i = 97; i < 123; i++) {
var bvar = b.$new(IntClass.$new(2));
var avar = a.$new(IntClass.$new(3));
?
var s = String.fromCharCode(i);
var c = MainActivity.a(s, bvar, avar);
console.log(`enc(${s}) => ${c}, b.a => ${b._b.value}`);
}
} catch (e) {
console.log(e);
}
console.log('[+] script end');
})
}
setImmediate(main)
結果如下
# python3 loader.py
[+] script load
enc(a) => a, b.b => bcdefghijklmnopqrstuvwxyza
enc(b) => a, b.b => cdefghijklmnopqrstuvwxyzab
enc(c) => a, b.b => defghijklmnopqrstuvwxyzabc
enc(d) => a, b.b => efghijklmnopqrstuvwxyzabcd
enc(e) => a, b.b => fghijklmnopqrstuvwxyzabcde
enc(f) => a, b.b => ghijklmnopqrstuvwxyzabcdef
enc(g) => a, b.b => hijklmnopqrstuvwxyzabcdefg
enc(h) => a, b.b => ijklmnopqrstuvwxyzabcdefgh
enc(i) => a, b.b => jklmnopqrstuvwxyzabcdefghi
enc(j) => a, b.b => klmnopqrstuvwxyzabcdefghij
enc(k) => a, b.b => lmnopqrstuvwxyzabcdefghijk
enc(l) => a, b.b => mnopqrstuvwxyzabcdefghijkl
enc(m) => a, b.b => nopqrstuvwxyzabcdefghijklm
enc(n) => a, b.b => opqrstuvwxyzabcdefghijklmn
enc(o) => a, b.b => pqrstuvwxyzabcdefghijklmno
enc(p) => a, b.b => qrstuvwxyzabcdefghijklmnop
enc(q) => a, b.b => rstuvwxyzabcdefghijklmnopq
enc(r) => a, b.b => stuvwxyzabcdefghijklmnopqr
enc(s) => a, b.b => tuvwxyzabcdefghijklmnopqrs
enc(t) => a, b.b => uvwxyzabcdefghijklmnopqrst
enc(u) => a, b.b => vwxyzabcdefghijklmnopqrstu
enc(v) => a, b.b => wxyzabcdefghijklmnopqrstuv
enc(w) => a, b.b => xyzabcdefghijklmnopqrstuvw
enc(x) => a, b.b => yzabcdefghijklmnopqrstuvwx
enc(y) => a, b.b => zabcdefghijklmnopqrstuvwxy
enc(z) => a, b.b => abcdefghijklmnopqrstuvwxyz
[+] script end
可以看到實際上,雖然每次new了一個新的實體,但是實體中的static變數是變了的,這導致了之前的爆破會影響到下一次爆破,同時也可以看到加密結果全部都是a,所以如果要爆破,就得想辦法讓每次爆破,新的實體中的值不變,
需要使用bvar._b.value = https://www.cnblogs.com/hetianlab/p/StringClass.$new("abcdefghijklmnopqrstuvwxyz");這樣的語法對static型別的變數重新設值,
需要注意的是有些變數在jadx/jeb中看到的名字可能會被多載,需要加一個下劃線比如b -> _b,可以通過console列印看看是不是unknow,也可以直接用jadx右鍵復制frida片段,查看此變數frida需不需要加一個下劃線
解題腳本的思路就很簡單,單個字符來爆破,每次重新生成類的實體,并將類中的值置為初始狀態(通過呼叫類$init方法),
exp
function main() {
Java.perform(function x() {
console.log('[+] script load');
?
var b = Java.use("com.a.easyjava.b");
var a = Java.use("com.a.easyjava.a");
var IntClass = Java.use("java.lang.Integer");
var StringClass = Java.use("java.lang.String");
var ArrayList = Java.use("java.util.ArrayList");
var MainActivity = Java.use("com.a.easyjava.MainActivity");
?
var flag = new Array();
var cipher = "wigwrkaugala";
?
var bvar = b.$new(IntClass.$new(2));
var avar = a.$new(IntClass.$new(3));
?
for (var _ = 0; _ < cipher.length; _++) {
for (var i = 97; i < 123; i++) { // 97 - 123是字母a-z
// reset static value
bvar._b.value = https://www.cnblogs.com/hetianlab/p/StringClass.$new("abcdefghijklmnopqrstuvwxyz");
bvar.d.value = https://www.cnblogs.com/hetianlab/p/IntClass.$new(0);
bvar._a.value = ArrayList.$new();
bvar["$init"](IntClass.$new(2));
?
avar.b.value = https://www.cnblogs.com/hetianlab/p/StringClass.$new("abcdefghijklmnopqrstuvwxyz");
avar.d.value = https://www.cnblogs.com/hetianlab/p/IntClass.$new(0);
avar._a.value = ArrayList.$new();
avar["$init"](IntClass.$new(3));
?
var s = String.fromCharCode(i);
flag.push(s);
?
for (var e = 0; e < flag.length; e++) {
var c = MainActivity.a(flag[e].toString(), bvar, avar);
if (c != cipher[e]) {
break;
}
}
if (c == cipher[flag.length - 1]) {
console.log(flag);
break
}
flag.length -= 1;
}
}
console.log('flag{' + flag.join('') + '}');
console.log('[+] script end');
})
}
setImmediate(main);
結果
root@kali ~/frida-script-dev# python3 loader.py
[+] script load
v
v,e
v,e,n
v,e,n,i
v,e,n,i,v
v,e,n,i,v,i
v,e,n,i,v,i,a
v,e,n,i,v,i,a,i
v,e,n,i,v,i,a,i,v
v,e,n,i,v,i,a,i,v,i
v,e,n,i,v,i,a,i,v,i,c
v,e,n,i,v,i,a,i,v,i,c,i
flag{veniviaivici}
[+] script end
更多網安技能的在線實操練習,請點擊這里>>
合天智匯:合天網路靶場、網安實戰虛擬環境轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/557024.html
標籤:其他
上一篇:2023年最具威脅的25種安全漏洞(CWE TOP 25)
下一篇:返回列表
