TL;DR
It’s my first time to create challenges after i entered Nu1L Team. I’m glad to see so many hackers could solve my challenges though they have few problems(Such as in eezzjs, flag is in /flag instead of /ffffflag because my new attachment did not update on competition platform in time). Here are my expected solutions for these challenges
eezzjs
In this challenges, your first work is to get a legal JWT that you could pass authenticateJWT middleware and use /upload to upload your file arbitrarily.
Actually it is easy to find this vuln. Beacuse when you try to debug locally, you could find information in this image
When you run npm audit, you got the vuln is in sha.js,even it tells you the advisory of this vuln XD.
The Principle of sha.js vuln is when you submit an Object as update() ’s arg, you could find length is assign by data.length,so this._len can be control that if data is an Object and it has a member named length
Hash.prototype.update = function (data, enc) {
if (typeof data === 'string') {
enc = enc || 'utf8'
data = Buffer.from(data, enc)
}
var block = this._block
var blockSize = this._blockSize
var length = data.length
var accum = this._len
for (var offset = 0; offset < length;) {
var assigned = accum % blockSize
var remainder = Math.min(length - offset, blockSize - assigned)
for (var i = 0; i < remainder; i++) {
block[assigned + i] = data[offset + i]
}
accum += remainder
offset += remainder
if ((accum % blockSize) === 0) {
this._update(block)
}
}
this._len += length
return this
}
where this._len equals to zero,its value always becomes the same.Then you could pass authenticateJWT and upload your file.
Next step,you should use /upload and / try to get RCE
As we all know,when ejs try to template a view in web.it would try to run this code
...
if (!opts.engines[this.ext]) {
// load engine
var mod = this.ext.slice(1)
debug('require "%s"', mod)
// default engine export
var fn = require(mod).__express
if (typeof fn !== 'function') {
throw new Error('Module "' + mod + '" does not provide a view engine.')
}
...
when you submit ?templ=abc.ddw,it would try to require ddw modules. It gives us a chance to run arbitrary code.
But we couldn’t create dir or js file.How do we attack?
In documents we could know
If the exact filename is not found, then Node.js will attempt to load the required filename with the added extensions:
.js,.json, and finally.node. When loading a file that has a different extension (e.g..cjs), its full name must be passed torequire(), including its file extension (e.g.require('./file.cjs')).
So we could use .node file to finish our attack,My exploit
At last, i felt sorry for this challenge really has some issues,and there many unexpected solutions can solve this challenge that could use simply ../ or ./ bypass my ez waf haha.
n1cat
n1cat is a gray challenge because if i provide full source code, the first step( CVE-2025-55752) is completely useless XD. In other words you could use this vulnerability to get full source code(maybe some libs was confused).
My attachment provide a Tomcat file rewrite.config,then you know CVE-2025-55752 is a point of this challenge. You could try to read web.xml.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>welcomeServlet</servlet-name>
<servlet-class>ctf.n1cat.welcomeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>welcomeServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
then you know welcomeServlet class path,you could use the same way to down it. The same applies to theUser class and detect lib.
User.class
package ctf.n1cat;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class User {
private String name;
private String word;
private String url;
public User(){
}
public String getName() {
return name;
}
public String getWord() {
return word;
}
public void setWord(String password) {
this.word = password;
}
public void setName(String name) throws NamingException {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
try{
new InitialContext().lookup(url);
} catch (NamingException e) {
throw new RuntimeException(e);
}
}
}
You could directly find a JNDI Injection vuln. Now first step is over.
The second step is try to use this vulnerability to get an rce.JDK version is 17,many ways of JNDI attack might not working.I uses RMI communicate deserialize(Communication between the RMI server and RMI client employs serialisation and deserialisation).About deserialize chains,we uses Jackson+SpringAOP to solve this (You could find Jackson dependence in welcomeServlet,SpringAOPdependence and version could use CVE-2025-55752 to detect).
About this chains analysis,could see this
END
All challenges and solutions has uploaded on GitHub.Hope next time will be better




