暂无简介
CVE-2022-1292的分析
由于本人不会perl
, 目前也没有别的文章参考, 所以有问题还请大家包容, 指正
漏洞信息
在openssl
中的c_rehash
存在命令注入, 允许以c_reash
脚本的权限执行命令
在某些系统下, c_rehash
会被自动运行, 可能可以用于提权, 漏洞详情
复现
在版本1.1.1n
下复现
创建文件名带有"`"的文件
并在第一行写入-----BEGIN CERTIFICATE-----
以通过c_rehash
对文件内容的检查
然后在当前文件夹执行c_rehash .
可以发现一个名为happi0
的空文件被创建
分析与调试
c_rehash
部分内容如下, 省去了无关部分
# 将命令行传入的参数赋值给dirlist
if (@ARGV) {
@dirlist = @ARGV;
} elsif ($ENV{SSL_CERT_DIR}) {
@dirlist = split /$path_delim/, $ENV{SSL_CERT_DIR};
} else {
$dirlist[0] = "$dir/certs";
}
# 判断$dirlist[0]目录是否存在, 并把工作目录修改为$dirlist[0]
# 检查是否存在$openssl是否存在
if (-d $dirlist[0]) {
chdir $dirlist[0];
$openssl="$pwd/$openssl" if (!-x $openssl);
chdir $pwd;
}
# 检查$dirlist中的每一项是否存在且可写, 均满足则调用hash_dir函数
foreach (@dirlist) {
if (-d $_ ) {
if ( -w $_) {
hash_dir($_);
} else {
print "Skipping $_, can't write\n";
$errorcount++;
}
}
}
exit($errorcount);
接下来进入hash_dir
函数, 也就是存在问题的函数
sub hash_dir {
my %hashlist;
print "Doing $_[0]\n";
chdir $_[0];
opendir(DIR, ".");
# 问题出在这里, 将改目录所有文件名读入到flist数组, 但没有处理, 导致文件名命令注入的可能
my @flist = sort readdir(DIR);
closedir DIR;
if ( $removelinks ) {
# Delete any existing symbolic links
foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) {
if (-l $_) {
print "unlink $_" if $verbose;
unlink $_ || warn "Can't unlink $_, $!\n";
}
}
}
# 这里也不是很严格, 仅仅需要文件名含有所定义的关键字即可
FILE: foreach $fname (grep {/\.(pem)|(crt)|(cer)|(crl)$/} @flist) {
# Check to see if certificates and/or CRLs present.
my ($cert, $crl) = check_file($fname);
if (!$cert && !$crl) {
print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n";
next;
}
link_hash_cert($fname) if ($cert);
link_hash_crl($fname) if ($crl);
}
}
使用perl -d c_rehash "."
调试一下, perl
自带的调式工具, 用法和gdb
差不多
可以看到$flist[5]
文件名中存在"`"特殊字符
由于文件名检测, 只要求文件名含有(pem)|(crt)|(cer)|(crl)
字符即可, 所以恶意文件名通过检测, 进入check_file
函数
sub check_file {
my ($is_cert, $is_crl) = (0,0);
my $fname = $_[0];
open IN, $fname;
while(<IN>) {
if (/^-----BEGIN (.*)-----/) {
my $hdr = $1;
if ($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) {
$is_cert = 1;
last if ($is_crl);
} elsif ($hdr eq "X509 CRL") {
$is_crl = 1;
last if ($is_cert);
}
}
}
close IN;
return ($is_cert, $is_crl);
}
主要检查文件头格式是否满足要求, 这样是为什么最开始制作恶意文件需要带上-----BEGIN CERTIFICATE-----
检查通过到link_hash_cert
函数也就是注入发生的函数
sub link_hash_cert {
my $fname = $_[0];
# 这里对于传过来的参数也没有检查, 并且把$fname直接用``包裹, 直接执行命令, 导致$fname中的命令也可以执行
$fname =~ s/\"/\\\"/g;
my ($hash, $fprint) = `"$openssl" x509 $x509hash -fingerprint -noout -in "$fname"`;
...
link_hash_crl
的情况和link_hash_cert
的情况相似, 就不跟踪了
修复分析和思考
主要增加一个了如下一个函数
核心在于以下这句
if (!open($fh, "-|", @_)) {
在调试状态下看一下
@_
其实是执行的一个命令, 由于debug模式下没有显示空格, 但也能大致看出是执行和原本通过"`"执行的一样的一条命令
这里是一个perl
的特殊用法, 找到资料
可以通过open
执行命令, 这里我进行了一些测试, 确实解决了命令注入的问题, 但和官方建议的写法不一样
后来找到了资料, 他说用two-argument form of open()
不安全, 所以意思大概是用三个参数就是比较安全的叭
这里写法和官方建议不一样, 可能会出现一定问题, 但由于本人能力有限, 并不理解开发者这样写的深意, 又或者只是因为开发者图方便?
希望有大佬可以指教.
- 本文作者: happi0
- 本文来源: 先知社区
- 原文链接: https://xz.aliyun.com/t/11703
- 版权声明: 除特别声明外,本文各项权利归原文作者和发表平台所有。转载请注明出处!