Pendahuluan

Untuk pendahuluan mengenai Vulnerability / Kerentanan Log4j2 ini bisa dilihat di artikel sebelumnya. link

Vulnerability Log4j ini bisa mengakibatkan :

  • RCE (Remote Code Execution) attack, yaitu peretas akan mudahnya mengambil Code java dari server remote dan dieksekusi menggunakan JNDI.
  • Terekspose nya environment variable, konfigurasi server, konfigurasi database, dan konfigurasi yang diset di server/program korban. Informasi ini bisa dimanfaatkan untuk aksi peretasan selanjutnya.

Mengetahui penyebab mengapa Vulnerability ini terjadi, akan sangat membantu kita dalam melakukan mitigasi terhadapnya.


Sebenarnya code bagian mana sih yang menyebabkan log4j vulnerability ini ?

Ok, sekarang kita coba telusuri secara teknikal.

Kita ambil contoh dari code biasa di dalam REST Controller yang menggunakan log4j2, contoh dari link :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PocLog4j2Controller  {

	Logger logger = LogManager.getLogger(PocLog4j2Controller.class);

	@RequestMapping("/testLookup")
    public String index() {
		String jndiLdap = "${jndi:ldap://localhost/a}";

		logger.info("A JNDI Lookup : {}", jndiLdap);

		return "Testing log4j2 vulnerability !";
    }
}

Ketika line 15 diatas dieksekusi, maka library Log4j2 akan melakukan fungsi JNDI Lookup terhadap line 13 => ${jndi:ldap://localhost/a} sebagai bagian dari fitur Property Support nya Log4j.

Fungsi JNDI Lookup ini didelegasikan ke class org.apache.logging.log4j.core.lookup.JndiLookup. Dan class lookup ini berada di library log4j-core-xxxx.jar. Class ini akan melakukan fungsi lookup terhadap JNDI.

Fungsi-fungsi lookup lainnya juga berada di package ini, seperti JavaLookup, EnvironmentLookup, dll.

JNDILookup

Coba kita lihat snipped code dari class org.apache.logging.log4j.core.lookup.JndiLookup ini (saya memakai versi log4j-core-2.14.1.jar):

Didalamnya ada fungsi lookup yang akan dipanggil oleh Log4j ketika menemui parameter ${jndi:xxx}.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Override
public String lookup(final LogEvent event, final String key) {
    if (key == null) {
        return null;
    }
    final String jndiName = convertJndiName(key);
    try (final JndiManager jndiManager = JndiManager.getDefaultManager()) {
        return Objects.toString(jndiManager.lookup(jndiName), null);
    } catch (final NamingException e) {
        LOGGER.warn(LOOKUP, "Error looking up JNDI resource [{}].", jndiName, e);
        return null;
    }

Fungsi lookup ini akan memanggil fungsi jndiManager.lookup(jndiName), yang melakukan proses inisiasi JNDI.

dan kalau kita trace sampai terakhir apa yang dilakukan oleh JNDI lookup, bisa kita lihat dari stack trace sbb :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
http-nio-8080-exec-1 WARN Error looking up JNDI resource [ldap://localhost/a].
javax.naming.CommunicationException: localhost:389 [Root exception is java.net.ConnectException: Connection refused: connect]
	at java.naming/com.sun.jndi.ldap.Connection.<init>(Connection.java:244)
	at java.naming/com.sun.jndi.ldap.LdapClient.<init>(LdapClient.java:137)
	at java.naming/com.sun.jndi.ldap.LdapClient.getInstance(LdapClient.java:1616)
	at java.naming/com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2847)
	at java.naming/com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:348)
	at java.naming/com.sun.jndi.url.ldap.ldapURLContextFactory.getUsingURLIgnoreRootDN(ldapURLContextFactory.java:60)
	at java.naming/com.sun.jndi.url.ldap.ldapURLContext.getRootURLContext(ldapURLContext.java:61)
	at java.naming/com.sun.jndi.toolkit.url.GenericURLContext.lookup(GenericURLContext.java:204)
	at java.naming/com.sun.jndi.url.ldap.ldapURLContext.lookup(ldapURLContext.java:94)
	at java.naming/javax.naming.InitialContext.lookup(InitialContext.java:409)
	at org.apache.logging.log4j.core.net.JndiManager.lookup(JndiManager.java:172)
	at org.apache.logging.log4j.core.lookup.JndiLookup.lookup(JndiLookup.java:56)

Secara aktif, untuk case diatas, class JndiLookup ini melakukan inisiasi LDAP connection ke server yang URL nya tertera di parameter ${jndi:xxx}. diatas. Dan selanjutnya menggunakan library nya Java untuk LDAP connection, dst.

Kapan JNDI lookup ini ditambahkan di library log4j ?

Fitur JNDI Lookup ini ditambahkan Juli 2013 pada release 2.0-beta9 , https://issues.apache.org/jira/browse/LOG4J2-313.

Dan semenjak release 2.10.0, ditambahkan property untuk on/off lookup secara global (sumber dari link dan link), sehingga JNDI Lookup dan lookup-lookup yang lainnya bisa dikonfigurasi on/off nya dengan setting : log4j2.formatMsgNoLookups = true