分享

iOS App 自动登录的安全性分析

 WindySky 2016-08-10

引子

Cookie 有时也用其复数形式Cookies, 指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密).

如果Cookie 以明文的方式存储,那是危险的,如果Cookie 以明文的方式存储在易得到的地方那就更危险了。现在很多的一些公司的APP Cookie都直接放在 APP 应用程序程序下,

这样会导致很大的安全问题,有一些不需要越狱的工具就可以导出,天真的小白们还认为不越狱就安全了吗?

当我们每次输入一次账户密码后,退出程序,然后再进来时一般人是不需要再次输入密码的,那么App 肯定存储了登录用的Cookie或者账户密码信息,这些信息如果不保存得当,

即使iOS 设备不越狱,照样也是不安全的!

开发过APP的都知道一般将Cookie存储在cookie.binary或者keychain。

1.cookie.binary 可以不越狱通过工具导出,一般采取这种方式还要配合混合加密才行。

Safari 浏览器和iOS应用程序将永久cookie保存在Cookies.binarycookies文件中

用BinaryCookieReader.py 去读取      下载地址: http:///wp-content/uploads/tools/iOS/BinaryCookieReader.py

方法为: python BinaryCookieReader.py   /private/var/mobile/Containers/Data/Application/x-x-x/Library/Cookies/Cookies.binarycookies

2.根据苹果的介绍,iOS设备中的Keychain是一个安全的存储容器,可以用来为不同应用保存敏感信息比如用户名,密码,网络密码,认证令牌。苹果自己用keychain来保存Wi-Fi网络密码,VPN凭证等等。它是一个sqlite数据库,位于/private/var/Keychains/keychain-2.db,其保存的所有数据都是加密过的。开发者通常会希望能够利用操作系统提供的功能来保存凭证(credentials)而不是把它们(凭证)保存到NSUserDefaults,plist文件等地方。保存这些数据的原因是开发者不想用户每次都要登录,因此会把认证信息保存到设备上的某个地方并且在用户再次打开应用的时候用这些数据自动登录。

 一般对于未越狱的手机,iOS App 一般将 Cookie 或者密码 存放在 iOS 设备的 keychain中就安全了,但是如果对于越狱的手机,存储在 keychain 中还是不安全的。

Keychain 的操作

SecItemCopyMatching

SecItemAdd

SecItemUpdate

SecItemDelete

SecItemCopyMatching 用于搜索。其他操作操作,SecItemAdd,SecItemUpdate,SecItemDelete 从字面上就能理解。具体的使用细节可以查看 Apple 的文档:Apple Keychain Services Reference。

关于keychain 开发

需要导入Security.framework

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#import “GegeKeyChainHelper.h"
@implementation GegeKeyChainHelper
NSString * const KEY_USERNAME = @"com.company.app.username"
NSString * const KEY_PASSWORD = @"com.company.app.password"
@implementation GegeKeyChainHelper
+ (NSMutableDictionary *)getKeyChainQuery:(NSString *)service { 
    return [NSMutableDictionary dictionaryWithObjectsAndKeys: 
            (id)kSecClassGenericPassword,(id)kSecClass, 
            service, (id)kSecAttrService, 
            service, (id)kSecAttrAccount, 
            (id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible, 
            nil]; 
}
+ (void) saveUserName:(NSString*)userName
      userNameService:(NSString*)userNameService
             psaaword:(NSString*)pwd
      psaawordService:(NSString*)pwdService
{
    NSMutableDictionary *keychainQuery = [self getKeyChainQuery:userNameService]; 
    SecItemDelete((CFDictionaryRef)keychainQuery);  //删除原来的旧数据
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:userName] forKey:(id)kSecValueData]; 
    SecItemAdd((CFDictionaryRef)keychainQuery, NULL); //添加新数据
    
    keychainQuery = [self getKeyChainQuery:pwdService]; 
    SecItemDelete((CFDictionaryRef)keychainQuery); 
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:pwd] forKey:(id)kSecValueData]; 
    SecItemAdd((CFDictionaryRef)keychainQuery, NULL);
}

最后调用

1
[GegeKeyChainHelper saveUserName:@“gegeda2015" userNameService:KEY_USERNAMEpsaaword:@“123456" psaawordService:KEY_PASSWORD];

网上有很多的开源keychain 项目,大家可以去看看。

Apple 也提供了一个关于 Keychain 操作的封装:KeychainItemWrapper。在 Xcode 的 Document 中可搜到此项目。

也可以直接看看 

github 上也有一个使用起来稍微简单一些的封装:PDKeychainBindingsController。但 PDKeychainBindingsController 不支持 Access Group。这在后面讲到的应用间共享 keychain 数据时需要用到,但是自己加上这个并不困难。

对每个应用来说,Keychain都有两个访问区,私有区和公共区。私有区是一个sandbox,本程序存储的任何数据都对其他程序不可见。Keychain中保存的信息是用app unique签名了的,默认只有自己能够访问

a)app保持的信息是用一个app unique 签名了的,默认只有自己能够访问。

b)不同app之间可以通过access_group共享

c)在不同app之间共享,只能在同一个公司内部的app共享。

通过上面的分析,我们知道要访问keychain里面的数据,需要

1. 和app同样的证书

jail break 相当于对苹果做签名检查的地方打了个补丁,使得不是苹果颁发的证书签名的文件,甚至伪造的签名文件签名的app也能正常使用。所以这个可以轻松绕过。

2. 获得Keychain Dumper

关于 iCloud Keychain 我们不再讨论,它是存储在云上的,关于iCloud Keychain安全大家可以另外找找资料。


探讨App 怎么实现自动登录的

1)

Weibo iOS App 算是很成熟的APP 了,下面我们来看看 Weibo App 是怎么存储用户Cookie 的,又是怎么实现自动登录的。

下面我们通过越狱手机装 Weibo App 进行分析

首先我们登陆自己的账户进 iOS App Weibo

t0138887eefa0509581.png

首先看看 /private/var/mobile/Containers/Data/Application/x-x-x/Library/Cookies/Cookies.binarycookies

可以看到是有 Cookie的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
python BinaryCookieReader.py Cookies.binarycookies
#*************************************************************************#
# BinaryCookieReader: developed by Satishb3: http://www. #
#*************************************************************************#
Cookie : SUB=_2A254DHPADeThGeNL7loY9C7FzDiIHXVbXieIrDV9PUJbr9ANLUXFkWsSyqBt7WYuQgyICc71QXczL_v9jQ..; domain=.sina.cn; path=/; expires=Thu, 16 Apr 2015; HttpOnly
Cookie : SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9Wh70L6N52f_2baA2FyG89He; domain=.sina.cn; path=/; expires=Wed, 16 Mar 2016;
Cookie : SUB=_2A254DHPADeThGeNL7loY9C7FzDiIHXVbXieIrDV_PUJbr9ANLVDjkWtnyTIJxQn9C6VPVcio7EmhIfhOVA..; domain=.sina.com.cn; path=/; expires=Thu, 16 Apr 2015; HttpOnly
Cookie : SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9Wh70L6N52f_2baA2FyG89He; domain=.sina.com.cn; path=/; expires=Wed, 16 Mar 2016;
Cookie : SUB=_2A254DHPADeThGeNL7loY9C7FzDiIHXVbXieIrDV6PUJbr9ANLW32kWuiULZ74HmOlYD6e1bTokSbdMTdOQ..; domain=.weibo.cn; path=/; expires=Thu, 16 Apr 2015; HttpOnly
Cookie : SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9Wh70L6N52f_2baA2FyG89He; domain=.weibo.cn; path=/; expires=Wed, 16 Mar 2016;
Cookie : SUHB=0U1Zi-W-QMPbyU; domain=.weibo.cn; path=/; expires=Wed, 16 Mar 2016;
Cookie : SUB=_2A254DHPADeThGeNL7loY9C7FzDiIHXVbXieIrDV8PUJbr9ANLRHHkWt5DRKgx9dj7Q_j8Vl9avimUWxFsw..; domain=.weibo.com; path=/; expires=Thu, 16 Apr 2015; HttpOnly
Cookie : SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9Wh70L6N52f_2baA2FyG89He; domain=.weibo.com; path=/; expires=Wed, 16 Mar 2016;
Cookie : SUHB=0auQsO5Yohjgmd; domain=.weibo.com; path=/; expires=Wed, 16 Mar 2016;

我们拼凑Cookie,用chrome 插件EditThisCookie 编辑插件 看到weibo.com的Cookie

t010264c44b35ec364d.png

设置Cookie 可是 怎么也登陆不上weibo.com 的网页。

看来Weibo 还使用了其他的值来确认登陆,这是用来迷惑我们用得。

先dump 出Weibo App 的二进制文件(方法网上很多) 丢进IDA

搜索 Apple  keychain 相关函数,分析找到

1
void __cdecl -[WBCookieManager storeCookiesToKeychain:](struct WBCookieManager *self, SEL a2, id keychain_data_a3)

保存用的标签可以看到这里没有加密

v23 = SecItemUpdate(v20, v22);//更新 Cookie

….

}

分析发现 微博 存取cookie 到 keychain 时也没用 加密解密的

然后我们dump   keychain  用得工具  keychain_dumper  (也可以使用 Snoop-it)针对 /private/var/Keychains/keychain-2.db    dump 出Generic Passwords

https://github.com/ptoomey3/Keychain-Dumper

一个应用能够访问的keychain数据是通过其entitlements文件指定的。keychain_dumper使用一个自签名文件,带有一个*通配符的entitlments,因此它能够访问keychain中的所有条目。 当然,也有其他方法来使得所有keychain信息都被授权,比如用一个包含所有访问组(access group)的entitlements文件,或者使用一个特定的访问组(access group)使得能够访问所有的keychain数据。

你可以通过 “-a” 命令导出所有数据

我们这里看看 sina_cookie

1
2
3
4
5
6
7
8
Generic Password
----------------
Service: sina_cookie
Account: 5558940974  //通过网页我们可以发现 这个是gegeda2015账户的ID
Entitlement Group: ZVC23L5QY4.*
Label: sina_cookie
Generic Field: (null)
Keychain Data: {"expire":1427249413,"uid":"5558940974","cookie":{"sina.cn":"SUB=_2A254FI-VDeThGeNL7loY9C7FzDiIHXVbSTvdrDV9PUJbr9ANLUH2kWsPmRs3fDRvV4IEBlUET1yd-F-5yQ..; path=/; domain=.sina.cn; httponly; expires=Thursday, 23-Apr-15 06:10:13 GMT\nSUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9Wh70L6N52f_2baA2FyG89He; expires=Wednesday, 23-Mar-16 06:10:13 GMT; path=/; domain=.sina.cn\ngsid_CTandWM=4uMKdcd31iovF3Ww6Cuhnnk8kfI; path=/; domain=.sina.cn; httponly","weibo.cn":"SUB=_2A254FI-VDeThGeNL7loY9C7FzDiIHXVbSTvdrDV6PUJbr9ANLXT2kWsn-nE4jiuIN7z3PferYgvKyxXjyQ..; path=/; domain=.weibo.cn; httponly; expires=Thursday, 23-Apr-15 06:10:13 GMT\nSUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9Wh70L6N52f_2baA2FyG89He; expires=Wednesday, 23-Mar-16 06:10:13 GMT; path=/; domain=.weibo.cn\nSUHB=0mxENQhmeVv-uk; expires=Wednesday, 23-Mar-16 06:10:13 GMT; path=/; domain=.weibo.cn\ngsid_CTandWM=4uMKdcd31iovF3Ww6Cuhnnk8kfI; path=/; domain=.weibo.cn; httponly","weibo.com":"SUB=_2A254FI-VDeThGeNL7loY9C7FzDiIHXVbSTvdrDV8PUJbr9ANLUWkkWsYEPcD1rG_hDAtjrCiwW1u7kEM8A..; path=/; domain=.weibo.com; httponly; expires=Thursday, 23-Apr-15 06:10:13 GMT\nSUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9Wh70L6N52f_2baA2FyG89He; expires=Wednesday, 23-Mar-16 06:10:13 GMT; path=/; domain=.weibo.com\nSUHB=0TPFiD6V0p6XL9; expires=Wednesday, 23-Mar-16 06:10:13 GMT; path=/; domain=.weibo.com\nSUS=SID-5558940974-1427177413-JA-ze5rk-b8095e80770d65565c111df6080e9df8; path=/; domain=.weibo.com; httponly\nSUE=es%3Da342b1b141227382d8a065f16824006c%26ev%3Dv1%26es2%3Dc9a756efdae09e01d26a10c265bf1784%26rs0%3Ds1XE7%252F22HggbuTOiQf5sjiSe7YDidbFOLwD%252BxIuYDdPMUG7pykEpS%252FZDf2tNiDVLyaEWURZ2j2PLpyn8ajQkHPiXRaGCdfmLPc2TGF3PxHm2LmWjorbOeRW8P9AP7W%252FnazZ6oFdcNjzxcxkKwodeobU095qa3JYgrpCLvZu6Lgc%253D%26rv%3D0;path=/;domain=.weibo.com;Httponly\nSUP=cv%3D1%26bt%3D1427177413%26et%3D1427263813%26d%3Dc909%26i%3D8e97%26us%3D1%26vf%3D%26vt%3D%26ac%3D%26st%3D0%26uid%3D5558940974%26name%3Dpandashellcode%2540163.com%26nick%3Dgegeda2015%26fmp%3D%26lcp%3D;path=/;domain=.weibo.com\ngsid_CTandWM=4uMKdcd31iovF3Ww6Cuhnnk8kfI; path=/; domain=.weibo.com; httponly","sina.com.cn":"SUB=_2A254FI-VDeThGeNL7loY9C7FzDiIHXVbSTvdrDV_PUJbr9ANLXDnkWtgDTNRMepDEjbVWYZRUhwIzlXKEQ..; path=/; domain=.sina.com.cn; httponly; expires=Thursday, 23-Apr-15 06:10:13 GMT\nSUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9Wh70L6N52f_2baA2FyG89He; expires=Wednesday, 23-Mar-16 06:10:13 GMT; path=/; domain=.sina.com.cn\nSUS=SID-5558940974-1427177413-JA-w3mlt-74ec2c9411b359057ba2d18b6c899df8; path=/; domain=.sina.com.cn; httponly\nSUE=es%3Dc36ee516440422c56b52d8e987ab7c0d%26ev%3Dv1%26es2%3D15fd7d0b38445de12a01a266a70c4021%26rs0%3DyNMOKKFkbtJTXYQj4ehed49LiW1nMMvSFfHOpYPeKswGETpqW5rxWHt5K5OG4hGNJUIAzHAvR6I%252Bvt%252BHnToIaPqakRzfuphEvxl0cZMdNK6JXxgvQahOtBsbQdN%252F9xiCCa6Noz1EeQGS%252FdY49u5nkJkmB%252FOrarWuLsiKrduSO78%253D%26rv%3D0;path=/;domain=.sina.com.cn;Httponly\nSUP=cv%3D1%26bt%3D1427177413%26et%3D1427263813%26d%3D40c3%26i%3D8e97%26us%3D1%26vf%3D%26vt%3D%26ac%3D%26st%3D0%26lt%3D1%26uid%3D5558940974%26user%3Dpandashellcode%2540163.com%26ag%3D4%26name%3Dpandashellcode%2540163.com%26nick%3Dgegeda2015%26sex%3D1%26ps%3D0%26email%3D%26dob%3D%26ln%3D%26os%3D%26fmp%3D%26lcp%3D;path=/;domain=.sina.com.cn\ngsid_CTandWM=4uMKdcd31iovF3Ww6Cuhnnk8kfI; path=/; domain=.sina.com.cn; httponly"}}


//这么一长串看着眼睛都花了,我们下面来分解一下

中分为了 三个 域名不同域名不同,我们先看看

1
2
3
4
5
6
7
8
Generic Password
----------------
Service: sina_cookie
Account: 5558940974  //通过网页我们可以发现 这个是gegeda2015账户的ID
Entitlement Group: ZVC23L5QY4.*
Label: sina_cookie
Generic Field: (null)
Keychain Data: {"expire":1427153318,"uid":"5558940974","cookie":{

))))))最后一个设置它,因为微博会检查到它改变了需要刷新页面

1
2
3
sid_CTandWM=4uMKdcd31iovF3Ww6Cuhnnk8kfI; path=/; domain=.
weibo.com
; httponly",
1
"sina.com.cn":"SUB=_2A254C_g2DeThGeNL7loY9C7FzDiIxxxxqJ-rDV_PUJbr9AKLUXkkWub49G0Z7qrMIsfiJ8pDI-JqomOcA..; path=/; domain=.sina.com.cn; httponly; expires=Wednesday, 22-Apr-15 03:28:38 GMT\nSUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9Wh70L6N52f_2baA2FyG89He; expires=Tuesday, 22-Mar-16 03:28:38 GMT; path=/; domain=.sina.com.cn\nSUS=SID-5558940974-1427081318-XD-5autn-decca88bf8b8ed1f2bc2f08f775ceb4a; path=/; domain=.sina.com.cn; httponly\nSUE=es%3D90b880602820cde55ffd32346def5f82%26ev%3Dv1%26es2%3D203c34a8868feaea9945d641339a7f98%26rs0%3DUXrKpjw9a5EYWyrc9DQKqGqwf3Dkgv0OlpK6gu5t%252B816JJti596RUaDyVuY%252BiVhnMWVEkfilzHsySBU4a8Zd4M9c3o2skkGja09R4GMzKoeBAR2djTrGW8wxkc34A1waWDFfF9IT%252FpIg2oT9u0FpJ5IeNmpreEgpTp7duS%252BgDaw%253D%26rv%3D0;path=/;domain=.sina.com.cn;Httponly\nSUP=cv%3D1%26bt%3D1427081318%26et%3D1427167718%26d%3D40c3%26i%3Def57%26us%3D1%26vf%3D%26vt%3D%26ac%3D%26st%3D0%26lt%3D1%26uid%3D5558940974%26user%3Dpandashellcode%2540163.com%26ag%3D4%26name%3Dpandashellcode%2540163.com%26nick%3Dgegeda2015%26sex%3D1%26ps%3D0%26email%3D%26dob%3D%26ln%3D%26os%3D%26fmp%3D%26lcp%3D;path=/;domain=.sina.com.cn\ngsid_CTandWM=4uMKdcd31iovF3Ww6Cuhnnk8kfI; path=/; domain=.sina.com.cn; httponly"}}

t013e6ec63fbfc4315e.jpg

用chrome 插件EditThisCookie 编辑插件 设置 上面6个值 刷新网页可以 ,不输入账号密码 登录 新浪微博

但是我们探究的是 iOS App Weibo ,还得继续看

我尝试着将账户退出,以为这样 Weibo就该删除我们的Cookie才对啊?可是再一次dump 发现 sina_cookie 这个Cookie还存在

经过分析我们知道 WeiboApp 还用了别的方式来控制自动登录

经过分析我们知道:

下面这些值和 sin_cookie 一同存在时iOS App 才能自动登录,退出微博账户会删除下面这些值,但不会删除 sina_cookie

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
 Generic Password
 ----------------
 Service: weibo_service
 Account: current_user_nick
 Entitlement Group: ZVC23L5QY4.*
 Label: weibo_service
 Generic Field: (null)
 Keychain Data: gegeda2015        current_user_nick
  
 Generic Password
 ----------------
 Service: weibo_service
 Account: current_user_id
 Entitlement Group: ZVC23L5QY4.*
 Label: weibo_service
 Generic Field: (null)
 Keychain Data: 5558940974         current_user_id
  
  
 Generic Password
 ----------------
 Service: weiboUserInfo5558940974
 Account: oauth2AccessTokenExpiresIn
 Entitlement Group: ZVC23L5QY4.*
 Label: weiboUserInfo5558940974
 Generic Field: (null)
 Keychain Data: 1429210792.915721     oauth2AccessTokenExpiresIn
  
 Generic Password
 ----------------
 Service: weiboUserInfo5558940974
 Account: oauth2AccessTokenIssueDate
 Entitlement Group: ZVC23L5QY4.*
 Label: weiboUserInfo5558940974
 Generic Field: (null)
 Keychain Data: 1426556782.000000     oauth2AccessTokenIssueDate
  
 Generic Password
 ----------------
 Service: weiboUserInfo5558940974
 Account: oauth2AccessToken
 Entitlement Group: ZVC23L5QY4.*
 Label: weiboUserInfo5558940974
 Generic Field: (null)
 Keychain Data: 2.00SUkMEGv1Vc_G9bbd3551caXsiKFD    oauth2AccessToken
  
  
 Generic Password
 ----------------
 Service: weiboUserInfo5558940974
 Account: accessGsid
 Entitlement Group: ZVC23L5QY4.*
 Label: weiboUserInfo5558940974
 Generic Field: (null)
 Keychain Data: 4u64666d3EQJaimoJF8jenk8kfI    accessGsid
  
 Generic Password
 ----------------
 Service: weiboUserInfo5558940974
 Account: accessToken
 Entitlement Group: ZVC23L5QY4.*
 Label: weiboUserInfo5558940974
 Generic Field: (null)
 Keychain Data: dd17c7e19363d9ca91d3455b7a5f0a10    accessToken
  
 Generic Password
 ----------------
 Service: weiboUserInfo5558940974
 Account: accessTokenSecret
 Entitlement Group: ZVC23L5QY4.*
 Label: weiboUserInfo5558940974
 Generic Field: (null)
 Keychain Data: 400c6b2100ea23cebd009dea71a215d7    accessTokenSecret
  
 Generic Password
 ----------------
 Service: weiboUserInfo5558940974
 Account: userID
 Entitlement Group: ZVC23L5QY4.*
 Label: weiboUserInfo5558940974
 Generic Field: (null)
 Keychain Data: pandashellcode@163.com    userID



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

也就是说 如果登录过一次,只要cookie不过期,它就还保留着这个明文 cookie ,当重新登录会刷新这个 sina_cookie

那么如果用户在越狱手机上登录过一次,那么直到这个 Cookie 过期,那么就有可能被窃取做坏事了。

2)总结

小菜逆向分析中总结了几点,考虑了效率问题,可以让 越狱与非越狱App相对安全

1.Cookie 存放在 非Keychain 中,那么就应该加 随机数和Token 双层加密,虽然还有被逆向的可能,但是将难度大大增加

2.Cookie 存放在 非Keychain 中,加入越狱检测代码,如果检测到越狱就提醒不要存放或者登陆,例子是 支付宝的指纹功能在越狱机提示不能用。

3.将Cookie的一部分 存放在 Keychain中,并且加密,另外一部分存放在别处(或者就在 另一处Keychain),被逆向的难度也大大增加.

4.将网页Cookie和App Cookie 的验证分开,这样的情况还没遇到过

实力有限,如果有错的地方,希望指出。

参考文档:

https://developer.apple.com/library/ios/documentation/Security/Reference/keychainservices/index.html

http://resources./ios-application-security-part-12-dumping-keychain-data/


本文作者:360iOS安全研究团队 360GreedTeam成员

本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/324.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多