网卡仿真的内存泄露漏洞——来重现QEMU的内存泄

彩屏显示使用之前修改好的ili9325的程序(lcd.c,lcd.h,gui.c,gui.h),在main.c中直接添加lcd_init()初始化函数,就可以使用lcd和gui中的绘图或者显示字符的函数了,不过需要注意要重定向printf输出到串口。

一、MPU6050中的IIC时序

3.内存泄露的利用

IIC使用IO模拟,创建IIC初始化和读写函数

1.1 START和STOP

美高梅棋牌官网 1
SDA和SCL在高电平时,SDA拉低表示START。SCL拉低,表示可以传输数据。
SDA和SCL在低电平时,SDA拉高表示STOP。 SCL拉高,表示传输数据结束。

  1. /******************************************

  2. *函数原型: void IIC_Start(void)

  3. *功能: 产生IIC起始信号
  4. ******************************************/
  5. void IIC_Start(void)
  6. {
  7.     SDA_OUT();
  8.     IIC_SDA=1;
  9.     IIC_SCL=1;
  10.     delay_us(4);
  11.     IIC_SDA=0; //START:when CLK is high,SDA change from hig to low
  12.     delay_us(4);
  13.     IIC_SCL=0; //Ready Transmit or Receive
  14. }
  15. /******************************************
  16. *函数原型: void IIC_Start(void)
  17. *功能: 产生IIC结束信号
  18. ******************************************/
  19. void IIC_Stop(void)
  20. {
  21.     SDA_OUT();
  22.     IIC_SDA=0;
  23.     IIC_SCL=0;
  24.     delay_us(4);
  25.     IIC_SDA=1; //STOP:when CLK is low,SDA change from low to high
  26.     IIC_SCL=1; //发送I2C总线结束信号
  27.     delay_us(4);
  28. }

一些的宏定义:

  1. #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))

  2. #define MEM_ADDR(addr) *((volatile unsigned long *)(addr))

  3. #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
  4. #define GPIOB_ODR_Addr (GPIOB_BASE+12)
  5. #define GPIOB_IDR_Addr (GPIOB_BASE+8)
  6. #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
  7. #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入
  8. //驱动接口,GPIO模拟IIC
  9. //PB7->I2C_SDA
  10. //PB6->I2C_SCL
  11. #define SDA_IN() {GPIOB->CRL&=0x0FFFFFFF;GPIOB->CRL|=0x80000000;} //上拉输入
  12. #define SDA_OUT() {GPIOB->CRL&=0x0FFFFFFF;GPIOB->CRL|=0x30000000;} //通用推挽输出,不用硬件IIC
  13. //IO操作函数
  14. #define IIC_SCL PBout(6)
  15. #define IIC_SDA PBout(7)
  16. #define READ_SDA PBin(7)

本节中,我们将利用CVE-2015-5165——一个影响RTL8139

ADX345的相关操作

查看器件 ID。ADXL345 的 ID 寄存器为 0x00

设置 ADXL345 存储数据的方式和通信方式。寄存器地址为:0x31。

设置数据的输出速率设置的是 BW_RATE 寄存器,地址为:0x2C。

设置测量模式和链接模式

设置不启用中断,设置 INT_ENABLE 寄存器,设置它不使用中断模式。

初始化偏移量,设置 OFSX 寄存器、OFSY 寄存器、OFSZ 寄存器。

1) 发送起始信号

2) 发送 I2C 写器件地址

3) 等待应答

4) 发送 I2C 要读的寄存器地址

5) 等待应答

6) 发送起始信号

7) 发送 I2C 读器件地址

8) 等待应答

9) 接收返回数据

10) 发送结束信号

1) 发送起始信号

2) 发送 I2C 写器件地址

3) 等待应答

4) 发送要写入的寄存器地址

5) 等待应答

6) 发送要写入的数据

7) 等待应答

8) 发送结束信号

注意读到的为8位,需要改成16位

uint8_t readValue[6];

|

*xValue = (readValue[1] << 8) + readValue[0];

*yValue = (readValue[3] << 8) + readValue[2]美高梅棋牌官网 ,;

*zValue = (readValue[5] << 8) + readValue[4];

1.2 ACK和NACK时序图

美高梅棋牌官网 2
在START信号后,读取8位的数据,STM32需要对MPU6050发出响应以同步。
第九个SCL时,SCL从低电平变成高电平后,SDA如果是低电平则是ACK,如果是高电平则是NACK。

  1. /******************************************

  2. *函数原型: void IIC_Wait_Ack(void)

  3. *功能: 等待应答信号到来
  4. *输出; 1,接收应答失败
  5.        0,接收应答成功
  6. ******************************************/
  7. 美高梅棋牌游戏 ,u8 IIC_Wait_Ack(void)
  8. {
  9.     u8 ucErrTime = 0;
  10.     SDA_IN();
  11.     IIC_SDA=1;
  12.     delay_us(1);
  13.     IIC_SCL=1;
  14.     delay_us(1);
  15.     while(IIC_SDA) //最多等待50us
  16.     {
  17.         ucErrTime++;
  18.         if(ucErrTime>50)
  19.         {
  20.             IIC_Stop();
  21.             return 1;
  22.         }
  23.         delay_us(1);
  24.     }
  25.     IIC_SCL=0; //时钟输出0
  26.     return 0;
  27. }
  28. /******************************************
  29. *函数原型: void IIC_Ack(void)
  30. *功能: 产生ACK应答信号SDA=0
  31. ******************************************/
  32. void IIC_Ack(void)
  33. {
  34.     IIC_SCL=0;
  35.     SDA_OUT();
  36.     IIC_SDA=0;
  37.     delay_us(1);
  38.     IIC_SCL=1;
  39.     delay_us(1);
  40.     IIC_SCL=0;
  41. }
  42. /******************************************
  43. *函数原型: void IIC_Ack(void)
  44. *功能: 产生ACK应答信号SDA=0
  45. ******************************************/
  46. void IIC_NAck(void)
  47. {
  48.     IIC_SCL=0;
  49.     SDA_OUT();
  50.     IIC_SDA=1;
  51.     delay_us(1);
  52.     IIC_SCL=1;
  53.     delay_us(1);
  54.     IIC_SCL=0;
  55. }

1.3 MPU6050写入时序
美高梅棋牌官网 3
美高梅棋牌官网 4
美高梅棋牌官网 5
写时序的步骤:START+(MPU6050地址+W)+等待ACK+寄存器地址+等待ACK+写入的数据+等待ACK+STOP。
读时序的步骤:START+(MPU6050地址+W)+等待ACK+寄存器地址+START+读取数据+ACK响应+STOP。

  1. /****************************************************

  2. *函数原型: u8 IICwriteBytes(u8 dev, u8 reg, u8 length, u8 *data)

  3. *功能: 将多个字节写入指定设备 指定寄存器
  4. *输入: dev 目标设备地址
  5. * reg 寄存器地址
  6. * length 要写的字节数
  7. * *data 将要写的数据的首地址
  8. *返回: 返回是否成功,1成功
  9. ****************************************************/
  10. u8 IICwriteBytes(u8 dev, u8 reg, u8 length, u8 *data)
  11. {
  12.     u8 count = 0;
  13.     IIC_Start();
  14.     IIC_Send_Byte(dev); //发送写命令
  15.     IIC_Wait_Ack();
  16.     IIC_Send_Byte(reg); //发送写入的地址
  17.     IIC_Wait_Ack();
  18.     for(count=0;count<length;count++)
  19.     {
  20.         IIC_Send_Byte(data[count]);
  21.         IIC_Wait_Ack();
  22.     }
  23.     IIC_Stop(); //发送停止信号
  24.     
  25.     return 1;
  26. }
  27. /******************************************
  28. *函数原型: u8 IIC_Read_Byte(unsigned char ack)
  29. *功能: 读取一个Byte的字节
  30. *输入: 读取一个字节,ack=1,发送ACK,ack=0,发送nACK
  31. *返回: 读取到的Byte
  32. ******************************************/
  33. u8 IIC_Read_Byte(unsigned char ack)
  34. {
  35.     unsigned char i, receive = 0;
  36.     SDA_IN(); //设置为输入
  37.     for(i=0;i<8;i++)
  38.     {
  39.         IIC_SCL=0;
  40.         delay_us(1);
  41.         IIC_SCL=1;
  42.         receive<<=1;
  43.         if(READ_SDA) receive++;
  44.         delay_us(1);
  45.     }
  46.     if(ack)
  47.         IIC_Ack(); //发送ACK
  48.     else
  49.         IIC_NAck(); //发送NACK
  50.     
  51.     return receive;    
  52. }

留下了一个不太清楚的内容,按位,位长度写数据:

  1. /****************************************************

  2. *函数原型: u8 IICwriteBits(u8 dev, u8 reg, u8 bitStart, u8 length, u8 data)

  3. *功能: 读、修改、写指定设备、指定寄存器一个字节中的多个位
  4. *输入: dev 目标设备地址
  5. * reg 寄存器地址
  6. * bitStart 目标字节的起始位,自左向右?
  7. * length 位长度
  8. * data 存放改变目标字节位的值
  9. *返回: 返回是否成功,1成功
  10. ****************************************************/
  11. u8 IICwriteBits(u8 dev, u8 reg, u8 bitStart, u8 length, u8 data)
  12. {
  13.     u8 b;
  14.     u8 mask;
  15.     if(IICreadByte(dev, reg, &b) != 0)
  16.     {
  17.         mask = (0xFF << (bitStart +1))| 0xFF >> ((8 - bitStart) + length -1);
  18.         data >>= (7 - bitStart);
  19.         b &= mask;
  20.         b |= data;
  21.         return IICwriteByte(dev, reg, b);
  22.     } else {
  23.         return 0;
  24.     }
  25. }

网卡仿真的内存泄露漏洞——来重现QEMU的内存泄露。更确切的说,我们需要泄露(1).text字段的基地址,用于构建shellcode(2)用户物理内存的基地址,用于得到一些虚拟结构的准确地址。

STM32CubeMX配置

美高梅棋牌官网 6

需要添加得到文件

lcd

void LCD_Init;

void LCD_DisplayOn;

void LCD_DisplayOff;

void LCD_Clear(uint16_t Color);

void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos);

void LCD_DrawPoint(uint16_t x,uint16_t y);//画点

uint16_t LCD_ReadPoint(uint16_t x,uint16_t y); //读点

void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);

void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);

void LCD_SetWindows(uint16_t xStar, uint16_t yStar,uint16_t xEnd,uint16_t yEnd);

void LCD_DrawPoint_16Bit(uint16_t color);

uint16_t LCD_RD_DATA;//读取LCD数据

void LCD_WriteReg(uint16_t LCD_Reg, uint16_t LCD_RegValue);

void LCD_WR_DATA(uint16_t data);

uint16_t LCD_ReadReg(uint8_t LCD_Reg);

void LCD_WriteRAM_Prepare;

void LCD_WriteRAM(uint16_t RGB_Code);

uint16_t LCD_ReadRAM;

uint16_t LCD_BGR2RGB(uint16_t c);

void LCD_SetParam;

gui

void GUI_DrawPoint(uint16_t x,uint16_t y,uint16_t color);

void LCD_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t color);

void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);

void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);

void Draw_Circle(uint16_t x0,uint16_t y0,uint16_t fc,uint8_t r);

void LCD_ShowChar(uint16_t x,uint16_t y,uint16_t fc, uint16_t bc, uint8_t num,uint8_t size,uint8_t mode);

void LCD_ShowNum(uint16_t x,uint16_t y,uint32_t num,uint8_t len,uint8_t size);

void LCD_Show2Num(uint16_t x,uint16_t y,uint16_t num,uint8_t len,uint8_t size,uint8_t mode);

void LCD_ShowString(uint16_t x,uint16_t y,uint8_t size,uint8_t *p,uint8_t mode);

void GUI_DrawFont16(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *s,uint8_t mode);

void GUI_DrawFont24(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *s,uint8_t mode);

void GUI_DrawFont32(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *s,uint8_t mode);

void Show_Str(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *str,uint8_t size,uint8_t mode);

iic

void IIC_Config;

void IIC_Start;

void IIC_Stop;

void IIC_SendData(uint8_t dat);

uint8_t IIC_ReceiveData(uint8_t ack);

int8_t IIC_WaitAck;

adx345

在mian函数中添加显示最终结果的程序,注意将获得的变量存入数组中,这样就可以使用原有函数显示变量了。

美高梅棋牌官网 7

3.1漏洞代码

REALTEK网卡支持两种接收/传送模式:C模式和C+模式。当网卡配置成C+模式时,NIC设备仿真器会错误计算IP数据包的长度并在结束时发送更多的数据。

漏洞出现在hw/net/rtl8139.c文件中的rtl8139_cplus_transmit_one函数:

美高梅棋牌官网 8

IP头包括两个参数:hlen表示ip数据包长度,ip->ip_len表示IP头的长度(一个包20字节,不包括可选字段),数据包的总长度包括ip头的长度。如下所示的代码片段最后,在计算IP数据长度(ip_data_len)时没有检查确保ip->ip_len不小于hlen。因为ip_data_len参数类型为unsigned short,这会导致发送比传送缓冲区实际更多的数据。

更确切的说,ip_data_len会被复制用于之后计算TCP数据的长度——如果数据超过了MTU的长度将会一直传送下去——最后进入一个malloced缓冲区:

美高梅棋牌官网 9

所以,如果我们伪造一个长度错误的包(比如长度ip->ip_len = hlen - 1),那我们就可以从QEMU的内存中泄露大约64KB的数据。这样,网卡就不会发送一个简单的包了,而是在结束时发送43个分散的包。

3.2配置网卡

为了传送我们伪造的包并读取泄露的数据,我们需要配置网卡的接收缓冲和发送缓冲,并设置一些标记来确保我们的包经过漏洞代码的路径传输。

下图是RTL8139的寄存器。这不是所有的寄存器,只列出与漏洞利用有关的寄存器。

美高梅棋牌官网 10

- TxConfig:开启/关闭Tx的标记,比如TxLoopBack(开启loopback测试模式),TxCRC(Tx包不添加冗余校验码)等。

- RxConfig:开启/关闭Rx的标记,比如AcceptBroadcast(接收广播包),AcceptMulticast(接收组播包)等。

- CpCmd:C+指令寄存器用来执行一些函数,比如CplusRxEnd(允许接收),CplusTxEnd(允许发送)等。

- TxAddr0:Tx表的物理内存地址。

- RxRingAddrLO:Rx表的物理内存地址的低32位。

- RxRingAddrHI:Rx表的物理内存地址的高32位。

- TxPoll:告诉网卡检查Tx。

一个Rx/Tx-descriptor定义有如下特征:buf_lo和buf_hi分别表示Tx/Rx缓冲的物理内存地址的低32位和高32位。这些地址指向存储要发送/接收的包的缓冲区,必须与页面大小对齐。变量dw0表示缓冲区的长度加上额外的标记,比如用来标记缓冲区归网卡还是驱动所有的ownership标记。

美高梅棋牌官网 11

网卡通过in*()和out*()(定义在sys/io.h)进行配置。配置需要CAP_SYS_RAWIO特权。以下代码段配置网卡并构建一个简单的Tx descriptor。

美高梅棋牌官网 12

3.3漏洞利用

完整的漏洞利用代码(cve-2015-5165.c)可参见附录的源代码压缩包。首先配置会用到的网卡寄存器并构建了Tx和Rx缓冲。然后伪造一个IP包并发送给网卡的MAC地址。这让我们能在配置的Rx缓冲中读到泄露的数据。

当分析泄露的数据时,会出现很多函数指针。仔细分析后发现,这些函数指针都有相同的QEMU内部结构:

美高梅棋牌官网 13

QEMU遵循一个对象模型来管理设备、内存等。QEMU在启动时会创建一些对象并分配属性。例如,以下调用会给一个内存对象添加属性“may-overlap”。该属性通过getter方法获得一个布尔值。

美高梅棋牌官网 14

RTL8139网卡需要在头中分配64KB的空间来重组包。很有可能这个空间与对象属性撤销后的空间正好合适。

在漏洞利用中,我们在溢出内存中搜索已知的对象属性。更确切的说,我们搜索至少有一个函数指针被设置(获取、设置、解决或释放)的80字节的内存块(一个自由ObjectProperty结构的块)。即使这些地址有ASLR(一种针对缓冲区溢出的安全保护技术)保护,但我们仍可以猜.text字段的基地址。实际上,他们的页偏移地址是确定的(12个最小有效位或虚地址都不是随机的)。我们可以计算获得一些QEMU函数的地址。我们还可以得到一些LibC函数的地址,比如从PLT入口获得mprotect()和system()的地址。

我们还发现PHY_MEM + 0x78的地址多次泄露,PHY_MEM表示分配给用户的物理内存空间的首地址。

目前的漏洞利用是搜索泄露的内存并尝试找到(1).text字段的基地址(2)物理内存的基地址。

4.堆溢出的利用

这部分讨论漏洞CVE-2015-7504并利用漏洞获得%rip寄存器的控制权。

4.1漏洞代码

AMD PCNET网卡仿真器在loopback测试模式下接收大型包时有一个堆溢出漏洞。PCNET用4KB的缓冲区存储包。如果开启了Tx缓冲的ADDFCS标记,网卡会给接收到的包添加一个冗余校验码,如下代码段所示,定义于hw/net/pcnet.c

的pcnet_receive()函数。如果接收到的包长度小于4096-4字节)就不会出现问题,然而,如果包长度正好是4096字节,我们就可以溢出目的缓冲区4个字节的数据。

美高梅棋牌官网 15

上述代码中s指向PCNET的主结构体,可以看到通过漏洞缓冲区的溢出,我们得到irq变量的值:

美高梅棋牌官网 16

irq变量是一个指针,指向IRQState结构体表示一个用于执行的处理程序。

美高梅棋牌官网 17

这个处理程序被PCNET网卡多次调用,比如在pcnet_receive()函数的最后,调用pcnet_update_irq()时会调用qemu_set_irq()函数:

美高梅棋牌官网 18

所以,为了利用这个漏洞,我们需要做:

-构造一个假的IRQState结构体用于执行的处理程序(比如system()函数)。

-计算该结构体的准确地址。多亏于精确内存泄露,我们准确的知道了该结构体在QEMU进程内存的准确地址(在用户物    理内存的基地址的一些偏移地址处)。

-构造一个4KB的恶意包。

-给该恶意包打补丁,让其冗余校验码与我们构造的假IRQState结构体相匹配。

-发送恶意包。

当PCNET接收到该恶意包时,调用pcnet_receive function()处理包,执行以下操作:

-复制接收包的内容到缓冲区变量。

-计算一个冗余校验码并添加到缓冲区中。缓冲区溢出4字节数据并泄露出irq变量。

-调用pcnet_update_irq()时会调用使用irq变量的qemu_set_irq()函数。然后输出处理程序执行。

注意我们可以控制替换处理程序的前两个参数(irq->opaque和irq->n),但多亏于我们之后会说到的小技巧,我们可以控制第三个参数(level参数)。这在调用mprotect()函数是必须的。

还要注意我们用4字节泄露了一个8字节的指针。这足够在我们的测试环境中成功控制%rip寄存器、然而,这会在没有设置CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE参数的内核上出现问题。这个问题会在5.4中讨论。

4.2配置网卡

在继续进行之前,我们需要配置PCNET网卡用以配置需要的参数、构造Tx和Rx缓冲和分配循环缓冲区用来保存发送和接收的数据包。

AMD PCNET网卡有16位和32位两种模式。这取决于DWIO(存储在网卡上的变量)的实际值。下面,我们详细列出了PCNET网卡在16位模式下的主要寄存器,该模式是网卡重启后的默认模式:

美高梅棋牌官网 19

通过访问复位寄存器让网卡复位到默认状态。

网卡有两种内部寄存器:CSR(控制和状态寄存器)和BCR(总线控制寄存器)。两种寄存器都通过首先设置对应的我们要访问的RAP(寄存器地址端口)寄存器来访问。比如,如果我们想启动并重置网卡,我们需要设置CSR0寄存器的bit0和bit1为1。可以通过写0进RAP寄存器来选择CSRO寄存器,然后设置CSR寄存器为0x3:

美高梅棋牌官网 20

网卡的配置可以通过填充一个初始化结构体,并将该结构体的物理地址传送到网卡(通过CSR1和CSR2代码)来完成:

美高梅棋牌官网 21

4.3逆向冗余校验码

如前面所说,我们需要给包打补丁,让其冗余校验码与我们构造的假结构体相匹配。幸运的是,冗余校验码是可以逆向的。得益于文章[6]的方法,我们可以打一个4字节的补丁让冗余校验码与我们的选择相匹配。源码reverse-crc.c添加了一个补丁到一个预填充缓冲区来让冗余校验码与0xdeadbeef相等。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

本文由美高梅游戏网站登录发布于美高梅棋牌游戏,转载请注明出处:网卡仿真的内存泄露漏洞——来重现QEMU的内存泄

您可能还会对下面的文章感兴趣: