본문 바로가기

카테고리 없음

DIVA 11단계

#1 문제 분석

가. 목적

앱 외부에서 private note 에 pin없이 접근해보자

#2 취약점 정보

가. 취약점

provider로 감싼 부분에서 notesprovider는 exported=true라서 외부에서 경로만으로 접근가능하다.

앱 밖에서 PIN을 모른채 private note에 접근하세요.

 

 

근데 왜 am start -d jakhar.aseem.diva.provider.notesprovider/notes는 이렇게 뜰까??

아 am start는 어떤 액티비티를 시작하는 거라서, 시작할 때의 어떤 값을 정해주는 거고

 

content query --uri 는 db내의 컨텐트 프로바이더를 쿼리하기 위한 것이다. --uri옵션은 쿼리할 컨텐트 프로바이더의 URI를 지정한다.

 

pin을 알고 접속하는 법은 없음 이건 db안에 존재하는거라 10번처럼 액티비티로 접속할 방법이 없음

 #3 코드 분석

 

1.

String pin = spref.getString(getString(R.string.pkey), "");

SharedPreferences 객체에서 문자열 값을 가져옴

2.

Cursor cr = getContentResolver().query(NotesProvider.CONTENT_URI, new String[]{"_id", "title", "note"}, null, null, null);

NotesProvider에서 "_id", "title", "note" 열을 반환하는 쿼리를 실행하고, 결과를 Cursor 객체인 cr에 저장

 

3.

String[] columns = {"title", "note"};
int[] fields = {R.id.title_entry, R.id.note_entry};

어댑터는 데이터와 뷰 간의 매핑을 담당하며, 이러한 배열을 사용하여 데이터를 표시할 때 각 열에 대해 어떤 뷰를 사용할지 결정

"title" 열의 값은 R.id.title_entry에 해당하는 뷰에 표시될 것이고, "note" 열의 값은 R.id.note_entry에 해당하는 뷰에 표시될 것

4.

SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.notes_entry, cr, columns, fields, 0);

 

SimpleCursorAdapter: CursorAdapter의 하위 클래스, Cursor 객체에서 데이터를 가져와 AdapterView의 각 항목을 채우는 역할

cr: 쿼리된 결과를 담고 있음

0: CursorAdapter가 데이터를 로드할 때 추가적인 조작을 수행하지 않도록 함

 

5.

lview.setAdapter((ListAdapter) adapter);

 

setAdapter(): AdapterView에 어댑터를 설정한다. SimpleCursorAdapter를 ListAdpter로 형변환해 전달

 

6.

pinTxt.setVisibility(4);

뷰를 인식할 수 없음으로 설정한다.

 

7.

static final Uri CONTENT_URI = Uri.parse("content://jakhar.aseem.diva.provider.notesprovider/notes");
static final UriMatcher urimatcher = new UriMatcher(-1);

Uri.parse: 문자열 형태의 URI르 uri객체로 변환한다.

UriMatcher: URI패턴을 매칭하여 처리할 액션을 결정하는 데 사용한다. -1은 초기화할 때 어떤 매치도 하지않음을 의미한다.

 

8.

    static {
        urimatcher.addURI(AUTHORITY, TABLE, 1);
        urimatcher.addURI(AUTHORITY, "notes/#", 2);
    }

URI패턴과 해당하는 매치 코드를 추가한다.

AUTHORITY는 컨텐트 프로바이더의 인증 정보, 주소 패키지 이름, TABLE은 DB의 테이블 이름, notes라는 테이블을 가리킨다. 

1은 테이블의 모든 데이터, notes/#은 특정 순서의 데이터 

 

9.

String id = uri.getLastPathSegment();
count = this.mDB.delete(TABLE, "_id = " + id + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);

삭제할 레코드의 id로 설정하기 위해 uri의 마지막 세그먼트를 가져온다.

특정 조건에 맞는 레코드를 삭제한다.

10.

    public String getType(Uri uri) {
        switch (urimatcher.match(uri)) {
            case 1:
                return "vnd.android.cursor.dir/vnd.jakhar.notes";
            case 2:
                return "vnd.android.cursor.item/vnd.jakhar.notes";
            default:
                throw new IllegalArgumentException("Divanotes: Unsupported URI: " + uri);
        }
    }

매치코드가 1이냐 2냐

 

11.

Uri newUri = ContentUris.withAppendedId(CONTENT_URI, row);

ContentUris.withAppendedId() 메서드를 사용하여 기본 URI인 CONTENT_URI와 삽입된 레코드의 행 번호를 결합합니다.

 

 

12.

Cursor cursor = queryBuilder.query(this.mDB, projection, selection, selectionArgs, null, null, sortOrder);

 

queryBuilder를 사용하여 데이터베이스에서 쿼리를 수행 하고, Cursor 객체로 반환된다.