Raspberry Pi Zero W: Headless bring up (Raspbian)

The following article describes the most straightforward way to setup and connect a Raspberry Pi Zero W to your WPA2 Wi-Fi network.

Preparation

Download and unpack the image:

wget -O raspbian-stretch-lite.zip https://downloads.raspberrypi.org/raspbian_lite_latest
unzip raspbian-stretch-lite.zip

Mount the image to the local filesystem:

su -c 'losetup -f --show 2017-11-29-raspbian-stretch-lite.img'
  /dev/loop0
su -c 'partx -a /dev/loop0'
mkdir boot root
su -c 'mount /dev/loop0p1 boot'
su -c 'mount /dev/loop0p2 root'

Enable SSH server

su -c 'touch boot/ssh'

Configure Wi-Fi interface

Automatically setup wlan0 for DHCP:

su -c 'emacs root/etc/network/interfaces'
source-directory /etc/network/interfaces.d
+
+auto wlan0
+allow-hotplug wlan0
+iface wlan0 inet dhcp
+    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

Create and open file wpa_supplicant.conf:

su -c 'emacs root/etc/wpa_supplicant/wpa_supplicant.conf'

Configure wpa_supplicant according to your Wi-Fi network:

-country=GB
+country=DE
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
+
+network={
+  ssid="YOUR_SSID"
+  psk="YOUR_PSK"
+  proto=RSN
+  key_mgmt=WPA-PSK
+  pairwise=CCMP
+  auth_alg=OPEN
+}

Clean up

Unmount image partitions and clean up:

su -c 'umount root'
su -c 'umount boot'
su -c 'partx -d /dev/loop0'
su -c 'losetup -d /dev/loop0'

Install image to MicroSD card

Insert the MicroSD card into your host computer and check the systemd journal for the appropriate device node:

journalctl -k -f | grep sd
  ...
  Jan 23 20:41:10 discordia kernel:  sdb: sdb1
  ...

Use dd to write the image to the card:

Be careful when running the following command! The output file (of) has to be the MicroSD card's device node!

su -c 'dd bs=4M if=2017-11-29-raspbian-stretch-lite.img of=/dev/sdb conv=fsync'

Now put the MicroSD card into your Raspberry Pi and attach the power supply. Give the device some time to boot up.

Connect to the Raspberry Pi

Scan your local network for the Raspberry Pi:

nmap -p22 192.168.1.0/24 | grep raspberrypi
  Nmap scan report for raspberrypi (192.168.1.27)

Finally connect to it via SSH:

ssh pi@192.168.1.27

Emulate Raspberry Pi with QEMU

It's not always practical to carry around a Raspberry Pi when you just want to do some basic ARM development or research. azeria-labs.com has a great article about how to emulate a Raspberry Pi (running Raspbian) with qemu. However, since not everybody likes the Debian based antiquary distro, this article shows how to do the same with Arch Linux ARM on a host system running a recent version of qemu:

qemu-system-arm --version
  QEMU emulator version 2.11.0

Preparation

We need a proper kernel and the Arch Linux ARM distro for the Raspberry Pi system. You can get both using wget:

wget https://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/kernel-qemu-4.4.34-jessie
wget http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-latest.tar.gz

Check the qemu-rpi-kernel github page for a more recent kernel if needed.

Image creation

Choose an appropriate size for your image, I'll go for 8 GiB in this example:

dd if=/dev/zero of=Arch.img count=8192 bs=1048576

We create two partitions inside the image, one 100 MiB partition for /boot and one / partition filling the rest of the image:

fdisk ./Arch.img
  Command (m for help): n
    Partition type
      p   primary (0 primary, 0 extended, 4 free)
      e   extended (container for logical partitions)
    Select (default p): p
    Partition number (1-4, default 1):
    First sector (2048-16777215, default 2048):
    Last sector, +sectors or +size{K,M,G,T,P} (2048-16777215, default 16777215): +100M

    Created a new partition 1 of type 'Linux' and of size 100 MiB.

    Command (m for help): n
    Partition type
      p   primary (1 primary, 0 extended, 3 free)
      e   extended (container for logical partitions)
    Select (default p): p
    Partition number (2-4, default 2):
    First sector (206848-16777215, default 206848):
    Last sector, +sectors or +size{K,M,G,T,P} (206848-16777215, default 16777215):

    Created a new partition 2 of type 'Linux' and of size 7.9 GiB.

    Command (m for help): w

Arch Linux ARM installation

Using losetup and partx, we setup a loop device for the image and add specific partitions:

su -c 'losetup -f --show Arch.img'
su -c 'partx -a /dev/loop0'

The partitions are now accessible as /dev/loop0p1 and /dev/loop0p2 within the local filesystem. Time to create an appropriate filesystem for each partition. We choose FAT for the /boot partition and ext4 for the / partition.

su -c 'mkfs.vfat /dev/loop0p1'
su -c 'mkfs.ext4 /dev/loop0p2'

We are now able to locally mount both partitions:

mkdir boot root
su -c 'mount /dev/loop0p1 boot/'
su -c 'mount /dev/loop0p2 root/'

The following commands install Arch Linux ARM to the image:

su -c 'bsdtar -xpf ArchLinuxARM-rpi-latest.tar.gz -C root/'
su -c 'mv root/boot/* boot/'

Since ArchLinuxARM-rpi-latest.tar.gz was created to fit onto a SD Card, the fstab file does not yet fit our needs. Without the following changes to fstab, the kernel would not find the partitions:

emacs root/etc/fstab
# Static information about the filesystems.
# See fstab(5) for details.

# <file system>  <dir>   <type>  <options>      <dump>  <pass>
-/dev/mmcblk0p1  /boot   vfat    defaults        0       0
+/dev/sda1       /boot   vfat    defaults        0       0
+/dev/sdb2       /       ext4    defaults        0       0

Now unmount the partitions and clean up things:

su -c 'umount /dev/loop0p1'
su -c 'umount /dev/loop0p2'
su -c 'partx -d /dev/loop0'
su -c 'losetup -d /dev/loop0'

Run the guest system

Let's finally run the Raspberry Pi image with qemu-system-arm:

qemu-system-arm -kernel kernel-qemu-4.4.34-jessie -cpu arm1176 -m 256 -M versatilepb -serial stdio -append "root=/dev/sda2 rootfstype=ext4 rw" -hda Arch.img -net nic,macaddr=de:ad:be:ef:ca:fe -net user,hostfwd=tcp::5555-:22

Note from the command above, that qemu will forward the guest's TCP port 22 (SSH) to the host TCP port 5555. Login into your guest system as root and activate the SSH server:

systemctl enable sshd
systemctl start sshd

Now you should be able to SSH from your host into your guest system:

ssh -p 5555 alarm@127.0.0.1

CodeMash 2018 CTF write-up

01 Do you like my Style?

Every one is talking about styles. Sometimes its about what you wear and sometimes its about what you do.

All I know is that the flag you want definitely has Style.

The Web Developer Tools (available for Firefox and Chrome) easily reveal the flag:

Flag01

The flag:

cm18-te94-1tuJ-ddx9-3dQO

02 Hobo Robo

Hobo Robo prepared a paper chase for you.

Start

A click on the provided link redirects to the C-3PO Wikipedia site. Downloading the site with wget sheds some more light into the dark.

wget https://codemash.hacking-lab.com/codemash/bots/bots.html
<html>
  <head>
        <title>Bots</title>
        <script type="text/javascript">
          eval(String.fromCharCode(105, 102, 32, 40, 33, 40, 110, 97, 118, 105, 103, 97, 116, 111, 114, 46, 117, 115, 101, 114, 65, 103, 101, 110, 116, 32, 61, 61, 61, 32, 39, 72, 111, 98, 111, 82, 111, 98, 111, 39, 41, 41, 32, 123, 32, 108, 111, 99, 97, 116, 105, 111, 110, 46, 114, 101, 112, 108, 97, 99, 101, 40, 39, 104, 116, 116, 112, 58, 47, 47, 101, 110, 46, 119, 105, 107, 105, 112, 101, 100, 105, 97, 46, 111, 114, 103, 47, 119, 105, 107, 105, 47, 67, 45, 51, 80, 79, 39, 41, 59, 125))
    </script>
  </head>
  <body style="background: white; border: 20px solid white;">
    <div style="widht: 100%; height: 100%; background: url('./robotbg.jpg') no-repeat center center fixed; -webkit-background-size: contain; -moz-background-size: contain; -o-background-size: contain; background-size: contain;">&#160;</div>
  </body>
</html>

At a first glance, the string looks promising. The following Python code can be used to decode it:

data = [105, 102, 32, 40, 33, 40, 110, 97, 118, 105, 103, 97, 116, 111, 114, 46, 117, 115, 101, 114, 65, 103, 101, 110, 116, 32, 61, 61, 61, 32, 39, 72, 111, 98, 111, 82, 111, 98, 111, 39, 41, 41, 32, 123, 32, 108, 111, 99, 97, 116, 105, 111, 110, 46, 114, 101, 112, 108, 97, 99, 101, 40, 39, 104, 116, 116, 112, 58, 47, 47, 101, 110, 46, 119, 105, 107, 105, 112, 101, 100, 105, 97, 46, 111, 114, 103, 47, 119, 105, 107, 105, 47, 67, 45, 51, 80,79, 39, 41, 59, 125]

buf = ""
for i in data:
    buf += chr(i)

print buf
python2 sol.py
  if (!(navigator.userAgent === 'HoboRobo')) { location.replace('http://en.wikipedia.org/wiki/C-3PO');}

We already know about the redirection, so let's take a look the mentioned URL (url('./robotbg.jpg')):

wget https://codemash.hacking-lab.com/codemash/bots/robotbg.jp
robotbg.jpg

The words

bama waboki pisal fatatu fomu wosebi seju sowu seju - bamas mufe wafub fomu mowewe

are written in the Robot Interaction Language (ROILA) and decode to:

you must make word of addition two and two - this be name of page
wget https://codemash.hacking-lab.com/codemash/bots/four.html

The file content leads to the next URL and the next image:

<html>
  <head>
        <title>Bots</title>
        <meta name="description" content="Robots talk in ROILA language: eman egap eht esrever tsum">
    <meta name="keywords" content="secret, page, robots, fun, hacky easter, blrt, five, beep">
        <script type="text/javascript">
          eval(String.fromCharCode(105, 102, 32, 40, 33, 40, 110, 97, 118, 105, 103, 97, 116, 111, 114, 46, 117, 115, 101, 114, 65, 103, 101, 110, 116, 32, 61, 61, 61, 32, 39, 72, 111, 98, 111, 82, 111, 98, 111, 39, 41, 41, 32, 123, 32, 108, 111, 99, 97, 116, 105, 111, 110, 46, 114, 101, 112, 108, 97, 99, 101, 40, 39, 104, 116, 116, 112, 58, 47, 47, 101, 110, 46, 119, 105, 107, 105, 112, 101, 100, 105, 97, 46, 111, 114, 103, 47, 119, 105, 107, 105, 47, 67, 45, 51, 80, 79, 39, 41, 59, 125))
    </script>
  </head>
  <body style="background: white; border: 20px solid white;">
    <div style="widht: 100%; height: 100%; background: url('./robotbg2.jpg') no-repeat center center fixed; -webkit-background-size: contain; -moz-background-size: contain; -o-background-size: contain; background-size: contain;">&#160;</div>
  </body>
</html>
wget https://codemash.hacking-lab.com/codemash/bots/robotbg2.jpg
robotbg2.jpg

The image shows the word metae, let's take a second look into four.html and especially the meta data entry:

<meta name="description" content="Robots talk in ROILA language: eman egap eht esrever tsum">
python2 -c 'print "eman egap eht esrever tsum"[::-1]'
   must reverse the page name
wget https://codemash.hacking-lab.com/codemash/bots/ruof.html
wget https://codemash.hacking-lab.com/codemash/bots/robotbg3_1337807.jpg
robotbg3_1337807.jpg

03 - 1337 Riddler

1337 r1ddler h4s a puzzl3 f0r u 2 solve!

H3 1s l1st3n1ng 0n th3 BEST p0r7 on this s3rv3r!

The "BEST p0r7"? Let's don't asume, let's test and verify:

nmap -p- codemash.hacking-lab.com
 PORT     STATE  SERVICE
 22/tcp   open   ssh
 80/tcp   open   http
 443/tcp  open   https
 3544/tcp closed teredo
 8357/tcp open   unknown

Port 8357 seems promising, let's verify using netcat:

nc codemash.hacking-lab.com 8357
  Make an educated guess, dude:
  1
  I need 20 digits, dude!
nc codemash.hacking-lab.com 8357
  Make an educated guess, dude:
  11111111111111111111
  0<
nc codemash.hacking-lab.com 8357
  Make an educated guess, dude:
  91111111111111111111
  0>
nc codemash.hacking-lab.com 8357
  Make an educated guess, dude:
  71111111111111111111
  1<

The task seems to be to guess the 20 digit code. The return value gives the number of already correct digits and a hint if the actual guess is smaller or bigger than the correct value.

The following Python code does not endeavour to be the most clever or elegant solution. It just works in a feasible time.

from pwn import *

context.log_level = 'error'

code = "0" * 20

i = 0
while i < 20:
        for j in range(10):
            conn = remote('codemash.hacking-lab.com', 8357)
            ret = conn.recvline()
            assert('Make an educated guess, dude' in ret)
            tmp = list(code)
            tmp[i] = str(j)
            tmp = ''.join(tmp)
            conn.send(tmp + '\n')
            ret = conn.recvline().rstrip()
            ret = ret.replace('<', '').rstrip()
            ret = ret.replace('>', '').rstrip()
            try:
                ret = int(ret)
            except:
                print j, "\n", tmp
                ret = ""
                while not "cm" in ret:
                    ret = conn.recvline().rstrip()
                    print ret

                conn.close()
                sys.exit()

            conn.close()
            if ret > i:
                code = tmp
                print j,
                i = i + 1
                break
python2 03.py
  7 8 0 2 5 9 2 8 2 3 2 9 2 0 7 1 2 9 6 7
  78025928232920712967
  Congrats! Here's your flag:
  cm18-Glz3-yM2k-h9i9-wntS

04 - Super Eyesight

Can you see what others cannot?

Here is an image to prove your super eyesight.

04_image.jpg

Opening the image in Gimp and playing with the color threshold reveals the flag.

04_flag.jpg

05 - Bools for fools

Calculate this!

((not(a) and b) or c) xor d

boolsforfools_fixed.zip

wget https://codemash.hacking-lab.com/codemash/attachments/boolsforfools_fixed.zip
unzip boolsforfools_fixed.zip
ls -ls
   a.txt
   b.txt
   c.txt
   c.txt
cat a.txt
   0111011001000100111111111
   0100011101001101101110100
   ...

The .zip file reveals four ASCII files (a.txt, b.txt, c.txt and c.txt) containing binary numbers. It seems we have to operate on the content of those files:

# 05 - Bools for fools
# Calculate this!
# ((not(a) and b) or c) xor d
#

import sys

def snot(s):
    ret = ""

    for i in s:
        if i == '1':
            ret += '0'
        elif i == '0':
            ret += '1'
        else:
            return False

    return ret

def sand(s1, s2):
    ret = ""

    if len(s1) != len(s2):
        return False

    for i, j in zip(s1, s2):
        ret += str(int(i) & int(j))

    return ret

def sor(s1, s2):
    ret = ""

    if len(s1) != len(s2):
        return False

    for i, j in zip(s1, s2):
        ret += str(int(i) | int(j))

    return ret

def sxor(s1, s2):
    ret = ""

    if len(s1) != len(s2):
        return False

    for i, j in zip(s1, s2):
        ret += str(int(i) ^ int(j))

    return ret

def get_file_content(fname):
    try:
        with open(fname, 'r') as f:
            cont = f.readlines()
    except Exception as e:
        print e
        sys.exit()

    return cont

# ((not(a) and b) or c) xor d

a = get_file_content('a.txt')
b = get_file_content('b.txt')
c = get_file_content('c.txt')
d = get_file_content('d.txt')

not_a = []
for line in a:
    tmp = snot(line.rstrip()) + '\r\n'
    not_a.append(tmp)

not_a_and_b = []
for i, j in zip(not_a, b):
    tmp = sand(i.rstrip(), j.rstrip())  + '\r\n'
    not_a_and_b.append(tmp)

or_c = []
for i, j in zip(not_a_and_b, c):
    tmp = sor(i.rstrip(), j.rstrip())  + '\r\n'
    or_c.append(tmp)

xor_d = []
for i, j in zip(or_c, d):
    tmp = sxor(i.rstrip(), j.rstrip())  + '\r\n'
    xor_d.append(tmp)

for l in xor_d:
    print l,
python2 05.py
  1111111000100110001111111
  1000001011100011001000001
  1011101010000010101011101
  1011101001001010001011101
  1011101011101100101011101
  ...

And now it gets crazy. The output file looks very similiar to the previous ones. So what now? Let's count lines and characters per line:

python2 05.py | wc -l
  25
python2 05.py | head -n 1 | wc -c
  27

Since the Python script added '\r\n' to each line, the actual count is 25.

echo $(( 25*25 ))
625

Lucky you if you know that a Version 2 QR code contains 25 x 25 pixels and indeed, changing the last print statement of the Python script helps to spot a QR code.

-for l in xor_d:
-    print l,
+for l in xor_d:
+    for c in l:
+        print c,
python2 05.py

Highlighting some of the 1 bits in red, clearly shows the QR code:

codemash2018_05_qr_raw.jpg

Adding the following code to the Python script above takes the content of xor_d and creates a file flag.png which finally contains the QR code (credits go to the author of an old writeup for a similiar challenge).

from PIL import Image
from qrtools import QR

binstring = ""
for line in xor_d:
    binstring += line.rstrip()

outimg = Image.new('RGB', (25, 25), "black")
pixels_out = outimg.load()

count = 0
for bit in binstring:
    i = count % 25
    j = count / 25
    if bit == '0':
        pixels_out[(i, j)] = (255, 255, 255)
    count += 1

outimgname = "flag.png"
outimg = outimg.resize((250, 250))
outimg.save(outimgname, "png")
python2 05.py
zbarimg flag.png
  QR-Code:cm18-eJb2-mfTz-pIMu-oKaV

06 - Witchcraft

I was just messing around with my magic wand trying out some new spells and all of a sudden the flag was gone.

All I was left with is the following:

363336643331333832643438363537373432326436383530

333137323264346337393738333932643635373035343465

Can you undo my spell and get the flag?

Abracadabra? Hocus-pocus? Sim salabim? Whizz whizz? Hex hex? Hex hex!

flag = "363336643331333832643438363537373432326436383530"
flag += "333137323264346337393738333932643635373035343465"

print flag.decode('hex').decode('hex')
python2 06.py
  cm18-HewB-hP1r-Lyx9-epTN

07 - Happy Eyes

Barbara really loves to chat with all friends.

To express joy they use the characters ^^ which represent eyes of a smiling face.

Can you find this happy flag?

Hint: Offset by 2

1xT-Gcm8FV-5cYN-iBc-syHW

The characters ^^ do not only represent eyes of a smiling face, but also a zigzag pattern. Lucky you if you already heard about the Rail Fence (ZigZag) Cipher.

codemash2018_07_flag.png

The flag:

cm18-FxVs-T5yc-YHNG-WicB

08 - Lock

The key for that lock got lost.

If you are good at lock picking you will find the flag.

A good tool to decompile Java code is jad (Java decompiler).

jad Lock.class

The decompiled code looks as follows:

package com.hackinglab.ctf;

import java.io.PrintStream;

class Lock
{

    public Lock()
    {
    }

    public static void main(String args[])
    {
              StringBuffer stringbuffer = new StringBuffer();
              for(int i = 0; i < cipher.length(); i++)
                  stringbuffer.append((char)((key.charAt(i % key.length()) - cipher.charAt(i)) + 54));

              System.out.println(stringbuffer.toString());
    }

    private static String key = "lockpickingisfun";
    private static String cipher = "?8hiyKT5fw*W^J~art3t.47i";
}

For less experienced Java programmers, it might be easier to reimplement the main function's functionality in Python:

cipher = "?8hiyKT5fw*W^J~art3t.47i"
key = "lockpickingisfun"

codeword = ""
for i in range(len(cipher)):
    codeword += chr(ord(key[i % len(key)]) - ord(cipher[i]) +  54)

print codeword
python2 08.py
  cm18-TEl9-sHKR-C01f-xkb8

09 - Meow!

Can you lure the cat out of the hiding place?
pdfimages -all meow.pdf out

The first image (out-000.jpg) contains the flag.

out-000.jpg

Don't worry if you cannot read it, it's not your fault. The flag is actually:

cm18-cxJg-MB4M-Q9E3-ZYlC

with the second last letter being a lower case ell.

10 - Chest

Can you find the flag inside of the chest?
wget https://codemash.hacking-lab.com/codemash/attachments/chest
file chest
  chest: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=5042299eb1d095cd4db443de65640c7073668114, not stripped

The file to examine is a x86-64 executable. Before actually running it, let's check if the flag appears in plain text.

strings chest | grep "cm18-"
  cm18-jNiO-bUon-ylon-flag
  cm18-eIdK-bUoC-orna-ment
  ...

Unfortunately, the binary contains a lot of canditates, 998 to be more precise.

strings chest | grep "cm18-" | wc -l
  998

Many of the canditates are very similar and differ only in a few letters. Let's try to sort them:

strings chest | grep "cm18-" | sort -u | less
  cm18-Ml2l-bUoC-vXXE-Fc8c
  cm18-bFaL-bUgo-lden-coin
  cm18-bFdG-bUgo-lden-coin
  cm18-bFgF-bUgo-lden-coin
  ...

The very first hit is unique within the chest and the searched flag.

cm18-Ml2l-bUoC-vXXE-Fc8c

11 - Bacon!

Get the bacon!

1000.zip

I'll skip this for now, be patient, I'll deliver an update, soon.

12 - On-site Challenge

The flag for this challenge can only be found onsite at the conference, in the location seen on top of the backside of the elephant, in this picture.

This challenge was on-site and I was, well, not on-sight.

13 - Alice

Follow the white rabbit.

The only usable information source on the website is an image of a white rabbit:

codemash2018_13_WhiteRabbit.jpg

Let's search for the image URL ...

codemash2018_13_SiteInfo.jpg

... and download the file.

wget https://codemash.hacking-lab.com/codemash/images/banner/challenge_13_2433.jpg

Then check the file for hidden data using binwalk:

binwalk challenge_13_2433.jpg

   DECIMAL       HEXADECIMAL     DESCRIPTION
   --------------------------------------------------------------------------------
   0             0x0             JPEG image data, JFIF standard 1.01
   382           0x17E           Copyright string: "Copyright (c) 1998 Hewlett-Packard Company"
   155385        0x25EF9         Zip archive data, at least v2.0 to extract, compressed size: 167065, uncompressed size: 167258, name: forest.jpg
   322518        0x4EBD6         Zip archive data, at least v2.0 to extract, compressed size: 139956, uncompressed size: 140213, name: meadow.jpg
   462542        0x70ECE         Zip archive data, at least v2.0 to extract, compressed size: 171261, uncompressed size: 171490, name: water.jpg
   634109        0x9ACFD         End of Zip archive

The image contains a .zip archive. binwalk can be used to extract it:

binwalk -e challenge_13_2433.jpg
cd _challenge_13_2433.jpg.extracted

The file contains three images:

  • forest.jpg
  • meadow.jpg
  • water.jpg
strings forest.jpg | head -n 3
  Exif
  2017:12:12 04:01:24
    This image has a protected secret.

strings meadow.jpg | head -n 3
  Exif
  2017:12:12 04:00:30
    This meadow is all dried out. Check the water first.

strings water.jpg | head -n 3
  Exif
  2017:12:12 03:58:52
    steghide was here. With an empty password

Steghide?

pacman -Ss steghide
  community/steghide 0.5.1-8
    Embeds a message in a file by replacing some of the least significant bits

Steghide is a program that can be used to hide data in various kinds of image- and audio-files. Let's install it...

su -c 'pacman -S steghide'

... and use it to extract the hidden data:

steghide extract -sf water.jpg
  Enter passphrase:
    wrote extracted data to "text.txt".

Let's finally view the content:

cat text.txt

  You search the whole place but you can't find anything.
  ...
  Now get out before you get flushed down

Ok, nothing here. Let's check the next file:

steghide extract -sf meadow.jpg
  Enter passphrase:
  the file "text.txt" does already exist. overwrite ? (y/n) y
  wrote extracted data to "text.txt".

And view its content:

cat text.txt
  So you think a mole can speak?!
  ...
  Lucky you, this one can!

  He's name is Fred and he tells you the passphrase:

  The-Mad-Hatter

Let's check the last file:

steghide extract -sf forest.jpg
  Enter passphrase: The-Mad-Hatter
  the file "text.txt" does already exist. overwrite ? (y/n) y
  wrote extracted data to "text.txt".

And finally:

cat text.txt
   Congratulations here is the flag!

   cm18-xZl2-eHC5-axW3-ZkZG

14 - Security Regulations

Due to some new privacy regulations this flag had to be shred. The classification will be secret or topsecret depending on the content.

____-____-____-____-____

Left over shred inside the paper shredder

Clicking the link leeds to a second website with the following URL:

https://codemash.hacking-lab.com/codemash/secret_challenge_shred1.html

Shred 1: Note: the other shreds are classified as <<topsecret>>!

cm18

Two simple changes to the URL lead to the second shred:

https://codemash.hacking-lab.com/codemash/topsecret_challenge_shred2.html

Shred 2

bWh0-VIkC

And one additional change to the third shred:

https://codemash.hacking-lab.com/codemash/topsecret_challenge_shred3.html

Shred 3

cMf4-72jY

The flag sums up to

cm18-bWh0-VIkC-cMf4-72jY

15 - P.A.L.M. Login

Folks at HOBO Authentication Systems implemented a new authentication system named P.A.L.M. Login

Prove that you can break it and find a pair of username and passcode to log on.

Login

codemash2018_15_checkEntries.png
function checkEntries()
{
    var u = document.getElementById('puser').value;
    var p = document.getElementById('ppass').value;
    var used = [0,0,0,0,0,0,0,0,0,0];
    var ok = false;
    if (u === 'cavs') {
        if (p > 0 && p.length == 10) {
            ok = true;
            for (i = 1; i <= 10; i++) {
                var digit = p.charAt(i-1);
                var part = p.substring(0, i);
                if (used[digit] != 0 || part % i != 0) {
                    ok = false
                }
                if (used[digit] == 0) {
                    used[digit] = 1
                }
            }
        }
    }
    if (ok) {
        document.location.href='palm_'+u+'_'+p+'.html'
    } else {
        alert('nope')
    }
}

The username is "cavs" and the password is a 10 digit number with the following characteristics:

  • Each digit appears only once (used[digit] != 0).
  • The first digit is divisible by 1 (part % i != 0).
  • The number build out of the first two digits is divisible by 2.
  • The number build out of the first three digits is divisible by 3.
  • The number build out of the first four digits is divisible by 4.
  • ...
  • The whole number is divisible by 10, so the last digit is 0.

A quick Google search with the search string The number build out of the first two digits is divisible by 2 is sufficiant:

3816547290

Providing cavs as username and 3816547290 as password reveals the flag:

cm18-zbIc-O4Zh-gmxl-r5J6

Reverse Engineering Remote Control Power Sockets - Part 3: Protocol analysis with SDR

Tooling

SDR

In the last blog post Part 2: Protocol analysis with oscilloscope, I used an oscilloscope to record the protocol send by the remote control. This time I'd like to show a cheaper approach to get to the same result. The DVB-T sticks supported by rtl-sdr are able to tune to the 433 MHz UHF band and can be used as a Software-defined radio (SDR). Using free software like Gqrx and Audacity, it's possible to fully reverse engineer the codewords send by the remote control's encoder chip. All needed information is already known from the blog post Part 1: Information gathering.

Record codeword with Gqrx

Gqrx is an excellent, easy to use, open source software defined radio receiver supporting rtl-sdr devices like the Noxon DAB Stick. See the list of Supported hardware to check if your device is supported.

Modulation

Readers interested in radio communication may have already noticed by reading the encoder datasheet, that all circuits showing UHF band data transmitters, implement an amplitude modulation (AM) modulator. The carrier frequency (433.92 MHz) can be found in the power outlet manual or on the remote control's backside.

Gqrx settings

Codeword 001

Gqrx can be used to record a complete remote control transmission to a .wav file. The recorded audio file can then be analyzed with Audacity. The output file gets stored to the home folder, the filename looks similar to gqrx_20170422_152940_433920000.wav. This file can now be opened by Audacity for analyzing the codeword.

Analyze codeword with Audacity

Audacity is a free, open source, cross-platform audio software. It can be used to view the demodulated codeword audio files generated by Gqrx.

Outlet group 0 | Outlet 0 | On

The following picture shows the recorded codeword for switching on outlet 0 within outlet group 0.

Codeword 001

Although the codeword seems to contain valid bit patterns, it is apparent that the first and the last bit (sync bit) look weird. A quick look into the decoder datasheet (PT2272) shows an inverting stage in the RF Application Circuit. Luckily, Audacity offers the possibility to just invert the audio track:

Effect -> Invert
Codeword 001

The first bit pattern still looks a little bit weird, but the rest of the codeword matches exactly the result we already know from Part 2: Protocol analysis with oscilloscope.

Group Outlet On/Off
FFFFF 0FFFF 0F

Damn Vulnerable Router Firmware - Hardware Bring-up

The Damn Vulnerable Router Firmware (DVRF) is a vulnerable firmware for Linksys E1550 routers. According to the author, "the goal of this project is to simulate a real world environment to help people learn about other CPU architectures outside of the x86_64 space."

Before overwriting the original firmware, make sure to get a copy of the most recent version: FW_E1550_1.0.03.002_US_20120201_code.bin.

DVLF can be installed to the Linksys E1550 by opening the device's firmware upgrade page.

UART connection

As stated in the project's README.md file, UART access is needed in order to execute the "pwnable" binaries. The UART pins are easily accessible after populating DJ12 with a 1x5 pin male header (2.54 mm spacing between pins).

Open Housing

housing

To avoid short-circuiting, remove the power plug before you open the housing!

The Linksys E1550 uses an external power supply so it was not designed with concern for hazardous voltages inside the enclosure. However, to avoid short-circuiting, remove the power plug before you open the housing!

To open the housing, remove the three screw covers on the back of the device. Please note that products with their warranty labels and barcodes removed or altered are not covered by the warranty any more.

The screws can be easily removed using a Phillips-tip screwdriver. After removal, use a special soft-plastic housing opening tool to lift the lid.

Attach Pin Header

pcb

The UART pins are located at DJ12, right above the Serial Flash IC (Winbond 25Q128BVFG). Use a solder iron to solder a 1x5 pin male header (2.54 mm spacing between pins) to DJ12.

Pinout

  • Pin1: 3.3 V
  • Pin2: Tx (Linksys E1550 transmits on this pin)
  • Pin3: Rx (Linksys E1550 receives on this pin)
  • Pin4: ?
  • Pin5: GND

Firmware Installation

Download DVRF

git clone https://github.com/praetorian-inc/DVRF.git
file DVRF/Firmware/DVRF_v03.bin
   DVRF/Firmware/DVRF_v03.bin: data

Install DVRF

Connect your PC to the Linksys E1550 via Ethernet. Your PC should get an IP address via DHCP, the default subnet is 192.168.1.0/24. Use your default browser to open the device's firmware upgrade page and upload file DVRF/Firmware/DVRF_v03.bin. The device will automatically reboot after the installation.

After the device rebooted, connect to the router's default page, you should see the following:

housing

Reverse Engineering Remote Control Power Sockets - Part 2: Protocol analysis with oscilloscope

Tooling

If you've read the first blog post of this series, you already know that the intention of this project is to replace the remote control of these devices by a cheap 433 MHz transceiver and a microcontroller platform. In order to do so, the protocol send by the remote control encoder chip PT2262, has to be imitated by the microcontroller. We already know from the previous blog post, that pushing one of the buttons of the remote control forces the PT2262 to create a unique codeword that is send to RF modulator. The datasheet:

The encoded waveform is serially outputted to this pin. When PT2262 is not transmitting, DOUT outputs low (Vss) voltage.

To be able to replace the remote control by an own circuit driven by a microcontroller, the special codeword for each button has to be determind.

Oscilloscope

Oscilloscope DOUT

Using an oscilloscope is the most comfortable way to reverse engineer the remote control protocol. A cheap one like the Rigol DS1052e is more than sufficient. Don't mind if you can't afford one, I will show a cheaper method to get behind the protocol in an upcoming blog post.

Connection

Connect your probe's ground clip to HX2262's pin 9 (VSS) and the probe tip to pin 17 (DOUT).

Rigol DS1052E settings

  • Long Memory (Acquire -> MemDepth -> Long Mem)
  • Single shot trigger

Determining the Oscillating Clock Period α

product info

We already know from the datasheet, that each bit waveform consists of two pulse cycles and each pulse cycle has 16 oscillating time periods. In the case of a Bit "0", one pulse cycle consists of four periods high and twelve periods low clock periods. This pattern can be easily found with the oszilloscope.

The picture on the left shows the overall time (2.62 ms) for a "0" bit:

\begin{equation*} \alpha = \frac{2620\,us}{2 * (4 + 12)} = 81.875\,us \end{equation*}
product info

The picture on the right shows the low part of the first pulse cycle (12 periods low bits) with a total time of 984 us:

\begin{equation*} \frac{984\,us}{12} = 82\,us \end{equation*}
product info

Given both results, we can asume the oscillating clock period α to be 82 us. According to the datasheet, α can be configured by a resistor connected between pins 15 (OSC 1) and 16 (OSC 2), so it might differ for other power outlets. It might be a good idea to not hardcode the value.

Another approach to determine α is to connect the probe tip to pin 15 (OSC 1) and to directly measure the oscillator frequency. The picture on the left shows one cycle duration of the oscillator frequency. The measured periodic time of 83.6 us fits our previously made assumption of 82 us.

Codeword analysis

A group of Code Bits is called a Code Word. A Code Word consists of 12 AD bits followed by one Sync Bit.
product info

In part 1 of this blog post series, we assumed that the first five bits encode the outlet group part of the codeword, the next five encode the socket within that group and the last two encode the on/off part. We can simply proof this assumption by just pressing the appropriate push-button on the remote control and displaying the waveform on the oscilloscope. A good starting point is to set all pins of the DIP switch (Code Address Pin 0 ~ 5) to off (outlet group 0) and press the on/off push-buttons for each outlet within that group.

The following sequence of images show one complete codeword for pushing the on and off buttons for different combinations of groups and outlets. Please notice that some signal changes overlap, just try to find the bit patterns that are already known from the datasheet. Each picture (except the last one) contains four bit patterns. This makes a summary of 12 AD bits followed by one sync bit. The codewords are then grouped together to their group (five bits), outlet (five bits) and data (two bits) parts.

Outlet group 0 | Outlet 0 | On

Pushing the on button for outlet 0 within group 0 leads to the following codeword:

product infoproduct infoproduct infoproduct info

Codeword: FFFF F0FF FF0F Sync

Group Outlet On/Off
FFFFF 0FFFF 0F

Outlet group 0 | Outlet 0 | Off

Pushing the off button for the same outlet (0) within the same group (0) leads to a very similar result. Solely the last two bits have changed.

product infoproduct infoproduct infoproduct info

Codeword: FFFF F0FF FFF0 Sync

Group Outlet On/Off
FFFFF 0FFFF F0

Outlet group 0 | Outlet 1 | On

The next image series shows the result for pushing the on button for outlet 1 within group 0. This time, the outlet part of the codeword has changed while the group part is still the same.

product infoproduct infoproduct infoproduct info

Codeword: FFFF FF0F FF0F Sync

Group Outlet On/Off
FFFFF F0FFF 0F

Outlet group 1 | Outlet 0 | On

Setting the first DIP switch to "on" and pressing the on button for socket 0 again, leads to another codeword. This time, the first bit group has changed.

product infoproduct infoproduct infoproduct info

Codeword: 0FFF F0FF FF0F Sync

Group Outlet On/Off
0FFFF 0FFFF 0F

Outlet group 31 | Outlet 0 | On

The last image series shows the codeword for the following setup: All remote control DIP switches are set to on (group 31) and the on button for outlet 0 has been pushed.

product infoproduct infoproduct infoproduct info

Codeword: 0000 00FF FF0F Sync

Group Outlet On/Off
00000 0FFFF 0F

Determining all codeword combinations is now either a question of diligence or just a riddle. One could just configure all possible group DIP switch settings, push all buttons and record all codewords with the oscilloscope. However, a more sophisticated approach would be to find the relationship between DIP switch settings and button presses by the already given information.

Conclusion

The assumtions made in part 1 of this series seem to be correct. One codeword consists of five bits for the outlet group, five bits for the outlet within that group and two bits for the on/off part of the codeword.

The timebase for the codeword (Oscillating Clock Period α) was measured with the oscilloscope and seems to be around 82 us.

Reverse Engineering Remote Control Power Sockets - Part 1: Information gathering

Tooling

  • Phillips-tip screwdriver
  • Computer with internet access
  • Multimeter (optional)

Remote control

product info

According to the information on the back, the remote control sends on 433.92 MHz, a frequency within the UHF band. The 433 MHz band is meant for short range consumer devices including automotive, alarm systems, home automation and temperature sensors.

Open housing

To avoid short-circuiting, remove the 12 V battery, then remove the three screws using a Phillips-tip screwdriver. When the srews are removed, you can easily lift the housing and remove the printed circuit board (PCB).

Printed circuit board

product info

There are only a few components placed on the PCB, the most interesting ones can be found on the top layer:

  • Battery holder
  • DIP switch
  • Integrated circuit (IC) in 18 pin dual in-line (DIP) package, labeled with HX2262
  • Contacts for push-buttons
  • 433 MHz oscillator
  • Light-emitting diode (LED)

Ignore the yellow dot added to the picture of the PCB's top layer at the moment, we'll come back to it later.

Remote Control Encoder

An internet search for HX2262 quickly leads to the IC's datasheet. The IC HX2262 (PT2262) is a Remote Control Encoder and can be paired with PT2272, the suitable Remote Control Decoder.

PT2262's purpose is quickly explained:

PT2262 encodes the code address and data set at A0 ~ A5 and A6/D5 ~ A11/D0 into a special waveform and outputs it to the DOUT when TE is pulled to 0 (Low State). This waveform is fed to the RF modulator for transmission. The transmitted radio frequency RF demodulator and reshaped to the special waveform. PT2272 is then used to decode the waveform and set the corresponding output pin(s). Thus completing a remote control encoding and decoding function.

Data Output Pin (DOUT)

All connections of the pins described later on have only one purpose, to influence the behaviour of pin 17, the Data Output Pin (DOUT).

The encoded waveform is serially outputted to this pin. When PT2262 is not transmitting, DOUT outputs low (Vss) voltage.

We already know from the Remote Control Encode description, that DOUT's output is fed into the RF modulator and send to the power plug. The lazy reader might stop reading at this point. The whole magic happens on DOUT as will be described in a future post.

Code Address Pin Group

product info

From the power plug manual, we already know that the DIP switch is used to control a specific outlet group and the push-buttons are used to control four outlets within that group. Using a multimeter in continuity test mode or just looking at the connections on the bottom layer shows, that five pins of the DIP switch are directly connected to the bottom layer polygone plane. The polygone plane is directly connected to the negative pole of the battery holder (GND).

The remaining five pins are directly connected to pins 1 to 5 of the HX2262 (red dots on bottom layer picture):

  • DIP switch Pin 1 <--> PT2261 Pin 1 (A0)
  • DIP switch Pin 2 <--> PT2261 Pin 2 (A1)
  • DIP switch Pin 3 <--> PT2261 Pin 3 (A2)
  • DIP switch Pin 4 <--> PT2261 Pin 4 (A3)
  • DIP switch Pin 5 <--> PT2261 Pin 5 (A4)

According to the datasheet, pins 1 to 5 belong to the Code Address Pin group (A0 ~ A5):

Code Address Pin 0 ~ 5: These six tri-state pins are detected by PT2262 to determine the encoded waveform bit 0 ~ bit 5. Each pin can be set to 0, 1 or f (floating).
R04

Taking a look at the bottom layer again shows that PT2262's pins 6, 7, 8 and 10 are connected to vias in the middle of the PCB (yellow dots). Together with pin 11 (yellow dot on the top layer picture), those pins are all connected to push-button contacts.

The description for pins 6, 7, 8, 10 and 11 states that those pins are named A6/D5 ~ A11/D0 and belong to the Code Address Pin group as well.

Code Address Pin 6 ~ 11 / Data Pin 5 ~ 0. These six tri-state pins are detected by PT2262 to determine the encoded waveform bit 6 ~ bit 11. When these pins are used as address pins, they can be set to 0, 1, or f (floating). When these pins are used as data pins, they can be set only to 0 or 1.

Since those pins are directly connected to the push-buttons, it is most likely that they are used as data pins for setting a power plug either on or off.

RF operation: Code bits

product info

A code bit is the basic component of the encoded waveform, and can be classified as either an AD (address/data) bit or a sync (synchronous) bit. The PT2262 protocol knows three different AD bits:

  • Bit "0"
  • Bit "1"
  • Bit "f" (floating)

A group of code bits is called a code word. A code word consists of 12 AD bits followed by one sync bit.

The time base for all code bits is the so called Oscillating Clock Period (α). To be able to create the codewords with a microcontroller, it is necessary to know α. The simplest way to get the Oscillating Clock Period is to connect an oscilloscope to the DOUT pin, search for a known bit pattern ("0", "1" or "f") and just measure the time for that pattern.

Signal Resistor Oscillator

R04

The PT2262 has a built-in oscillator circuitry that can be configured with a resistor connected between pins 15 (OSC1) and 16 (OSC2). Taking a look at the bottom layer shows that the respective resistor is R04. The SMD resistor code "335" indicates the numerical resistance value of 3.3 MΩ, a value suggested by the datasheet.

Osc

The Signal Resistor Oscillator directly affects the DOUT carrier frequency. The datasheet includes a diagram showing the relationship between R04 and the encoder oscillator frequency. For the resistor value of 3.3 MΩ, the frequency amounts to approximately 10 kHz.

Schematics

As stated before, all relevant information, needed to reverse engineer the protocol send by the remote control, is already known. However, the nosy reader may want to grab a multimeter in continuity test mode to reverse engineer the functionality of the push-buttons and the DIP switch.

product info
  • As stated before, one pin row of the DIP switch is directly connected to GND. The other row is connected to PT2262's pins A0 to A4. The DIP switch is used to configure the outlet group part of the code word send out by the DOUT pin.
  • Pin A10 is pulled high by R03 by default. Pushing one of the ON buttons pulls the pin to GND. Pin A10 encodes the ON information part of the codeword.
  • Pin A11 is pulled high by R01 by default. Pushing one of the OFF buttons pulls the pin to GND. Pin A11 encodes the OFF information part of the codeword.
  • One of the three contacts of each push-button pair is connected to one of PT2262'S pins A5 to A8:
    • Push-buttons A: A5
    • Push-buttons B: A6
    • Push-buttons C: A7
    • Push-buttons D: A8
  • The low-active Transmission Enable (/TE) pin is pulled high by R02 normally. Pushing one of the buttons brings the corresponding diode in its conductive state and pulls /TE towards GND. PT2262 starts to output the encoded waveform to DOUT.

Reverse Engineering Remote Control Power Sockets

pollin frontpollin back

For about 13 EUR, the German electronics dispatcher Pollin sells remote controlled power plugs that can be used as kind of a poor man's home automation system. Four plugs can be grouped together and switched on or off by a remote control.

Inspired by an article in the German c't Hacks magazine (3/2012), the following series of post will guide through a reverse engineering process with the intention to replace the remote control in two different ways. The first approach uses an Andoid smartphone connected to a Raspberry Pi via WiFi, the second one makes use of a STM32F0DISCOVERY. Both microcontroller platforms make use of a cheap 433 MHz transceiver ordered in China. If you plan to rebuild one of the projects, make sure to order right now, the shipping from China may take weeks to month.

In case of the Raspberry Pi, two approaches will be described, one in userspace and one in kernel space. The kernel space approach comes in form of a Linux Kernel Module (LKM) and hides the fact that the Raspberry Pi normally is not capable of fulfilling realtime tasks.

Tooling

In order to follow the articles, or to rebuild one of the projects, you'll need the following items:

  • Raspberry Pi and Android smartphone or
  • STM32F0DISCOVERY
  • 433 MHz transceiver (e.g. from ebay)
  • Multimeter (optional, e.g UNI-T UT61C)
  • Oscilloscope (e.g. RIGOL DS1052E) or
  • Software-defined radio supported by rtl-sdr (e.g. Noxon DAB Stick)
  • Phillips-tip screwdriver

Fix PlayStation 2 not reading discs

Open housing

product info

To avoid short-circuiting, remove the power plug before you open the housing!

The PlayStation 2 (PS 2) uses an external power supply so it was not designed with concern for hazardous voltages inside the enclosure. However, to avoid short-circuiting, remove the power plug before you open the housing!

To open the housing, remove the five screw covers on the back of the PS 2. One of the screw covers is hidden behind the guarantee sticker. Please note that products with their warranty labels and barcodes removed or altered are not covered by the warranty any more.

The screws can be easily removed using a Phillips-tip screwdriver. After removal, use a special soft-plastic housing opening tool to lift the lid.

Clean-up

Clean housing

After removing the housing, use a slightly damp cloth to clean the inside of the PS 2.

Let the device dry for several hours in order to avoid a short-circuiting.

Clean laser lens

lense

Never look into the lens!

Avoid touching the lens or some of the fat from your fingers will stick on it. Use a clean cotton bud, dip it into denatured alcohol (methylated spirits) and gently clean the lens. It should appear completely clean.

Check DVD drive motors

  • Never look into the laser beam inside the PS 2!
power_plug

The DVD reader has two motors, one to spin the DVD (left rectangle) and one to move the laser unit (right rectangle) back and forth. Obviously, both motors have to work properly to guarantee an error-free operation of the DVD drive. A special safety mechanism avoids motor spinning while the cover is removed.

Put a DVD into the PS 2 (onto the spindle) and attach the power plug. Inserting a DVD has two advantages, the DVD will cover the laser and it will be easier to check if the DVD motor is spinning. The red LED should indicate that the PlayStation 2 is powered properly.

power_plug

Push the power button (see picture on the right) to power up the PS 2. As usal, the green status LED should indicate the device start-up.

Notice the small black push-botton on the top of the power button PCB. It gets pushed when the DVD tray gets closed.

front push-button

As noted before, a special safety mechanism avoids motor spinning while the cover is removed. The safety mechanism consists of two push-buttons, one on the top of the power button PCB (left picture) and one on the mainboard (right picture). Both buttons normaly get pushed when the DVD tray gets closes. To be able to check if the motors work properly, the buttons have to be pushed manually. Press and hold both buttons simultaneously. The DVD should start spinning and the optical unit containing the laser should start moving.

mainboard push-button

If both motors do not start to spin, remove the power plug and use the continuity test mode of your digital multimeter to check both switches. If both are working correctly, your housing might be the problem. Check if one of the plastic pins (pushing the buttons when you close the housing) is broken. If one of the pins is broken, you may want to either fix it (glue) or just short-circuit the corresponding push-button.

Send SMS from Python on the Nokia N900

The script

The following Python script can be used to send a SMS on the Nokia N900.

#!/usr/bin/python

import pexpect # Python module for controlling other programms.
import time
import sys
from subprocess import * # Pyton module for spwaning new processes.

tmp  = raw_input("Enter mobile number:\n");
tmp = tmp.rstrip('\n')

if (tmp[0] == tmp[1] == "0"):
    number = tmp
elif (tmp[0] == "0" ) and (tmp[1] != "0"):
    number = "+49"+tmp[1:]
else:
    print "[-] This does not seem to be a mobile phone number. "
    sys.exit()

string = 'at+cmgs='+"\""+number+"\""+'\r'
string = string.rstrip('\n')

#print string
Message = raw_input("Enter text:\n")

child = pexpect.spawn('pnatd');
child.send('at\r');
time.sleep(0.25);
child.send('at+cmgf=1\r');
time.sleep(0.25);
child.send(string);
child.send(Message);
child.send(chr(26));
child.send(chr(26));
child.sendeof();

Issues

'module' object has no attribute 'GPSDControl'

The Python script name shall not be 'location.py' otherwise the interpreter will fail with the following error message:

Traceback (most recent call last):
File "location.py", line 1, in <module>
import location
File "/home/user/location.py", line 25, in <module>
control = location.GPSDControl.get_default()
AttributeError: 'module' object has no attribute 'GPSDControl'