Go make some posts http://35.207.83.242/ Hint: flag is in db Hint2: the lovely XSS is part ofthe beautiful design and insignificant forthe challenge Hint3: You probably want togetthe source code, luckily for you it's rather hard to configure nginx correctly.
server { listen80; access_log /var/log/nginx/example.log;
server_name localhost;
root /var/www/html;
location /uploads { autoindexon; alias /var/www/uploads/; }
location / { alias /var/www/html/; index index.php;
location~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php7.2-fpm.sock; } }
location /inc/ { deny all; } }
server { listen127.0.0.1:8080; access_log /var/log/nginx/proxy.log;
if ( $request_method !~ ^(GET)$ ) { return405; } root /var/www/miniProxy; location / { index index.php;
location~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php7.2-fpm.sock; } } }
下载下来所有的代码,进行审计
0x2 post服务的任意类伪造
先下载下来 html 目录post服务的代码,发现基本功能如下:
1.创建post的功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#filename:default.php
if (isset($_POST["title"])) { $attachments = array(); if (isset($_FILES["attach"]) && is_array($_FILES["attach"])) { $folder = sha1(random_bytes(10)); mkdir("../uploads/$folder"); for ($i = 0; $i < count($_FILES["attach"]["tmp_name"]); $i++) { if ($_FILES["attach"]["error"][$i] !== 0) continue; $name = basename($_FILES["attach"]["name"][$i]); move_uploaded_file($_FILES["attach"]["tmp_name"][$i], "../uploads/$folder/$name"); $attachments[] = new Attachment("/uploads/$folder/$name"); } } $post = new Post($_POST["title"], $_POST["content"], $attachments); $post->save(); }
2.显示post的功能
1 2 3 4 5 6 7 8 9 10 11 12 13
#filename:default.php
$posts = Post::loadall(); if (empty($posts)) { echo"<b>You do not have any posts. Create <a href=\"/?action=create\">some</a>!</b>"; } else { echo"<b>You have " . count($posts) ." posts. Create <a href=\"/?action=create\">some</a> more if you want! Or <a href=\"/?action=restart\">restart your blog</a>.</b>"; }
foreach($posts as $p) { echo $p; echo"<br><br>"; }
publicfunctionsave(){ global $USER; if (is_null($this->id)) { DB::insert("INSERT INTO posts (userid, title, content, attachment) VALUES (?,?,?,?)", array($USER->uid, $this->title, $this->content, $this->attachment)); } else { DB::query("UPDATE posts SET title = ?, content = ?, attachment = ? WHERE userid = ? AND id = ?", array($this->title, $this->content, $this->attachment, $USER->uid, $this->id)); } }
publicstaticfunctiontruncate(){ global $USER; DB::query("DELETE FROM posts WHERE userid = ?", array($USER->uid)); }
publicstaticfunctionload($id){ global $USER; $res = DB::query("SELECT * FROM posts WHERE userid = ? AND id = ?", array($USER->uid, $id)); if (!$res) die("db error"); $res = $res[0]; $post = new Post($res["title"], $res["content"], $res["attachment"]); $post->id = $id; return $post; }
publicstaticfunctionloadall(){ global $USER; $result = array(); $posts = DB::query("SELECT id FROM posts WHERE userid = ? ORDER BY id DESC", array($USER->uid)) ; if (!$posts) return $result; foreach ($posts as $p) { $result[] = Post::load($p["id"]); } return $result; }
#filename:post.php publicstaticfunctionload($id){ global $USER; $res = DB::query("SELECT * FROM posts WHERE userid = ? AND id = ?", array($USER->uid, $id)); if (!$res) die("db error"); $res = $res[0]; $post = new Post($res["title"], $res["content"], $res["attachment"]); $post->id = $id; return $post; }
publicstaticfunctionloadall(){ global $USER; $result = array(); $posts = DB::query("SELECT id FROM posts WHERE userid = ? ORDER BY id DESC", array($USER->uid)) ; if (!$posts) return $result; foreach ($posts as $p) { $result[] = Post::load($p["id"]); } return $result; }
privatestaticfunctionprepare_params($params){ return array_map(function($x){ if (is_object($x) or is_array($x)) { return'$serializedobject$' . serialize($x); }
if (preg_match('/^\$serializedobject\$/i', $x)) { die("invalid data"); return""; }
return $x; }, $params); }
看了官方的WP,才知道这里有个小trick:
Luckily, MSSQL automatically converts full-width unicode characters to their ASCII representation. For example, if a string contains 0xEF 0xBC 0x84, it will be stored as $.
if (isset($_POST["miniProxyFormAction"])) { $url = $_POST["miniProxyFormAction"]; unset($_POST["miniProxyFormAction"]); } else { $queryParams = Array(); parse_str($_SERVER["QUERY_STRING"], $queryParams); //If the miniProxyFormAction field appears in the query string, make $url start with its value, and rebuild the the query string without it. if (isset($queryParams["miniProxyFormAction"])) { $formAction = $queryParams["miniProxyFormAction"]; unset($queryParams["miniProxyFormAction"]); $url = $formAction . "?" . http_build_query($queryParams); } else { $url = substr($_SERVER["REQUEST_URI"], strlen($_SERVER["SCRIPT_NAME"]) + 1); } }