I participated in Hack The Boo 2023 and solved all the web challenges (2/2)
HauntMart
#ssrf #flask
Description: HauntMart, a beloved Halloween webstore, has fallen victim to a curse, bringing its products to life. You must explore its ghostly webpages, and break the enchantment before Halloween night. Can you save Spooky Surprises from its supernatural woes?.
Difficulty: Easy
Analysis
The Challenge provides a source code for the web application. It is written in Flask.
After learning this functionality, I thought that the way to exploit it is by finding an SSRF. This is the next step I took.
Navigating the website this looks like an ecommerce web application where the user can sell products. After logging in, we can see a product list Home and a Sell Product page where the ff: is shown:
Notice the interesting field Manual Url. If we look at the source code of the Sell Product. we can see that the manualPath provided is passed into a downloadManual function
@api.route('/product',methods=['POST'])@isAuthenticateddefsellProduct(user):ifnotrequest.is_json:returnresponse('Invalid JSON!'),400data=request.get_json()name=data.get('name','')price=data.get('price','')description=data.get('description','')manualUrl=data.get('manual','')ifnotnameornotpriceornotdescriptionornotmanualUrl:returnresponse('All fields are required!'),401manualPath=downloadManual(manualUrl)if(manualPath):addProduct(name,description,price)returnresponse('Product submitted! Our mods will review your request')returnresponse('Invalid Manual URL!'),400
The downloadManual function shows that its performing a request.get which can be used to request for the /addAdmin route. At this point I can just do a request through the Manual URL field to upgrade my user to an admin.
However there is an isSafeURL function being run before performing the request.
We can see that there is a list of not allowed URL.
Solution (SSRF)
If I can bypass the isSafeUrl function. I can request to the makeAdmin to make my user an admin.
The payload i used was http://0:1337/api/addAdmin?username=admin to upgrade my user called admin to an admin.
Note: the port and the endpoint for addAdmin can be inferred from the routes and the run.py.
Visit the Home page to get the flag.
Flag
Ghostly Templates
#SSTI/Go #LFI
Description: In the dark corners of the internet, a mysterious website has been making waves among the cybersecurity community. This site, known for its Halloween-themed templates, has sparked rumors of an eerie secret lurking beneath the surface. Will you delve into this dark and spooky webapp to uncover the hidden truth?
Difficulty: Medium
Analysis
The application looks like it loads a template from a link
After analysis of the source code. The function that interests me is the getTpl function. This is where the logic of the frontend is processed.
funcgetTpl(whttp.ResponseWriter,r*http.Request){varpagestring=r.URL.Query().Get("page")varremotestring=r.URL.Query().Get("remote")ifpage==""{http.Error(w,"Missing required parameters",http.StatusBadRequest)return}reqData:=&RequestData{}userIPCookie,err:=r.Cookie("user_ip")clientIP:=""iferr==nil{clientIP=userIPCookie.Value}else{clientIP=strings.Split(r.RemoteAddr,":")[0]}userAgent:=r.Header.Get("User-Agent")locationInfo,err:=reqData.GetLocationInfo("https://freeipapi.com/api/json/"+clientIP)iferr!=nil{http.Error(w,"Could not fetch IP location info",http.StatusInternalServerError)return}reqData.ClientIP=clientIPreqData.ClientUA=userAgentreqData.ClientIpInfo=*locationInforeqData.ServerInfo.Hostname=GetServerInfo("hostname")reqData.ServerInfo.OS=GetServerInfo("cat /etc/os-release | grep PRETTY_NAME | cut -d '\"' -f 2")reqData.ServerInfo.KernelVersion=GetServerInfo("uname -r")reqData.ServerInfo.Memory=GetServerInfo("free -h | awk '/^Mem/{print $2}'")vartmplFilestringifremote=="true"{tmplFile,err=readRemoteFile(page)iferr!=nil{http.Error(w,"Internal Server Error",http.StatusInternalServerError)return}}else{if!reqData.IsSubdirectory("./",TEMPLATE_DIR+"/"+page){http.Error(w,"Internal Server Error",http.StatusInternalServerError)return}tmplFile=reqData.OutFileContents(TEMPLATE_DIR+"/"+page)}tmpl,err:=template.New("page").Parse(tmplFile)iferr!=nil{http.Error(w,"Internal Server Error",http.StatusInternalServerError)return}err=tmpl.Execute(w,reqData)iferr!=nil{http.Error(w,"Internal Server Error",http.StatusInternalServerError)return}}
After going through the code and researching I learned that we can read a remote file if remote is set to true.
The remote file can be a go template file that can access the variables from reqData struct when parsed.
RequestData, LocationInfo and MachineInfo struct for context
I learned that I can define my own go template and access the variables passed on the reqData. I also learned there is a method passed in the template called OutFileContents