In this RingZer0 challenge, we are to visit the challenge url where we are given 2 seconds to SHA512 hash the message represented by the binary provided string. We must send the response with the request parameter r. Let’s write a go program to do that.

First let’s declare the url as a constant.

const uri = "http://challenges.ringzer0team.com:10014/"

We fetch the challenge page and defer closing its body once the program ends.

resp, err := http.Get(uri)
if err != nil {
	log.Fatalln(err)
}
defer resp.Body.Close()

We will use the goquery library to parse the response HTML.

doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
	log.Fatalln(err)
}

We find the single (goquery.Single) element with the “message” class and get the text contents of the element.

text := doc.FindMatcher(goquery.Single(".message")).Text()

To grab the line which has the actual binary string, we split the lines and take the third (which is index 2, remember computers begin indexing from 0).

binary := strings.Split(text, "\n")[2]

Let’s also trim any spaces and tabs as a precaution.

binary = strings.Trim(binary, " \t")

We declare a buffer where we can store the decoded contents.

var buf []byte

Since each character in the string represents a bit, 8 of them represent a byte. We will loop with a sliding window of 8 characters, parse them as an integer into a byte and append them to the buffer.

for i := 0; i < len(binary)/8; i++ {
	// decode sequence of 8 bits with base 2
	if b, err := strconv.ParseInt(binary[i*8:8+i*8], 2, 8); err != nil {
		log.Fatal(err)
	} else {
		buf = append(buf, byte(b))
	}
}

Let’s find the SHA512 hash of the decoded string using the Sum512 function from the standard crypto/sha512 library.

hash := sha512.Sum512(buf)

We use format strings to construct the new URI, we can use format strings. Here %s is a placeholder for the constant URI, ?r= is the parameter we are supply the answer to and %x represents the hex digest of the hash.

flagUri := fmt.Sprintf("%s?r=%x", uri, hash)

Once we have this URI, we can send this through to get a response. As done previously, we defer closing the response body once the program ends.

flagPage, err := http.Get(flagUri)
if err != nil {
	log.Fatalln(err)
}
defer flagPage.Body.Close()

Pause and ponder to make sure you have understood the code so far.

Now you could print the response body as I did the first time solving this. However, as with any other writeup, I will write the rest of the program so that it only prints the flag when run.


Let’s parse the response body using goquery again.

doc, err = goquery.NewDocumentFromReader(flagPage.Body)
if err != nil {
	log.Fatalln(err)
}

The flag is located in the div element with the class “alert-info”.

flag := doc.FindMatcher(goquery.Single(".alert-info")).Text()

Finally, we print out the flag.

fmt.Println(flag)

The final code becomes the following:

package main

import (
	"crypto/sha512"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"log"
	"net/http"
	"strconv"
	"strings"
)

const uri = "http://challenges.ringzer0team.com:10014/"

func main() {
	resp, err := http.Get(uri)
	if err != nil {
		log.Fatalln(err)
	}
	defer resp.Body.Close()
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		log.Fatalln(err)
	}
	text := doc.FindMatcher(goquery.Single(".message")).Text()
	binary := strings.Split(text, "\n")[2]
	binary = strings.Trim(binary, " \t")
	var buf []byte
	for i := 0; i < len(binary)/8; i++ {
		// decode sequence of 8 bits with base 2
		if b, err := strconv.ParseInt(binary[i*8:8+i*8], 2, 8); err != nil {
			log.Fatal(err)
		} else {
			buf = append(buf, byte(b))
		}
	}
	hash := sha512.Sum512(buf)
	flagUri := fmt.Sprintf("%s?r=%x", uri, hash)
	flagPage, err := http.Get(flagUri)
	if err != nil {
		log.Fatalln(err)
	}
	defer flagPage.Body.Close()
	doc, err = goquery.NewDocumentFromReader(flagPage.Body)
	if err != nil {
		log.Fatalln(err)
	}
	flag := doc.FindMatcher(goquery.Single(".alert-info")).Text()
	fmt.Println(flag)
}