日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

cve-2015-0569 安卓手机提权ROOT漏洞 分析

發布時間:2025/3/15 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 cve-2015-0569 安卓手机提权ROOT漏洞 分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
測試機器:nexus4???????android版本:4.4???內核版本3.4.0?
漏洞介紹:函數進行拷貝時沒有對長度進行判斷,導致用戶可以修改內核棧中值。
漏洞利用:通過修改函數返回地址,來進行提權操作


1,首先找到官方的修補代碼
修補代碼地址:https://www.codeaurora.org/cgit/quic/la/platform/vendor/qcom-opensource/wlan/qcacld-2.0/diff/CORE/HDD/src/wlan_hdd_wext.c?id=a079d716b5481223f0166c644e9ec7c75a31b02c

@@?-9741,6?+9741,9?@@?int?wlan_hdd_set_filter(hdd_context_t?*pHddCtx,?tpPacketFilterCfg?pRequest,
?
?????????????????hddLog(VOS_TRACE_LEVEL_INFO,?"Data?Offset?%d?Data?Len?%d",
?????????????????????????pRequest->paramsData[i].dataOffset,?pRequest->paramsData[i].dataLength);
+????????????????if?((sizeof(packetFilterSetReq.paramsData[i].compareData))?<
+???????????????????????????(pRequest->paramsData[i].dataLength))
+????????????????????return?-EINVAL;
?
????????????????memcpy(&packetFilterSetReq.paramsData[i].compareData,
????????????????????????pRequest->paramsData[i].compareData,?pRequest->paramsData[i].dataLength);
????????????????????????
????????????????memcpy(&packetFilterSetReq.paramsData[i].dataMask,
????????????????????????pRequest->paramsData[i].dataMask,?pRequest->paramsData[i].dataLength);

2,推測漏洞的產生原理
從官方的修補來看,這里只是添加了一個拷貝長度的限制,那么漏洞產生的原因,應該是memcpy拷貝時數據越界有關。
為了證實我的推測,我們看看packetFilterSetReq?,?pRequest?兩個結構體是從何而來。
int?wlan_hdd_set_filter(hdd_context_t?*pHddCtx,? tpPacketFilterCfg?pReques t,?
????????????????????????????tANI_U8?sessionId)
{
???? tSirRcvPktFilterCfgType????packetFilterSetReq?=?{0};
????tSirRcvFltPktClearParam????packetFilterClrReq?=?{0};
????int?i=0;


從內核代碼上看,packetFilterSetReq?是局部變量,而pRequest則是作為參數傳入。
結合起來看,我推測,漏洞產生的原因應該是,memcpy拷貝時越界修改掉了棧的值,覆蓋掉了函數的返回地址。


3,查找調用漏洞函數的過程
為了利用,以及驗證我的推測,現在要找出從漏洞函數到入口函數的整條調用的線
首先從產生漏洞的函數 wlan_hdd_set_filter ;開始找
(wlan_hdd_set_filter在內核源碼drivers\staging\prima\core\hdd\src\Wlan_hdd_wext.c文件中)
查看wlan_hdd_set_filter的調用,發現了兩處,分別是同文件下的 wlan_hdd_set_mc_addr_list ?和? iw_set_packet_filter_params
首先看? wlan_hdd_set_mc_addr_list? 函數


void?wlan_hdd_set_mc_addr_list(hdd_adapter_t?*pAdapter,?v_U8_t?set)
{
????v_U8_t?filterAction;
????tPacketFilterCfg?request;
????v_U8_t?i;
????hdd_context_t?*pHddCtx?=?WLAN_HDD_GET_CTX(pAdapter);

????filterAction?=?set???HDD_RCV_FILTER_SET?:?HDD_RCV_FILTER_CLEAR;

????/*set?mulitcast?addr?list*/
????for?(i?=?0;?i?<?pAdapter->mc_addr_list.mc_cnt;?i++)
????{
????????memset(&request,?0,?sizeof?(tPacketFilterCfg));
????????request.filterAction?=?filterAction;
????????request.filterId?=?i;?
????????if?(set)
????????{
????????????request.numParams?=?1;?
????????????request.paramsData[0].protocolLayer?=?HDD_FILTER_PROTO_TYPE_MAC;?
????????????request.paramsData[0].cmpFlag?=?HDD_FILTER_CMP_TYPE_EQUAL;???
????????????request.paramsData[0].dataOffset?=?WLAN_HDD_80211_FRM_DA_OFFSET;
???????????? request.paramsData[0].dataLength?=?ETH_ALEN; ?//長度變成固定,不符合觸發漏洞的要求
????????????memcpy(&(request.paramsData[0].compareData[0]),?
????????????????????&(pAdapter->mc_addr_list.addr[i][0]),?ETH_ALEN);
????????????/*set?mulitcast?filters*/
????????????hddLog(VOS_TRACE_LEVEL_INFO,?
????????????????????"%s:?%s?multicast?filter:?addr?="?
????????????????????MAC_ADDRESS_STR,
????????????????????__func__,?set???"setting"?:?"clearing",?
????????????????????MAC_ADDR_ARRAY(request.paramsData[0].compareData));
????????}
????????wlan_hdd_set_filter(pHddCtx,?&request,?pAdapter->sessionId);
????}
????pAdapter->mc_addr_list.isFilterApplied?=?set???TRUE?:?FALSE;
}
從代碼上來看,再看看這個宏的值
#define?ETH_ALEN????6
發現這個長度,根本無法達到產生漏洞的條件,因此可以判斷出,這個函數不是我們所要找的目標函數。
回過頭看另外一個函數 iw_set_packet_filter_params


static?int?iw_set_packet_filter_params(struct?net_device?*dev,?struct?iw_request_info?*info,
????????union?iwreq_data?*wrqu,?char?*extra)
{???
????hdd_adapter_t?*pAdapter?=?WLAN_HDD_GET_PRIV_PTR(dev);
????tpPacketFilterCfg?pRequest?=?(tpPacketFilterCfg)wrqu->data.pointer;

return?wlan_hdd_set_filter(WLAN_HDD_GET_CTX(pAdapter),?pRequest,?pAdapter->sessionId)
}
發現這個pRequest的值是作為參數傳入,那么繼續找他的調用點,但是發現,卻找不到調用點,那么這個函數應該是函數指針調用的,在文件中搜索函數名發現了一個結構體中保存了函數地址
static?const?iw_handler?we_private[]? =?{
其中有這一項


static?const?iw_handler?we_private[]?=?{

???[WLAN_PRIV_SET_INT_GET_NONE??????-?SIOCIWFIRSTPRIV]???=?iw_setint_getnone,??//set?priv?ioctl
???[WLAN_PRIV_SET_NONE_GET_INT??????-?SIOCIWFIRSTPRIV]???=?iw_setnone_getint,??//get?priv?ioctl
???[WLAN_PRIV_SET_CHAR_GET_NONE?????-?SIOCIWFIRSTPRIV]???=?iw_setchar_getnone,?//get?priv?ioctl
???[WLAN_PRIV_SET_THREE_INT_GET_NONE?-?SIOCIWFIRSTPRIV]??=?iw_set_three_ints_getnone,
???[WLAN_PRIV_GET_CHAR_SET_NONE??????-?SIOCIWFIRSTPRIV]??=?iw_get_char_setnone,
???[WLAN_PRIV_SET_NONE_GET_NONE?????-?SIOCIWFIRSTPRIV]???=?iw_setnone_getnone,?//action?priv?ioctl
???[WLAN_PRIV_SET_VAR_INT_GET_NONE??-?SIOCIWFIRSTPRIV]???=?iw_set_var_ints_getnone,
???[WLAN_PRIV_ADD_TSPEC?????????????-?SIOCIWFIRSTPRIV]???=?iw_add_tspec,
???[WLAN_PRIV_DEL_TSPEC?????????????-?SIOCIWFIRSTPRIV]???=?iw_del_tspec,
???[WLAN_PRIV_GET_TSPEC?????????????-?SIOCIWFIRSTPRIV]???=?iw_get_tspec,
#ifdef?FEATURE_OEM_DATA_SUPPORT
???[WLAN_PRIV_SET_OEM_DATA_REQ?-?SIOCIWFIRSTPRIV]?=?iw_set_oem_data_req,?//oem?data?req?Specifc
???[WLAN_PRIV_GET_OEM_DATA_RSP?-?SIOCIWFIRSTPRIV]?=?iw_get_oem_data_rsp,?//oem?data?req?Specifc
#endif

#ifdef?FEATURE_WLAN_WAPI
???[WLAN_PRIV_SET_WAPI_MODE?????????????-?SIOCIWFIRSTPRIV]??=?iw_qcom_set_wapi_mode,
???[WLAN_PRIV_GET_WAPI_MODE?????????????-?SIOCIWFIRSTPRIV]??=?iw_qcom_get_wapi_mode,
???[WLAN_PRIV_SET_WAPI_ASSOC_INFO???????-?SIOCIWFIRSTPRIV]??=?iw_qcom_set_wapi_assoc_info,
???[WLAN_PRIV_SET_WAPI_KEY??????????????-?SIOCIWFIRSTPRIV]??=?iw_qcom_set_wapi_key,
???[WLAN_PRIV_SET_WAPI_BKID?????????????-?SIOCIWFIRSTPRIV]??=?iw_qcom_set_wapi_bkid,
???[WLAN_PRIV_GET_WAPI_BKID?????????????-?SIOCIWFIRSTPRIV]??=?iw_qcom_get_wapi_bkid,
#endif?/*?FEATURE_WLAN_WAPI?*/
#ifdef?WLAN_FEATURE_VOWIFI_11R
???[WLAN_PRIV_SET_FTIES?????????????????-?SIOCIWFIRSTPRIV]???=?iw_set_fties,
#endif
???[WLAN_PRIV_SET_HOST_OFFLOAD??????????-?SIOCIWFIRSTPRIV]???=?iw_set_host_offload,
???[WLAN_GET_WLAN_STATISTICS????????????-?SIOCIWFIRSTPRIV]???=?iw_get_statistics,
???[WLAN_SET_KEEPALIVE_PARAMS???????????-?SIOCIWFIRSTPRIV]???=?iw_set_keepalive_params
#ifdef?WLAN_FEATURE_PACKET_FILTERING
???,
?? ?[WLAN_SET_PACKET_FILTER_PARAMS???????-?SIOCIWFIRSTPRIV]???=?iw_set_packet_filter_params
#endif
#ifdef?FEATURE_WLAN_SCAN_PNO
???,
???[WLAN_SET_PNO????????????????????????-?SIOCIWFIRSTPRIV]???=?iw_set_pno_priv
#endif
???,
???[WLAN_SET_BAND_CONFIG????????????????-?SIOCIWFIRSTPRIV]???=?iw_set_band_config,
???[WLAN_PRIV_SET_MCBC_FILTER???????????-?SIOCIWFIRSTPRIV]???=?iw_set_dynamic_mcbc_filter,
???[WLAN_PRIV_CLEAR_MCBC_FILTER?????????-?SIOCIWFIRSTPRIV]???=?iw_clear_dynamic_mcbc_filter,
???[WLAN_SET_POWER_PARAMS???????????????-?SIOCIWFIRSTPRIV]???=?iw_set_power_params_priv,
???[WLAN_GET_LINK_SPEED?????????????????-?SIOCIWFIRSTPRIV]???=?iw_get_linkspeed,
};
那么在看看哪里使用? we_private? ?


const?struct?iw_handler_def?we_handler_def?=?{
???.num_standard?????=?sizeof(we_handler)?/?sizeof(we_handler[0]),
???.num_private??????=?sizeof(we_private)?/?sizeof(we_private[0]),
???.num_private_args?=?sizeof(we_private_args)?/?sizeof(we_private_args[0]),

???.standard?????????=?(iw_handler?*)we_handler,
??? .private??????????=?(iw_handler?*)we_private,
???.private_args?????=?we_private_args,
???.get_wireless_stats?=?get_wireless_stats,
};
發現最后賦值給了 const?struct?iw_handler_def?we_handler_def ?中的? .private ??


int?hdd_register_wext(struct?net_device?*dev)
????{
?????......
????if?(!VOS_IS_STATUS_SUCCESS(vos_event_init(&pwextBuf->scanevent)))
????{
????????VOS_TRACE(VOS_MODULE_ID_HDD,?VOS_TRACE_LEVEL_ERROR,?("ERROR:?HDD?scan?event?init?failed!!\n"));
????????return?eHAL_STATUS_FAILURE;
????}

????//?Register?as?a?wireless?device
???? dev->wireless_handlers?=?(struct?iw_handler_def?*)&we_handler_def; //搜索文件看哪里使用了dev->wireless_handlers

????EXIT();
????return?0;
}
到這步之后,再繼續看調 we_handler_def 的調用點。
發現最后給了 dev->wireless_handlers ?這個成員變量。現在我們在使用lookup?References功能?看看?哪些地方使用了 ?dev->wireless_handlers


發現,很多地方都使用了dev->wireless_handlers這個成員變量,那么現在來根據條件(看哪些地方是獲取這個成員變量)來排除
最后發現,只有這一處是獲取到了dev->wireless_handlers這個成員變量。

然后打開這個目錄文件搜索(目錄: net\wireless\Wext-core.c )

static?iw_handler?get_handler(struct?net_device?*dev,?unsigned?int?cmd)
{
??/*?Don't?"optimise"?the?following?variable,?it?will?crash?*/
??unsigned?int??index;????/*?*MUST*?be?unsigned?*/
??const?struct?iw_handler_def?*handlers?=?NULL;

#ifdef?CONFIG_CFG80211_WEXT
??if?(dev->ieee80211_ptr?&&?dev->ieee80211_ptr->wiphy)
????handlers?=?dev->ieee80211_ptr->wiphy->wext;
#endif
#ifdef?CONFIG_WIRELESS_EXT
if?(dev->wireless_handlers)
handlers?=?dev->wireless_handlers;

#endif

??if?(!handlers)
????return?NULL;

??/*?Try?as?a?standard?command?*/
??index?=?IW_IOCTL_IDX(cmd);
??if?(index?<?handlers->num_standard)
????return?handlers->standard[index];

#ifdef?CONFIG_WEXT_PRIV
??/*?Try?as?a?private?command?*/
?? index?=?cmd?-?SIOCIWFIRSTPRIV;
??if?(index?<?handlers->num_private)
???? return?handlers->private[index]; ??//獲取了漏洞函數地址
#endif

??/*?Not?found?*/
??return?NULL;
}
找到了 get_handler 這個函數,看他下面代碼
?? index?=?cmd?-?SIOCIWFIRSTPRIV;
??if?(index?<?handlers->num_private)
???? return?handlers->private[index]; ??//獲取了漏洞函數地址
發現他是根據傳入的CMD指令來獲取函數地址,根據之前的? we_private ?存放地址??? [WLAN_SET_PACKET_FILTER_PARAMS???????-?SIOCIWFIRSTPRIV]???=?iw_set_packet_filter_params ?得出了CMD值


static?int?wireless_process_ioctl(struct?net?*net,?struct?ifreq?*ifr,
??????????unsigned?int?cmd,
??????????struct?iw_request_info?*info,
??????????wext_ioctl_func?standard,
??????????wext_ioctl_func?private)
{
?? struct?iwreq?*iwr?=?(struct?iwreq?*)?ifr;
??struct?net_device?*dev;
??iw_handler??handler;

????????......

??/*?Basic?check?*/
??if?(!netif_device_present(dev))
????return?-ENODEV;

??/*?New?driver?API?:?try?to?find?the?handler?*/
?? handler?=?get_handler(dev,?cmd); ?????獲取了漏洞函數地址
??if?(handler)?{
????/*?Standard?and?private?are?not?the?same?*/
????if?(cmd?<?SIOCIWFIRSTPRIV)
??????return?standard(dev,?iwr,?cmd,?info,?handler);
????else?if?(private)
?????? return?private(dev,?iwr,?cmd,?info,?handler);
??}
??/*?Old?driver?API?:?call?driver?ioctl?handler?*/
???????.....
}
現在繼續看 get_handler ?的調用點,
根據圖片代碼看到,將調用漏洞的函數地址作為參數,然后調用了 standard? or?[COLOR="rgb(139,?0,?0)"]private[/COLOR]?發現這兩個函數都是作為參數傳入進來的。
(?iwr?就是漏洞產生的條件,struct?iwreq?*iwr?=?(struct?iwreq?*)?ifr;????ifr則作為參數傳入?)
那么再繼續看上級調用。


static?int?wext_ioctl_dispatch(struct?net?*net,?struct?ifreq?*ifr,
?????????????unsigned?int?cmd,?struct?iw_request_info?*info,
?????????????wext_ioctl_func?standard,
?????????????wext_ioctl_func?private)
{
??int?ret?=?wext_permission_check(cmd);

??if?(ret)
????return?ret;

??dev_load(net,?ifr->ifr_name);
??rtnl_lock();
??ret?=?wireless_process_ioctl(net,?ifr,?cmd,?info,?standard,?private);
??rtnl_unlock();

??return?ret;
}
發現我們所感興趣的值還是作為參數傳入的,那么繼續往上,


int?wext_handle_ioctl(struct?net?*net,?struct?ifreq?*ifr,?unsigned?int?cmd,
??????????void?__user?*arg)
{
??struct?iw_request_info?info?=?{?.cmd?=?cmd,?.flags?=?0?};
??int?ret;

?? ret?=?wext_ioctl_dispatch(net,?ifr,?cmd,?&info,
??????????ioctl_standard_call,
??????????ioctl_private_call);
??//ioctl_private_call?中調用了漏洞函數
??if?(ret?>=?0?&&
??????IW_IS_GET(cmd)?&&
??????copy_to_user(arg,?ifr,?sizeof(struct?iwreq)))
????return?-EFAULT;

??return?ret;
}
現在得到了這兩個函數的地址。
查看 ioctl_private_call 的代碼


int?ioctl_private_call(struct?net_device?*dev,?struct?iwreq?*iwr,
???????????unsigned?int?cmd,?struct?iw_request_info?*info,
???????????iw_handler?handler)
{
??int?extra_size?=?0,?ret?=?-EINVAL;
??const?struct?iw_priv_args?*descr;

??extra_size?=?get_priv_descr_and_size(dev,?cmd,?&descr);

??/*?Check?if?we?have?a?pointer?to?user?space?data?or?not.?*/
??if?(extra_size?==?0)?{
????/*?No?extra?arguments.?Trivial?to?handle?*/
???? ret?=?handler(dev,?info,?&(iwr->u),?(char?*)?&(iwr->u)); //handler:漏洞函數,iwr->u:觸發條件
??}?else?{
????ret?=?ioctl_private_iw_point(&iwr->u.data,?cmd,?descr,
???????????????handler,?dev,?info,?extra_size);
??}

??/*?Call?commit?handler?if?needed?and?defined?*/
??if?(ret?==?-EIWCOMMIT)
????ret?=?call_commit_handler(dev);

??return?ret;
}
可以看到這里調用了漏洞函數。?&(iwr->u)?,則是漏洞產生的條件


int?dev_ioctl(struct?net?*net,?unsigned?int?cmd,?void?__user?*arg)
{
?? struct?ifreq?ifr;
??int?ret;
??char?*colon;

??/*?One?special?case:?SIOCGIFCONF?takes?ifconf?argument
?????and?requires?shared?lock,?because?it?sleeps?writing
?????to?user?space.
???*/

??if?(cmd?==?SIOCGIFCONF)?{
????rtnl_lock();
????ret?=?dev_ifconf(net,?(char?__user?*)?arg);
????rtnl_unlock();
????return?ret;
??}
??if?(cmd?==?SIOCGIFNAME)
????return?dev_ifname(net,?(struct?ifreq?__user?*)arg);

?? if?(copy_from_user(&ifr,?arg,?sizeof(struct?ifreq))) ??//給ifr結構體賦值
????return?-EFAULT;

???????........

????????ret?=?-EFAULT;
??????return?ret;
????}
????/*?Take?care?of?Wireless?Extensions?*/
????if?(cmd?>=?SIOCIWFIRST?&&?cmd?<=?SIOCIWLAST)
?????? return?wext_handle_ioctl(net,?&ifr,?cmd,?arg);
????return?-ENOTTY;
??}
現在繼續看 wext_handle_ioctl 函數( 注意:ifr參數就是漏洞的產生條件 )繼續看上級調用


int?dev_ioctl(struct?net?*net,?unsigned?int?cmd,?void?__user?*arg)
{
??struct?ifreq?ifr;
??int?ret;
??char?*colon;

??/*?One?special?case:?SIOCGIFCONF?takes?ifconf?argument
?????and?requires?shared?lock,?because?it?sleeps?writing
?????to?user?space.
???*/

??if?(cmd?==?SIOCGIFCONF)?{
????rtnl_lock();
????ret?=?dev_ifconf(net,?(char?__user?*)?arg);
????rtnl_unlock();
????return?ret;
??}
??if?(cmd?==?SIOCGIFNAME)
????return?dev_ifname(net,?(struct?ifreq?__user?*)arg);

?? if?(copy_from_user(&ifr,?arg,?sizeof(struct?ifreq)))
????return?-EFAULT;
看函數頭
發現ifr的內容是拷貝的 dev_ioctl 中的[COLOR="rgb(139,?0,?0)"]arg[/COLOR]參數


static?long?sock_ioctl(struct?file?*file,?unsigned?cmd,?unsigned?long?arg)
{
??struct?socket?*sock;
??struct?sock?*sk;
??void?__user?*argp?=?(void?__user?*)arg;
??int?pid,?err;
??struct?net?*net;

??sock?=?file->private_data;
??sk?=?sock->sk;
??net?=?sock_net(sk);
??if?(cmd?>=?SIOCDEVPRIVATE?&&?cmd?<=?(SIOCDEVPRIVATE?+?15))?{
???? err?=?dev_ioctl(net,?cmd,?argp);
??}?else
到這里 sock_ioctl 沒有發現上級調用,那么看哪些地方出現過這個函數


搜索sock_ioctl發現

static?const?struct?file_operations?socket_file_ops?=?{
??.owner?=??THIS_MODULE,
??.llseek?=??no_llseek,
??.aio_read?=??sock_aio_read,
??.aio_write?=??sock_aio_write,
??.poll?=????sock_poll,
?? .unlocked_ioctl?=?sock_ioctl, //保存在了?unlocked_ioctl?中
#ifdef?CONFIG_COMPAT
??.compat_ioctl?=?compat_sock_ioctl,
#endif
??.mmap?=????sock_mmap,
??.open?=????sock_no_open,??/*?special?open?code?to?disallow?open?via?/proc?*/
??.release?=??sock_close,
??.fasync?=??sock_fasync,
??.sendpage?=??sock_sendpage,
??.splice_write?=?generic_splice_sendpage,
??.splice_read?=??sock_splice_read,
};
file_operations 結構體中獲取
linux大多都是使用ioctl系統調用來控制驅動設備的。所以我們跟蹤 ioctl 函數


SYSCALL_DEFINE3(ioctl,?unsigned?int,?fd,?unsigned?int,?cmd,?unsigned?long,?arg)
{
??struct?file?*filp;
??
int?error?=?-EBADF;
??int?fput_needed;

??filp?=?fget_light(fd,?&fput_needed);
??if?(!filp)
????goto?out;

??error?=?security_file_ioctl(filp,?cmd,?arg);
??if?(error)
????goto?out_fput;

?? error?=?do_vfs_ioctl(filp,?fd,?cmd,?arg);
?out_fput:
??fput_light(filp,?fput_needed);
?out:
??return?error;
}

int?do_vfs_ioctl(struct?file?*filp,?unsigned?int?fd,?unsigned?int?cmd,
???????unsigned?long?arg)
{
??int?error?=?0;
??int?__user?*argp?=?(int?__user?*)arg;
??struct?inode?*inode?=?filp->f_path.dentry->d_inode;

????????.....

??default:
????if?(S_ISREG(inode->i_mode))
??????error?=?file_ioctl(filp,?cmd,?arg);
????else
?????? error?=?vfs_ioctl(filp,?cmd,?arg);
????break;
??}
do_vfs_ioctl ?函數下找到? vfs_ioctl

static?long?vfs_ioctl(struct?file?*filp,?unsigned?int?cmd,
??????????unsigned?long?arg)
{
??int?error?=?-ENOTTY;

??if?(!filp->f_op?||?!filp->f_op->unlocked_ioctl)
????goto?out;

?? error?=?filp->f_op->unlocked_ioctl(filp,?cmd,?arg);
??if?(error?==?-ENOIOCTLCMD)
????error?=?-ENOTTY;
?out:
??return?error;
}
這樣調用漏洞函數的過程就全部串聯起來。


4,構建觸發漏洞條件
首先看下? ioctl? ?有三個參數
param1 首先打開網絡驅動設備(linux大多數驅動都是以文件形式存在的,只有網絡驅動例外。想了解詳細的可以看下socket函數)

param2 cmd,之前就已經找函數調用路徑的時候我們就發現

#define?SIOCIWFIRSTPRIV??0x8BE0
#define?WLAN_SET_PACKET_FILTER_PARAMS?(SIOCIWFIRSTPRIV?+?23)


param3 [/IMG]
首先傳入的時候


if?(copy_from_user(&ifr,?arg,?sizeof(struct?ifreq)))
然后


static?int?iw_set_packet_filter_params(struct?net_device?*dev,?struct?iw_request_info?*info,
????????union?iwreq_data?*wrqu,?char?*extra)
{???
????hdd_adapter_t?*pAdapter?=?WLAN_HDD_GET_PRIV_PTR(dev);
???? tpPacketFilterCfg?pRequest?=?(tpPacketFilterCfg)wrqu->data.pointer;

????return?wlan_hdd_set_filter(WLAN_HDD_GET_CTX(pAdapter),?pRequest,?pAdapter->sessionId);
}
強制轉換了下我們看下?[COLOR="rgb(139,?0,?0)"]iwreq[/COLOR]?的成員


struct??iwreq?
{
??union
??{
????char??ifrn_name[IFNAMSIZ];??/*?if?name,?e.g.?"eth0"?*/
??}?ifr_ifrn;

??/*?Data?part?(defined?just?above)?*/
??union??iwreq_data??u;
};

union??iwreq_data
{
??struct?iw_point??data;????/*?Other?large?parameters?*/
};

struct??iw_point
{
??void?__user??*pointer;??/*?Pointer?to?the?data??(in?user?space)?*/????
??__u16????length;????/*?number?of?fields?or?size?in?bytes?*/??????
??__u16????flags;????/*?Optional?params?*/????????????????
};

看下tpPacketFilterCfg的結構體
typedef?struct
{
????v_U8_t????????????filterAction;
????v_U8_t????????????filterId;
????v_U8_t????????????numParams;
????struct?PacketFilterParamsCfg?paramsData?[HDD_MAX_CMP_PER_PACKET_FILTER];
}tPacketFilterCfg,?*tpPacketFilterCfg;

struct?PacketFilterParamsCfg
{
????v_U8_t??????????????protocolLayer;
????v_U8_t??????????????cmpFlag;
????v_U8_t??????????????dataOffset;
????v_U8_t??????????????dataLength;
????v_U8_t??????????????compareData[8];
????v_U8_t??????????????dataMask[8];
};

現在構造觸發漏洞的結構體
int?wlan_hdd_set_filter(hdd_context_t?*pHddCtx,?tpPacketFilterCfg?pRequest,?
????????????????????????????tANI_U8?sessionId)
{
????tSirRcvPktFilterCfgType????packetFilterSetReq?=?{0};
????tSirRcvFltPktClearParam????packetFilterClrReq?=?{0};
????int?i=0;

????if?(pHddCtx->cfg_ini->disablePacketFilter)
????{
????????hddLog(VOS_TRACE_LEVEL_FATAL,?"%s:?Packet?Filtering?Disabled.?Returning?",
????????????????__func__?);
????????return?0;
????}
????if?(pHddCtx->isLogpInProgress)
????{
???????VOS_TRACE(VOS_MODULE_ID_HDD,?VOS_TRACE_LEVEL_FATAL,
??????????????????????????????????"%s:LOGP?in?Progress.?Ignore!!!",?__func__);
???????return?-EBUSY;
????}
????/*?Debug?display?of?request?components.?*/
????hddLog(VOS_TRACE_LEVEL_ERROR,?"%s:?Packet?Filter?Request?:?FA?%d?params?%d",
????????????__func__,?pRequest->filterAction,?pRequest->numParams);

????switch?(pRequest->filterAction)? 進入條件
????{
????????case?HDD_RCV_FILTER_SET:
????????????hddLog(VOS_TRACE_LEVEL_INFO,?"%s:?Set?Packet?Filter?Request?for?Id:?%d",
????????????????????__func__,?pRequest->filterId);

????????????packetFilterSetReq.filterId?=?pRequest->filterId;
????????????if?(?pRequest->numParams?>=?HDD_MAX_CMP_PER_PACKET_FILTER)
????????????{
????????????????hddLog(VOS_TRACE_LEVEL_ERROR,?"%s:?Number?of?Params?exceed?Max?limit?%d\n",
????????????????????????__func__,?pRequest->numParams);
????????????????return?-EINVAL;
????????????}
????????????packetFilterSetReq.numFieldParams?=?pRequest->numParams;
????????????packetFilterSetReq.coalesceTime?=?0;
????????????packetFilterSetReq.filterType?=?1;
???????????? for?(i=0;?i?<?pRequest->numParams;?i++) //因為=?pRequest->paramsData[i].dataLength?定義為unsigned?char,覆蓋長度無法觸發漏洞,所以這里要設定pRequest->numParams的值,已確保能覆蓋的地址能到達函數返回地址的長度
????????????{
????????????????packetFilterSetReq.paramsData[i].protocolLayer?=?pRequest->paramsData[i].protocolLayer;
????????????????packetFilterSetReq.paramsData[i].cmpFlag?=?pRequest->paramsData[i].cmpFlag;
????????????????packetFilterSetReq.paramsData[i].dataOffset?=?pRequest->paramsData[i].dataOffset;
????????????????? ?packetFilterSetReq.paramsData[i].dataLength?=?pRequest->paramsData[i].dataLength;
?????????????????//這個成員變量定義為unsigned?char,最大數字只能設置255個字節。
????????????????packetFilterSetReq.paramsData[i].reserved?=?0;

????????????????hddLog(VOS_TRACE_LEVEL_INFO,?"Proto?%d?Comp?Flag?%d?Filter?Type?%d\n",
????????????????????????pRequest->paramsData[i].protocolLayer,?pRequest->paramsData[i].cmpFlag,
????????????????????????packetFilterSetReq.filterType);

????????????????hddLog(VOS_TRACE_LEVEL_INFO,?"Data?Offset?%d?Data?Len?%d\n",
????????????????????????pRequest->paramsData[i].dataOffset,?pRequest->paramsData[i].dataLength);

??????????????? ?/*因為沒有對長度進行判斷,而packetFilterSetReq又屬于局部變量,導致了我們可以設置適量的長度,覆蓋掉wlan_hdd_set_filter的返回地址,讓其跳轉到自己所寫函數的,進行提權操作.*/
????????????????memcpy(&packetFilterSetReq.paramsData[i].compareData,
????????????????????????pRequest->paramsData[i].compareData,?pRequest->paramsData[i].dataLength);
????????????????memcpy(&packetFilterSetReq.paramsData[i].dataMask,
????????????????????????pRequest->paramsData[i].dataMask,?pRequest->paramsData[i].dataLength);

????????????????hddLog(VOS_TRACE_LEVEL_INFO,?"CData?%d?CData?%d?CData?%d?CData?%d?CData?%d?CData?%d\n",
????????????????????????pRequest->paramsData[i].compareData[0],?pRequest->paramsData[i].compareData[1],
????????????????????????pRequest->paramsData[i].compareData[2],?pRequest->paramsData[i].compareData[3],
????????????????????????pRequest->paramsData[i].compareData[4],?pRequest->paramsData[i].compareData[5]);

????????????????hddLog(VOS_TRACE_LEVEL_INFO,?"MData?%d?MData?%d?MData?%d?MData?%d?MData?%d?MData?%d\n",
????????????????????????pRequest->paramsData[i].dataMask[0],?pRequest->paramsData[i].dataMask[1],
????????????????????????pRequest->paramsData[i].dataMask[2],?pRequest->paramsData[i].dataMask[3],
????????????????????????pRequest->paramsData[i].dataMask[4],?pRequest->paramsData[i].dataMask[5]);
????????????}

????????????if?(eHAL_STATUS_SUCCESS?!=?sme_ReceiveFilterSetFilter(pHddCtx->hHal,?&packetFilterSetReq,?sessionId))
????????????{
????????????????hddLog(VOS_TRACE_LEVEL_ERROR,?"%s:?Failure?to?execute?Set?Filter\n",
????????????????????????__func__);
????????????????return?-EINVAL;
????????????}

????????????break;

????????case?HDD_RCV_FILTER_CLEAR:

????????????hddLog(VOS_TRACE_LEVEL_INFO_HIGH,?"%s:?Clear?Packet?Filter?Request?for?Id:?%d\n",
????????????????????__func__,?pRequest->filterId);
????????????packetFilterClrReq.filterId?=?pRequest->filterId;
????????????if?(eHAL_STATUS_SUCCESS?!=?sme_ReceiveFilterClearFilter(pHddCtx->hHal,?&packetFilterClrReq,?sessionId))
????????????{
????????????????hddLog(VOS_TRACE_LEVEL_ERROR,?"%s:?Failure?to?execute?Clear?Filter\n",
????????????????????????__func__);
????????????????return?-EINVAL;
????????????}
????????????break;

????????default?:
????????????hddLog(VOS_TRACE_LEVEL_INFO_HIGH,?"%s:?Packet?Filter?Request:?Invalid?%d\n",
????????????????????__func__,?pRequest->filterAction);
????????????return?-EINVAL;
????}
????return?0;
}

iwreq.ifrn_name?=?網絡驅動名字
tpPacketFilterCfg.numParams?=?4??

PacketFilterParamsCfg.dataLength?=?255
PacketFilterParamsCfg.compareData?=?my_fun_address

這樣設置參數就能觸發漏洞


5,函數返回崩潰問題

wlan_hdd_set_filter?因為返回地址被修改,所以調用完函數后,會導致內核崩潰,但是我們可以使用上級函數的地址來返回。這樣就能避免內核崩潰.


?原文地址:?http://www.kanxue.com/bbs/showthread.php?t=208066

總結

以上是生活随笔為你收集整理的cve-2015-0569 安卓手机提权ROOT漏洞 分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。