GSM Sniffing入门之软件篇:GSMTAP抓取与SMS(Short Message Service)

重点介绍如何利用50元左右的设备,抓包并还原SMS短信内容:

ps:研究GSM Sniffing纯属个人兴趣,能抓SMS报文只是捡了个明文传输的漏子,切勿用于非法用途。就像sylvain说的,osmocomBB并不是为抓包而实现的,如果没有足够的GSM相关知识,想实现还原语音通话内容根本就无从下手。

---------------------------------------------------------------------------------------------------

第二部分-软件篇:GSMTAP抓取与SMS(Short Message Service)还原

之前介绍了OsmocomBB的硬件与刷机,这里重点介绍下其附带软件的使用。

参考官方wiki可以知道osmocomBB的代码可以分为两种:一种是在手机基带芯片上跑的layer1(物理传输层);另一种是在PC上跑的与layer1通信,提供上层服务的程序:

代码:

[root@ArchDev ~]# cd osmocom-bb/src/
[root@ArchDev src]# ls
Makefile  README.building  README.development  host  shared  target  target_dsp  wireshark

target下就是针对各手机的固件,bin位于target/firmware/board/compal_e88下。Baseband firmware一节介绍了不同固件的功能和对应程序,*.compalram是软刷用的,断电后需要重新刷机。*.e88flash/*.e88loader是配合loader使用的,刷入前需要参考 http://bb.osmocom.org/trac/wiki/flashing_new 把loader写到手机中,然后在手机上用loader运行。
后面cell_log和ccch_scan都是对应layer1的,因为直接写入有一定危险性,本文只演示软刷(layer1.compalram)的使用方法。
回到src目录下,接着看PC侧的工具:

代码:

[root@ArchDev ~]# cd ~/osmocom-bb/src/
[root@ArchDev host]# ls
calypso_pll  fb_tools  gsmmap  layer23  osmocon  rita_pll

osmocon是刷入固件,并与固件通信的程序,使用方法(注意C118选compal_e88/layer1.compalram.bin这个固件):

代码:

$ cd host/osmocon/
$ ./osmocon -p /dev/ttyUSB0 -m c123xor ../../target/firmware/board/compal_e88/layer1.compalram.bin

将C118关机后,短按电源键就开始运行了。刷机过程和常见问题硬件篇都已经提过,这里不再详述。

layer23下,有实现不同功能的数据链路层/网络层程序,比如模拟手机功能的mobile(接入网络需要SIM卡),以及抓取相关信息的杂项程序。直接进入misc目录:

代码:

cd layer23/src/misc/

cell_log是一个扫描有效运营商频率,并收集BCCH上基本信息的工具,我们先用它来获取运营商的ARFCN、MNC和MCC等信息。这里不需要gprs数据,直接使用这个参数:

代码:

-O --only-scan  Do a scan and show available ARFCNs, no data logging

./cell_log --only-scan
...
<000e> cell_log.c:248 Cell: ARFCN=56 PWR=-67dB MCC=460 MNC=00 (China, China Mobile)

例如这里选取信号最强的ARFCN=56 (China Mobile),有了这个就可以开始抓取Common Control Channel (CCCH)了:

代码:

./ccch_scan -a 56 -i 127.0.0.1

看到ccch_scan开始输出burst内容后,就可以

代码:

sudo wireshark -k -i lo -f 'port 4729'

打开Wireshark来抓GSMTAP,设置 gsm_sms 过滤器即可看到SMS报文内容:

-------------------------------------------------------------------------

为了加深对SMS传输的理解,我写了个Python脚本来重组短信的PDU。
下面部分需要些GSM网络相关的知识,推荐 GSM network and services 2G1723 2006 

从协议图中得知,移动设备(MS)和基站(BTS)间使用Um接口,最底层就是刷入手机的layer1物理传输层,之上分别是layer2数据链路层layer3网络层

位于图中layer2的LAPDm,是一种保证数据传输不会出错的协议。一个LAPDm帧共有23个字节(184个比特),提供分片管理控制等功能:

layer3的协议则可以分为RR/MM/CM三种,这里只列出嗅探相关的功能:

代码:

RR(Radio Resource Management):channel, cell控制等信息,可以忽略
MM(Mobility Management):Location updating(如果需要接收方号码,需要关注这个动作)
CM(Connection Management):Call Control(语音通话时的控制信息,可以知道何时开始捕获TCH), SMS(这里的重点)

参考GSM的文档 TS 04.06 得知 LAPDm 的Address field字段中,定义了 3.3.3 Service access point identifier (SAPI)

代码:

SAPI value  Related entity
0  Call control signalling, mobility management signalling and radio resource management signalling
3  Short message service

SAPI=3就是我们要的Short message service,如图:

3gpp的GSM文档看得比较晕,这里直接对照Wireshark里的gsm_sms报文分析,发现SMS帧实际是重组LAPDm的payload得到的。也就说如果想自己处理SMS帧,就必须也和Wireshark一样重组LAPDm的payload,并解析其中的SMS PDU。

这是一个SAPI=3的LAPDm报文头部。GSMTAP是一种伪头部http://bb.osmocom.org/trac/wiki/GSMTAP,记录了burst的一些基本信息(如ChannelType,ARFCN,上行还是下行等)。因为是用ccch_scan捕获的流量,编码时只用关注 Channel Type: SDCCH/8 的LADPm协议。
为了方便访问,定义GSMTAP类如下,传入udp payload部分,解析GSMTAP并提供其后的数据:

代码:

class GSMTAP:
  def __init__(self, gsmtap):
    self.gsmtap = gsmtap

    setattr(self, "version", ord(gsmtap[0]))
    setattr(self, "hdr_len", ord(gsmtap[1]) << 2)
    setattr(self, "payload_type", ord(gsmtap[2]))

    setattr(self, "time_slot", ord(gsmtap[3]))
    ARFCN = (ord(gsmtap[4])&0x3F)*0x100 + ord(gsmtap[5])
    UPLINK = ord(gsmtap[4]) >> 6
    setattr(self, "arfcn", ARFCN)
    setattr(self, "link", UPLINK)

    setattr(self, "signal_noise", ord(gsmtap[6]))
    setattr(self, "signal_level", ord(gsmtap[7]))
    # GSM Frame Number
    setattr(self, "channel_type", ord(gsmtap[12]))
    setattr(self, "antenna_number", ord(gsmtap[13]))
    setattr(self, "sub_slot", ord(gsmtap[14]))

  def get_payload(self):
    return self.gsmtap[self.hdr_len:]

GSMTAP Header之后是 Link Access Procedure, Channel Dm,即LAPDm。参考TS 04.06有3个关键字段: Address Field,Control Field,Length Field
Address Field除了上面说的SAPI外都可以不关注。
Control Field比较关键,里面记录了该LAPDm的分片信息。Frame type: Information frame说明当前是I帧(I frame),其余bit为N(S)和N(R)。Send sequence number N(S)标记该分片的顺序,从0开始递增。看Wireshark源码说实际有些N(S)可能不是从0开始的,这里组包就不判断N(S)是否为0直接按顺序附加。N(R)是Receive sequence number,看文档上I帧传输时N(R)的状态没看明白,直接默认同时间只有1个下行短信了,这样收到的N(R)基本是一样的(事实上大部分时候都是如此)
Length Field除了长度信息,还有 More segments 标记,直到这个位为0才表示接收完一个完整的SMS报文

代码:

class LAPDm:
  def __init__(self, lapdm):
    setattr(self, "lapdm", lapdm)

    setattr(self, "addr_field", ord(lapdm[0]))
    setattr(self, "lpd", (ord(lapdm[0])>>5)&0x3)
    setattr(self, "sapi", (ord(lapdm[0])>>2)&0x7)

    setattr(self, "ctrl_field", ord(lapdm[1]))
    setattr(self, "n_r", ord(lapdm[1])>>5)
    setattr(self, "n_s", (ord(lapdm[1])>>1)&0x7)

    setattr(self, "len_field", ord(lapdm[2]))
    setattr(self, "has_more", (ord(lapdm[2])>>1)&0x1)
    setattr(self, "length", ord(lapdm[2])>>2)

  def get_data(self):
    return self.lapdm[3:]

之后就可以这样,获得LAPDm的相关信息了:

代码:

gsmtap = GSMTAP(gsm_payload)
lapdm = LAPDm(gsmtap.get_payload())

if (gsmtap.channel_type == 8) and (lapdm.sapi == 3):  # TS 04.06, 3.3.3, SAPI: 3 - Short message service
  debug_printf("LINK[%d] ARFCN=%d TIME_SLOT=%d CHANNEL=%d, N(R)=%d N(S)=%d, segment more[%d], payload len=%d\n" % \
    (gsmtap.link, gsmtap.arfcn, gsmtap.time_slot, gsmtap.channel_type, lapdm.n_r, lapdm.n_s, lapdm.has_more, lapdm.length))

  last_sms_payload += lapdm.get_data()    # 附加本次收到的数据
  if (lapdm.has_more == 0):      # 最后一个分片,解析整个 SMS payload
    hexdump(last_sms_payload)
    last_sms_payload = ""

接着看wireshark中重组的payload,确认得到的last_sms_payload和wireshark中解析的一致。
在wireshark中展开一个重组后的SMS报文

可以看到,在 GSM SMS TPDU (GSM 03.40) SMS-DELIVER 之前,还有CP-DATA/RP-DATA头,RP-DATA中有短信中心的信息,但没什么作用直接跳过。我们只需要知道后面SMS TPDU的长度即可:

代码:

class SMS:
  def __init__(self, payload):
    self.payload = payload

    iOff = 0
    # CP-DATA
    setattr(self, "protocol", ord(payload[iOff])&0xF); iOff+=1
    iOff += 2

    # RP-DATA (Network to MS)
    iOff += 2
    setattr(self, "RP_origin_len", ord(payload[iOff])); iOff+=1
    setattr(self, "RP_origin_ext", ord(payload[iOff]));
    setattr(self, "RP_origin", bcdDigits(payload[iOff+1:iOff+self.RP_origin_len]))
    iOff += self.RP_origin_len

    setattr(self, "RP_dest_len", ord(payload[iOff])); iOff+=1
    iOff += self.RP_dest_len

    setattr(self, "length", ord(payload[iOff])); iOff+=1
    setattr(self, "tpdu_off", iOff);

  def get_tpdu(self):
    return self.payload[self.tpdu_off:self.tpdu_off+self.length]

调用 get_tpdu() 就会返回TPDU内容,里面TP-Originating-Address就是发送者的号码,TP-User-Data就是我们要的短信内容。

代码:

class TPDU:
  def __init__(self, tpdu):
    setattr(self, "tpdu", tpdu)

    iOff = 0
    # SMS-DELIVER
    iOff += 1
    setattr(self, "TP_origin_num", ord(tpdu[iOff])); iOff+=1
    setattr(self, "TP_origin_len", (self.TP_origin_num>>1)+(self.TP_origin_num%2))
    setattr(self, "TP_origin_ext", ord(tpdu[iOff])); iOff+=1
    setattr(self, "TP_origin", bcdDigits(tpdu[iOff:iOff+self.TP_origin_len]))
    iOff += self.TP_origin_len

    iOff += 2
    iOff += 7  # TimeStamp

    setattr(self, "tpu_len", ord(tpdu[iOff])); iOff+=1
    setattr(self, "data", tpdu[iOff:iOff+self.tpu_len])

  def get_data(self):
    return self.data.decode("utf-16be").encode("utf-8")

中文在SMS中是UCS2编码的,get_data() 是用python的utf-16be解码原始数据,并转成UTF-8输出。

好了,加上process_sms_tpdu()函数,最终代码就是这样:

代码:

def process_sms_tpdu(sms_payload):
  hexdump(sms_payload)

  sms = SMS(sms_payload)
  tpdu = TPDU(sms.get_tpdu())
  debug_printf("[SMS from %s] %s" % (tpdu.TP_origin, tpdu.get_data()))

def handle_tcpdump_buffer(title, buffer):
  raw_struct = str2rawbuf(buffer)
  udp_packet = UDP(raw_struct)
  gsm_payload = udp_packet.get_payload()
  #hexdump(gsm_payload)

  gsmtap = GSMTAP(gsm_payload)
  lapdm = LAPDm(gsmtap.get_payload())

  if (gsmtap.channel_type == 8) and (lapdm.sapi == 3):    # TS 04.06, 3.3.3, SAPI: 3 - Short message service
    debug_printf("LINK[%d] ARFCN=%d TIME_SLOT=%d CHANNEL=%d, N(R)=%d N(S)=%d, segment more[%d], payload len=%d\n" % \
      (gsmtap.link, gsmtap.arfcn, gsmtap.time_slot, gsmtap.channel_type, lapdm.n_r, lapdm.n_s, lapdm.has_more, lapdm.length))

    global last_sms_payload
    last_sms_payload += lapdm.get_data()
    if (lapdm.has_more == 0):
      process_sms_tpdu(last_sms_payload)
      last_sms_payload = ""

注:文末的 gsmtap_sms_decode_src.7z 里有完整的解析脚本 使用 ./ccch_scan -a ARFCN -i 127.0.0.1 将GSMTAP转发到本机的4729端口后,可以用这个脚本来重组SMS报文:

tcpdump -l -ilo -nXs0 udp and port 4729 | python2 -u show_gsmtap_sms.py

运行截图:

-----------------------------------------------------------------------------------------

上面脚本只是为了熟悉lapdm的重组,并未处理N(S)非零,以及并发时下行短信的重组建议有一定编码能力的同学,可以参考wireshark源码进行数据还原:

代码:

static void
dissect_lapdm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
            ... ...
            /* Rely on caller to provide a way to group fragments */
            fragment_id = (pinfo->circuit_id << 4) | (sapi << 1) | pinfo->p2p_dir;

            /* This doesn't seem the best way of doing it as doesn't
               take N(S) into account, but N(S) isn't always 0 for
               the first fragment!
             */
            fd_m = fragment_add_seq_next (&lapdm_reassembly_table, payload, 0,
                                pinfo,
                                fragment_id, /* guint32 ID for fragments belonging together */
                                NULL,
                                /*n_s guint32 fragment sequence number */
                                len, /* guint32 fragment length */
                                m); /* More fragments? */
            ... ...
}

另外细心的各位可能会奇怪,下行短信里怎么没有短信接受者的号码,这里有篇关于SMS传输的基本原理说明:
http://robinlea.com/pub/Amphol/Secur...arch_Labs.html
简单来讲,短信接受者的号码、IMEI等数据,只有在"Location Update"时才会在网络中出现,并且是以加密形式传输的。当接收短信时,基站根据之前位置更新时注册的信息,判断接收者的位置。所以,想要拿到接受者的号码,需要破解A5/1算法并还原出"Location Update"时的原文
Airprobe项目里有介绍如何破解A5/1算法找到Kc:https://srlabs.de/airprobe-how-to/ 只不过需要价格昂贵的USRP2...
另外还看到个RTL-SDR的文章(就是以前传说中可以跟踪飞机的电视棒),也支持Airprobe:
http://www.rtl-sdr.com/rtl-sdr-tutor...and-wireshark/
到此,GSM Sniffering入门算是告一段落了,感谢各位!

附件:gsmtap_sms_decode_src.7z

-----------------------------------------------------------------------------------------

关于抓上行短信或语音嗅探。看到这里有篇讨论:

http://baseband-devel.722152.n3.nabb...td3531044.html
以及http://wulujia.com/2013/11/10/OsmocomBB-Guide/的文末也有图片
里面都提到,除了代码里增加ARFCN的上行偏移,还需要移除C118上的一个RX过滤器。这里是官方的一个指引:
http://bb.osmocom.org/trac/wiki/Hardware/FilterReplacement
语音除了需要抓TCH外(sniff_tch_sched_set也还有定义),还需要算出Kc才能解码。

这篇论文附录里有提到如何操作,他是在USRP2上实现的(A5/1 rainbow-table攻击)。
OsmocomBB上好像做不到实时,不过mail list中倒是有些资料。TCH部分目前还是一头雾水,如果有什么比较好的思路可以探讨一二

时间: 2024-10-04 09:49:05

GSM Sniffing入门之软件篇:GSMTAP抓取与SMS(Short Message Service)的相关文章

GSM Sniffing入门之硬件篇

3个月前,听朋友介绍得知OsmocomBB项目.此前一直以为GSM Sniffing需要价格昂贵的专用设备,但osmocomBB的上手成本:一个25元左右的手机,外加一根USB转TTL的串口线,着实让我吃了一惊(我自己前后买了3台手机和2种串口线以测试稳定性,总共花了100元不到) OsmocomBB教程想必很多人都看过了.写这篇文章的目的,一则是把我所遇到的问题列出来,避免以后或者其他人像我一样,被"2.5mm耳机没插到位"这种低级问题纠缠大半个月另外,如果大家还在用GSM的2G网络

Win32开发入门(22):抓取屏幕

关于如何拷贝屏幕并保存,这里已经有现成的例子,我也不必去Copy人家了,我一向不喜欢Copy. 这里有一个完整的例子,可以看看. http://msdn.microsoft.com/EN- US/library/windows/desktop/dd183402(v=vs.85).aspx 把屏幕的内容复制到窗口的客户区域中 ,通常会用BitBlt函数,函数的功能是把一块颜色数据从一个DC复制到另一个DC,这个我也不知道怎么 翻译才能通俗一点.这样说吧,就是从源设备上下文的图形表面截取一个矩形区域

页面数据抓取-关于网页表格抓取问题,用什么软件

问题描述 关于网页表格抓取问题,用什么软件 我要抓取的是一个系统内部网页,不能外部访问,数据表格的链接插入有插件.怎么能实现动态抓取??大神啊 解决方案 用抓包的方法最好,然后再分析数据,如果不行,可以考虑用webbrowse这个控件,里面的内容也比较好抓取

微信公众号文章如何抓取

问题描述 微信公众号文章如何抓取 如题,请问,现在有什么好的方式抓取微信公众号文章的方式吗?我现在用的是搜狗的入口,但是这个入口每几个月就会变换规则,接口整体大改,不稳定,有没有其他什么好的方法? 解决方案 搜狗微信公众号文章抓取 解决方案二: 没有什么好办法,只能通过搜狗,而且如果信息多还无法捉取全部的,好像只能显示前40条.. 解决方案三: 微信文章内容的话可以使用辅助工具, 把微信文章链接输入,然后把整篇内容抓取出来,一般像微小宝之类的工具都有这个功能 解决方案四: 是指这个吗http:/

Java爬虫抓取视频网站下载链接_java

本篇文章抓取目标网站的链接的基础上,进一步提高难度,抓取目标页面上我们所需要的内容并保存在数据库中.这里的测试案例选用了一个我常用的电影下载网站(http://www.80s.la/).本来是想抓取网站上的所有电影的下载链接,后来感觉需要的时间太长,因此改成了抓取2015年电影的下载链接. 一 原理简介 其实原理都跟第一篇文章差不多,不同的是鉴于这个网站的分类列表实在太多,如果不对这些标签加以取舍的话,需要花费的时间难以想象. 分类链接和标签链接都不要,不通过这些链接去爬取其他页面,只通过页底的

数据分析师成长之路-软件篇

数据分析师成长之路-软件篇  对于各式各样的数据统计分析软件,你了解多少呢?经过潜心搜集,整理,这里总结了一些软件的大体介绍及区别,欢迎大家指正和补充. 这里先略过Excel和Eviews这种入门软件的介绍,直接从SPSS开始吧! SPSS:傻瓜相机SPSS(Statistical Product and Service Solutions),"统计产品与服务解决方案"软件,是数据定量分析的工具,适用于社会科学(如经济分析,市场调研分析)和自然科学等林林总总的统计分析,国内使用的最多,

逆向工程恶意软件入门(基础篇)

本文讲的是逆向工程恶意软件入门(基础篇), 前言 在这个系列文章中,我会向大家介绍逆向工程恶意软件的各个方面的知识.逆向工程恶意软件是一个很深奥和复杂的主题,因此很少有人掌握它,这也是这个领域的薪酬很高的主要原因. 在开始本文之前,我需要先阐述一个概念框架,并阐述与逆向工程恶意软件有关的一些策略和问题. 什么是逆向工程? 在本系列文章中,即使我无法访问源代码(通常是这种情况),我也将尝试确定该恶意软件的功能.在确定软件功能之后,我将尝试对其调整或在另一个恶意软件中重新构建相关功能. 逆向工程用于

土人AS入门教程语法篇

教程|入门教程|语法 AS 语法篇 ----------------------------------- 看过我的第一个教程--基础篇之后,现在你对AS的存在位子有了一定的概念了吧?如果还没有,那么去复习一下吧 土人系列AS入门教程--基础篇 接下来我要讲的是AS的语法. 首先要让大家明白的是: AS 语法的大小写是敏感的. 如: gotoAndPlay() 正确 gotoAndplay() 错误 . 关键字的拼写必须和语法一致,要做到很容易,因为在Flash的AS面板里面,关键字会有不一样的

虫友们该怎么样利用虫虫软件抓取资源

现在做一个网站很容易,后期推广却很难,有可能站长们都有这种感受,至于后期推广不过就是外链+实质内容,实质内容就不说了,chongseo要强调的是 怎么样利用虫虫软件抓取功能,去获取更多的群发外链的资源,如今能做外链的地方并不是很多,不过就是那末几个类型,bbs,zhidao,B2B,分类信 息,收藏夹,等等.下边用虫虫怎么样去抓取资源呢?一起来看下吧! 一.bbs论坛:站长们应当都晓得如今网上比较流行的BBS开源CMS就属discuz,PHPWIND了,站长们建论坛CMS基本都是运用的这种开源