铁路12306通信加解密破解

编号190761
Urlhttp://www.wooyun.org/bug.php?action=view&id=190761
漏洞状态厂商已经确认
漏洞标题铁路12306通信加解密破解
漏洞类型账户体系控制不严
厂商12306
白帽子chaoxilab
提交日期2016-03-30 16:51:00
公开日期2016-05-16 16:00:00
修复时间(not set)
确认时间2016-04-01 00:00:00
Confirm Spend2
漏洞标签
关注数0
收藏数0
白帽评级
白帽自评rank20
厂商评级
厂商评rank8
漏洞简介
None
漏洞细节

信任所有证书极易导致中间人攻击,完全可以控制整个通信内容。业界公认高危漏洞。

POC

一、 https未校验证书导致数据被捕获(中间人攻击风险)
客户端虽采用了https,但并未对服务端证书进行校验能够捕获通讯数据,可导致中间人攻击。

1.png


信任所有证书

1.png


1.png


可以正常截获通讯数据
二、通信数据解密
铁路12306通信加解密主要通过checkcode、decheckcode两个函数进行通信加解密,虽然采用加固方式,但是太过依赖于加固技术,从而造成通信接口过于暴露。
dex部分:

1.png


加解密函数代码

1.png


so部分:

Java_com_MobileTicket_CheckCodeUtil_checkcode伪代码非常多,这里就不贴出来了。
Java_com_MobileTicket_CheckCodeUtil_decheckcode伪代码:
int __fastcall Java_com_MobileTicket_CheckCodeUtil_decheckcode(int *a1, int a2, int a3, int a4)
{
int *v4; // r4@1
int v5; // r5@1
void *v6; // r0@1
int v7; // r0@1
int v8; // r3@1
int (__fastcall *v9)(int *, _BYTE *); // r3@2
int *v10; // r0@2
_BYTE *v11; // r1@2
unsigned __int8 *v12; // r0@3
int v13; // r3@3
void (__fastcall **v14)(_BYTE *, int *); // r5@3
_BYTE *i; // r7@8
size_t v16; // r7@11
unsigned int v17; // r7@11
_BYTE *j; // r3@11
int v19; // r0@17
void (__fastcall *v20)(_BYTE *, int *); // r3@17
_BYTE *v22; // [sp+0h] [bp-30h]@11
int v23; // [sp+4h] [bp-2Ch]@5
void *v24; // [sp+8h] [bp-28h]@3
void *ptr; // [sp+Ch] [bp-24h]@1
int v26; // [sp+14h] [bp-1Ch]@17
v4 = a1;
v5 = a4;
v6 = j_j_malloc(0x21u);
ptr = v6;
v7 = verification(v4, v6);
v8 = *v4;
if ( v7 )
{
v12 = (unsigned __int8 *)(*(int (__fastcall **)(int *, int, _DWORD))(v8 + 0x2A4))(v4, v5, 0);
v13 = *v12;
v24 = v12;
v14 = (void (__fastcall **)(_BYTE *, int *))off_24E94;
if ( v13 == 0x46 )
{
v23 = (int)(v12 + 1);
*(_DWORD *)off_24E94 = off_24E9C;
}
else if ( (unsigned __int8)v13 == 0x53 )
{
v23 = (int)(v12 + 1);
*(_DWORD *)off_24E94 = off_24E98;
}
else
{
*(_DWORD *)off_24E94 = off_24E9C;
v23 = (int)v12;
}
for ( i = (_BYTE *)v23; *i; ++i )
;
v16 = (size_t)&i[-v23];
v22 = j_j_malloc(v16);
v17 = (unsigned int)&v22[v16];
for ( j = v22; (unsigned int)j < v17; j += 4 )
{
*j = 0;
if ( v17 <= (unsigned int)(j + 1) )
break;
j[1] = 0;
if ( v17 <= (unsigned int)(j + 2) )
break;
j[2] = 0;
if ( v17 <= (unsigned int)(j + 3) )
break;
j[3] = 0;
}
v19 = base64_decode(v23, v22);
v20 = *v14;
v26 = v19;
v20(v22, &v26);
v22[v26] = 0;
j_j_free(ptr);
j_j_free(v24);
v9 = *(int (__fastcall **)(int *, _BYTE *))(*v4 + 0x29C);
v11 = v22;
v10 = v4;
}
else
{
v9 = *(int (__fastcall **)(int *, _BYTE *))(v8 + 0x29C);
v10 = v4;
v11 = ptr;
}
return v9(v10, v11);
}


这里以解密代码为例:

1.png


调用R3,这里就调用到了aes_decrypt1

1.png


在 aes_decrypt1函数中调用了CWAESCipher::WBACRAES128_DecryptCBC

1.png


在这个循环1中,调用CWAESCipher::WBACRAES_DecryptOneBlock进行解密,解密的顺序为逆序,第一次解密的key为:00 00 00 00 00 00 00 00 00 00 00 00 最后四字节为base64数据长度+1。
解密出来的数据有2个作用:1> 作为下次解密使用的key,2>通过第2个循环修复出真正的解密数据。

1.png


逆序进行数据解密
编写封包解析程序验证登录加密数据和返回数据的解密:

1.png


登录数据中parameters项中para中数据是加密的

1.png


通过编写程序测试,checkcode加密后的数据为para中的内容。
服务器返回数据中respData中的数据为加密内容,解密后的数据:

1.png


手机号、生日、身份证号码、姓名、邮箱、用户名等等信息暴露。
三、数据重放

1.png


登录数据信息

1.png


退出之后登录,仍然可以重放登录数据
解密登录返回数据内容信息:

1.png


重放某人的登录包,可拿到手机号、生日、身份证号码、姓名、邮箱、用户名等等信息

修复方案

你们更专业!

状态信息 2016-03-30: 细节已通知厂商并且等待厂商处理中
2016-04-01: 厂商已经确认,细节仅向厂商公开
2016-04-11: 细节向核心白帽子及相关领域专家公开
2016-04-21: 细节向普通白帽子公开
2016-05-01: 细节向实习白帽子公开
2016-05-16: 细节向公众公开
厂商回复谢谢!
回应信息危害等级:中漏洞Rank:8 确认时间:2016-04-01 15:58
Showing 1-4 of 4 items.
评论内容评论人点赞数评论时间

学习

猪猪侠02016-05-16 16:10:00

12306的Android?iOS?是的话兄弟很牛逼啊~

Moonight02016-04-01 17:50:00

这么猛?

Praise02016-04-01 16:17:00

木人关注?

坏男孩-A_A02016-03-31 02:05:00