Monday, 19 November 2018

Gimme sum fud RITSEC CTF 2018

In this challenge, we are given a 64-bit ELF binary which is compiled from Go code.

file command output:

$ file pwn3
pwn3: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.2.0, BuildID[sha1]=7bf36f31cd9a2014bad5fb119d30119e3ea0cad9, not stripped

We can confirm that the binary was compiled using Go language with the following command:

$ readelf -e pwn3 | grep -i .gopclntab
  [19] .gopclntab        PROGBITS         00000000004d9740  000d9740
   04     .rodata .typelink .itablink .gopclntab .eh_frame_hdr .eh_frame

The binary has a section called ".gopclntab" which is corresponding to Go compiled binaries.

Let's execute the binary:

./pwn3

Gimme some bytes, I'm hangry...
1234
mmmmm...., your 1234
 is so good. Thanks. Bye.

So, the binary expects some input and the input is printed back to stdout along with some other text.

We can get more details using ltrace as well:

malloc(16)                                                                                    = 0x5631a0
malloc(100)                                                                                   = 0x563420
malloc(10)                                                                                    = 0x563050
Gimme some bytes, I'm hangry...
read(01234
, "1234\n", 4919)                                                                       = 5
mmmmm...., your printf("%s", "1234\n"1234
)                                                                        = 5
 is so good. Thanks. Bye.+++ exited (status 0) +++

Also in the above output, we can see 3 buffers. These will be useful later.

In the main subroutine, we can see that the binary reads the flag from flag.txt file.


Inside, main_main_func1 subroutine, it allocates new memory and copies the flag to this memory location using memmove() as shown below:


It then reads the input from the user and prints it back as shown below:


We can create a new file called flag.txt in the present directory so that it's contents are read while debugging.

Now, to understand how to read the flag in this case, we need to understand the memory layout. Below is the memory layout which shows the location of our input in memory as well as the flag location.

Location of input in memory:


Location of flag in memory:


So, in our case, the input is located at address: 0x563050 and the flag is located at address: 0x563490

The difference between the two memory locations is: 0x440 bytes

It is important to note that the location of flag in memory will change because this memory is allocated using malloc()

The memory layout looks like this: [input][data][flag]

The data in between input and flag contains null bytes as shown above.

In the, main__Cfunc_myGets() function, we can see that the binary reads a maximum of 0x1337 bytes as shown below:


Binary prints the input back to stdout as shown below:


The output is printed using printf() function with a format string, "%s"

This means if the data in between the input and the flag location in memory contains any null bytes, then the flag will not be printed.

So, we have to make sure that all the data between the location of input and the flag does not contain null bytes.

Since we don't know the exact location of flag however we know the format of the flag, we can bruteforce the number of bytes to be sent so that all the space between the flag and the input is filled with data that does not contain null bytes.

I wrote the following code to bruteforce it:


When the string, "RITSEC" is found in the output, it will print the flag.

Flag: RITSEC{Muff1n_G0verFl0w_mmmm}

c0d3inj3cT

Wednesday, 14 November 2018

Gofuscated Square CTF 2018

This is a writeup for the Gofuscated challenge in Square CTF 2018.

We were provided a Go program which takes a 26 characters input and performs several checks on it. If all the checks are true, then the value of flag will be printed.

Note: In Go language, you can print the value of the variables using fmt.Println(). This will be useful while solving the challenge.

The main function of the Go program looked like shown below:


There were 4 compute functions and their purpose is as follows:

1. compute1: It displays an interesting animation :)

2. compute2: It runs a long FOR loop for Space * Rounds iterations (total iterations: 100000 * 100000). This will take a few minutes to complete. After completing the iterations, it returns a 16 bytes hex string.

h := compute2([]byte(input), done)

As we can see later in the code, h corresponds to our flag:

flag := <-h

3. Before the flag, we have a call to the function, another_helper() and we can see that the return value of this function should be true so that our flag is printed.

4. another_helper() function takes an input string which was generated by compute4()

So, let's see how compute4() is used to process our input.

It first generates a mapping as shown below:


We can print the value of the map using fmt.Println(m)

This gives us the mapping as:

[100:113 114:114 109:121 107:122 122:102 97:104 111:110 110:97 102:106 116:120 112:119 118:101 106:111 117:112 113:103 105:105 115:107 121:108 104:109 120:98 101:99 108:100 103:118 98:115 99:116 119:117]

Then, this mapping is used to shuffle the characters in our input string.

If our input is: abcdefghijklmnopqrstuvwxyz

Then after shuffling the characters in the input using the above mapping we get: hstqcjvmiozdyanwgrkxpeublf

This value is passed to another_helper() function to validate.

another_helper() function is as shown below:


It checks the input to ensure that the ASCII value of each character is less than or equal to the ASCII value of the characters after it.

So, if another_helper() function receives: abcdefghijklmnopqrstuvwxyz as an input, it will return us true.

To solve this challenge, we need to pass an input such that compute4() function returns us: abcdefghijklmnopqrstuvwxyz

We can leverage the mapping above to get the value of an input which satisfies the above requirement.

Input: nxelvzqaifsyhojudrbcwgptmk

Now, we can pass the string: "nxelvzqaifsyhojudrbcwgptmk" as an input to the program and it will print our flag as shown below:

flag-705787f208e6eff63768ae166482125b

c0d3inj3cT

Postfuscator - Square CTF 2018

This is the writeup for Postfuscator challenge in Square CTF 2018.

We were provided a shell script which takes a key as an input and writes the key inside a postscript file.

The postscript file was obfuscated.

Postscript is a stack based language and ghostscript interpreter can be used to debug it.

So, this is how the generated Postscript file looks like:


Important things to note from the Postscript file:

1. The size of the input is 65 bytes.
2. encrypt_str is a function which generates an encrypted string by doing an XOR encryption using an 8 byte key, "4L0ksa1t" and the input.
3. test_str is a function which takes the encrypted output generated by encrypt_str() function and processes it.
4. Inside test_str() function, buf_z holds an encoded string. We can see that it is decoded as follows:

buf = LZWDecode(ASCIIHexDecode(buf_z))

So, how do we decode it? We could rewrite the implementation for ASCIIHexDecode() and LZWDecode() and then pass the encoded string to it ;)

Or we could leverage the ghostscript interpreter to output this value for us.

In ghostscript interpreter, you can print the value of a variable using "=" operator.

So, to print the value of buf which will store the decoded output, we can add a "buf =" statement after buf.

It is important to note that if you only use the "=" operator, it will pop the value from the top of the stack. Doing this will change the stack and have an impact on execution of program as it proceeds. So, its better to use "buf ="

After decoding it, we get:

buf = "1712009367807218646859018292134521568805686127287089876612468382748236461208592688982686121828975882178245515674851882"

test_str() function also has a for loop which can be rewritten in Python as follows:


Since Postscript is a stack based language, when the encrypt_str function was called to encrypt our input with an 8 byte key, each encrypted byte was pushed on to the stack. Also, the value is stored in decimal form and not hex which is important to note as well.

So, each encrypted value is read from the stack and based on the length of it, the corresponding number of digits from buf are compared with it. Each time they are equal, the variable ok is incremented by the length of the value which was compared.

At the end of the FOR loop, if ok == len(buf), then it means that our input was correct.

Also, len(buf) = 118

To solve this challenge, we need to find an input such that when it is encrypted with an 8 byte XOR key: 4L0ksa1t, then each value of the encrypted output should match the corresponding place in the buffer.

In the shell script provided to us which was used to generate the PostScript file, we can see the following line:

echo $key | tr -Cd a-f0-9 >> postfuscator.ps

This means that our input contains the charset: a-f0-9 (only hex values)

Also, a "%" symbol was added as a  prefix to the input.

Now, I generated all the possible encrypted values for each combination of XOR between the digits of input and each byte of the 8 byte XOR key.

For example:

When the first byte of our XOR key: "4" is encrypted with each possible combination of input charset, we get:

['4', '%', 17]
['4', '0', 4]
['4', '1', 5]
['4', '2', 6]
['4', '3', 7]
['4', '4', 0]
['4', '5', 1]
['4', '6', 2]
['4', '7', 3]
['4', '8', 12]
['4', '9', 13]
['4', 'a', 85]
['4', 'b', 86]
['4', 'c', 87]
['4', 'd', 80]
['4', 'e', 81]
['4', 'f', 82]
 

As you can see, 17 are the first two digits of the buffer. So, we know that the first value in our input should be: %

Similarly, the possible mappings for the next byte of the XOR key are:

['L', '%', 105]
['L', '0', 124]
['L', '1', 125]
['L', '2', 126]
['L', '3', 127]
['L', '4', 120]
['L', '5', 121]
['L', '6', 122]
['L', '7', 123]
['L', '8', 116]
['L', '9', 117]
['L', 'a', 45]
['L', 'b', 46]
['L', 'c', 47]
['L', 'd', 40]
['L', 'e', 41]
['L', 'f', 42]


We can see that input value of 4 after encrypting with "L" gives 120 which are the next 3 digits of the buffer.

Similarly, we can continue finding the remaining bytes of the input and the final value of input is: 

406016abbe1ac8a7a2d7140232c58f68bc9932424e778c025b2893efa5d0edff

We can pass this value as a key to the shell script so that it generates a postscript file. The flag will be present inside the newly generated Postscript as file as shown below:


Flag: flag-6016abbe1ac8a7a2d714

c0d3inj3cT