水一篇蓝牙CVE的分析文章,站在巨人的肩膀上。
漏洞分析
Bleedingtooth
2020年谷歌安全研究人员在Linux kernel中发现了多个蓝牙的安全漏洞,这些漏洞被称之为BleedingTooth。攻击者利用BleedingTooth 漏洞可以实现无用户交互的零点击攻击(zero-click attack)。包括CVE-2020-12351、CVE-2020-12352、CVE-2020-24490。
CVE-2020-12351位于net/bluetooth/l2cap_core.c,基于堆的类型混淆漏洞。在 l2cap_data_channel函数中,当使用的 CID 是 L2CAP_CID_A2MP 并且还没建立一个channel时 , a2mp_channel_create()会被调用用于建立channel, 设定的chan->data 的类型是struct amp_mgr* 。如果 channel 的 mode 是 L2CAP_MODE_ERTM 或 L2CAP_MODE_STREAMING, 就会调用 l2cap_data_rcv(),在l2cap_data_rcv()调用了sk_filter(chan->data, skb),此时chan->data被转换成了struct sock*类型。
CVE-2020-12352位于/net/bluetooth/a2mp.c, 基于栈的信息泄漏漏洞。在a2mp_getinfo_req函数中,如果指定了一个无效的hci device id或者不是 HCI_AMP 类型的 hci device ,错误响应函数a2mp_send会回送一个没完全初始化的结构体a2mp_info_rsp rsp,这时 a2mp_info_rsp 被分配在栈上并且只有前2个字节被初始化了,这意味着可以泄漏前一个栈帧中的16个字节。
CVE-2020-24490 位于net/bluetooth/hci_event.c ,基于堆的缓冲区溢出漏洞。处理扩展广播报告事件的hci_le_ext_adv_report_evt()使用store_pending_adv_report()拷贝数据时,会将最多255个字节的扩展广告数据拷贝到discovery_state->last_adv_addr,但是后者的大小是HCI_MAX_AD_LENGTH=31 bytes,不足以容纳,导致堆溢出。
CVE-2020-12351
CVE-2020-12351,该漏洞CVSS评分为8.3分,是一个基于堆的类型混淆(type confusion) 漏洞。在受害者蓝牙范围内的远程攻击者在指导目标设备的bd地址的情况下就可以利用该漏洞。攻击者可以通过发送恶意l2cap包的方式来触发该漏洞,引发DoS或kernel权限的任意代码执行。谷歌安全研究人员称该漏洞是一个零点击漏洞,也就是说利用的过程中无需任何的用户交互。
A heap-based 类型混淆 affecting Linux kernel 4.8 and higher was discovered in net/bluetooth/l2cap_core.c.
当 CID 不是 L2CAP_CID_SIGNALING, L2CAP_CID_CONN_LESS 或 L2CAP_CID_LE_SIGNALING时, l2cap_recv_frame 会调用 l2cap_data_channel() 。在l2cap_data_channel()中需要关注的是第8行的第27行的这两个分支。
///net/bluetooth/l2cap_core.c
static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
{
struct l2cap_chan *chan;
chan = l2cap_get_chan_by_scid(conn, cid);
if (!chan) {
if (cid == L2CAP_CID_A2MP) {
chan = a2mp_channel_create(conn, skb); //here
if (!chan) {
kfree_skb(skb);
return;
}
l2cap_chan_lock(chan);
} else {
BT_DBG("unknown cid 0x%4.4x", cid);
/* Drop packet and return */
kfree_skb(skb);
return;
}
}
...
switch (chan->mode) {
...
case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING:
l2cap_data_rcv(chan, skb); //here
goto done;
...
}
drop:
kfree_skb(skb);
done:
l2cap_chan_unlock(chan);
}
第27行:在 l2cap_data_channel 函数里如果 channel 的 mode 是 L2CAP_MODE_ERTM 或 L2CAP_MODE_STREAMING, 就会调用 l2cap_data_rcv()。
///net/bluetooth/l2cap_core.c
static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
{
struct l2cap_ctrl *control = &bt_cb(skb)->l2cap;
u16 len;
u8 event;
__unpack_control(chan, skb);
len = skb->len;
/*
* We can just drop the corrupted I-frame here.
* Receiver will miss it and start proper recovery
* procedures and ask for retransmission.
*/
if (l2cap_check_fcs(chan, skb))
goto drop;
if (!control->sframe && control->sar == L2CAP_SAR_START)
len -= L2CAP_SDULEN_SIZE;
if (chan->fcs == L2CAP_FCS_CRC16)
len -= L2CAP_FCS_SIZE;
if (len > chan->mps) {
l2cap_send_disconn_req(chan, ECONNRESET);
goto drop;
}
if ((chan->mode == L2CAP_MODE_ERTM ||
chan->mode == L2CAP_MODE_STREAMING) && sk_filter(chan->data, skb)) //here
goto drop;
...
}
当packet的 checksum 被验证通过 , 继续调用 sk_filter()//sk_filter是对sk_filter_trim_cap的简单封装。
第8行: l2cap_data_channel 函数里 当使用的 CID 是 L2CAP_CID_A2MP 并且还没建立一个channel时 , a2mp_channel_create() 将被调用。
///net/bluetooth/a2mp.c
static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn, bool locked)
{
struct amp_mgr *mgr;
struct l2cap_chan *chan;
mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
if (!mgr)
return NULL;
BT_DBG("conn %p mgr %p", conn, mgr);
mgr->l2cap_conn = conn;
chan = a2mp_chan_open(conn, locked); //here
if (!chan) {
kfree(mgr);
return NULL;
}
mgr->a2mp_chan = chan;
chan->data = mgr;
...
return mgr;
}
a2mp_chan_open 创建了一个 channel 并且把 mode 初试化为 L2CAP_MODE_ERTM
static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked)
{
struct l2cap_chan *chan;
int err;
chan = l2cap_chan_create();
if (!chan)
return NULL;
BT_DBG("chan %p", chan);
chan->chan_type = L2CAP_CHAN_FIXED;
chan->scid = L2CAP_CID_A2MP;
chan->dcid = L2CAP_CID_A2MP;
...
chan->mode = L2CAP_MODE_ERTM;
...
return chan;
}
!!!问题在这里:
amp_mgr_create()里 chan->data 的类型是struct amp_mgr*
static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn, bool locked)
{
struct amp_mgr *mgr;
...
chan->data = mgr;
...
}
在l2cap_data_rcv()调用了sk_filter(chan->data, skb),定义是这样的 sk_filter(struct sock *sk, struct sk_buff skb); chan->data被转换成了struct sock\类型,类型混淆在此产生。
static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
{
...
if ((chan->mode == L2CAP_MODE_ERTM ||
chan->mode == L2CAP_MODE_STREAMING) && sk_filter(chan->data, skb))
goto drop;
...
}
int sk_filter(struct sock *sk, struct sk_buff *skb);
{}
POC
https://github.com/google/security-research/security/advisories/GHSA-h637-c88j-47wq
mode:a2mp_chan_open 创建 channel的时候已把 mode 初试化为 L2CAP_MODE_ERTM。
cid:不应是 L2CAP_CID_SIGNALING, L2CAP_CID_CONN_LESS 或 L2CAP_CID_LE_SIGNALING,这里选择L2CAP_CID_A2MP。
#define L2CAP_CID_SIGNALING 0x0001
#define L2CAP_CID_CONN_LESS 0x0002
#define L2CAP_CID_A2MP 0x0003
#define L2CAP_CID_ATT 0x0004
#define L2CAP_CID_LE_SIGNALING 0x0005
#define L2CAP_CID_SMP 0x0006
#define L2CAP_CID_SMP_BREDR 0x0007
#define L2CAP_CID_DYN_START 0x0040
#define L2CAP_CID_DYN_END 0xffff
#define L2CAP_CID_LE_DYN_END 0x007f
crash了
CVE-2020-12352
CVE-2020-12352 是基于栈的信息泄露漏洞,漏洞影响Linux kernel 3.6 及更高版本,CVSS 评分为5.3,被评为中危。在蓝牙距离范围内的知道受害者 bd 地址的远程攻击者可以提取含有不同指针的 kernel 栈信息,这些信息可以用来预测内存的布局以及攻击 KASL(内核地址空间布局随机化)。同时泄露的信息还包括加密密钥等重要信息。
when specifying an invalid hci device id or one that is not of type HCI_AMP in the A2MP_GETINFO_REQ request, an error response is sent back with not fully initialized struct members.
//net/bluetooth/a2mp.c.
//在一个A2MP_GETINFO_REQ request中,如果指定了一个无效的hci device id或者不是 HCI_AMP 类型的 hci device
//错误响应会回送一个没完全初始化结构成员。
static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
struct a2mp_cmd *hdr)
{
struct a2mp_info_req *req = (void *) skb->data;
struct hci_dev *hdev;
struct hci_request hreq;
int err = 0;
if (le16_to_cpu(hdr->len) < sizeof(*req))
return -EINVAL;
BT_DBG("id %d", req->id);
hdev = hci_dev_get(req->id);
if (!hdev || hdev->dev_type != HCI_AMP) {
struct a2mp_info_rsp rsp; //this
rsp.id = req->id;
rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp),
&rsp);//
goto done;
}
...
}
//a2mp_info_rsp包含以下成员
struct a2mp_info_rsp {
__u8 id;
__u8 status;
__le32 total_bw;
__le32 max_bw;
__le32 min_latency;
__le16 pal_cap;
__le16 assoc_size;
} __packed;
这时 a2mp_info_rsp 被分配在栈上并且只有前2个字节被初始化了,这意味着可以泄漏前一个栈帧中的16个字节。
a2mp_send_getinfo_rsp()也存在相同的漏洞
CVE-2020-24490
CVE-2020-24490 是位于 net/bluetooth/hci_event.c 中的一个基于堆的缓冲区溢出漏洞。漏洞影响Linux kernel 4.19 及更高版本。该漏洞CVSS 评分为5.3 分,为中危漏洞。远程攻击者可以广播扩展的广告数据,引发配备了蓝牙5芯片以及处于扫描模式的受害者机 DoS 或以 kernel 权限执行任意代码。恶意或有漏洞的蓝牙芯片也可以触发该漏洞。
蓝牙5标准于2016年发布,提供了八倍的广播消息传递能力以及更多功能。 在蓝牙4.0中,广告的有效载荷最大为31个八位位组。在蓝牙5中,我们通过添加其他广告渠道和新的广告PDU将有效负载增加到255个八位位组。
引入了hci_le_ext_adv_report_evt()来处理扩展的advertising报告事件,它基于处理旧的 advertisements的 hci_le_adv_report_evt()。
//在hci_le_adv_report_evt()中,会检查ev->length小于HCI_MAX_AD_LENGTH与否
//但在hci_le_ext_adv_report_evt()中却没有这个检查,但这可能是故意的,因为ev->length是一个 8bit的字段而扩展advertising数据最大为255 bytes
static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
u8 num_reports = skb->data[0];
void *ptr = &skb->data[1];
hci_dev_lock(hdev);
while (num_reports--) {
struct hci_ev_le_advertising_info *ev = ptr;
s8 rssi;
if (ev->length <= HCI_MAX_AD_LENGTH) {
rssi = ev->data[ev->length];
process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
ev->bdaddr_type, NULL, 0, rssi,
ev->data, ev->length);
} else {
bt_dev_err(hdev, "Dropping invalid advertising data");
}
ptr += sizeof(*ev) + ev->length + 1;
}
hci_dev_unlock(hdev);
}
...
static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
u8 num_reports = skb->data[0];
void *ptr = &skb->data[1];
hci_dev_lock(hdev);
while (num_reports--) {
struct hci_ev_le_ext_adv_report *ev = ptr;
u8 legacy_evt_type;
u16 evt_type;
evt_type = __le16_to_cpu(ev->evt_type);
legacy_evt_type = ext_evt_type_to_legacy(hdev, evt_type);
if (legacy_evt_type != LE_ADV_INVALID) {
process_adv_report(hdev, legacy_evt_type, &ev->bdaddr,
ev->bdaddr_type, NULL, 0, ev->rssi,
ev->data, ev->length);
}
ptr += sizeof(*ev) + ev->length;
}
hci_dev_unlock(hdev);
}
At some point in process_adv_report(), the data is stored using store_pending_adv_report() if the advertiser is doing indirect advertisement and the recipient is doing active scanning.
static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
u8 bdaddr_type, bdaddr_t *direct_addr,
u8 direct_addr_type, s8 rssi, u8 *data, u8 len)
{
struct discovery_state *d = &hdev->discovery;
struct smp_irk *irk;
struct hci_conn *conn;
bool match;
u32 flags;
u8 *ptr, real_len;
...
/* Passive scanning shouldn't trigger any device found events,
* except for devices marked as CONN_REPORT for which we do send
* device found events.
*/
if (hdev->le_scan_type == LE_SCAN_PASSIVE) {
...
return;
}
...
/* If there's nothing pending either store the data from this
* event or send an immediate device found event if the data
* should not be stored for later.
*/
if (!has_pending_adv_report(hdev)) {
/* If the report will trigger a SCAN_REQ store it for
* later merging.
*/
if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) {
store_pending_adv_report(hdev, bdaddr, bdaddr_type,
rssi, flags, data, len);
return;
}
mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
rssi, flags, data, len, NULL, 0);
return;
}
...
}
store_pending_adv_report() 将data拷贝到 d->last_adv_data.
static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 bdaddr_type, s8 rssi, u32 flags,
u8 *data, u8 len)
{
struct discovery_state *d = &hdev->discovery;
bacpy(&d->last_adv_addr, bdaddr);
d->last_adv_addr_type = bdaddr_type;
d->last_adv_rssi = rssi;
d->last_adv_flags = flags;
memcpy(d->last_adv_data, data, len);
d->last_adv_data_len = len;
}
但discovery_state->last_adv_addr的大小HCI_MAX_AD_LENGTH=31 bytes不足以容纳最多255个字节的扩展广告数据。因此将导致后续hci_dev的缓冲区溢出。
struct hci_dev {
...
struct discovery_state {
...
u8 last_adv_data[HCI_MAX_AD_LENGTH];
u8 last_adv_data_len;
bool report_invalid_rssi;
bool result_filtering;
bool limited;
s8 rssi;
u16 uuid_count;
u8 (*uuids)[16];
unsigned long scan_start;
unsigned long scan_duration;
} discovery;
// BEGIN
// The following fields are available since Linux kernel 5.7.
int discovery_old_state;
bool discovery_paused;
int advertising_old_state;
bool advertising_paused;
struct notifier_block suspend_notifier;
struct work_struct suspend_prepare;
enum suspended_state suspend_state_next;
enum suspended_state suspend_state;
bool scanning_paused;
bool suspended;
wait_queue_head_t suspend_wait_q;
DECLARE_BITMAP(suspend_tasks, __SUSPEND_NUM_TASKS);
// END
struct hci_conn_hash conn_hash;
struct list_head mgmt_pending;
...
};
BlueBorne
包括 CVE-2017-1000250 Linux bluetoothd进程信息泄露 、CVE-2017-1000251 Linux 内核栈溢出 、CVE-2017-0785 Android com.android.bluetooth进程信息泄露 、CVE-2017-0781 Android com.android.bluetooth进程堆溢出、 CVE-2017-0782 Android com.android.bluetooth进程堆溢出、CVE-2017-0783 Android 中间人攻击。
CVE-2017-1000251位于Linux L2CAP层,l2cap_bredr_sig_cmd处理L2CAP的cmd数据时,当cmd->code是L2CAP_CONF_RSP时,会调用l2cap_config_rsp,然后在满足result == L2CAP_CONF_PENDING,且自身的连接状态conf_state == CONF_LOC_CONF_PEND的时候,会走到 l2cap_parse_conf_rsp函数里。l2cap_parse_conf_rsp函数的功能就是根据传进来的包,来构造将要发出去的包,传进来的包的内容都是任意确定的(包括参数len ,参数rsp->data),但是要发出去的包却暂存在长度为64字节的栈空间buf中,那么当len很大时,就会一直往出口buf里写数据,比如有64个L2CAP_CONF_MTU类型的opt,那么就会往buf里写上64*(L2CAP_CONF_OPT_SIZE + 2)个字节,那么显然这里就发生了溢出。由于buf是栈上定义的数据结构,那么这里就是一个栈溢出。
static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
void *data, u16 *result)
{
struct l2cap_conf_req *req = data;
void *ptr = req->data;
int type, olen;
unsigned long val;
while (len >= L2CAP_CONF_OPT_SIZE) { //len没有被检查,由接收到的包内容控制
len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
switch (type) {
case L2CAP_CONF_MTU:
if (val < L2CAP_DEFAULT_MIN_MTU) {
*result = L2CAP_CONF_UNACCEPT;
chan->imtu = L2CAP_DEFAULT_MIN_MTU;
} else
chan->imtu = val;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
break;
case ...
}
}
}
static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
{
struct l2cap_conf_opt *opt = *ptr;
opt->type = type;
opt->len = len;
switch (len) {
case 1:
*((u8 *) opt->val) = val;
break;
case 2:
put_unaligned_le16(val, opt->val);
break;
case 4:
put_unaligned_le32(val, opt->val);
break;
default:
memcpy(opt->val, (void *) val, len);
break;
}
*ptr += L2CAP_CONF_OPT_SIZE + len;
}
BlueFrag
参考 https://paper.seebug.org/1121/#_3
CVE-2020-0022,又称BlueFrag,可影响Android蓝牙子系统。该漏洞是一个远程代码执行漏洞,出现在Bluedroid蓝牙协议栈的HCI层,当无线模块处于活动状态时,攻击者可以利用蓝牙守护程序提升权限进而在设备上执行代码。该漏洞影响Android Oreo(8.0和8.1)、Pie(9),但无法在Android 10上进行利用,仅能触发DoS攻击。
CVE-2020-0022漏洞位于HCI层,代码位于hci/src/packet_fragmenter.cc中的reassemble_and_dispatch()函数中。
reassemble_and_dispatch()函数用于数据包分片的重组,对于过长的ACL数据包进行包重组时,主要是根据ACL包中的PB Flag标志位进行重组,如果当前是起始部分并且是不完整的,则生成一个部分包(partial_packet)放到map里,等下次收到它的后续部分进行拼装,拼装完毕后就分发出去。拼装过程中长度计算有误,导致
第一个参数为partial_packet->data + partial_packet->offset,目的地址是正确的,第二个参数为packet->data + packet->offset,源地址也是正确的,第三个参数是要拷贝的长度len为packet->len - packet->offset,这个值是有问题的,分两种情况。第一种情况是projected_offset小于partial_packet->len,packet->len - packet->offset为L2CAP数据包片段总长度,并且是个正数。第二种是行211的情况,packet->len已经被修正过,不需要再一次packet->len - packet->offset的操作,如果partial_packet剩余空间长度小于4字节,那packet->len - packet->offset 是小于零的,是一个负数。由于memcpy()函数第三个参数类型是一个无符号整型类型,因此整数溢出导致堆溢出。
真机调试环境搭建
Debugger配置
1、下载符号文件和内核源码文件
为了更好地调试内核,gdb需要Debuggee的内核符号文件和源代码文件来实现源码级别的调试。之前发现了一个launchpad.net(https://launchpad.net/ubuntu/+source/linux/5.4.0-42.46)的站点,该站点提供了当前发行版Linux系统的内核符号文件和源码文件供开发者下载。
找到Debuggee的ubuntu版本、 找带dbgsym、unsigned的、系统架构amd64
2、安装符号文件
下载得到linux-image-unsigned-5.4.0-42-generic-dbgsym_5.4.0-42.46_amd64.ddeb文件,在Debugger中执行“dpkg -i”命令安装符号文件。 vmlinux-5.4.0-42-generic是Linux内核公共部分的可执行文件的符号版本
file /usr/lib/debug/boot/vmlinux-5.11.0-38-generic
/usr/lib/debug/boot/vmlinux-5.11.0-38-generic: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=3943780ac8a93e50813a3906c205bba1515216d3, with debug_info, not stripped
file /usr/lib/debug/lib/modules/5.11.0-38-generic/kernel/drivers/net/ethernet/realtek/r8169.ko
/usr/lib/debug/lib/modules/5.11.0-38-generic/kernel/drivers/net/ethernet/realtek/r8169.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=ffa1e397cf00e133476ed9d9bcf168dac70a70c7, with debug_info, not stripped
Debugee配置
1、开启kgdb
双机调试需要Debuggee开启Kgdb功能,当前Ubuntu发行版内核已经默认开启了 Kgdb支持,通过命令“cat /boot/config-$(uname -r)| grep -i GDB”查看可知当前内核支持Kgdb以及串口调试。
q1iq@q1iq:~$ cat /boot/config-$(uname -r)| grep -i GDB
CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y
CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y
CONFIG_SERIAL_KGDB_NMI=y
CONFIG_GDB_SCRIPTS=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_KGDB=y
CONFIG_KGDB_HONOUR_BLOCKLIST=y
CONFIG_KGDB_SERIAL_CONSOLE=y
# CONFIG_KGDB_TESTS is not set
CONFIG_KGDB_LOW_LEVEL_TRAP=y
CONFIG_KGDB_KDB=y
如果内核不支持Kgdb,则可以通过下载、编译、安装对应版本的内核源码来打开Kgdb。以Linux5.4.0内核为例,需要设置的编译选项有:
CONFIG_KGDB=y //开启kgdb服务
CONFIG_KGDB_SERIAL_CONSOLE=y //kgdb默认连接到主板串口
CONFIG_DEBUG_INFO=y //内核中加入调试符号
2、配置grub文件
内核开启Kgdb功能后需要手动配置grub启动文件才能在开机的时候进入Kgdb调试选项,因为默认情况下Kgdb是不工作的,需要向内核传递相关启动参数才能启用。编辑/etc/grub.d/40_custom文件,添加如下menuentry。
kgdboc(串口调试)应加的选项
kgdbwait kgdboc=ttyS0,115200 nokaslr
kgdbwait:进入该启动选项后等待远程主机连接Kgdb
kgdboc:“kgdb over console”的缩写,表示远程主机通过串口连接到Kgdb
ttyS0:在本地默认串口监听连接事件,通常这也是主板上唯一的串口
115200:本地串口的波特率 nokaslr:关闭内核地址随机化。kaslr选项会干扰内核的调试因此要关闭
除了串口还可以使用以太网连接Kgdb,除了传递启动参数还可以在运行时通过sysfs文件系统开启Kgdb 更多详细的Kgdb操作请参考“linux5.4/Documentation/dev-tools/kgdb.rst”。Linux的documentation是一个非常有用的东⻄
kgbboe(网络调试)应该加这些选项(https://mirrors.edge.kernel.org/pub/linux/kernel/people/jwessel/kgdb/ch03s04.html)
kgdbwait kgdbcon kgdboe=@192.168.43.82/,@192.168.43.206/ nokaslr
kgdboe=[src-port]@<src-ip>/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]
src-port默认6443
tgt-port默认6442
系统运行时修改kgdboe
echo "@/,@10.0.2.2/" > /sys/module/kgdboe/paramters/kgdboe
编辑完成后在控制台执行“sudo update-grub”命令更新启动项,重启Debuggee,可以在grub页面看到多出了“Ubuntu,KGDB with nokaslr”选项,这个选项是可以自己写的。
参考
https://mp.weixin.qq.com/s/sl9-2GZaJfqGwoHAHG8onQ
https://www.freebuf.com/vuls/271834.html
CVE-2020-12351 https://github.com/google/security-research/security/advisories/GHSA-h637-c88j-47wq
CVE-2020-12352 https://github.com/google/security-research/security/advisories/GHSA-7mh3-gq28-gfrq
CVE-2020-24490 https://github.com/google/security-research/security/advisories/GHSA-ccx2-w2r4-x649