Showing posts with label #RE. Show all posts
Showing posts with label #RE. Show all posts

Monday, 8 October 2018

mast3r - InCTF 2018

Hope all of you had fun playing InCTF 2018!

We had a variety of challenges this year. I made the challenge mast3r, it's based on unicorn engine, the platform emulation framework. Sometime back I was trying to write a binary analysis tool using unicorn engine and had found the framework to be awesome. So this time I thought of making a challenge using unicorn. You can find the challenge files here.

There are 2 files given in this challenge. The file mast3r is the challenge file, if you dont have unicorn engine installed, you will need to use the second file libunicorn.so.1 to run the challenge, just set the environment variable LD_LIBRARY_PATH to the path of libunicorn.so.1 and after that you will be able to run the challenge.


Briefly speaking, there are 2 stages for this challenge. The checks in the first stage happens in emulated ARM code and the checks in second stage happens in x64 and emulated MIPS code. The user needs to pass both the stages to get the flag.

If you are not familiar with unicorn I suggest you to take a look at this tutorial. Just get a basic idea on how the emulation happens and continue reading.

The main function clearly shows that there are two stages, check1 takes input1 as parameter whereas check2 takes input2 as patameter, if both checks are passed then the printflag function is called, which prints out the flag by wrapping input1 and input2 between inctf{}.

While running the challenge, we saw that the program prints out invalid length. So, lets see what happens inside the first check. Below is the check1 function.



Check1: In this check, first of all, the length of input is checked, if the length is not equal to 20, the program exits by printing invalid length. If the length is correct then an instance of unicorn engine is created using the function uc_open, it takes architecture, mode as first, second arguments respectively. In the compiled binary you can see only the enum constant and not the string. So, you will have to refer the source to find it. You can find all the details related to architecture and mode there.

Now, we know that 1 is for ARM and 0 is for little endian mode. If the uc_open function was successful then memory is mapped and some data is written at addresses 0x10000, 0x11000 and 0x12000. From the arguments of uc_emu_start function we know that code being emulated starts at address 0x10000 and ends at address 0x100044. Your input gets copied to the address 0x11000 and at address 0x12000 a const string "xt=aok}x=~as}a~<<xw}" is written. Then the emulation starts, if it was successful then register r11 (enum const 77) is read and the value is copied to v6. The same value is returned as result and from the main function we know that the return value must not be equal to zero. Let's fire up radare2 and dump the code being emulated.


The offsets in the above image does not start from 0x10000, you can use rasm2 to make the base address 0x10000.


We can write a small python script to pass the above check.



Let's give this input to the program and see what happens.


Yay! We passed the first stage. So the correct input was th3_mast3r_is_r00tus. But we have reached half way only, need to pass the next stage as well to get the flag.

Check2: Diving into check2 we see lot more code. Following the same procedure as check1, we can find that MIPS code is being emulated here. The input must be of length 24. It is divided into several parts and is copied into few registers and other memory locations which are used during code emulation. All details regarding MIPS registers in unicorn can be found here. Emulated code starts at address 0x10000. After emulation some register values are being checked. Try to understand the following pseudocode to get a better idea about the check.


We can see a hook function in the above code. Let's take a look at that as well. We can understand that instructions are getting hooked and a number of registers are being read. At addresses 0x10010, 0x10020, 0x10030, 0x100D0 few more check are happening and we need to pass those as well.


Let's dump the code being emulated and try to understand it. I dumped the code (at address 0x00401758, size 0xf8) using rasm2 and beautified it a bit to view the addresses.

There are different types of checks happening in this stage. Some checks happen before emulation, some during and some after emulation.

Remember the length of input in this stage is 24. The following check happens before emulation. The last 8 characters of the input must be "un1c0rn!", found during the begining of check2, compared using strcmp. Next, two different types of checks happen during emulation. As I said before, few checks happen by instruction hooking see the hook function to find at which addresses these checks happen, other checks happen in the MIPS code itself, some character by character comparisons. The final check, in the MIPS code, some characters of the input are incremented and stored into registers then checked after the emulation. See the final part of check2 function. You can solve all these checks without any scripts.

We need to find an input which will satisfy all these checks and that input is 3r_and_h3_l0v3s_un1c0rn!.

Once we pass this stage the printflag function is called.


Lets run the program and see what happens.


Finally, the flag is printed out:
inctf{th3_mast3r_is_r00tus3r_and_h3_l0v3s_un1c0rn!}


I hope you had fun while reversing it. Please let me know if you have any doubts.

Happy hacking!

Sunday, 11 February 2018

Quad Math - HackIM 2018

This time HackIM had a variety of RE challenges. There was one LLVM IR, one ARM, one Mach-O, one Linux x64 and one more(didn't unlock it, so don't know about that).

I solved the ARM challenge, named Quad math. It was a 150 pointer challenge. I couldn't run it. So I fired up radare to analyse it statically. The main function looked something like this:

       

From the disassembly, it is clear that the binary takes one string as input, then it goes through a series of checks, and finally the result gets printed out. There were a total of 65 check functions which checked the input, character by character. But the checks turned out to be a little short as multiple correct answers were being accepted by the binary. It will become clear in a little while. And each of the checking functions looked something like this:

 

It is actually checking the first and third character of the input(i.e. flag).

        void func_6b8()
        {
             fin = input[0] * input[0] - 203 * input[0] != -10296 || input[2] * input[2] - 203 * input[2] != -10296;
        }

Rest of the characters were being checked similarly(i.e. two alternate characters at a time). So, what I did is, I wrote a z3 script to find the correct input.


As I earlier said, the constraints for checking the flag were a little less, therefore the script printed out many possible answers. So I sent few of them having only printable characters to the admin and he was kind enough to send me the correct flag which will be accepted by the server.

The correct flag was:

hackim18{'W0W_wow_w0w_WoW_y0u_h4v3_m4th_sk1ll5_W0oW_w0ow_wo0w_Wo0W'}

Tuesday, 6 February 2018

Codegate CTF 2018 Preliminary - Boom

Even though I didn't solve any challenge during the CTF, Codegate was fun. There were a variety of RE challenges this time. Half of the day I tried the challenge Easy Serial. I understood that it was a haskell program. I haven't used it before and debugging in GDB did not make much sense as haskell programs do not use the conventional stack. I read about haskell program and it's stack structure then left it midway to look at the challenge Boom. I guess this challenge can be solved in many ways. I approached it in the following way:

Boom was written in rust. I tried running the program.


From the output it is evident that there are 5 stages in this challenge.

Let's figure out what is the first one. Inside the main::main function there is a function called main::func1 which looks interesting. The first input and check happens in that function itself.
We can see an if statement and a string compare in it. Our input is compared with the string "Know what? It's a new day~". If it is correct then main::func13 checks if the file /tmp/files/1 is present or not. If that is present then only we move on to the second check.
The second check happens in the function main::func2. First of all it checks if the input has 7 characters. In this case, the characters are space separated integers which will become clear with little debugging.

This is a predefined array in the program:
f7*zq5$ase0t6ui#^yd2owgb_n8pu4!k&vc@lrj19mx3h

The input is 7 integers which after few calculations must match with the position of characters of the string pand0ra in the above array. With a little trial and error along with one of my teammates, I was able to find the correct input as 57 14 23 92 50 7 14. If it is correct then the check for file /tmp/files/6 happens. If that is present then we move on to the next check.

The third input is also a string of integers i.e. 25 space separated integer values. Put a breakpoint in GDB at the address of _ZN4main5func717h1a0f9200721da090E+2791 and we can observe that the value at rdx (our input, one character at a time) is compared with QWORD PTR [rax+rsi*8]. To get all the values at that memory location, I wrote a small GDB script.
Running the script at that address gives the correct input and that is:
17 24 1 8 15 23 5 7 14 16 4 6 13 20 22 10 12 19 21 3 11 18 25 2 9

Now make the file named 10 at the same location as other files. So now we have passed the first 3 checks. Moving onto the 4th check. 

The 4th input is just an integer. The most important check for it happens in the function _ZN4main6func1217h2c7664a1999a9c74E. The integer should be such that the return value of the function must be 0x6b.

I was too lazy to reverse the function, so I wrote a GDB script to bruteforce the correct input. The correct input is 188. Also we need to have a file named 13 at the location /tmp/files.
The final input is a bit confusing because many values are possible (that might be the reason why they hosted the challenge on a server). We need to enter 4 indexes as input. I gave the input 1 1 1 1 and it worked.

The complete output of the binary:

This is just a brief summary of how to solve the challenge. There are many checks and exception handling in the program. I hope giving these inputs on the remote server will print the flag, can't confirm as the server is down after the CTF.

Wednesday, 5 April 2017

Starblind - Teaser CONFidence CTF 2017

This was a 200 points reverse engineering challenge.
Challenge Description:

The light of the star is blinding.

Clicking on the above link, it redirects to another website. It was actually very surprising to get a link to a website as a reversing challenge. When we view the source code, we can find a javascript link which is base64 encoded. After decoding, we get the following file Starblind.html.

The input to be supplied is 27 characters long. After encoding it using  CalcSHA4, it is compared with the following string:
983bb35ed0a800fcc85d12806df9225364713be578ba67f65bc508b77f0c54878eda18a5eed50bac705bdc7db205623221e8ffe330483955a22216960754a122

I guessed that the correct input must be the flag. Actually, some junk values were being added to our input to make its length 64. Then is was encoded by two functions xor and perm. Each function was being called alternatively. The xor function had an array of length 64 as argument and perm had an array of length 512 as argument. Then many operations were being carried out on our input with the help of those arguments. In total both of those functions were being called alternatively for a total of 512 times.

The functions were being called in the following order:
perm()
xor()
perm()
xor()

What we have to do is this:
reverse_perm()
xor()
reverse_perm()
xor()

Now lets see what the perm function actually does:
        let perm = function(imm) {
            let n = new Uint8Array(64);
            for (let i = 0; i < 512; i++) {
                const dst_bit = i % 8;
                const dst_byte = i / 8 | 0;
                const sign = Math.sgn(imm[i]);
                const idx = sign ? -imm[i] : imm[i];
                const src_bit = idx % 8;
                const src_byte = idx / 8 | 0;
                let b = (r[src_byte] >> src_bit) & 1;
                if (sign) {
                    b ^= 1;
                }
                n[dst_byte] |= b << dst_bit;
            }
            r = n;
        };
What this function is actually doing is,
n[dst_byte][dst_bit]=r[src_byte][src_bit]
The function does this for each bit. So the total no. of iterations will be 64 X 8 times i.e 512.
Finally the value of n is saved to r. Then xor function is called with the integer array of length 64 as argument. Then r is xor ' ed with that array and result is stored in r. The same things are repeated again and again for a total of 512 times.

Now what I did is decode the encoded string given in the program to find out the flag. For that I wrote the following script:

Finally the script prints out the following flag:

DrgnS{Humank1ndEmpire0fAbh}

Sunday, 26 March 2017

KeyPass - VolgaCTF 2017

This was a 100 points re challenge.
The challenge description was as follows:

For reasons unknown an amature cryptographer wrote an application to generate "strong encryption keys". One of these keys was used to encrypt a tar archive with the flag. They used openssl command line util with -aes-128-cbc. Could you please get the flag? It shouldn't take much time...



The file command gives the following output:
~/D/V/keypass 100 ❯❯❯ file flag.zip.enc keypass
flag.zip.enc: data
keypass:      ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=a2bcacc1e853c36e757ec1608a37f79b30315da4, stripped


Now,
What we have to do is decrypt flag.zip.enc using a particular key generated by the program keypass.

So, we have to find the right key.

When I tried running the program, it asked for a command line argument, so I supplied it with a random input, it gave out the following ouput:

~/D/V/keypass 100 ❯❯❯ ./keypass asdf
evMSVbNx7SmvxT#46

Then I loaded the file in IDA and then disassembled it. The main function looks like this.



First of all, it was checking if the number of command line arguments supplied was 2. If it is true then it goes inside the if condition else it exits the program.

If argc==2, the next thing the binary does is calculate the length of the input. After that we can see a while loop. The loop is actually, xor-ing the characters of the input one by one starting from the first character to the last character. The final value is stored in v5.

Then a buffer v24, of size 256 bytes is allocated. After that the value of v7 is calculated as 
v7= 16631*v5*511115. 

We can also see that there is an array arr[ ] . So I checked what is stored at that address using gdb and I got the following string.

gdb-peda$ x/s 0x0400A41
0x400a41: "2FuMlX%3kBJ:.N*epqA0Lh=En/diT1cwyaz$7SH,OoP;rUsWv4g\\Z<tx(8mf>-#I?bDYC+RQ!K5jV69&)G"

So it is character array of size 82.
From the ida disassembly we can see that, the array index is calculated by the mod of 0x7fffffff and 82.
As shown in the disassembly the same thing is repeated again and again. Total 17 times. Therefore the output of the program or our key is calculated in the above manner.

After the xor-ing of the input the value in v5 can vary between 0x0 to 0x7f. So we have a total 0x80 possibilities. One of them is the right key.

So what I did is bruteforce all the possible keys and then try to decrypt the flag.zip.enc using openssl. But make sure that the openssl version is 1.1.0e or higher. The reason for the same can be found in the comments section.

This is the script I wrote for bruteforcing and decrypting the flag.zip.enc file using openssl:


The output that I got after running that script is:
\M)R<.DDe/:;d>JZP

It is the right key to decrypt the flag.zip.enc file.
After running the script, you can see the decrypted flag.zip file in the parent folder.
Simply extract the .zip file. After extracting, you can find flag.txt inside which is the flag.

The flag is :


VolgaCTF{L0ve_a11_trust_@_few_d0_not_reinvent_the_wh33l}



If you have any doubts, feel free to ask in the comments section.

Thursday, 9 February 2017

ALEX CTF 2017


RE5: packed movement


It was fun playing Alex CTF. Most of the challenges were simple yet very interesting.
As usual, first I checked what kind of a binary this was using the file command:
file move
ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, stripped
I then tried opening it in IDA, but it refused to open. So I asked the admin what the matter was.
He said that the binary was somehow packed and I need to unpack it.
Now I needed to find the type of packing and then unpack it.
So, I tried binwalk on the the binary. It showed the following:

1. ELF, 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux)
2. Copyright string: "Copyright (C) 1996-2013 the UPX Team. All Rights Reserved. $"

As you can see, this file was packed using UPX packer.
So I installed UPX and ran the following command on the file:

./upx -d move

Now the file is unpacked.
When I finally opened the file in IDA, I saw that it was movfuscated (obfuscation). Now I had to demovfuscate it to understand what the input should be.
So I google for demovfuscator and found the following link to be useful:
https://github.com/kirschju/demovfuscator
I installed it and deobfuscated the binary.
Now everything's set. We just need to find the flag... :p
For that I have the following script ready. I found it somewhere online, I don't remember where.
This is the script:


Perf is a Performance counter for Linux. What this script does is count the number of instructions executed for each input (where the input is a printable character). Then append that input to the string key, which made the compiler execute the maximum number of instructions. The same process is repeated until the closing bracket is encountered ( '}' ).
The string which we finally obtain is the flag.

ALEXCTF{M0Vfusc4t0r_w0rk5_l1ke_m4g1c}

Sunday, 5 February 2017

BITS CTF 2017

RE20: Mission improbable


This was a hexdump file. It was an easy challenge.

I used xxd tool to  convert the file back to binary form.

    xxd -r -p MissionImprobable.TEENSY31.hex  out


Then I tried strings command on the out file.
There were only a few strings, so I looked at those, and there I saw a string:
BITCTF{B4d_bad_U5B0

I then just replaced the 0 with a '}'.
That's it, it's the flag.

    BITCTF{B4d_bad_U5B}

RE80: Riskv and Reward


First of all I used the file command.

    riskv_and_reward: ELF 64-bit LSB executable, UCB RISC-V, version 1 (SYSV), statically linked, stripped

The file command says it is in RISC-V arch.

So we need to use an emulator.

I  googled for it and found this:
    
    https://github.com/riscv/riscv-qemu

So I installed it as per the instructions mentioned in it's git repository.

After installing I tried to debug it , and it started to gives me many errors. I tried to fix those and it took a lot of time. Then I thought that I haven't run it till now, so why not give it a try.

I must say, I was shocked, the bin printed out the flag.

I didn't expect a 80 point challenge to be this simple.

The flag was:

    BITSCTF{s0m3_r1sc5_4r3_w0rth_1t}

Sunday, 18 December 2016

Sharif CTF : RE Challenges

The first 3 re challenges were very simple. Out of the 4 others 3 were windows re and 1 was an apk file.

I could solve only the first 3.

Getit - 50 Points challenge

This challenge I couldn't understand the disassembly much. I was just stepping through the code in GDB. Saw a string comparison, above that a string was being moved to edi. It turned out to be the flag. :-)

      0x40081c <main+198>: movsxd rbx,eax
      0x40081f <main+201>: mov    edi,0x6010e0
      0x400824 <main+206>: call   0x4005e0 <strlen@plt>
=> 0x400829 <main+211>: cmp    rbx,rax

The flag was stored at address 0x6010e0, it was moved to rdi.
We can see that by-

      x/s $rdi

Flag :

SharifCTF{b70c59275fcfa8aebf2d5911223c6589}


RepairMe - 100 Points challenge

I don't know why they gave this challenge. I got the flag while just executing it.

Flag :

SharifCTF{98ad7e41c78b7df41cb2ad0c17c61408}


SCrack- 150 Points challenge

In this challenge either you have to give right input to get the flag or you can get the flag directly by examining the disassembly. I chose the second way. Starting from the following address, start converting the hex value which is being moved to esi into character. First character will be 'S'. Till you get the whole flag repeat the same  process.

      0x0000000000400c50 <+515>: mov    esi,0x53
      0x0000000000400c55 <+520>: mov    edi,0x6021c0
      0x0000000000400c5a <+525>: call   0x4008e0  <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_c@plt>
      0x0000000000400c5f <+530>: mov    esi,0x68
      0x0000000000400c64 <+535>: mov    rdi,rax
      0x0000000000400c67 <+538>: call   0x4008e0    <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_c@plt>

Finally you will get the flag as:

SharifCTF{ed97d286f356dadb5cde0902006c7deb}

Monday, 21 November 2016

RC3 CTF - Logmein

This re challenge was pretty simple.

First of all I saw the following pseudo code of the binary file.
We can easily understand what is going on in the program by looking at the code.



We have to reach the CorrectPass function by giving the correct input i.e the flag.
I was particularly interested in the second if statement inside the for loop.

So I put a breakpoint  at that statement in GDB.



So the rdx and rdi values are being compared. After each true comparison we will get the char of the next comparison. So just make sure that you change your input according to the register values after each iteration.

Finally I found the flag to be:

RC3-2016-XORISGUD

Thanks for reading

Monday, 22 August 2016

BioTerra CTF - Wathzefugg

This RE challenge was pretty easy. It compares between each character  of two different strings and stores the character which has higher ascii value at another location. All the characters with the higher ascii value form the flag of the challenge.

I have used IDA pro and GDB to solve the challenge.

1. Go to the main function after loading the file in IDA. There we can see the two strings used for comparison and a function call before the puts statement, go to that function.

1

2. In that function we can see a comparison statement. It is used to compare between the ascii value of each character of string 1 with that of string 2.

21

3. After the comparison the value is stored at [rax], put a break point at the address of loc_400703 in GDB and then keep noting the [rax] value after each iteration.

22

After the final iteration you will get the flag as:

{Easy_P3aSyeLpk3NwraTJJmEcvKRUr}


Also for the better understanding of the you might want to look at the pseudocode produced by IDA :

23.jpg

Thanks for reading.