OTP Smasher — H@cktivityCon 2021 CTF

ScreaM
3 min readSep 19, 2021

--

This is my write-up for H@cktivityCon 2021 CTF. I had already completed 2 of the challenges, I noticed that points were dependent on the number of solves. So to get more points for the team I decided to go for the challenge which would have fewer attempts like scripting challenges. The one I knew could be solved was OTP Smasher.

The description of the challenge hints at automating the process.
First look at OTP Smasher.

The image had an OTP which had to be submitted continuously. For the flag to appear I had to read OTP from the image and submit these OTP instantaneously and continuously. After having a closer look, I noticed there is a number that marks the number of correct submissions. It was obvious to use OCR to get OTP then submit the number.

So my first attempt was using python with pytesseract to read numbers and then use selenium to submit. However, after completing the code, I realized selenium is too slow. The count went up 1 then again to 0. Hence the idea of using selenium was dropped. I even tried to send concurrent requests but the count would reset 0 as the same OTP was sent multiple times.

I spoke about this with my team member Dexter0us. So his idea was to use Golang for this challenge, and even multi-thread this process if needed. For this code to work, you will need to install tesseract.

Here is a snippet of our code.

package main

import (
"fmt"
"io"
"log"
"net/http"
"net/url"
"os"
"strconv"

"github.com/otiai10/gosseract/v2"
)

func smasher() {

i := 0

for {
response, e := http.Get("http://challenge.ctf.games:30911/static/otp.png")
if e != nil {
log.Fatal(e)
}
defer response.Body.Close()

fileName := "/tmp/" + strconv.Itoa(i) + ".png"

file, err := os.Create(fileName)
if err != nil {
log.Fatal(err)
}
defer file.Close()

_, err = io.Copy(file, response.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Request no: %d, OTP: ", i+1)

client := gosseract.NewClient()
defer client.Close()
client.SetImage(s)
otp, _ := client.Text()
fmt.Println(otp)

resp, err := http.PostForm("http://challenge.ctf.games:30911/",
url.Values{"otp_entry": {otp}})

if err != nil {
log.Fatal(err)
}

defer resp.Body.Close()

resCode := resp.StatusCode

if resCode != 200 {

fmt.Println("Exiting as response code: ", resCode)
os.Exit(3)

}

flag, err := http.Get("http://challenge.ctf.games:30911/static/flag.png")
if e != nil {
log.Fatal(err)
}
defer response.Body.Close()

if flag.StatusCode == 200 {
file, err := os.Create("/tmp/flag.png")
if err != nil {
log.Fatal(err)
}
defer file.Close()

_, err = io.Copy(file, response.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println("Flag Found! : ")

client := gosseract.NewClient()
defer client.Close()
client.SetImage("/tmp/flag.png")
flagText, _ := client.Text()
fmt.Println(flagText)
os.Exit(3)

}

i++
}

}

func main() {

smasher()
}
The flag
The flag

In the end, we didn’t need to multi-thread the code. And also here is gist of the code.

And lastly, if you’re to join my team and be a part of the community, come join the Bounty Hunters Discord! https://discord.gg/bugbounty.

--

--

ScreaM

A Computer enthusiast ,gamer, programmer and learning to hack