https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-0728
cve-2016-0728是一个linux平台上的UAF漏洞.漏洞主要的原因是由于keyrings组件当中的引用计数问题导致的.它使用一个32位的无符号整数做引用计数,但是在计数器出现溢出的时候没有进行合理的处理.当对象的引用计数达到最大时会变成0,因此释放对象的内存空间.而此时程序还保留对引用对象的引用,所以形成了UAF漏洞.
long join_session_keyring(const char *name)
{
const struct cred *old;
struct cred *new;
struct key *keyring;
long ret, serial;
new = prepare_creds();
if (!new)
return -ENOMEM;
old = current_cred();
/* if no name is provided, install an anonymous keyring */
if (!name) {
ret = install_session_keyring_to_cred(new, NULL);
if (ret < 0)
goto error;
serial = new->session_keyring->serial;
ret = commit_creds(new);
if (ret == 0)
ret = serial;
goto okay;
}
/* allow the user to join or create a named keyring */
mutex_lock(&key_session_mutex);
/* look for an existing keyring of this name */
keyring = find_keyring_by_name(name, false); //key->usage + 1
if (PTR_ERR(keyring) == -ENOKEY) {
/* not found - try and create a new one */
keyring = keyring_alloc(name, old->uid, old->gid, old,
KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
}
} else if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
} else if (keyring == new->session_keyring) { //keyname == 当前cred中的key name
ret = 0; //直接返回,绕过key_put
goto error2;
}
/* we've got a keyring - now to install it */
ret = install_session_keyring_to_cred(new, keyring);
if (ret < 0)
goto error2;
commit_creds(new);
mutex_unlock(&key_session_mutex);
ret = keyring->serial;
key_put(keyring);
okay:
return ret;
error2:
mutex_unlock(&key_session_mutex);
error:
abort_creds(new);
return ret;
}
通过以上代码可以得出只要进程使用当前正在使用的keyring名,程序就会跳过kref_put(keyring),造成引用计数的只增不减.由于引用计数是无符号整形,可以通过循环调用,整数溢出的方法来将它置0.
1. 漏洞代码所在的内核版本应该是3.8以后.但是大部分安卓5.0的设备都运行在3.4的内核版本之中.
2. 网上的poc没有成功的原因是因为没有获得commit_creds和prepare_kernel_cred的地址,攻击者需要得到root权限,将kptrstrict标志置为0后,才能通过/proc/kallsyms来查看符号的地址.
3. 在用户空间的提权代码则需要commit_creds(prepare_kernel_cred(0));函数将cred结构置为0,从而获取root权限.
4. 使用ret2usr来在用户态调用提权代码需要考虑pxn的问题.在没有pxn防护的手机中可以在内核空间执行用户态代码.然而在有pxn防护的情况下,则需要考虑使用ROP来寻找内核gadget来绕过保护.
5. 需要调用4294967295次,时间过长有可能导致shell反弹超时.所以很难利用.
6. 出现漏洞的代码存在于linux内核中的keyring服务.但是该服务必须在内核编译时启用CONFIG_KEYS 选项.在AOSP内核的config文件中,并没有发现CONFIG_KEYS被启用.所以说android设备并没有包含漏洞相关的代码,因此就是说android设备没有被该漏洞所影响.
7. 在安卓4.4版本以后,强制开启了SELinux的策略.SELinux减少了Linux内核的攻击面.SELinux的策略也限制了ASOP在设备上通过非授信app调用exp的权限.比如当一个app尝试去执行keyctl系统调用去创建一个keyring的对象时,系统调用会被拒绝. 开源的poc代码使用了SysV IPC (msgget) 来分配内存传递漏洞利用代码.安卓5.0的SELinux策略限制了SysV IPC因此阻止了包含利用的代码.
1. 首先去掉get_symbol的函数,root掉手机以后,直接将kptrstrict置为0,读取kallsyms的全部信息.获取相关符号地址
2. arm版的通过使用syscall来取代keyctl调用.
3. 通过添加一个计算来显示循环的百分比
在我的设备上测试的时间为12:00 – 16:46 ,进度显示为0.1%.
所以大约要执行166天左右才能跑完…