写在前面
最近需要在SDR环境中验证目标终端中的GSM协议实现漏洞,本文记录下环境的搭建(踩坑)过程。最开始是尝试根据Grant大佬的博客尝试安装,其中对于GSM环境的搭建原文采用的是YateBTS+BladeRF或者USRP N210的组合,然而,在根据文章安装YateBTS时访问不了官方的SVN库,并且似乎最新版的YateBTS不再支持UHD驱动,因此最后选择了使用OpenBTS+USRP B210的方式。
参考:
-
https://www.twblogs.net/a/5b8661f72b71775d1cd52363/?lang=zh-cn
-
https://blog.white-alone.com/OpenBTS使用指南/
-
https://www.miralishahidi.ir/resources/Open BTS Application Suite.pdf
背景知识
首先在SDR方面比较小白,先去了解了下当前主流的集中SDR软件+硬件的组合,其中常见硬件有:
- HackRF
- BladeRF
- LimeSDR
- PlutoSDR
- USRP
- …
这些硬件支持的频率范围、带宽等不仅相同,价格也有高有低,根据具体需求选择即可。此外,对于开源的基站项目,由于横跨2G-5G的不同版本,具体选取哪个开源实现也是根据需求而定
2G:
- YateBTS+BladeRF
- OpenBTS+USRP
- OpenBSC + (USRP、Fairwaves UmTRX、LimeSDR)
3G:
- Accelerate3g5
- OpenBTS
4G
- Open Air Interface (OAI) +USRP
- OpenLTE (BladeRF USRP)
- SRSRAN+USRP
5G
- OAI-5G
最后由于前边的尝试,最后选择OpenBTS+USRP B210进行安装
GSM SDR环境搭建
系统-Ubuntu16.04 LTS
选择使用Ubuntu16.04 LTS的虚拟机作为安装系统(最好选择纯净系统+原始的源,我这边换了国内源之后出现了有些依赖包找不到的问题,手动一个个寻找巨麻烦)
安装UHD
- 首先从github上clone UHD的开源项目,并将其切换为3.14.0.0的分支
git clone https://github.com/EttusResearch/uhd
cd uhd
git checkout v3.14.0.0
- 其次就是编译和安装了
首先安装依赖
sudo apt-get -y install git swig cmake doxygen build-essential libboost-all-dev libtool libusb-1.0-0 libusb-1.0-0-dev libudev-dev libncurses5-dev libfftw3-bin libfftw3-dev libfftw3-doc libcppunit-1.13-0v5 libcppunit-dev libcppunit-doc ncurses-bin cpufrequtils python-numpy python-numpy-doc python-numpy-dbg python-scipy python-docutils qt4-bin-dbg qt4-default qt4-doc libqt4-dev libqt4-dev-bin python-qt4 python-qt4-dbg python-qt4-dev python-qt4-doc python-qt4-doc libqwt6abi1 libfftw3-bin libfftw3-dev libfftw3-doc ncurses-bin libncurses5 libncurses5-dev libncurses5-dbg libfontconfig1-dev libxrender-dev libpulse-dev swig g++ automake autoconf libtool python-dev libfftw3-dev libcppunit-dev libboost-all-dev libusb-dev libusb-1.0-0-dev fort77 libsdl1.2-dev python-wxgtk3.0 git-core libqt4-dev python-numpy ccache python-opengl libgsl-dev python-cheetah python-mako python-lxml doxygen qt4-default qt4-dev-tools libusb-1.0-0-dev libqwt5-qt4-dev libqwtplot3d-qt4-dev pyqt4-dev-tools python-qwt5-qt4 cmake git-core wget libxi-dev gtk2-engines-pixbuf r-base-dev python-tk liborc-0.4-0 liborc-0.4-dev libasound2-dev python-gtk2 libzmq-dev libzmq1 python-requests python-sphinx libcomedi-dev python-zmq python-setuptools
其次
cd uhd/host
mkdir build
cd build
cmake ../
make -j 8
make test # 测试
sudo make install # 这里使用root权限安装不然会失败
- 设置环境变量
在build目录下
sudo ldconfig
export LD_LIBRARY_PATH=/usr/local/lib
然后运行脚本安装所需镜像
sudo /usr/local/lib/uhd/utils/uhd_images_downloader.py
- 测试是否安装成功
sudo uhd_find_devices
--------------------------------------------------
-- UHD Device 0
--------------------------------------------------
Device Address:
serial: 171830
name:
product: B210
type: b200
安装OpenBTS
参考官方的安装文档,首先安装依赖
git clone https://github.com/PentHertz/OpenBTS.git
$ cd OpenBTS
$ # Optionally, checkout 5.1.0 branch which is the stable one with `git checkout 5.1.0`
$ ./preinstall.sh # note that for now libcoredumper will show some failures but we quickly bypass them forcing the compilation
编译安装OpenBTS
$ ./autogen.sh
$ ./configure --with-uhd # use different options for other drivers
$ make -j$(nproc)
$ sudo make install
$ sudo ldconfig
在make这里我遇到了一些报错,修改了如下两个地方
- 将下边代码中的
(BctbxLogFunc)
删掉
void MySipInterface::msiInit()
{
siInit();
// Start the ortp stuff.
ortp_init();
ortp_scheduler_init();
// FIXME -- Can we coordinate this with the global logger?
//ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR);
ortp_set_log_handler((BctbxLogFunc) ortpLogFunc);
mDriveThread.start((void *(*)(void*))driveLoop2, &gSipInterface );
mPeriodicServiceThread.start((void *(*)(void*))periodicServiceLoop, &gSipInterface );
}
- 将下边代码中的强制类型转换中的
(void *)
删掉
rtp_session_signal_connect(mSession,"timestamp_jump",(RtpCallback)ourRtpTimestampJumpCallback,(void *) dialogId);
然后即可成功编译,运行固件
$ uhd_usrp_probe
[INFO] [UHD] linux; GNU C++ version 11.2.0; Boost_107400; UHD_4.1.0.5-3
[INFO] [B200] Loading firmware image: /usr/share/uhd/images/usrp_b200_fw.hex...
[INFO] [B200] Detected Device: B210
[INFO] [B200] Loading FPGA image: /usr/share/uhd/images/usrp_b210_fpga.bin...
[...]
设置流量转发
sudo su
echo 1 >> /proc/sys/net/ipv4/ip_forward
配置iptables规则,/etc/OpenBTS/iptables.rules 配置规则文件内容如下:
# Generated by iptables-save v1.4.4
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A POSTROUTING -o eth0 -j MASQUERADE
COMMIT
# Generated by iptables-save v1.4.4
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
根据情况设置为自己的网卡
sudo iptables-restore < /etc/OpenBTS/iptables.rules
iptables -t nat -L -n -v
启动OpenBTS
上述组件全部安装完毕后,需要启动以下组件以连接USRP B210以及手机
配置数据库
cd apps
sudo sqlite3 -init OpenBTS.example.sql /etc/OpenBTS/OpenBTS.db ".quit"
cd subscriberRegistry/apps
sudo sqlite3 -init sipauthserve.example.sql /etc/OpenBTS/sipauthserve.db ".quit"
cd smqueue/smqueue
sudo sqlite3 -init smqueue.example.sql /etc/OpenBTS/smqueue.db ".quit"
启动transceiver连接SDR硬件
cd Transceiver52M/
sudo ./transceiver
执行OpenBTS启动基站
cd apps/
sudo ./OpenBTS
启用短信服务
cd smqueue/smqueue
sudo ./smqueue
启动鉴权服务
cd subscriberRegistry/apps
sudo ./sipauthserve
启动OpenBTS终端控制台
cd ./apps
sudo ./OpenBTSCLI
根据参考链接,刚搭建完成的基站由于天线功率过大以及手机跟基站的距离太近等原因,可能会导致手机不能正常加入到基站,这时需要配置加入基站的条件以及设置天线功率:
开启任意终端准入
OpenBTS> config Control.LUR.OpenRegistration .*
Control.LUR.OpenRegistration changed from "" to ".*"
设置天线功率
如果手机可以搜索到基站,就表明网络状态良好,但如果有较强的无线干扰,也就是噪声干扰俗称底噪,手机和基站的链路就可能会有问题。可以用noise命令检查噪声强度:
OpenBTS> noise
noise RSSI is -60 dB wrt full scale
MS RSSI target is -50 dB wrt full scale
WARNING: the current noise level is approaching the MS RSSI target, uplink connectivity will be extremely limited.
表示检测到的背景噪声RSSI信号强度为-71dB,这个数值越小表明底噪越少。配置的RSSI信号强度为-50dB,也就是说,基站所能提供的最高信号强度为 21 dB。一个好的差值意味着上行链路质量不错。两个数据的差值不同反馈信息也不同,如果差值小于10db,那么就会像前一个反馈的警告信息,提示噪声干扰强度已经接近所配的RSSI,上行链路质量非常有限。如果差值小于0db,会有警告提示噪声干扰比配置的RSSI信号还强,无法建立上行链路。
OpenBTS> devconfig GSM.Radio.RxGain 18
GSM.Radio.RxGain changed from "50" to "18"
GSM.Radio.RxGain is static; change takes effect on restart
设置频段
OpenBTS> config GSM.Radio.Band 900
GSM.Radio.Band changed from "850" to "900"
GSM.Radio.Band is static; change takes effect on restart
设置欢迎短信
config Control.LUR.NormalRegistration.Message Welcome to BTS 1
终端管理
cd NodeManager/
python2 ./nmcli.py sipauthserve subscribers create "Redmi Note 12 Turbo" IMSI460110123456789 123456
python2 ./nmcli.py sipauthserve subscribers read
查看注册的手机:
OpenBTS> tmsis
IMSI TMSI IMEI AUTH CREATED ACCESSED TMSI_ASSIGNED
我理解这个步骤应该只是为接入的的中断在当前网络注册相应的电话号。前边设置允许任意终端准入时,只需要把蜂窝网络设置为仅GSM即可接入当前OpenBTS
短消息测试
启动短消息服务时, 我们就可以给任意终端发送短信,并且在设备初次接入网络时,收到我们上述设置的欢迎短信。在手机中,写一条短信发给411。这是smqueue中的一个简码处理流程,只管回显,不管其他接收、网络及用户信息等整个流程所用任何信息。发送给411的短信的可以是任意内容,可以是任意的文字或者数字或者字母。这个可以用来帮你确认哪条消息在回应时候出错。编写一条发往411短信,点击发送,几秒钟之后,应该会出现应答
使用命令行发送短信
OpenBTS> sendsms XXXXXXX AAAAA "You are arrested"
message submitted for delivery
其中XXXXXXX是设备的IMSI号码,AAAAAA是虚拟的手机号(显示为发送方),注意不支持中文内容
互相发送短信:
- 设备之间也可以互相发送短信,比如两台都在该网络中注册的手机设备,通过手机号即可向对方发送消息
电话测试
Asterisk配置
sudo asterisk -r
拨打电话600在经过一段语音后,会回传你发送过去的语音信息
两个手机通话
这里默认使用apt安装的Asterisk,在/etc/asterisk下的配置文件看起来非常不好配置,网上找的博客也没有介绍,后来偶然间发现github上有人配置好的文件,配合前文参考链接,在sip.conf添加
;openbts
[IMSI001010123456789]
callerid=12580
canreinvite=no
type=friend
context=sip-external
allow=gsm
host=dynamic
dtmfmode=info
[IMSI460110123456789]
callerid=10123
canreinvite=no
type=friend
context=sip-external
allow=gsm
host=dynamic
dtmfmode=info
在extensions.conf添加
[sip-external]
exten => 100,1,Dial(SIP/0000FFFF0001) ; Replace 0000FFFF0001 with your device name
exten => 101,1,Dial(SIP/0000FFFF0002) ; Replace 0000FFFF0002 with your device name
exten => 200,1,Answer()
same => n,Playback(hello-world)
same => n,Hangup()
exten => 201,1,Goto(TestMenu,start,1) ; add this to the end of the
; [LocalSets] context
exten => 12580,1,Dial(SIP/IMSI001010123456789@127.0.0.1:5062) ; Replace 0000FFFF0002 with your device name
exten => 10123,1,Dial(SIP/IMSI460110123456789@127.0.0.1:5062) ; Replace 0000FFFF0002 with your device name
GSM抓包&重放
捕获GSM报文(未实现)
根据[手册](https://www.miralishahidi.ir/resources/Open BTS Application Suite.pdf) 6.5章节中的提示,需要手动开启GSM流量转发才能用wireshark捕获到GSM流量。因此需要运行以下命令:
OpenBTS> rawconfig Control.GSMTAP 1
OpenBTS> rawconfig Control.GPRS 1
但是我这里只能捕获到RR协议的报文以及SMS协议的报文,MM、CC等L3层的报文还是捕获不到(大概是因为具体的payload都是在sip协议里边发过去的)。
报文篡改
- OpenBTS的官方手册
[https://www.miralishahidi.ir/resources/Open%20BTS%20Project.pdf](https://www.miralishahidi.ir/resources/Open BTS Project.pdf)
根据架构推测OpenBTS是这样实现通话逻辑的:发起通话请求是手机1->BTS->手机2,其中手机1->BTS用GSM消息通信,BTS将SETUP请求解析并包装成SIP报文,根据asterisk的配置找到手机2,基于解析的SIP报文,包装成GSM报文发送给手机2。
由上可知一个可行的思路为直接修改BTS代码,让其直接发送加了payload的报文。
日志监控
- 拨打
*#9900#
可以进入三星的日志系统sysdump,可以dump一些有意思的日志(暂未深入研究),这篇文章说了下怎么本地激活sysdump中的两个特殊功能(暂时没用到) - 使用adb的logcat(FIRMWIRE作者曾在talk中用这个观察到设备崩溃)
真机调试?
可以参考Synacktiv的文章,通过TEE的漏洞,重写modem固件,将一个调试器写到不用的代码段中实现调试功能:
- SSTIC 2020 How to design a baseband debugger