【逆向安全】-工具(一)AppShark

一、介绍

Appshark 是一个静态污点分析工具,用于扫描 Android 应用程序中的漏洞。我做了一点改造,增加了应用批处理能力。

  • 工具能力:自动扫描apk漏洞,筛选出符合条件的应用集合,再对这部分应用有针对性的进行人工详细分析。主要价值在于对厂商海量的系统应用能减少人力筛查成本;

  • 工具特点:支持漏洞规则自定义、多漏洞规则并行筛查、支持文件批处理;

  • 工具局限性:分析的是污点在变量之间的传递关系,所以无论是source、sink还是sanitizer描述的具体粒度都是变量(但是也已满足绝大多数场景)。

改造后项目仓库地址:晚点补链接//todo
开源项目地址:https://github.com/bytedance/appshark
官方文档:https://github.com/bytedance/appshark/blob/main/doc/zh/overview.md

二、使用

2.1 工具运行及结果分析

环境:>= JDK-11
配置:config/config.json
运行:$ python3 appShark.py -s
输入
① config配置:主要设置文件路径及选择使用何种漏洞分析规则来处理文件
② rules: 漏洞分析规则 (后面会介绍规则编写)
输出
① results.json文件(这里对其他非必要文件做了精简)
② 发现匹配漏洞规则的应用,且至少有1个导出组件的情况下,会在包名加上_marked后缀。

results.json文件说明:

{
    "AppInfo": { // App信息
        "AppName": "NFC Service",
        "PackageName": "com.android.nfc",
        "min_sdk": 34,
        "target_sdk": 34,
        "versionCode": 34,
        "versionName": "14",
        "classCount": 1254,
        "methodCount": 8466,
        "appsharkTakeTime": 8571
    },
    "ManifestRisk": { // AndroidManifest安全信息
        "debuggable": false, // 是否允许调试
        "allowBackup": false, // 是否允许对应用数据的备份和恢复
        "usesCleartextTraffic": false //是否使用明文流量(非加密的Http)
    },
    "SecurityInfo": { // 匹配自定义静态扫描规则生成的安全结果,这里以全局扫描是否有setWifiEnabled调用为例
        "camille": {
            "setWifiEnabled": {
                "category": "camille",
                "detail": "setWifiEnabled",
                "name": "setWifiEnabled",
                "vulners": [
                    {
                        "details": {
                            "url": "/Users/XX/appshark-main/out/vulnerability/0-setWifiEnabled.html",
                            "position": "<com.android.nfc.ConfirmConnectToWifiNetworkActivity: void onClick(android.view.View)>",
                            "target": [ // 调用链
                                "<com.android.nfc.ConfirmConnectToWifiNetworkActivity: void onClick(android.view.View)>",
                                "virtualinvoke $r3.<android.net.wifi.WifiManager: boolean setWifiEnabled(boolean)>(1)"
                            ]
                        },
                        "hash": "eb84e25e4fd117ff421ff2a2c81ef92671f087c7",
                        "old_hash": "68064390a20df5d492e9525b7c43acf8096e8c83"
                    },
                    ...
                ],
                "deobfApk": ""
            }
        }
    },
    "DeepLinkInfo": {
    },
    "HTTP_API": [
    ],
    "JsBridgeInfo": [
    ],
    "BasicInfo": { // 组件基本信息,这里主要是呈现组件是否导出及其相关信息
        "ComponentsInfo": {
            "exportedReceivers": {
                "com.android.nfc.NfcReaderDetector$1": {
                    "exported": true,
                    "DynamicBroadcastReceiver": "com.android.nfc.NfcReaderDetector$1",
                    "RegisteredMethod": "<com.android.nfc.NfcReaderDetector: void <init>(android.content.Context)>",
                    "RegisteredStmt": "virtualinvoke $r1_1.<android.content.Context: android.content.Intent registerReceiver(android.content.BroadcastReceiver,android.content.IntentFilter,int)>($r3, $r7, 2)"
                },
                "com.android.nfc.NfcBootCompletedReceiver": {
                    "exported": true,
                    "<receiver exported=true name=com.android.nfc.NfcBootCompletedReceiver>": [
                        {
                            "<intent-filter>": [
                                {
                                    "content": "<action name=android.intent.action.BOOT_COMPLETED>",
                                    "isString": true
                                }
                            ]
                        }
                    ]
                },
                ...
            },
            "unExportedActivities": {
                "com.android.nfc.TechListChooserActivity": {
                    "exported": false,
                    "<activity process=:com.android.nfc.chooser finishOnCloseSystemDialogs=true name=com.android.nfc.TechListChooserActivity launchMode=3 multiprocess=false theme=16974850 excludeFromRecents=true>": [
                    ]
                },
                "com.android.nfc.cardemulation.AppChooserActivity": {
                    "exported": false,
                    "<activity clearTaskOnLaunch=true finishOnCloseSystemDialogs=true name=com.android.nfc.cardemulation.AppChooserActivity multiprocess=true theme=2131886364 excludeFromRecents=true>": [
                    ]
                },
                ...
            },
            "unExportedProviders": {
                "androidx.startup.InitializationProvider": {
                    "exported": false,
                    "<provider exported=false name=androidx.startup.InitializationProvider authorities=com.android.nfc.androidx-startup>": [
                        {
                            "<meta-data name=androidx.lifecycle.ProcessLifecycleInitializer value=androidx.startup>": [
                            ]
                        }
                    ]
                },
                ...
            },
            "unExportedServices": {
                "com.android.nfc.handover.PeripheralHandoverService": {
                    "exported": false,
                    "<service name=com.android.nfc.handover.PeripheralHandoverService>": [
                    ]
                },
                ...
            },
            "unExportedReceivers": {
                "androidx.profileinstaller.ProfileInstallReceiver": {
                    "exported": false,
                    "<receiver exported=true name=androidx.profileinstaller.ProfileInstallReceiver permission=android.permission.DUMP enabled=true directBootAware=false>": [
                        {
                            "<intent-filter>": [
                                {
                                    "content": "<action name=androidx.profileinstaller.action.INSTALL_PROFILE>",
                                    "isString": true
                                }
                            ]
                        },
                        ...
                    ]
                }
            },
            "exportedActivities": {
                "com.android.nfc.BeamShareActivity": {
                    "exported": true,
                    "<activity exported=true noHistory=true finishOnCloseSystemDialogs=true icon=2131230958 name=com.android.nfc.BeamShareActivity theme=16973839 excludeFromRecents=true label=2131820586>": [
                        {
                            "<intent-filter>": [
                                {
                                    "content": "<action name=android.intent.action.SEND>",
                                    "isString": true
                                },
                                {
                                    "content": "<category name=android.intent.category.DEFAULT>",
                                    "isString": true
                                },
                                {
                                    "content": "<data mimeType=*/*>",
                                    "isString": true
                                }
                            ]
                        },
                        ...
                    ]
                }
            }
        },
        "JSNativeInterface": [
        ]
    },
    "UsePermissions": [ // 申请的权限
        "android.permission.BLUETOOTH_PRIVILEGED",
      ...
    ],
    "DefinePermissions": { // 自定义权限
        "com.miui.nfc.permission.SEND_HCI_EVENT": "signatureOrSystem",
       ...
    },
    "Profile": "/Users/XX/appshark-main/out/vulnerability/2-profiler.json"
}

2.2 配置文件设置

config.json5主要的设置项:
"apkPath": // apk文件路径,必要参数
"out": "", // 结果输出路径
"maxThread": 1, // 控制内部进行指针分析等操作时的并行度,默认数量为2
"rules": "wifiEnable.json", // 自定义规则配置
"rulePath": "config/rules", //specifies the rule's parent directory, default is ./config/rules
"logLevel": 1, //debug 0;info 1;warn 2;error 3
"javaSource": true, //是否在最终的漏洞详情中展示源码. 该源码是通过jadx反编译得到.
"supportFragment":true , //是否对处理Fragment的lifeCycle函数. 类似于处理Activity的onCreate等函数
"wholeProcessMode": //是否进行全程序分析,默认为false. 全行程分析主要是影响分析的范围和性能表现

2.3 自定义规则撰写

  1. 规则模块介绍:
    entry : 分析入口,一般是个函数
    source:污染源
    sink:污染利用点
    sanitizer: 过滤source到sink的无效链路,消除误报。

注:appshark分析的是污点在变量之间的传递关系,所以无论是source,还是sink,还是sanitizer描述的具体粒度都是变量。

  1. 各模块规则撰写实现:
    规则JSON编写框架
{
  "unZipSlip": {
    "SliceMode": true, // 1 分析模式入口
    "desc": {
      "category": "FileRisk", // 2 分类
    },
    "entry": { // 3 分析入口
    },
    "source": { // 4 污染源定义
    },
    "sanitizer": { // 6 过滤无效链路
    },
    "sink": { // 5 污染利用点
    }
  }
}

① 分析入口模式(mode)
DirectMode: 固定分析入口。需要明确指明分析的入口,即 : entry;
SliceMode: 不固定分析入口。和DirectMode的区别是它的分析入口不是固定的,而是根据具体的source,sink计算得到的;
ConstStringMode: 以常量字符串所在的函数作为分析入口。不受traceDepth的约束;
ConstNumberMode: 以常量数值所在的函数作为分析入口。不受traceDepth的约束;
APIMode: APIMode和前面的几种mode都不一样,他并不是一个数据流分析的规则,而是一个简单的查找指定api的规则。

② 分类(category)
这里就是封装安全信息的key,这里key已经优化了配置:保持名称与分类一致即可

"setWifiEnabled": {
     "desc": {     
        "category": "setWifiEnabled",
      }
}

③ 分析入口(entry)

"entry": { 
     "methods": [  "<net.bytedance.security.app.ruleprocessor.testdata.ZipSlip: void UnZipFolder(java.lang.String,java.lang.String)>" ] 
}

分析入口一般是一个函数。按jimple规则:<类名>:<返回值> <函数> (<函数参数>...) 为模板设置,entry只有在DirectMode下需要明确指定,其他三个模式下,都无需明确指明分析入口。

④ 污染源定义(source)

  • 常量字符串
  • 函数返回值
  • 某对象的field
  • 某个函数的参数
  • 某个对象的创建

I 常量字符串

"source": { 
    "ConstString": ["path1"]
 }

对应:
String s="path1";
f(12,"path1");
s将成为source. 函数f的参数1将成为source

II 函数返回值

"source": { 
      "Return": ["<java.util.zip.ZipEntry: java.lang.String getName()>" ]
    }

也就是getName的返回值将会是source, 那么:
ZipEntry e=getEntry();
String name=e.getName();
name将成为source点。

III 某对象的field

"source": {
    "Field": [  "<android.provider.CalendarContract: android.net.Uri CONTENT_URI>", ] 
}

Uri uri=CalendarContract.CONTENT_URI;
uri将会成为source点. 注意不区分该field是静态field还是非静态field。

IV 某个函数的参数

"source": { 
          "Param": { 
              "<android.webkit.WebViewClient: android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView, android.webkit.WebResourceRequest)>": [ "p1" ]
           } 
}

p0是第一个参数,p1是第二个参数,这里p1对应的是WebResourceRequest,它才是source。

V 某个对象的创建

"source": {
      "NewInstance": ["android.content.Intent"] 
}

那么:
android.content.Intent i=new android.content.Intent();
这时候变量i将成为source点。

⑤ 污染源利用(sink)
key:

  • LibraryOnly 默认值为false,如果设置为true,那么就要求匹配到的函数签名必须是EngineConfig.json5中指定的Library
  • TaintParamType 参数类型限制
  • TaintCheck 检查规则

限制条件(目前sink点只能是函数的周边)

  • this指针 @this "TaintCheck": [ "@this"]
  • 函数的某个参数 p0,p1,p2,所有参数p* "TaintCheck": [ "p*" ]
  • 函数的返回值 return "TaintCheck": [ "return" ]

多条件设置写法:"TaintCheck": [ "@this","return" ]
举例:

"sink": {     
     "<*: * startActivit*(*)>": {          
                  "LibraryOnly": true,          
                  "TaintParamType": [                  
                                 "android.content.Intent",                  
                                 "android.content.Intent[]"           
                  ],            
                  "TaintCheck": ["p*"]          
                 }    
 }

这里定startActivit相关泛函数的入参.Intent/.Intent[]为漏洞利用点,即sink,appshark会检查能否找到从source到这些变量的一个污点传播路径。

⑥ 过滤无效链路规则(sanitizer)
sanitizer目的是消除误报. 发现了一条从source到sink的完整传播路径, 该路径经由sanitizer规则过滤,如果满足条件就删掉这条路径,否则保留。

以上面unZipSlip举例:

"rule1": {
        "<java.io.File: java.lang.String getCanonicalPath()>": {
          "TaintCheck": ["@this" ]
        }
      },

      "containsDotDot": {
        "<java.lang.String: boolean contains(java.lang.CharSequence)>": {
          "TaintCheck": [ "@this"],
          "p0": ["..*"]
        }
      },

      "indexDotDot": {
        "<java.lang.String: boolean indexOf(java.lang.String)>": {
          "TaintCheck": ["@this"],
          "p0": [ "..*"]
        }
      }

顶层规则是或的关系:也就是说,你可以自定义多个一级key,这里就是指rule1、containsDotDot、indexDotDot,过滤规则满足他们3个中的1个就过滤掉;

二层规则间是与的关系:containsDotDot下的TaintCheck和p0规则是与的关系,即:
if(path.contains("../")){
return false
}

"TaintCheck": ["@this"]:从source出发,传播到的所有变量中,是否污染到了<java.lang.String: boolean contains(java.lang.CharSequence)>这个函数的this指针,即path

"p0": [ ".."] :常量字符串..污染到contains的参数0

因此这个规则意思就是看代码里是否有"../"相关的判断语句,如果有就认为是对这种漏洞有预防,就不用统计了。

更详细撰写规则说明参考官方文档:https://github.com/bytedance/appshark/blob/main/doc/zh/how_to_write_rules.md

了解到这,结合官方详细文档,自己就可以编写简单规则试试看了,项目中也提供了一些写好的规则模板,可以借鉴学习。

三、实现原理分析

① 配置文件解析 :Json解析config.json;
② apk解析:使用jadx对apk反编译成java; 解析manifest和resource文件,提权清单文件信息,包括:应用、组件信息、权限信息等;
③ 代码预处理:通过soot框架构建call graph, 即各函数的可达路径图;
④ 用户自定义规则解析:解析规则,查找source、sink;
⑤ 数据流分析:基于call graph和漏洞规则,寻找source到sink调用链;
⑥ 输出报告:封装数据,输出报告文件。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容